drm-misc-next for v5.3, try #2: UAPI Changes: - Add HDR source metadata property. - Make drm.h compile on GNU/kFreeBSD by including stdint.h - Clarify how the userspace reviewer has to review new kernel UAPI. - Clarify that for using new UAPI, merging to drm-next or drm-misc-next should be enough. Cross-subsystem Changes: - video/hdmi: Add unpack function for DRM infoframes. - Device tree bindings: * Updating a property for Mali Midgard GPUs * Updating a property for STM32 DSI panel * Adding support for FriendlyELEC HD702E 800x1280 panel * Adding support for Evervision VGG804821 800x480 5.0" WVGA TFT panel * Adding support for the EDT ET035012DM6 3.5" 320x240 QVGA 24-bit RGB TFT. * Adding support for Three Five displays TFC S9700RTWV43TR-01B 800x480 panel with resistive touch found on TI's AM335X-EVM. * Adding support for EDT ETM0430G0DH6 480x272 panel. - Add OSD101T2587-53TS driver with DT bindings. - Add Samsung S6E63M0 panel driver with DT bindings. - Add VXT VL050-8048NT-C01 800x480 panel with DT bindings. - Dma-buf: - Make mmap callback actually optional. - Documentation updates. - Fix debugfs refcount inbalance. - Remove unused sync_dump function. - Fix device tree bindings in drm-misc-next after a botched merge. Core Changes: - Add support for HDR infoframes and related EDID parsing. - Remove prime sg_table caching, now done inside dma-buf. - Add shiny new drm_gem_vram helpers for simple VRAM drivers; with some fixes to the new API on top. - Small fix to job cleanup without timeout handler. - Documentation fixes to drm_fourcc. - Replace lookups of drm_format with struct drm_format_info; remove functions that become obsolete by this conversion. - Remove double include in bridge/panel.c and some drivers. - Remove drmP.h include from drm/edid and drm/dp. - Fix null pointer deref in drm_fb_helper_hotplug_event(). - Remove most members from drm_fb_helper_crtc, only mode_set is kept. - Remove race of fb helpers with userspace; only restore mode when userspace is not master. - Move legacy setup from drm_file.c to drm_legacy_misc.c - Rework scheduler job destruction. - drm/bus was removed, remove from TODO. - Add __drm_atomic_helper_crtc_reset() to subclass crtc_state, and convert some drivers to use it (conversion is not complete yet). - Bump vblank timeout wait to 100 ms for atomic. - Docbook fix for drm_hdmi_infoframe_set_hdr_metadata. Driver Changes: - sun4i: Use DRM_GEM_CMA_VMAP_DRIVER_OPS instead of definining manually. - v3d: Small cleanups, adding support for compute shaders, reservation/synchronization fixes and job management refactoring, fixes MMU and debugfs. - lima: Fix null pointer in irq handler on startup, set default timeout for scheduled jobs. - stm/ltdc: Assorted fixes and adding FB modifier support. - amdgpu: Avoid hw reset if guilty job was already signaled. - virtio: Add seqno to fences, add trace events, use correct flags for fence allocation. - Convert AST, bochs, mgag200, vboxvideo, hisilicon to the new drm_gem_vram API. - sun6i_mipi_dsi: Support DSI GENERIC_SHORT_WRITE_2 transfers. - bochs: Small fix to use PTR_RET_OR_ZERO and driver unload. - gma500: header fixes - cirrus: Remove unused files. - mediatek: Fix compiler warning after merging the HDR series. - vc4: Rework binner bo handling. Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -6,6 +6,22 @@ Display bindings for EDT Display Technology Corp. Displays which are · 5 unmodified lines | |||
| 6 | compatible with the simple-panel binding, which is specified in | 6 | compatible with the simple-panel binding, which is specified in |
| 7 | simple-panel.txt | 7 | simple-panel.txt |
| 8 | 8 | ||
| 9 | 3,5" QVGA TFT Panels | ||
| 10 | -------------------- | ||
| 11 | +-----------------+---------------------+-------------------------------------+ | ||
| 12 | | Identifier | compatbile | description | | ||
| 13 | +=================+=====================+=====================================+ | ||
| 14 | | ET035012DM6 | edt,et035012dm6 | 3.5" QVGA TFT LCD panel | | ||
| 15 | +-----------------+---------------------+-------------------------------------+ | ||
| 16 | |||
| 17 | 4,3" WVGA TFT Panels | ||
| 18 | -------------------- | ||
| 19 | |||
| 20 | +-----------------+---------------------+-------------------------------------+ | ||
| 21 | | Identifier | compatbile | description | | ||
| 22 | +=================+=====================+=====================================+ | ||
| 23 | | ETM0430G0DH6 | edt,etm0430g0dh6 | 480x272 TFT Display | | ||
| 24 | +-----------------+---------------------+-------------------------------------+ | ||
| 9 | 25 | ||
| 10 | 5,7" WVGA TFT Panels | 26 | 5,7" WVGA TFT Panels |
| 11 | -------------------- | 27 | -------------------- |
| @@ -0,0 +1,12 @@ | |||
| 1 | Evervision Electronics Co. Ltd. VGG804821 5.0" WVGA TFT LCD Panel | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: should be "evervision,vgg804821" | ||
| 5 | - power-supply: See simple-panel.txt | ||
| 6 | |||
| 7 | Optional properties: | ||
| 8 | - backlight: See simple-panel.txt | ||
| 9 | - enable-gpios: See simple-panel.txt | ||
| 10 | |||
| 11 | This binding is compatible with the simple-panel binding, which is specified | ||
| 12 | in simple-panel.txt in this directory. | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | FriendlyELEC HD702E 800x1280 LCD panel | ||
| 2 | |||
| 3 | HD702E lcd is FriendlyELEC developed eDP LCD panel with 800x1280 | ||
| 4 | resolution. It has built in Goodix, GT9271 captive touchscreen | ||
| 5 | with backlight adjustable via PWM. | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | - compatible: should be "friendlyarm,hd702e" | ||
| 9 | - power-supply: regulator to provide the supply voltage | ||
| 10 | |||
| 11 | Optional properties: | ||
| 12 | - backlight: phandle of the backlight device attached to the panel | ||
| 13 | |||
| 14 | Optional nodes: | ||
| 15 | - Video port for LCD panel input. | ||
| 16 | |||
| 17 | This binding is compatible with the simple-panel binding, which is specified | ||
| 18 | in simple-panel.txt in this directory. | ||
| 19 | |||
| 20 | Example: | ||
| 21 | |||
| 22 | panel { | ||
| 23 | compatible ="friendlyarm,hd702e", "simple-panel"; | ||
| 24 | backlight = <&backlight>; | ||
| 25 | power-supply = <&vcc3v3_sys>; | ||
| 26 | |||
| 27 | port { | ||
| 28 | panel_in_edp: endpoint { | ||
| 29 | remote-endpoint = <&edp_out_panel>; | ||
| 30 | }; | ||
| 31 | }; | ||
| 32 | }; | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: should be "osddisplays,osd101t2045-53ts" | ||
| 5 | - power-supply: as specified in the base binding | ||
| 6 | |||
| 7 | Optional properties: | ||
| 8 | - backlight: as specified in the base binding | ||
| 9 | |||
| 10 | This binding is compatible with the simple-panel binding, which is specified | ||
| 11 | in simple-panel.txt in this directory. | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | One Stop Displays OSD101T2587-53TS 10.1" 1920x1200 panel | ||
| 2 | |||
| 3 | The panel is similar to OSD101T2045-53TS, but it needs additional | ||
| 4 | MIPI_DSI_TURN_ON_PERIPHERAL message from the host. | ||
| 5 | |||
| 6 | Required properties: | ||
| 7 | - compatible: should be "osddisplays,osd101t2587-53ts" | ||
| 8 | - power-supply: as specified in the base binding | ||
| 9 | |||
| 10 | Optional properties: | ||
| 11 | - backlight: as specified in the base binding | ||
| 12 | |||
| 13 | This binding is compatible with the simple-panel binding, which is specified | ||
| 14 | in simple-panel.txt in this directory. | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | Samsung s6e63m0 AMOLED LCD panel | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "samsung,s6e63m0" | ||
| 5 | - reset-gpios: GPIO spec for reset pin | ||
| 6 | - vdd3-supply: VDD regulator | ||
| 7 | - vci-supply: VCI regulator | ||
| 8 | |||
| 9 | The panel must obey rules for SPI slave device specified in document [1]. | ||
| 10 | |||
| 11 | The device node can contain one 'port' child node with one child | ||
| 12 | 'endpoint' node, according to the bindings defined in [2]. This | ||
| 13 | node should describe panel's video bus. | ||
| 14 | |||
| 15 | [1]: Documentation/devicetree/bindings/spi/spi-bus.txt | ||
| 16 | [2]: Documentation/devicetree/bindings/media/video-interfaces.txt | ||
| 17 | |||
| 18 | Example: | ||
| 19 | |||
| 20 | s6e63m0: display@0 { | ||
| 21 | compatible = "samsung,s6e63m0"; | ||
| 22 | reg = <0>; | ||
| 23 | reset-gpio = <&mp05 5 1>; | ||
| 24 | vdd3-supply = <&ldo12_reg>; | ||
| 25 | vci-supply = <&ldo11_reg>; | ||
| 26 | spi-max-frequency = <1200000>; | ||
| 27 | |||
| 28 | port { | ||
| 29 | lcd_ep: endpoint { | ||
| 30 | remote-endpoint = <&fimd_ep>; | ||
| 31 | }; | ||
| 32 | }; | ||
| 33 | }; | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | TFC S9700RTWV43TR-01B 7" Three Five Corp 800x480 LCD panel with | ||
| 2 | resistive touch | ||
| 3 | |||
| 4 | The panel is found on TI AM335x-evm. | ||
| 5 | |||
| 6 | Required properties: | ||
| 7 | - compatible: should be "tfc,s9700rtwv43tr-01b" | ||
| 8 | - power-supply: See panel-common.txt | ||
| 9 | |||
| 10 | Optional properties: | ||
| 11 | - enable-gpios: GPIO pin to enable or disable the panel, if there is one | ||
| 12 | - backlight: phandle of the backlight device attached to the panel | ||
| 13 | |||
| 14 | This binding is compatible with the simple-panel binding, which is specified | ||
| 15 | in simple-panel.txt in this directory. | ||
| @@ -0,0 +1,12 @@ | |||
| 1 | VXT 800x480 color TFT LCD panel | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: should be "vxt,vl050-8048nt-c01" | ||
| 5 | - power-supply: as specified in the base binding | ||
| 6 | |||
| 7 | Optional properties: | ||
| 8 | - backlight: as specified in the base binding | ||
| 9 | - enable-gpios: as specified in the base binding | ||
| 10 | |||
| 11 | This binding is compatible with the simple-panel binding, which is specified | ||
| 12 | in simple-panel.txt in this directory. | ||
| @@ -40,6 +40,8 @@ Mandatory nodes specific to STM32 DSI: · 39 unmodified lines | |||
| 40 | - panel or bridge node: A node containing the panel or bridge description as | 40 | - panel or bridge node: A node containing the panel or bridge description as |
| 41 | documented in [6]. | 41 | documented in [6]. |
| 42 | - port: panel or bridge port node, connected to the DSI output port (port@1). | 42 | - port: panel or bridge port node, connected to the DSI output port (port@1). |
| 43 | Optional properties: | ||
| 44 | - phy-dsi-supply: phandle of the regulator that provides the supply voltage. | ||
| 43 | 45 | ||
| 44 | Note: You can find more documentation in the following references | 46 | Note: You can find more documentation in the following references |
| 45 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt | 47 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt |
| @@ -101,6 +103,7 @@ Example 2: DSI panel · 55 unmodified lines | |||
| 101 | clock-names = "pclk", "ref"; | 103 | clock-names = "pclk", "ref"; |
| 102 | resets = <&rcc STM32F4_APB2_RESET(DSI)>; | 104 | resets = <&rcc STM32F4_APB2_RESET(DSI)>; |
| 103 | reset-names = "apb"; | 105 | reset-names = "apb"; |
| 106 | phy-dsi-supply = <®18>; | ||
| 104 | 107 | ||
| 105 | ports { | 108 | ports { |
| 106 | #address-cells = <1>; | 109 | #address-cells = <1>; |
| @@ -15,6 +15,7 @@ Required properties: · 14 unmodified lines | |||
| 15 | + "arm,mali-t860" | 15 | + "arm,mali-t860" |
| 16 | + "arm,mali-t880" | 16 | + "arm,mali-t880" |
| 17 | * which must be preceded by one of the following vendor specifics: | 17 | * which must be preceded by one of the following vendor specifics: |
| 18 | + "allwinner,sun50i-h6-mali" | ||
| 18 | + "amlogic,meson-gxm-mali" | 19 | + "amlogic,meson-gxm-mali" |
| 19 | + "rockchip,rk3288-mali" | 20 | + "rockchip,rk3288-mali" |
| 20 | + "rockchip,rk3399-mali" | 21 | + "rockchip,rk3399-mali" |
| @@ -31,21 +32,36 @@ Optional properties: · 10 unmodified lines | |||
| 31 | 32 | ||
| 32 | - clocks : Phandle to clock for the Mali Midgard device. | 33 | - clocks : Phandle to clock for the Mali Midgard device. |
| 33 | 34 | ||
| 35 | - clock-names : Specify the names of the clocks specified in clocks | ||
| 36 | when multiple clocks are present. | ||
| 37 | * core: clock driving the GPU itself (When only one clock is present, | ||
| 38 | assume it's this clock.) | ||
| 39 | * bus: bus clock for the GPU | ||
| 40 | |||
| 34 | - mali-supply : Phandle to regulator for the Mali device. Refer to | 41 | - mali-supply : Phandle to regulator for the Mali device. Refer to |
| 35 | Documentation/devicetree/bindings/regulator/regulator.txt for details. | 42 | Documentation/devicetree/bindings/regulator/regulator.txt for details. |
| 36 | 43 | ||
| 37 | - operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt | 44 | - operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt |
| 38 | for details. | 45 | for details. |
| 39 | 46 | ||
| 47 | - #cooling-cells: Refer to Documentation/devicetree/bindings/thermal/thermal.txt | ||
| 48 | for details. | ||
| 49 | |||
| 40 | - resets : Phandle of the GPU reset line. | 50 | - resets : Phandle of the GPU reset line. |
| 41 | 51 | ||
| 42 | Vendor-specific bindings | 52 | Vendor-specific bindings |
| 43 | ------------------------ | 53 | ------------------------ |
| 44 | 54 | ||
| 45 | The Mali GPU is integrated very differently from one SoC to | 55 | The Mali GPU is integrated very differently from one SoC to |
| 46 | another. In order to accomodate those differences, you have the option | 56 | another. In order to accommodate those differences, you have the option |
| 47 | to specify one more vendor-specific compatible, among: | 57 | to specify one more vendor-specific compatible, among: |
| 48 | 58 | ||
| 59 | - "allwinner,sun50i-h6-mali" | ||
| 60 | Required properties: | ||
| 61 | - clocks : phandles to core and bus clocks | ||
| 62 | - clock-names : must contain "core" and "bus" | ||
| 63 | - resets: phandle to GPU reset line | ||
| 64 | |||
| 49 | - "amlogic,meson-gxm-mali" | 65 | - "amlogic,meson-gxm-mali" |
| 50 | Required properties: | 66 | Required properties: |
| 51 | - resets : Should contain phandles of : | 67 | - resets : Should contain phandles of : |
| @@ -65,6 +81,7 @@ gpu@ffa30000 { · 13 unmodified lines | |||
| 65 | mali-supply = <&vdd_gpu>; | 81 | mali-supply = <&vdd_gpu>; |
| 66 | operating-points-v2 = <&gpu_opp_table>; | 82 | operating-points-v2 = <&gpu_opp_table>; |
| 67 | power-domains = <&power RK3288_PD_GPU>; | 83 | power-domains = <&power RK3288_PD_GPU>; |
| 84 | #cooling-cells = <2>; | ||
| 68 | }; | 85 | }; |
| 69 | 86 | ||
| 70 | gpu_opp_table: opp_table0 { | 87 | gpu_opp_table: opp_table0 { |
| @@ -287,6 +287,8 @@ patternProperties: · 286 unmodified lines | |||
| 287 | description: Everest Semiconductor Co. Ltd. | 287 | description: Everest Semiconductor Co. Ltd. |
| 288 | "^everspin,.*": | 288 | "^everspin,.*": |
| 289 | description: Everspin Technologies, Inc. | 289 | description: Everspin Technologies, Inc. |
| 290 | "^evervision,.*": | ||
| 291 | description: Evervision Electronics Co. Ltd. | ||
| 290 | "^exar,.*": | 292 | "^exar,.*": |
| 291 | description: Exar Corporation | 293 | description: Exar Corporation |
| 292 | "^excito,.*": | 294 | "^excito,.*": |
| @@ -849,6 +851,8 @@ patternProperties: · 556 unmodified lines | |||
| 849 | description: Shenzhen Techstar Electronics Co., Ltd. | 851 | description: Shenzhen Techstar Electronics Co., Ltd. |
| 850 | "^terasic,.*": | 852 | "^terasic,.*": |
| 851 | description: Terasic Inc. | 853 | description: Terasic Inc. |
| 854 | "^tfc,.*": | ||
| 855 | description: Three Five Corp | ||
| 852 | "^thine,.*": | 856 | "^thine,.*": |
| 853 | description: THine Electronics, Inc. | 857 | description: THine Electronics, Inc. |
| 854 | "^ti,.*": | 858 | "^ti,.*": |
| @@ -923,6 +927,8 @@ patternProperties: · 68 unmodified lines | |||
| 923 | description: Voipac Technologies s.r.o. | 927 | description: Voipac Technologies s.r.o. |
| 924 | "^vot,.*": | 928 | "^vot,.*": |
| 925 | description: Vision Optical Technology Co., Ltd. | 929 | description: Vision Optical Technology Co., Ltd. |
| 930 | "^vxt,.*": | ||
| 931 | description: VXT Ltd | ||
| 926 | "^wd,.*": | 932 | "^wd,.*": |
| 927 | description: Western Digital Corp. | 933 | description: Western Digital Corp. |
| 928 | "^wetek,.*": | 934 | "^wetek,.*": |
| @@ -79,7 +79,6 @@ count for the TTM, which will call your initialization function. · 78 unmodified lines | |||
| 79 | 79 | ||
| 80 | See the radeon_ttm.c file for an example of usage. | 80 | See the radeon_ttm.c file for an example of usage. |
| 81 | 81 | ||
| 82 | |||
| 83 | The Graphics Execution Manager (GEM) | 82 | The Graphics Execution Manager (GEM) |
| 84 | ==================================== | 83 | ==================================== |
| 85 | 84 | ||
| @@ -380,6 +379,39 @@ GEM CMA Helper Functions Reference · 294 unmodified lines | |||
| 380 | .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c | 379 | .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c |
| 381 | :export: | 380 | :export: |
| 382 | 381 | ||
| 382 | VRAM Helper Function Reference | ||
| 383 | ============================== | ||
| 384 | |||
| 385 | .. kernel-doc:: drivers/gpu/drm/drm_vram_helper_common.c | ||
| 386 | :doc: overview | ||
| 387 | |||
| 388 | .. kernel-doc:: include/drm/drm_gem_vram_helper.h | ||
| 389 | :internal: | ||
| 390 | |||
| 391 | GEM VRAM Helper Functions Reference | ||
| 392 | ----------------------------------- | ||
| 393 | |||
| 394 | .. kernel-doc:: drivers/gpu/drm/drm_gem_vram_helper.c | ||
| 395 | :doc: overview | ||
| 396 | |||
| 397 | .. kernel-doc:: include/drm/drm_gem_vram_helper.h | ||
| 398 | :internal: | ||
| 399 | |||
| 400 | .. kernel-doc:: drivers/gpu/drm/drm_gem_vram_helper.c | ||
| 401 | :export: | ||
| 402 | |||
| 403 | VRAM MM Helper Functions Reference | ||
| 404 | ---------------------------------- | ||
| 405 | |||
| 406 | .. kernel-doc:: drivers/gpu/drm/drm_vram_mm_helper.c | ||
| 407 | :doc: overview | ||
| 408 | |||
| 409 | .. kernel-doc:: include/drm/drm_vram_mm_helper.h | ||
| 410 | :internal: | ||
| 411 | |||
| 412 | .. kernel-doc:: drivers/gpu/drm/drm_vram_mm_helper.c | ||
| 413 | :export: | ||
| 414 | |||
| 383 | VMA Offset Manager | 415 | VMA Offset Manager |
| 384 | ================== | 416 | ================== |
| 385 | 417 | ||
| @@ -85,16 +85,18 @@ leads to a few additional requirements: · 84 unmodified lines | |||
| 85 | - The userspace side must be fully reviewed and tested to the standards of that | 85 | - The userspace side must be fully reviewed and tested to the standards of that |
| 86 | userspace project. For e.g. mesa this means piglit testcases and review on the | 86 | userspace project. For e.g. mesa this means piglit testcases and review on the |
| 87 | mailing list. This is again to ensure that the new interface actually gets the | 87 | mailing list. This is again to ensure that the new interface actually gets the |
| 88 | job done. | 88 | job done. The userspace-side reviewer should also provide at least an |
| 89 | Acked-by on the kernel uAPI patch indicating that they've looked at how the | ||
| 90 | kernel side is implementing the new feature being used. | ||
| 89 | 91 | ||
| 90 | - The userspace patches must be against the canonical upstream, not some vendor | 92 | - The userspace patches must be against the canonical upstream, not some vendor |
| 91 | fork. This is to make sure that no one cheats on the review and testing | 93 | fork. This is to make sure that no one cheats on the review and testing |
| 92 | requirements by doing a quick fork. | 94 | requirements by doing a quick fork. |
| 93 | 95 | ||
| 94 | - The kernel patch can only be merged after all the above requirements are met, | 96 | - The kernel patch can only be merged after all the above requirements are met, |
| 95 | but it **must** be merged **before** the userspace patches land. uAPI always flows | 97 | but it **must** be merged to either drm-next or drm-misc-next **before** the |
| 96 | from the kernel, doing things the other way round risks divergence of the uAPI | 98 | userspace patches land. uAPI always flows from the kernel, doing things the |
| 97 | definitions and header files. | 99 | other way round risks divergence of the uAPI definitions and header files. |
| 98 | 100 | ||
| 99 | These are fairly steep requirements, but have grown out from years of shared | 101 | These are fairly steep requirements, but have grown out from years of shared |
| 100 | pain and experience with uAPI added hastily, and almost always regretted about | 102 | pain and experience with uAPI added hastily, and almost always regretted about |
| @@ -10,25 +10,6 @@ graphics subsystem useful as newbie projects. Or for slow rainy days. · 9 unmodified lines | |||
| 10 | Subsystem-wide refactorings | 10 | Subsystem-wide refactorings |
| 11 | =========================== | 11 | =========================== |
| 12 | 12 | ||
| 13 | De-midlayer drivers | ||
| 14 | ------------------- | ||
| 15 | |||
| 16 | With the recent ``drm_bus`` cleanup patches for 3.17 it is no longer required | ||
| 17 | to have a ``drm_bus`` structure set up. Drivers can directly set up the | ||
| 18 | ``drm_device`` structure instead of relying on bus methods in ``drm_usb.c`` | ||
| 19 | and ``drm_pci.c``. The goal is to get rid of the driver's ``->load`` / | ||
| 20 | ``->unload`` callbacks and open-code the load/unload sequence properly, using | ||
| 21 | the new two-stage ``drm_device`` setup/teardown. | ||
| 22 | |||
| 23 | Once all existing drivers are converted we can also remove those bus support | ||
| 24 | files for USB and platform devices. | ||
| 25 | |||
| 26 | All you need is a GPU for a non-converted driver (currently almost all of | ||
| 27 | them, but also all the virtual ones used by KVM, so everyone qualifies). | ||
| 28 | |||
| 29 | Contact: Daniel Vetter, Thierry Reding, respective driver maintainers | ||
| 30 | |||
| 31 | |||
| 32 | Remove custom dumb_map_offset implementations | 13 | Remove custom dumb_map_offset implementations |
| 33 | --------------------------------------------- | 14 | --------------------------------------------- |
| 34 | 15 | ||
| @@ -300,6 +281,14 @@ it to use drm_mode_hsync() instead. · 265 unmodified lines | |||
| 300 | 281 | ||
| 301 | Contact: Sean Paul | 282 | Contact: Sean Paul |
| 302 | 283 | ||
| 284 | drm_fb_helper tasks | ||
| 285 | ------------------- | ||
| 286 | |||
| 287 | - drm_fb_helper_restore_fbdev_mode_unlocked() should call restore_fbdev_mode() | ||
| 288 | not the _force variant so it can bail out if there is a master. But first | ||
| 289 | these igt tests need to be fixed: kms_fbcon_fbt@psr and | ||
| 290 | kms_fbcon_fbt@psr-suspend. | ||
| 291 | |||
| 303 | Core refactorings | 292 | Core refactorings |
| 304 | ================= | 293 | ================= |
| 305 | 294 | ||
| @@ -5413,6 +5413,7 @@ T: git git://anongit.freedesktop.org/drm/drm-misc · 5412 unmodified lines | |||
| 5413 | 5413 | ||
| 5414 | DRM PANEL DRIVERS | 5414 | DRM PANEL DRIVERS |
| 5415 | M: Thierry Reding <thierry.reding@gmail.com> | 5415 | M: Thierry Reding <thierry.reding@gmail.com> |
| 5416 | R: Sam Ravnborg <sam@ravnborg.org> | ||
| 5416 | L: dri-devel@lists.freedesktop.org | 5417 | L: dri-devel@lists.freedesktop.org |
| 5417 | T: git git://anongit.freedesktop.org/drm/drm-misc | 5418 | T: git git://anongit.freedesktop.org/drm/drm-misc |
| 5418 | S: Maintained | 5419 | S: Maintained |
| @@ -5441,7 +5442,6 @@ F: Documentation/gpu/xen-front.rst · 22 unmodified lines | |||
| 5441 | DRM TTM SUBSYSTEM | 5442 | DRM TTM SUBSYSTEM |
| 5442 | M: Christian Koenig <christian.koenig@amd.com> | 5443 | M: Christian Koenig <christian.koenig@amd.com> |
| 5443 | M: Huang Rui <ray.huang@amd.com> | 5444 | M: Huang Rui <ray.huang@amd.com> |
| 5444 | M: Junwei Zhang <Jerry.Zhang@amd.com> | ||
| 5445 | T: git git://people.freedesktop.org/~agd5f/linux | 5445 | T: git git://people.freedesktop.org/~agd5f/linux |
| 5446 | S: Maintained | 5446 | S: Maintained |
| 5447 | L: dri-devel@lists.freedesktop.org | 5447 | L: dri-devel@lists.freedesktop.org |
| @@ -90,6 +90,10 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) · 89 unmodified lines | |||
| 90 | 90 | ||
| 91 | dmabuf = file->private_data; | 91 | dmabuf = file->private_data; |
| 92 | 92 | ||
| 93 | /* check if buffer supports mmap */ | ||
| 94 | if (!dmabuf->ops->mmap) | ||
| 95 | return -EINVAL; | ||
| 96 | |||
| 93 | /* check for overflowing the buffer's size */ | 97 | /* check for overflowing the buffer's size */ |
| 94 | if (vma->vm_pgoff + vma_pages(vma) > | 98 | if (vma->vm_pgoff + vma_pages(vma) > |
| 95 | dmabuf->size >> PAGE_SHIFT) | 99 | dmabuf->size >> PAGE_SHIFT) |
| @@ -404,8 +408,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) · 308 unmodified lines | |||
| 404 | || !exp_info->ops | 408 | || !exp_info->ops |
| 405 | || !exp_info->ops->map_dma_buf | 409 | || !exp_info->ops->map_dma_buf |
| 406 | || !exp_info->ops->unmap_dma_buf | 410 | || !exp_info->ops->unmap_dma_buf |
| 407 | || !exp_info->ops->release | 411 | || !exp_info->ops->release)) { |
| 408 | || !exp_info->ops->mmap)) { | ||
| 409 | return ERR_PTR(-EINVAL); | 412 | return ERR_PTR(-EINVAL); |
| 410 | } | 413 | } |
| 411 | 414 | ||
| @@ -573,6 +576,7 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, · 161 unmodified lines | |||
| 573 | list_add(&attach->node, &dmabuf->attachments); | 576 | list_add(&attach->node, &dmabuf->attachments); |
| 574 | 577 | ||
| 575 | mutex_unlock(&dmabuf->lock); | 578 | mutex_unlock(&dmabuf->lock); |
| 579 | |||
| 576 | return attach; | 580 | return attach; |
| 577 | 581 | ||
| 578 | err_attach: | 582 | err_attach: |
| @@ -595,6 +599,9 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) · 16 unmodified lines | |||
| 595 | if (WARN_ON(!dmabuf || !attach)) | 599 | if (WARN_ON(!dmabuf || !attach)) |
| 596 | return; | 600 | return; |
| 597 | 601 | ||
| 602 | if (attach->sgt) | ||
| 603 | dmabuf->ops->unmap_dma_buf(attach, attach->sgt, attach->dir); | ||
| 604 | |||
| 598 | mutex_lock(&dmabuf->lock); | 605 | mutex_lock(&dmabuf->lock); |
| 599 | list_del(&attach->node); | 606 | list_del(&attach->node); |
| 600 | if (dmabuf->ops->detach) | 607 | if (dmabuf->ops->detach) |
| @@ -630,10 +637,27 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, · 29 unmodified lines | |||
| 630 | if (WARN_ON(!attach || !attach->dmabuf)) | 637 | if (WARN_ON(!attach || !attach->dmabuf)) |
| 631 | return ERR_PTR(-EINVAL); | 638 | return ERR_PTR(-EINVAL); |
| 632 | 639 | ||
| 640 | if (attach->sgt) { | ||
| 641 | /* | ||
| 642 | * Two mappings with different directions for the same | ||
| 643 | * attachment are not allowed. | ||
| 644 | */ | ||
| 645 | if (attach->dir != direction && | ||
| 646 | attach->dir != DMA_BIDIRECTIONAL) | ||
| 647 | return ERR_PTR(-EBUSY); | ||
| 648 | |||
| 649 | return attach->sgt; | ||
| 650 | } | ||
| 651 | |||
| 633 | sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); | 652 | sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); |
| 634 | if (!sg_table) | 653 | if (!sg_table) |
| 635 | sg_table = ERR_PTR(-ENOMEM); | 654 | sg_table = ERR_PTR(-ENOMEM); |
| 636 | 655 | ||
| 656 | if (!IS_ERR(sg_table) && attach->dmabuf->ops->cache_sgt_mapping) { | ||
| 657 | attach->sgt = sg_table; | ||
| 658 | attach->dir = direction; | ||
| 659 | } | ||
| 660 | |||
| 637 | return sg_table; | 661 | return sg_table; |
| 638 | } | 662 | } |
| 639 | EXPORT_SYMBOL_GPL(dma_buf_map_attachment); | 663 | EXPORT_SYMBOL_GPL(dma_buf_map_attachment); |
| @@ -657,8 +681,10 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, · 17 unmodified lines | |||
| 657 | if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) | 681 | if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) |
| 658 | return; | 682 | return; |
| 659 | 683 | ||
| 660 | attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, | 684 | if (attach->sgt == sg_table) |
| 661 | direction); | 685 | return; |
| 686 | |||
| 687 | attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction); | ||
| 662 | } | 688 | } |
| 663 | EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); | 689 | EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); |
| 664 | 690 | ||
| @@ -906,6 +932,10 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, · 241 unmodified lines | |||
| 906 | if (WARN_ON(!dmabuf || !vma)) | 932 | if (WARN_ON(!dmabuf || !vma)) |
| 907 | return -EINVAL; | 933 | return -EINVAL; |
| 908 | 934 | ||
| 935 | /* check if buffer supports mmap */ | ||
| 936 | if (!dmabuf->ops->mmap) | ||
| 937 | return -EINVAL; | ||
| 938 | |||
| 909 | /* check for offset overflow */ | 939 | /* check for offset overflow */ |
| 910 | if (pgoff + vma_pages(vma) < pgoff) | 940 | if (pgoff + vma_pages(vma) < pgoff) |
| 911 | return -EOVERFLOW; | 941 | return -EOVERFLOW; |
| @@ -1068,6 +1098,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) · 156 unmodified lines | |||
| 1068 | fence->ops->get_driver_name(fence), | 1098 | fence->ops->get_driver_name(fence), |
| 1069 | fence->ops->get_timeline_name(fence), | 1099 | fence->ops->get_timeline_name(fence), |
| 1070 | dma_fence_is_signaled(fence) ? "" : "un"); | 1100 | dma_fence_is_signaled(fence) ? "" : "un"); |
| 1101 | dma_fence_put(fence); | ||
| 1071 | } | 1102 | } |
| 1072 | rcu_read_unlock(); | 1103 | rcu_read_unlock(); |
| 1073 | 1104 | ||
| @@ -197,29 +197,3 @@ static __init int sync_debugfs_init(void) · 196 unmodified lines | |||
| 197 | return 0; | 197 | return 0; |
| 198 | } | 198 | } |
| 199 | late_initcall(sync_debugfs_init); | 199 | late_initcall(sync_debugfs_init); |
| 200 | |||
| 201 | #define DUMP_CHUNK 256 | ||
| 202 | static char sync_dump_buf[64 * 1024]; | ||
| 203 | void sync_dump(void) | ||
| 204 | { | ||
| 205 | struct seq_file s = { | ||
| 206 | .buf = sync_dump_buf, | ||
| 207 | .size = sizeof(sync_dump_buf) - 1, | ||
| 208 | }; | ||
| 209 | int i; | ||
| 210 | |||
| 211 | sync_info_debugfs_show(&s, NULL); | ||
| 212 | |||
| 213 | for (i = 0; i < s.count; i += DUMP_CHUNK) { | ||
| 214 | if ((s.count - i) > DUMP_CHUNK) { | ||
| 215 | char c = s.buf[i + DUMP_CHUNK]; | ||
| 216 | |||
| 217 | s.buf[i + DUMP_CHUNK] = 0; | ||
| 218 | pr_cont("%s", s.buf + i); | ||
| 219 | s.buf[i + DUMP_CHUNK] = c; | ||
| 220 | } else { | ||
| 221 | s.buf[s.count] = 0; | ||
| 222 | pr_cont("%s", s.buf + i); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | } | ||
| @@ -68,6 +68,5 @@ void sync_timeline_debug_add(struct sync_timeline *obj); · 67 unmodified lines | |||
| 68 | void sync_timeline_debug_remove(struct sync_timeline *obj); | 68 | void sync_timeline_debug_remove(struct sync_timeline *obj); |
| 69 | void sync_file_debug_add(struct sync_file *fence); | 69 | void sync_file_debug_add(struct sync_file *fence); |
| 70 | void sync_file_debug_remove(struct sync_file *fence); | 70 | void sync_file_debug_remove(struct sync_file *fence); |
| 71 | void sync_dump(void); | ||
| 72 | 71 | ||
| 73 | #endif /* _LINUX_SYNC_H */ | 72 | #endif /* _LINUX_SYNC_H */ |
| @@ -161,6 +161,13 @@ config DRM_TTM · 160 unmodified lines | |||
| 161 | GPU memory types. Will be enabled automatically if a device driver | 161 | GPU memory types. Will be enabled automatically if a device driver |
| 162 | uses it. | 162 | uses it. |
| 163 | 163 | ||
| 164 | config DRM_VRAM_HELPER | ||
| 165 | tristate | ||
| 166 | depends on DRM | ||
| 167 | select DRM_TTM | ||
| 168 | help | ||
| 169 | Helpers for VRAM memory management | ||
| 170 | |||
| 164 | config DRM_GEM_CMA_HELPER | 171 | config DRM_GEM_CMA_HELPER |
| 165 | bool | 172 | bool |
| 166 | depends on DRM | 173 | depends on DRM |
| @@ -32,6 +32,11 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o · 31 unmodified lines | |||
| 32 | drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | 32 | drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o |
| 33 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | 33 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o |
| 34 | 34 | ||
| 35 | drm_vram_helper-y := drm_gem_vram_helper.o \ | ||
| 36 | drm_vram_helper_common.o \ | ||
| 37 | drm_vram_mm_helper.o | ||
| 38 | obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o | ||
| 39 | |||
| 35 | drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \ | 40 | drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \ |
| 36 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ | 41 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ |
| 37 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ | 42 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ |
| @@ -3341,8 +3341,6 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, · 3340 unmodified lines | |||
| 3341 | if (!ring || !ring->sched.thread) | 3341 | if (!ring || !ring->sched.thread) |
| 3342 | continue; | 3342 | continue; |
| 3343 | 3343 | ||
| 3344 | drm_sched_stop(&ring->sched); | ||
| 3345 | |||
| 3346 | /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ | 3344 | /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ |
| 3347 | amdgpu_fence_driver_force_completion(ring); | 3345 | amdgpu_fence_driver_force_completion(ring); |
| 3348 | } | 3346 | } |
| @@ -3350,8 +3348,7 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, · 1 unmodified line | |||
| 3350 | if(job) | 3348 | if(job) |
| 3351 | drm_sched_increase_karma(&job->base); | 3349 | drm_sched_increase_karma(&job->base); |
| 3352 | 3350 | ||
| 3353 | 3351 | /* Don't suspend on bare metal if we are not going to HW reset the ASIC */ | |
| 3354 | |||
| 3355 | if (!amdgpu_sriov_vf(adev)) { | 3352 | if (!amdgpu_sriov_vf(adev)) { |
| 3356 | 3353 | ||
| 3357 | if (!need_full_reset) | 3354 | if (!need_full_reset) |
| @@ -3489,38 +3486,21 @@ end: · 131 unmodified lines | |||
| 3489 | return r; | 3486 | return r; |
| 3490 | } | 3487 | } |
| 3491 | 3488 | ||
| 3492 | static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, | 3489 | static bool amdgpu_device_lock_adev(struct amdgpu_device *adev, bool trylock) |
| 3493 | struct amdgpu_job *job) | ||
| 3494 | { | 3490 | { |
| 3495 | int i; | 3491 | if (trylock) { |
| 3496 | 3492 | if (!mutex_trylock(&adev->lock_reset)) | |
| 3497 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { | 3493 | return false; |
| 3498 | struct amdgpu_ring *ring = adev->rings[i]; | 3494 | } else |
| 3499 | 3495 | mutex_lock(&adev->lock_reset); | |
| 3500 | if (!ring || !ring->sched.thread) | ||
| 3501 | continue; | ||
| 3502 | 3496 | ||
| 3503 | if (!adev->asic_reset_res) | ||
| 3504 | drm_sched_resubmit_jobs(&ring->sched); | ||
| 3505 | |||
| 3506 | drm_sched_start(&ring->sched, !adev->asic_reset_res); | ||
| 3507 | } | ||
| 3508 | |||
| 3509 | if (!amdgpu_device_has_dc_support(adev)) { | ||
| 3510 | drm_helper_resume_force_mode(adev->ddev); | ||
| 3511 | } | ||
| 3512 | |||
| 3513 | adev->asic_reset_res = 0; | ||
| 3514 | } | ||
| 3515 | |||
| 3516 | static void amdgpu_device_lock_adev(struct amdgpu_device *adev) | ||
| 3517 | { | ||
| 3518 | mutex_lock(&adev->lock_reset); | ||
| 3519 | atomic_inc(&adev->gpu_reset_counter); | 3497 | atomic_inc(&adev->gpu_reset_counter); |
| 3520 | adev->in_gpu_reset = 1; | 3498 | adev->in_gpu_reset = 1; |
| 3521 | /* Block kfd: SRIOV would do it separately */ | 3499 | /* Block kfd: SRIOV would do it separately */ |
| 3522 | if (!amdgpu_sriov_vf(adev)) | 3500 | if (!amdgpu_sriov_vf(adev)) |
| 3523 | amdgpu_amdkfd_pre_reset(adev); | 3501 | amdgpu_amdkfd_pre_reset(adev); |
| 3502 | |||
| 3503 | return true; | ||
| 3524 | } | 3504 | } |
| 3525 | 3505 | ||
| 3526 | static void amdgpu_device_unlock_adev(struct amdgpu_device *adev) | 3506 | static void amdgpu_device_unlock_adev(struct amdgpu_device *adev) |
| @@ -3548,40 +3528,42 @@ static void amdgpu_device_unlock_adev(struct amdgpu_device *adev) · 21 unmodified lines | |||
| 3548 | int amdgpu_device_gpu_recover(struct amdgpu_device *adev, | 3528 | int amdgpu_device_gpu_recover(struct amdgpu_device *adev, |
| 3549 | struct amdgpu_job *job) | 3529 | struct amdgpu_job *job) |
| 3550 | { | 3530 | { |
| 3551 | int r; | 3531 | struct list_head device_list, *device_list_handle = NULL; |
| 3532 | bool need_full_reset, job_signaled; | ||
| 3552 | struct amdgpu_hive_info *hive = NULL; | 3533 | struct amdgpu_hive_info *hive = NULL; |
| 3553 | bool need_full_reset = false; | ||
| 3554 | struct amdgpu_device *tmp_adev = NULL; | 3534 | struct amdgpu_device *tmp_adev = NULL; |
| 3555 | struct list_head device_list, *device_list_handle = NULL; | 3535 | int i, r = 0; |
| 3556 | 3536 | ||
| 3537 | need_full_reset = job_signaled = false; | ||
| 3557 | INIT_LIST_HEAD(&device_list); | 3538 | INIT_LIST_HEAD(&device_list); |
| 3558 | 3539 | ||
| 3559 | dev_info(adev->dev, "GPU reset begin!\n"); | 3540 | dev_info(adev->dev, "GPU reset begin!\n"); |
| 3560 | 3541 | ||
| 3542 | hive = amdgpu_get_xgmi_hive(adev, false); | ||
| 3543 | |||
| 3561 | /* | 3544 | /* |
| 3562 | * In case of XGMI hive disallow concurrent resets to be triggered | 3545 | * Here we trylock to avoid chain of resets executing from |
| 3563 | * by different nodes. No point also since the one node already executing | 3546 | * either trigger by jobs on different adevs in XGMI hive or jobs on |
| 3564 | * reset will also reset all the other nodes in the hive. | 3547 | * different schedulers for same device while this TO handler is running. |
| 3548 | * We always reset all schedulers for device and all devices for XGMI | ||
| 3549 | * hive so that should take care of them too. | ||
| 3565 | */ | 3550 | */ |
| 3566 | hive = amdgpu_get_xgmi_hive(adev, 0); | 3551 | |
| 3567 | if (hive && adev->gmc.xgmi.num_physical_nodes > 1 && | 3552 | if (hive && !mutex_trylock(&hive->reset_lock)) { |
| 3568 | !mutex_trylock(&hive->reset_lock)) | 3553 | DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress", |
| 3554 | job->base.id, hive->hive_id); | ||
| 3569 | return 0; | 3555 | return 0; |
| 3556 | } | ||
| 3570 | 3557 | ||
| 3571 | /* Start with adev pre asic reset first for soft reset check.*/ | 3558 | /* Start with adev pre asic reset first for soft reset check.*/ |
| 3572 | amdgpu_device_lock_adev(adev); | 3559 | if (!amdgpu_device_lock_adev(adev, !hive)) { |
| 3573 | r = amdgpu_device_pre_asic_reset(adev, | 3560 | DRM_INFO("Bailing on TDR for s_job:%llx, as another already in progress", |
| 3574 | job, | 3561 | job->base.id); |
| 3575 | &need_full_reset); | 3562 | return 0; |
| 3576 | if (r) { | ||
| 3577 | /*TODO Should we stop ?*/ | ||
| 3578 | DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", | ||
| 3579 | r, adev->ddev->unique); | ||
| 3580 | adev->asic_reset_res = r; | ||
| 3581 | } | 3563 | } |
| 3582 | 3564 | ||
| 3583 | /* Build list of devices to reset */ | 3565 | /* Build list of devices to reset */ |
| 3584 | if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { | 3566 | if (adev->gmc.xgmi.num_physical_nodes > 1) { |
| 3585 | if (!hive) { | 3567 | if (!hive) { |
| 3586 | amdgpu_device_unlock_adev(adev); | 3568 | amdgpu_device_unlock_adev(adev); |
| 3587 | return -ENODEV; | 3569 | return -ENODEV; |
| @@ -3598,13 +3580,56 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, · 10 unmodified lines | |||
| 3598 | device_list_handle = &device_list; | 3580 | device_list_handle = &device_list; |
| 3599 | } | 3581 | } |
| 3600 | 3582 | ||
| 3583 | /* block all schedulers and reset given job's ring */ | ||
| 3584 | list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { | ||
| 3585 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { | ||
| 3586 | struct amdgpu_ring *ring = tmp_adev->rings[i]; | ||
| 3587 | |||
| 3588 | if (!ring || !ring->sched.thread) | ||
| 3589 | continue; | ||
| 3590 | |||
| 3591 | drm_sched_stop(&ring->sched, &job->base); | ||
| 3592 | } | ||
| 3593 | } | ||
| 3594 | |||
| 3595 | |||
| 3596 | /* | ||
| 3597 | * Must check guilty signal here since after this point all old | ||
| 3598 | * HW fences are force signaled. | ||
| 3599 | * | ||
| 3600 | * job->base holds a reference to parent fence | ||
| 3601 | */ | ||
| 3602 | if (job && job->base.s_fence->parent && | ||
| 3603 | dma_fence_is_signaled(job->base.s_fence->parent)) | ||
| 3604 | job_signaled = true; | ||
| 3605 | |||
| 3606 | if (!amdgpu_device_ip_need_full_reset(adev)) | ||
| 3607 | device_list_handle = &device_list; | ||
| 3608 | |||
| 3609 | if (job_signaled) { | ||
| 3610 | dev_info(adev->dev, "Guilty job already signaled, skipping HW reset"); | ||
| 3611 | goto skip_hw_reset; | ||
| 3612 | } | ||
| 3613 | |||
| 3614 | |||
| 3615 | /* Guilty job will be freed after this*/ | ||
| 3616 | r = amdgpu_device_pre_asic_reset(adev, | ||
| 3617 | job, | ||
| 3618 | &need_full_reset); | ||
| 3619 | if (r) { | ||
| 3620 | /*TODO Should we stop ?*/ | ||
| 3621 | DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", | ||
| 3622 | r, adev->ddev->unique); | ||
| 3623 | adev->asic_reset_res = r; | ||
| 3624 | } | ||
| 3625 | |||
| 3601 | retry: /* Rest of adevs pre asic reset from XGMI hive. */ | 3626 | retry: /* Rest of adevs pre asic reset from XGMI hive. */ |
| 3602 | list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { | 3627 | list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { |
| 3603 | 3628 | ||
| 3604 | if (tmp_adev == adev) | 3629 | if (tmp_adev == adev) |
| 3605 | continue; | 3630 | continue; |
| 3606 | 3631 | ||
| 3607 | amdgpu_device_lock_adev(tmp_adev); | 3632 | amdgpu_device_lock_adev(tmp_adev, false); |
| 3608 | r = amdgpu_device_pre_asic_reset(tmp_adev, | 3633 | r = amdgpu_device_pre_asic_reset(tmp_adev, |
| 3609 | NULL, | 3634 | NULL, |
| 3610 | &need_full_reset); | 3635 | &need_full_reset); |
| @@ -3628,9 +3653,28 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ · 17 unmodified lines | |||
| 3628 | goto retry; | 3653 | goto retry; |
| 3629 | } | 3654 | } |
| 3630 | 3655 | ||
| 3656 | skip_hw_reset: | ||
| 3657 | |||
| 3631 | /* Post ASIC reset for all devs .*/ | 3658 | /* Post ASIC reset for all devs .*/ |
| 3632 | list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { | 3659 | list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { |
| 3633 | amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL); | 3660 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { |
| 3661 | struct amdgpu_ring *ring = tmp_adev->rings[i]; | ||
| 3662 | |||
| 3663 | if (!ring || !ring->sched.thread) | ||
| 3664 | continue; | ||
| 3665 | |||
| 3666 | /* No point to resubmit jobs if we didn't HW reset*/ | ||
| 3667 | if (!tmp_adev->asic_reset_res && !job_signaled) | ||
| 3668 | drm_sched_resubmit_jobs(&ring->sched); | ||
| 3669 | |||
| 3670 | drm_sched_start(&ring->sched, !tmp_adev->asic_reset_res); | ||
| 3671 | } | ||
| 3672 | |||
| 3673 | if (!amdgpu_device_has_dc_support(tmp_adev) && !job_signaled) { | ||
| 3674 | drm_helper_resume_force_mode(tmp_adev->ddev); | ||
| 3675 | } | ||
| 3676 | |||
| 3677 | tmp_adev->asic_reset_res = 0; | ||
| 3634 | 3678 | ||
| 3635 | if (r) { | 3679 | if (r) { |
| 3636 | /* bad news, how to tell it to userspace ? */ | 3680 | /* bad news, how to tell it to userspace ? */ |
| @@ -3643,7 +3687,7 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ · 6 unmodified lines | |||
| 3643 | amdgpu_device_unlock_adev(tmp_adev); | 3687 | amdgpu_device_unlock_adev(tmp_adev); |
| 3644 | } | 3688 | } |
| 3645 | 3689 | ||
| 3646 | if (hive && adev->gmc.xgmi.num_physical_nodes > 1) | 3690 | if (hive) |
| 3647 | mutex_unlock(&hive->reset_lock); | 3691 | mutex_unlock(&hive->reset_lock); |
| 3648 | 3692 | ||
| 3649 | if (r) | 3693 | if (r) |
| @@ -121,6 +121,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, · 120 unmodified lines | |||
| 121 | struct drm_mode_fb_cmd2 *mode_cmd, | 121 | struct drm_mode_fb_cmd2 *mode_cmd, |
| 122 | struct drm_gem_object **gobj_p) | 122 | struct drm_gem_object **gobj_p) |
| 123 | { | 123 | { |
| 124 | const struct drm_format_info *info; | ||
| 124 | struct amdgpu_device *adev = rfbdev->adev; | 125 | struct amdgpu_device *adev = rfbdev->adev; |
| 125 | struct drm_gem_object *gobj = NULL; | 126 | struct drm_gem_object *gobj = NULL; |
| 126 | struct amdgpu_bo *abo = NULL; | 127 | struct amdgpu_bo *abo = NULL; |
| @@ -131,7 +132,8 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, · 4 unmodified lines | |||
| 131 | int height = mode_cmd->height; | 132 | int height = mode_cmd->height; |
| 132 | u32 cpp; | 133 | u32 cpp; |
| 133 | 134 | ||
| 134 | cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); | 135 | info = drm_get_format_info(adev->ddev, mode_cmd); |
| 136 | cpp = info->cpp[0]; | ||
| 135 | 137 | ||
| 136 | /* need to align pitch with crtc limits */ | 138 | /* need to align pitch with crtc limits */ |
| 137 | mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, cpp, | 139 | mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, cpp, |
| @@ -463,23 +463,6 @@ static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) · 462 unmodified lines | |||
| 463 | return &state->base; | 463 | return &state->base; |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | static void malidp_crtc_reset(struct drm_crtc *crtc) | ||
| 467 | { | ||
| 468 | struct malidp_crtc_state *state = NULL; | ||
| 469 | |||
| 470 | if (crtc->state) { | ||
| 471 | state = to_malidp_crtc_state(crtc->state); | ||
| 472 | __drm_atomic_helper_crtc_destroy_state(crtc->state); | ||
| 473 | } | ||
| 474 | |||
| 475 | kfree(state); | ||
| 476 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
| 477 | if (state) { | ||
| 478 | crtc->state = &state->base; | ||
| 479 | crtc->state->crtc = crtc; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | static void malidp_crtc_destroy_state(struct drm_crtc *crtc, | 466 | static void malidp_crtc_destroy_state(struct drm_crtc *crtc, |
| 484 | struct drm_crtc_state *state) | 467 | struct drm_crtc_state *state) |
| 485 | { | 468 | { |
| @@ -493,6 +476,17 @@ static void malidp_crtc_destroy_state(struct drm_crtc *crtc, · 7 unmodified lines | |||
| 493 | kfree(mali_state); | 476 | kfree(mali_state); |
| 494 | } | 477 | } |
| 495 | 478 | ||
| 479 | static void malidp_crtc_reset(struct drm_crtc *crtc) | ||
| 480 | { | ||
| 481 | struct malidp_crtc_state *state = | ||
| 482 | kzalloc(sizeof(*state), GFP_KERNEL); | ||
| 483 | |||
| 484 | if (crtc->state) | ||
| 485 | malidp_crtc_destroy_state(crtc, crtc->state); | ||
| 486 | |||
| 487 | __drm_atomic_helper_crtc_reset(crtc, &state->base); | ||
| 488 | } | ||
| 489 | |||
| 496 | static int malidp_crtc_enable_vblank(struct drm_crtc *crtc) | 490 | static int malidp_crtc_enable_vblank(struct drm_crtc *crtc) |
| 497 | { | 491 | { |
| 498 | struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | 492 | struct malidp_drm *malidp = crtc_to_malidp_device(crtc); |
| @@ -382,7 +382,8 @@ static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode * · 381 unmodified lines | |||
| 382 | 382 | ||
| 383 | int malidp_format_get_bpp(u32 fmt) | 383 | int malidp_format_get_bpp(u32 fmt) |
| 384 | { | 384 | { |
| 385 | int bpp = drm_format_plane_cpp(fmt, 0) * 8; | 385 | const struct drm_format_info *info = drm_format_info(fmt); |
| 386 | int bpp = info->cpp[0] * 8; | ||
| 386 | 387 | ||
| 387 | if (bpp == 0) { | 388 | if (bpp == 0) { |
| 388 | switch (fmt) { | 389 | switch (fmt) { |
| @@ -158,7 +158,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder, · 157 unmodified lines | |||
| 158 | return -EINVAL; | 158 | return -EINVAL; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | n_planes = drm_format_num_planes(fb->format->format); | 161 | n_planes = fb->format->num_planes; |
| 162 | for (i = 0; i < n_planes; i++) { | 162 | for (i = 0; i < n_planes; i++) { |
| 163 | struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i); | 163 | struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i); |
| 164 | /* memory write buffers are never rotated */ | 164 | /* memory write buffers are never rotated */ |
| @@ -227,14 +227,13 @@ bool malidp_format_mod_supported(struct drm_device *drm, · 226 unmodified lines | |||
| 227 | 227 | ||
| 228 | if (modifier & AFBC_SPLIT) { | 228 | if (modifier & AFBC_SPLIT) { |
| 229 | if (!info->is_yuv) { | 229 | if (!info->is_yuv) { |
| 230 | if (drm_format_plane_cpp(format, 0) <= 2) { | 230 | if (info->cpp[0] <= 2) { |
| 231 | DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n"); | 231 | DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n"); |
| 232 | return false; | 232 | return false; |
| 233 | } | 233 | } |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | if ((drm_format_horz_chroma_subsampling(format) != 1) || | 236 | if ((info->hsub != 1) || (info->vsub != 1)) { |
| 237 | (drm_format_vert_chroma_subsampling(format) != 1)) { | ||
| 238 | if (!(format == DRM_FORMAT_YUV420_10BIT && | 237 | if (!(format == DRM_FORMAT_YUV420_10BIT && |
| 239 | (map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) { | 238 | (map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) { |
| 240 | DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n"); | 239 | DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n"); |
| @@ -244,8 +243,7 @@ bool malidp_format_mod_supported(struct drm_device *drm, · 3 unmodified lines | |||
| 244 | } | 243 | } |
| 245 | 244 | ||
| 246 | if (modifier & AFBC_CBR) { | 245 | if (modifier & AFBC_CBR) { |
| 247 | if ((drm_format_horz_chroma_subsampling(format) == 1) || | 246 | if ((info->hsub == 1) || (info->vsub == 1)) { |
| 248 | (drm_format_vert_chroma_subsampling(format) == 1)) { | ||
| 249 | DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n"); | 247 | DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n"); |
| 250 | return false; | 248 | return false; |
| 251 | } | 249 | } |
| @@ -87,6 +87,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, · 86 unmodified lines | |||
| 87 | struct drm_framebuffer *armada_fb_create(struct drm_device *dev, | 87 | struct drm_framebuffer *armada_fb_create(struct drm_device *dev, |
| 88 | struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode) | 88 | struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode) |
| 89 | { | 89 | { |
| 90 | const struct drm_format_info *info = drm_get_format_info(dev, mode); | ||
| 90 | struct armada_gem_object *obj; | 91 | struct armada_gem_object *obj; |
| 91 | struct armada_framebuffer *dfb; | 92 | struct armada_framebuffer *dfb; |
| 92 | int ret; | 93 | int ret; |
| @@ -97,7 +98,7 @@ struct drm_framebuffer *armada_fb_create(struct drm_device *dev, · 4 unmodified lines | |||
| 97 | mode->pitches[2]); | 98 | mode->pitches[2]); |
| 98 | 99 | ||
| 99 | /* We can only handle a single plane at the moment */ | 100 | /* We can only handle a single plane at the moment */ |
| 100 | if (drm_format_num_planes(mode->pixel_format) > 1 && | 101 | if (info->num_planes > 1 && |
| 101 | (mode->handles[0] != mode->handles[1] || | 102 | (mode->handles[0] != mode->handles[1] || |
| 102 | mode->handles[0] != mode->handles[2])) { | 103 | mode->handles[0] != mode->handles[2])) { |
| 103 | ret = -EINVAL; | 104 | ret = -EINVAL; |
| @@ -2,9 +2,8 @@ · 1 unmodified line | |||
| 2 | config DRM_AST | 2 | config DRM_AST |
| 3 | tristate "AST server chips" | 3 | tristate "AST server chips" |
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select DRM_TTM | ||
| 6 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 7 | select DRM_TTM | 6 | select DRM_VRAM_HELPER |
| 8 | help | 7 | help |
| 9 | Say yes for experimental AST GPU driver. Do not enable | 8 | Say yes for experimental AST GPU driver. Do not enable |
| 10 | this driver without having a working -modesetting, | 9 | this driver without having a working -modesetting, |
| @@ -205,13 +205,7 @@ static struct pci_driver ast_pci_driver = { · 204 unmodified lines | |||
| 205 | 205 | ||
| 206 | static const struct file_operations ast_fops = { | 206 | static const struct file_operations ast_fops = { |
| 207 | .owner = THIS_MODULE, | 207 | .owner = THIS_MODULE, |
| 208 | .open = drm_open, | 208 | DRM_VRAM_MM_FILE_OPERATIONS |
| 209 | .release = drm_release, | ||
| 210 | .unlocked_ioctl = drm_ioctl, | ||
| 211 | .mmap = ast_mmap, | ||
| 212 | .poll = drm_poll, | ||
| 213 | .compat_ioctl = drm_compat_ioctl, | ||
| 214 | .read = drm_read, | ||
| 215 | }; | 209 | }; |
| 216 | 210 | ||
| 217 | static struct drm_driver driver = { | 211 | static struct drm_driver driver = { |
| @@ -228,10 +222,7 @@ static struct drm_driver driver = { · 10 unmodified lines | |||
| 228 | .minor = DRIVER_MINOR, | 222 | .minor = DRIVER_MINOR, |
| 229 | .patchlevel = DRIVER_PATCHLEVEL, | 223 | .patchlevel = DRIVER_PATCHLEVEL, |
| 230 | 224 | ||
| 231 | .gem_free_object_unlocked = ast_gem_free_object, | 225 | DRM_GEM_VRAM_DRIVER |
| 232 | .dumb_create = ast_dumb_create, | ||
| 233 | .dumb_map_offset = ast_dumb_mmap_offset, | ||
| 234 | |||
| 235 | }; | 226 | }; |
| 236 | 227 | ||
| 237 | static int __init ast_init(void) | 228 | static int __init ast_init(void) |
| @@ -31,13 +31,10 @@ · 30 unmodified lines | |||
| 31 | #include <drm/drm_encoder.h> | 31 | #include <drm/drm_encoder.h> |
| 32 | #include <drm/drm_fb_helper.h> | 32 | #include <drm/drm_fb_helper.h> |
| 33 | 33 | ||
| 34 | #include <drm/ttm/ttm_bo_api.h> | ||
| 35 | #include <drm/ttm/ttm_bo_driver.h> | ||
| 36 | #include <drm/ttm/ttm_placement.h> | ||
| 37 | #include <drm/ttm/ttm_memory.h> | ||
| 38 | #include <drm/ttm/ttm_module.h> | ||
| 39 | |||
| 40 | #include <drm/drm_gem.h> | 34 | #include <drm/drm_gem.h> |
| 35 | #include <drm/drm_gem_vram_helper.h> | ||
| 36 | |||
| 37 | #include <drm/drm_vram_mm_helper.h> | ||
| 41 | 38 | ||
| 42 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
| 43 | #include <linux/i2c-algo-bit.h> | 40 | #include <linux/i2c-algo-bit.h> |
| @@ -103,10 +100,6 @@ struct ast_private { · 59 unmodified lines | |||
| 103 | 100 | ||
| 104 | int fb_mtrr; | 101 | int fb_mtrr; |
| 105 | 102 | ||
| 106 | struct { | ||
| 107 | struct ttm_bo_device bdev; | ||
| 108 | } ttm; | ||
| 109 | |||
| 110 | struct drm_gem_object *cursor_cache; | 103 | struct drm_gem_object *cursor_cache; |
| 111 | uint64_t cursor_cache_gpu_addr; | 104 | uint64_t cursor_cache_gpu_addr; |
| 112 | /* Acces to this cache is protected by the crtc->mutex of the only crtc | 105 | /* Acces to this cache is protected by the crtc->mutex of the only crtc |
| @@ -263,7 +256,6 @@ struct ast_fbdev { · 150 unmodified lines | |||
| 263 | struct ast_framebuffer afb; | 256 | struct ast_framebuffer afb; |
| 264 | void *sysram; | 257 | void *sysram; |
| 265 | int size; | 258 | int size; |
| 266 | struct ttm_bo_kmap_obj mapping; | ||
| 267 | int x1, y1, x2, y2; /* dirty rect */ | 259 | int x1, y1, x2, y2; /* dirty rect */ |
| 268 | spinlock_t dirty_lock; | 260 | spinlock_t dirty_lock; |
| 269 | }; | 261 | }; |
| @@ -321,73 +313,16 @@ void ast_fbdev_fini(struct drm_device *dev); · 51 unmodified lines | |||
| 321 | void ast_fbdev_set_suspend(struct drm_device *dev, int state); | 313 | void ast_fbdev_set_suspend(struct drm_device *dev, int state); |
| 322 | void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr); | 314 | void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr); |
| 323 | 315 | ||
| 324 | struct ast_bo { | ||
| 325 | struct ttm_buffer_object bo; | ||
| 326 | struct ttm_placement placement; | ||
| 327 | struct ttm_bo_kmap_obj kmap; | ||
| 328 | struct drm_gem_object gem; | ||
| 329 | struct ttm_place placements[3]; | ||
| 330 | int pin_count; | ||
| 331 | }; | ||
| 332 | #define gem_to_ast_bo(gobj) container_of((gobj), struct ast_bo, gem) | ||
| 333 | |||
| 334 | static inline struct ast_bo * | ||
| 335 | ast_bo(struct ttm_buffer_object *bo) | ||
| 336 | { | ||
| 337 | return container_of(bo, struct ast_bo, bo); | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | #define to_ast_obj(x) container_of(x, struct ast_gem_object, base) | ||
| 342 | |||
| 343 | #define AST_MM_ALIGN_SHIFT 4 | 316 | #define AST_MM_ALIGN_SHIFT 4 |
| 344 | #define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1) | 317 | #define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1) |
| 345 | 318 | ||
| 346 | extern int ast_dumb_create(struct drm_file *file, | ||
| 347 | struct drm_device *dev, | ||
| 348 | struct drm_mode_create_dumb *args); | ||
| 349 | |||
| 350 | extern void ast_gem_free_object(struct drm_gem_object *obj); | ||
| 351 | extern int ast_dumb_mmap_offset(struct drm_file *file, | ||
| 352 | struct drm_device *dev, | ||
| 353 | uint32_t handle, | ||
| 354 | uint64_t *offset); | ||
| 355 | |||
| 356 | int ast_mm_init(struct ast_private *ast); | 319 | int ast_mm_init(struct ast_private *ast); |
| 357 | void ast_mm_fini(struct ast_private *ast); | 320 | void ast_mm_fini(struct ast_private *ast); |
| 358 | 321 | ||
| 359 | int ast_bo_create(struct drm_device *dev, int size, int align, | ||
| 360 | uint32_t flags, struct ast_bo **pastbo); | ||
| 361 | |||
| 362 | int ast_gem_create(struct drm_device *dev, | 322 | int ast_gem_create(struct drm_device *dev, |
| 363 | u32 size, bool iskernel, | 323 | u32 size, bool iskernel, |
| 364 | struct drm_gem_object **obj); | 324 | struct drm_gem_object **obj); |
| 365 | 325 | ||
| 366 | int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr); | ||
| 367 | int ast_bo_unpin(struct ast_bo *bo); | ||
| 368 | |||
| 369 | static inline int ast_bo_reserve(struct ast_bo *bo, bool no_wait) | ||
| 370 | { | ||
| 371 | int ret; | ||
| 372 | |||
| 373 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); | ||
| 374 | if (ret) { | ||
| 375 | if (ret != -ERESTARTSYS && ret != -EBUSY) | ||
| 376 | DRM_ERROR("reserve failed %p\n", bo); | ||
| 377 | return ret; | ||
| 378 | } | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | static inline void ast_bo_unreserve(struct ast_bo *bo) | ||
| 383 | { | ||
| 384 | ttm_bo_unreserve(&bo->bo); | ||
| 385 | } | ||
| 386 | |||
| 387 | void ast_ttm_placement(struct ast_bo *bo, int domain); | ||
| 388 | int ast_bo_push_sysram(struct ast_bo *bo); | ||
| 389 | int ast_mmap(struct file *filp, struct vm_area_struct *vma); | ||
| 390 | |||
| 391 | /* ast post */ | 326 | /* ast post */ |
| 392 | void ast_enable_vga(struct drm_device *dev); | 327 | void ast_enable_vga(struct drm_device *dev); |
| 393 | void ast_enable_mmio(struct drm_device *dev); | 328 | void ast_enable_mmio(struct drm_device *dev); |
| @@ -49,25 +49,25 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, · 48 unmodified lines | |||
| 49 | { | 49 | { |
| 50 | int i; | 50 | int i; |
| 51 | struct drm_gem_object *obj; | 51 | struct drm_gem_object *obj; |
| 52 | struct ast_bo *bo; | 52 | struct drm_gem_vram_object *gbo; |
| 53 | int src_offset, dst_offset; | 53 | int src_offset, dst_offset; |
| 54 | int bpp = afbdev->afb.base.format->cpp[0]; | 54 | int bpp = afbdev->afb.base.format->cpp[0]; |
| 55 | int ret = -EBUSY; | 55 | int ret = -EBUSY; |
| 56 | u8 *dst; | ||
| 56 | bool unmap = false; | 57 | bool unmap = false; |
| 57 | bool store_for_later = false; | 58 | bool store_for_later = false; |
| 58 | int x2, y2; | 59 | int x2, y2; |
| 59 | unsigned long flags; | 60 | unsigned long flags; |
| 60 | 61 | ||
| 61 | obj = afbdev->afb.obj; | 62 | obj = afbdev->afb.obj; |
| 62 | bo = gem_to_ast_bo(obj); | 63 | gbo = drm_gem_vram_of_gem(obj); |
| 63 | 64 | ||
| 64 | /* | 65 | /* Try to lock the BO. If we fail with -EBUSY then |
| 65 | * try and reserve the BO, if we fail with busy | 66 | * the BO is being moved and we should store up the |
| 66 | * then the BO is being moved and we should | 67 | * damage until later. |
| 67 | * store up the damage until later. | ||
| 68 | */ | 68 | */ |
| 69 | if (drm_can_sleep()) | 69 | if (drm_can_sleep()) |
| 70 | ret = ast_bo_reserve(bo, true); | 70 | ret = drm_gem_vram_lock(gbo, true); |
| 71 | if (ret) { | 71 | if (ret) { |
| 72 | if (ret != -EBUSY) | 72 | if (ret != -EBUSY) |
| 73 | return; | 73 | return; |
| @@ -101,25 +101,32 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, · 27 unmodified lines | |||
| 101 | afbdev->x2 = afbdev->y2 = 0; | 101 | afbdev->x2 = afbdev->y2 = 0; |
| 102 | spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | 102 | spin_unlock_irqrestore(&afbdev->dirty_lock, flags); |
| 103 | 103 | ||
| 104 | if (!bo->kmap.virtual) { | 104 | dst = drm_gem_vram_kmap(gbo, false, NULL); |
| 105 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 105 | if (IS_ERR(dst)) { |
| 106 | if (ret) { | 106 | DRM_ERROR("failed to kmap fb updates\n"); |
| 107 | goto out; | ||
| 108 | } else if (!dst) { | ||
| 109 | dst = drm_gem_vram_kmap(gbo, true, NULL); | ||
| 110 | if (IS_ERR(dst)) { | ||
| 107 | DRM_ERROR("failed to kmap fb updates\n"); | 111 | DRM_ERROR("failed to kmap fb updates\n"); |
| 108 | ast_bo_unreserve(bo); | 112 | goto out; |
| 109 | return; | ||
| 110 | } | 113 | } |
| 111 | unmap = true; | 114 | unmap = true; |
| 112 | } | 115 | } |
| 116 | |||
| 113 | for (i = y; i <= y2; i++) { | 117 | for (i = y; i <= y2; i++) { |
| 114 | /* assume equal stride for now */ | 118 | /* assume equal stride for now */ |
| 115 | src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp); | 119 | src_offset = dst_offset = |
| 116 | memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, (x2 - x + 1) * bpp); | 120 | i * afbdev->afb.base.pitches[0] + (x * bpp); |
| 117 | 121 | memcpy_toio(dst + dst_offset, afbdev->sysram + src_offset, | |
| 122 | (x2 - x + 1) * bpp); | ||
| 118 | } | 123 | } |
| 124 | |||
| 119 | if (unmap) | 125 | if (unmap) |
| 120 | ttm_bo_kunmap(&bo->kmap); | 126 | drm_gem_vram_kunmap(gbo); |
| 121 | 127 | ||
| 122 | ast_bo_unreserve(bo); | 128 | out: |
| 129 | drm_gem_vram_unlock(gbo); | ||
| 123 | } | 130 | } |
| 124 | 131 | ||
| 125 | static void ast_fillrect(struct fb_info *info, | 132 | static void ast_fillrect(struct fb_info *info, |
| @@ -593,7 +593,7 @@ int ast_gem_create(struct drm_device *dev, · 592 unmodified lines | |||
| 593 | u32 size, bool iskernel, | 593 | u32 size, bool iskernel, |
| 594 | struct drm_gem_object **obj) | 594 | struct drm_gem_object **obj) |
| 595 | { | 595 | { |
| 596 | struct ast_bo *astbo; | 596 | struct drm_gem_vram_object *gbo; |
| 597 | int ret; | 597 | int ret; |
| 598 | 598 | ||
| 599 | *obj = NULL; | 599 | *obj = NULL; |
| @@ -602,80 +602,13 @@ int ast_gem_create(struct drm_device *dev, · 2 unmodified lines | |||
| 602 | if (size == 0) | 602 | if (size == 0) |
| 603 | return -EINVAL; | 603 | return -EINVAL; |
| 604 | 604 | ||
| 605 | ret = ast_bo_create(dev, size, 0, 0, &astbo); | 605 | gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); |
| 606 | if (ret) { | 606 | if (IS_ERR(gbo)) { |
| 607 | ret = PTR_ERR(gbo); | ||
| 607 | if (ret != -ERESTARTSYS) | 608 | if (ret != -ERESTARTSYS) |
| 608 | DRM_ERROR("failed to allocate GEM object\n"); | 609 | DRM_ERROR("failed to allocate GEM object\n"); |
| 609 | return ret; | 610 | return ret; |
| 610 | } | 611 | } |
| 611 | *obj = &astbo->gem; | 612 | *obj = &gbo->gem; |
| 612 | return 0; | 613 | return 0; |
| 613 | } | 614 | } |
| 614 | |||
| 615 | int ast_dumb_create(struct drm_file *file, | ||
| 616 | struct drm_device *dev, | ||
| 617 | struct drm_mode_create_dumb *args) | ||
| 618 | { | ||
| 619 | int ret; | ||
| 620 | struct drm_gem_object *gobj; | ||
| 621 | u32 handle; | ||
| 622 | |||
| 623 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
| 624 | args->size = args->pitch * args->height; | ||
| 625 | |||
| 626 | ret = ast_gem_create(dev, args->size, false, | ||
| 627 | &gobj); | ||
| 628 | if (ret) | ||
| 629 | return ret; | ||
| 630 | |||
| 631 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
| 632 | drm_gem_object_put_unlocked(gobj); | ||
| 633 | if (ret) | ||
| 634 | return ret; | ||
| 635 | |||
| 636 | args->handle = handle; | ||
| 637 | return 0; | ||
| 638 | } | ||
| 639 | |||
| 640 | static void ast_bo_unref(struct ast_bo **bo) | ||
| 641 | { | ||
| 642 | if ((*bo) == NULL) | ||
| 643 | return; | ||
| 644 | ttm_bo_put(&((*bo)->bo)); | ||
| 645 | *bo = NULL; | ||
| 646 | } | ||
| 647 | |||
| 648 | void ast_gem_free_object(struct drm_gem_object *obj) | ||
| 649 | { | ||
| 650 | struct ast_bo *ast_bo = gem_to_ast_bo(obj); | ||
| 651 | |||
| 652 | ast_bo_unref(&ast_bo); | ||
| 653 | } | ||
| 654 | |||
| 655 | |||
| 656 | static inline u64 ast_bo_mmap_offset(struct ast_bo *bo) | ||
| 657 | { | ||
| 658 | return drm_vma_node_offset_addr(&bo->bo.vma_node); | ||
| 659 | } | ||
| 660 | int | ||
| 661 | ast_dumb_mmap_offset(struct drm_file *file, | ||
| 662 | struct drm_device *dev, | ||
| 663 | uint32_t handle, | ||
| 664 | uint64_t *offset) | ||
| 665 | { | ||
| 666 | struct drm_gem_object *obj; | ||
| 667 | struct ast_bo *bo; | ||
| 668 | |||
| 669 | obj = drm_gem_object_lookup(file, handle); | ||
| 670 | if (obj == NULL) | ||
| 671 | return -ENOENT; | ||
| 672 | |||
| 673 | bo = gem_to_ast_bo(obj); | ||
| 674 | *offset = ast_bo_mmap_offset(bo); | ||
| 675 | |||
| 676 | drm_gem_object_put_unlocked(obj); | ||
| 677 | |||
| 678 | return 0; | ||
| 679 | |||
| 680 | } | ||
| 681 | |||
| @@ -521,7 +521,6 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) · 520 unmodified lines | |||
| 521 | } | 521 | } |
| 522 | } | 522 | } |
| 523 | 523 | ||
| 524 | /* ast is different - we will force move buffers out of VRAM */ | ||
| 525 | static int ast_crtc_do_set_base(struct drm_crtc *crtc, | 524 | static int ast_crtc_do_set_base(struct drm_crtc *crtc, |
| 526 | struct drm_framebuffer *fb, | 525 | struct drm_framebuffer *fb, |
| 527 | int x, int y, int atomic) | 526 | int x, int y, int atomic) |
| @@ -529,50 +528,54 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc, · 1 unmodified line | |||
| 529 | struct ast_private *ast = crtc->dev->dev_private; | 528 | struct ast_private *ast = crtc->dev->dev_private; |
| 530 | struct drm_gem_object *obj; | 529 | struct drm_gem_object *obj; |
| 531 | struct ast_framebuffer *ast_fb; | 530 | struct ast_framebuffer *ast_fb; |
| 532 | struct ast_bo *bo; | 531 | struct drm_gem_vram_object *gbo; |
| 533 | int ret; | 532 | int ret; |
| 534 | u64 gpu_addr; | 533 | s64 gpu_addr; |
| 534 | void *base; | ||
| 535 | 535 | ||
| 536 | /* push the previous fb to system ram */ | ||
| 537 | if (!atomic && fb) { | 536 | if (!atomic && fb) { |
| 538 | ast_fb = to_ast_framebuffer(fb); | 537 | ast_fb = to_ast_framebuffer(fb); |
| 539 | obj = ast_fb->obj; | 538 | obj = ast_fb->obj; |
| 540 | bo = gem_to_ast_bo(obj); | 539 | gbo = drm_gem_vram_of_gem(obj); |
| 541 | ret = ast_bo_reserve(bo, false); | 540 | |
| 542 | if (ret) | 541 | /* unmap if console */ |
| 543 | return ret; | 542 | if (&ast->fbdev->afb == ast_fb) |
| 544 | ast_bo_push_sysram(bo); | 543 | drm_gem_vram_kunmap(gbo); |
| 545 | ast_bo_unreserve(bo); | 544 | drm_gem_vram_unpin(gbo); |
| 546 | } | 545 | } |
| 547 | 546 | ||
| 548 | ast_fb = to_ast_framebuffer(crtc->primary->fb); | 547 | ast_fb = to_ast_framebuffer(crtc->primary->fb); |
| 549 | obj = ast_fb->obj; | 548 | obj = ast_fb->obj; |
| 550 | bo = gem_to_ast_bo(obj); | 549 | gbo = drm_gem_vram_of_gem(obj); |
| 551 | 550 | ||
| 552 | ret = ast_bo_reserve(bo, false); | 551 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 553 | if (ret) | 552 | if (ret) |
| 554 | return ret; | 553 | return ret; |
| 555 | 554 | gpu_addr = drm_gem_vram_offset(gbo); | |
| 556 | ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | 555 | if (gpu_addr < 0) { |
| 557 | if (ret) { | 556 | ret = (int)gpu_addr; |
| 558 | ast_bo_unreserve(bo); | 557 | goto err_drm_gem_vram_unpin; |
| 559 | return ret; | ||
| 560 | } | 558 | } |
| 561 | 559 | ||
| 562 | if (&ast->fbdev->afb == ast_fb) { | 560 | if (&ast->fbdev->afb == ast_fb) { |
| 563 | /* if pushing console in kmap it */ | 561 | /* if pushing console in kmap it */ |
| 564 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 562 | base = drm_gem_vram_kmap(gbo, true, NULL); |
| 565 | if (ret) | 563 | if (IS_ERR(base)) { |
| 564 | ret = PTR_ERR(base); | ||
| 566 | DRM_ERROR("failed to kmap fbcon\n"); | 565 | DRM_ERROR("failed to kmap fbcon\n"); |
| 567 | else | 566 | } else { |
| 568 | ast_fbdev_set_base(ast, gpu_addr); | 567 | ast_fbdev_set_base(ast, gpu_addr); |
| 568 | } | ||
| 569 | } | 569 | } |
| 570 | ast_bo_unreserve(bo); | ||
| 571 | 570 | ||
| 572 | ast_set_offset_reg(crtc); | 571 | ast_set_offset_reg(crtc); |
| 573 | ast_set_start_address_crt1(crtc, (u32)gpu_addr); | 572 | ast_set_start_address_crt1(crtc, (u32)gpu_addr); |
| 574 | 573 | ||
| 575 | return 0; | 574 | return 0; |
| 575 | |||
| 576 | err_drm_gem_vram_unpin: | ||
| 577 | drm_gem_vram_unpin(gbo); | ||
| 578 | return ret; | ||
| 576 | } | 579 | } |
| 577 | 580 | ||
| 578 | static int ast_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | 581 | static int ast_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, |
| @@ -618,21 +621,18 @@ static int ast_crtc_mode_set(struct drm_crtc *crtc, · 39 unmodified lines | |||
| 618 | 621 | ||
| 619 | static void ast_crtc_disable(struct drm_crtc *crtc) | 622 | static void ast_crtc_disable(struct drm_crtc *crtc) |
| 620 | { | 623 | { |
| 621 | int ret; | ||
| 622 | |||
| 623 | DRM_DEBUG_KMS("\n"); | 624 | DRM_DEBUG_KMS("\n"); |
| 624 | ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 625 | ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
| 625 | if (crtc->primary->fb) { | 626 | if (crtc->primary->fb) { |
| 627 | struct ast_private *ast = crtc->dev->dev_private; | ||
| 626 | struct ast_framebuffer *ast_fb = to_ast_framebuffer(crtc->primary->fb); | 628 | struct ast_framebuffer *ast_fb = to_ast_framebuffer(crtc->primary->fb); |
| 627 | struct drm_gem_object *obj = ast_fb->obj; | 629 | struct drm_gem_object *obj = ast_fb->obj; |
| 628 | struct ast_bo *bo = gem_to_ast_bo(obj); | 630 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(obj); |
| 629 | |||
| 630 | ret = ast_bo_reserve(bo, false); | ||
| 631 | if (ret) | ||
| 632 | return; | ||
| 633 | 631 | ||
| 634 | ast_bo_push_sysram(bo); | 632 | /* unmap if console */ |
| 635 | ast_bo_unreserve(bo); | 633 | if (&ast->fbdev->afb == ast_fb) |
| 634 | drm_gem_vram_kunmap(gbo); | ||
| 635 | drm_gem_vram_unpin(gbo); | ||
| 636 | } | 636 | } |
| 637 | crtc->primary->fb = NULL; | 637 | crtc->primary->fb = NULL; |
| 638 | } | 638 | } |
| @@ -918,28 +918,32 @@ static int ast_cursor_init(struct drm_device *dev) · 279 unmodified lines | |||
| 918 | int size; | 918 | int size; |
| 919 | int ret; | 919 | int ret; |
| 920 | struct drm_gem_object *obj; | 920 | struct drm_gem_object *obj; |
| 921 | struct ast_bo *bo; | 921 | struct drm_gem_vram_object *gbo; |
| 922 | uint64_t gpu_addr; | 922 | s64 gpu_addr; |
| 923 | void *base; | ||
| 923 | 924 | ||
| 924 | size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM; | 925 | size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM; |
| 925 | 926 | ||
| 926 | ret = ast_gem_create(dev, size, true, &obj); | 927 | ret = ast_gem_create(dev, size, true, &obj); |
| 927 | if (ret) | 928 | if (ret) |
| 928 | return ret; | 929 | return ret; |
| 929 | bo = gem_to_ast_bo(obj); | 930 | gbo = drm_gem_vram_of_gem(obj); |
| 930 | ret = ast_bo_reserve(bo, false); | 931 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 931 | if (unlikely(ret != 0)) | ||
| 932 | goto fail; | ||
| 933 | |||
| 934 | ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
| 935 | ast_bo_unreserve(bo); | ||
| 936 | if (ret) | 932 | if (ret) |
| 937 | goto fail; | 933 | goto fail; |
| 934 | gpu_addr = drm_gem_vram_offset(gbo); | ||
| 935 | if (gpu_addr < 0) { | ||
| 936 | drm_gem_vram_unpin(gbo); | ||
| 937 | ret = (int)gpu_addr; | ||
| 938 | goto fail; | ||
| 939 | } | ||
| 938 | 940 | ||
| 939 | /* kmap the object */ | 941 | /* kmap the object */ |
| 940 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &ast->cache_kmap); | 942 | base = drm_gem_vram_kmap_at(gbo, true, NULL, &ast->cache_kmap); |
| 941 | if (ret) | 943 | if (IS_ERR(base)) { |
| 944 | ret = PTR_ERR(base); | ||
| 942 | goto fail; | 945 | goto fail; |
| 946 | } | ||
| 943 | 947 | ||
| 944 | ast->cursor_cache = obj; | 948 | ast->cursor_cache = obj; |
| 945 | ast->cursor_cache_gpu_addr = gpu_addr; | 949 | ast->cursor_cache_gpu_addr = gpu_addr; |
| @@ -952,7 +956,9 @@ fail: · 6 unmodified lines | |||
| 952 | static void ast_cursor_fini(struct drm_device *dev) | 956 | static void ast_cursor_fini(struct drm_device *dev) |
| 953 | { | 957 | { |
| 954 | struct ast_private *ast = dev->dev_private; | 958 | struct ast_private *ast = dev->dev_private; |
| 955 | ttm_bo_kunmap(&ast->cache_kmap); | 959 | struct drm_gem_vram_object *gbo = |
| 960 | drm_gem_vram_of_gem(ast->cursor_cache); | ||
| 961 | drm_gem_vram_kunmap_at(gbo, &ast->cache_kmap); | ||
| 956 | drm_gem_object_put_unlocked(ast->cursor_cache); | 962 | drm_gem_object_put_unlocked(ast->cursor_cache); |
| 957 | } | 963 | } |
| 958 | 964 | ||
| @@ -1173,8 +1179,8 @@ static int ast_cursor_set(struct drm_crtc *crtc, · 214 unmodified lines | |||
| 1173 | struct ast_private *ast = crtc->dev->dev_private; | 1179 | struct ast_private *ast = crtc->dev->dev_private; |
| 1174 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); | 1180 | struct ast_crtc *ast_crtc = to_ast_crtc(crtc); |
| 1175 | struct drm_gem_object *obj; | 1181 | struct drm_gem_object *obj; |
| 1176 | struct ast_bo *bo; | 1182 | struct drm_gem_vram_object *gbo; |
| 1177 | uint64_t gpu_addr; | 1183 | s64 gpu_addr; |
| 1178 | u32 csum; | 1184 | u32 csum; |
| 1179 | int ret; | 1185 | int ret; |
| 1180 | struct ttm_bo_kmap_obj uobj_map; | 1186 | struct ttm_bo_kmap_obj uobj_map; |
| @@ -1193,19 +1199,27 @@ static int ast_cursor_set(struct drm_crtc *crtc, · 12 unmodified lines | |||
| 1193 | DRM_ERROR("Cannot find cursor object %x for crtc\n", handle); | 1199 | DRM_ERROR("Cannot find cursor object %x for crtc\n", handle); |
| 1194 | return -ENOENT; | 1200 | return -ENOENT; |
| 1195 | } | 1201 | } |
| 1196 | bo = gem_to_ast_bo(obj); | 1202 | gbo = drm_gem_vram_of_gem(obj); |
| 1197 | 1203 | ||
| 1198 | ret = ast_bo_reserve(bo, false); | 1204 | ret = drm_gem_vram_lock(gbo, false); |
| 1199 | if (ret) | 1205 | if (ret) |
| 1200 | goto fail; | 1206 | goto fail; |
| 1201 | 1207 | ||
| 1202 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map); | 1208 | memset(&uobj_map, 0, sizeof(uobj_map)); |
| 1203 | 1209 | src = drm_gem_vram_kmap_at(gbo, true, &src_isiomem, &uobj_map); | |
| 1204 | src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem); | 1210 | if (IS_ERR(src)) { |
| 1205 | dst = ttm_kmap_obj_virtual(&ast->cache_kmap, &dst_isiomem); | 1211 | ret = PTR_ERR(src); |
| 1206 | 1212 | goto fail_unlock; | |
| 1213 | } | ||
| 1207 | if (src_isiomem == true) | 1214 | if (src_isiomem == true) |
| 1208 | DRM_ERROR("src cursor bo should be in main memory\n"); | 1215 | DRM_ERROR("src cursor bo should be in main memory\n"); |
| 1216 | |||
| 1217 | dst = drm_gem_vram_kmap_at(drm_gem_vram_of_gem(ast->cursor_cache), | ||
| 1218 | false, &dst_isiomem, &ast->cache_kmap); | ||
| 1219 | if (IS_ERR(dst)) { | ||
| 1220 | ret = PTR_ERR(dst); | ||
| 1221 | goto fail_unlock; | ||
| 1222 | } | ||
| 1209 | if (dst_isiomem == false) | 1223 | if (dst_isiomem == false) |
| 1210 | DRM_ERROR("dst bo should be in VRAM\n"); | 1224 | DRM_ERROR("dst bo should be in VRAM\n"); |
| 1211 | 1225 | ||
| @@ -1214,11 +1228,14 @@ static int ast_cursor_set(struct drm_crtc *crtc, · 2 unmodified lines | |||
| 1214 | /* do data transfer to cursor cache */ | 1228 | /* do data transfer to cursor cache */ |
| 1215 | csum = copy_cursor_image(src, dst, width, height); | 1229 | csum = copy_cursor_image(src, dst, width, height); |
| 1216 | 1230 | ||
| 1231 | drm_gem_vram_kunmap_at(gbo, &uobj_map); | ||
| 1232 | drm_gem_vram_unlock(gbo); | ||
| 1233 | |||
| 1217 | /* write checksum + signature */ | 1234 | /* write checksum + signature */ |
| 1218 | ttm_bo_kunmap(&uobj_map); | ||
| 1219 | ast_bo_unreserve(bo); | ||
| 1220 | { | 1235 | { |
| 1221 | u8 *dst = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; | 1236 | u8 *dst = drm_gem_vram_kmap_at(drm_gem_vram_of_gem(ast->cursor_cache), |
| 1237 | false, NULL, &ast->cache_kmap); | ||
| 1238 | dst += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; | ||
| 1222 | writel(csum, dst); | 1239 | writel(csum, dst); |
| 1223 | writel(width, dst + AST_HWC_SIGNATURE_SizeX); | 1240 | writel(width, dst + AST_HWC_SIGNATURE_SizeX); |
| 1224 | writel(height, dst + AST_HWC_SIGNATURE_SizeY); | 1241 | writel(height, dst + AST_HWC_SIGNATURE_SizeY); |
| @@ -1244,6 +1261,9 @@ static int ast_cursor_set(struct drm_crtc *crtc, · 19 unmodified lines | |||
| 1244 | 1261 | ||
| 1245 | drm_gem_object_put_unlocked(obj); | 1262 | drm_gem_object_put_unlocked(obj); |
| 1246 | return 0; | 1263 | return 0; |
| 1264 | |||
| 1265 | fail_unlock: | ||
| 1266 | drm_gem_vram_unlock(gbo); | ||
| 1247 | fail: | 1267 | fail: |
| 1248 | drm_gem_object_put_unlocked(obj); | 1268 | drm_gem_object_put_unlocked(obj); |
| 1249 | return ret; | 1269 | return ret; |
| @@ -1257,7 +1277,9 @@ static int ast_cursor_move(struct drm_crtc *crtc, · 7 unmodified lines | |||
| 1257 | int x_offset, y_offset; | 1277 | int x_offset, y_offset; |
| 1258 | u8 *sig; | 1278 | u8 *sig; |
| 1259 | 1279 | ||
| 1260 | sig = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; | 1280 | sig = drm_gem_vram_kmap_at(drm_gem_vram_of_gem(ast->cursor_cache), |
| 1281 | false, NULL, &ast->cache_kmap); | ||
| 1282 | sig += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE; | ||
| 1261 | writel(x, sig + AST_HWC_SIGNATURE_X); | 1283 | writel(x, sig + AST_HWC_SIGNATURE_X); |
| 1262 | writel(y, sig + AST_HWC_SIGNATURE_Y); | 1284 | writel(y, sig + AST_HWC_SIGNATURE_Y); |
| 1263 | 1285 | ||
| @@ -26,168 +26,21 @@ · 25 unmodified lines | |||
| 26 | * Authors: Dave Airlie <airlied@redhat.com> | 26 | * Authors: Dave Airlie <airlied@redhat.com> |
| 27 | */ | 27 | */ |
| 28 | #include <drm/drmP.h> | 28 | #include <drm/drmP.h> |
| 29 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 30 | 29 | ||
| 31 | #include "ast_drv.h" | 30 | #include "ast_drv.h" |
| 32 | 31 | ||
| 33 | static inline struct ast_private * | ||
| 34 | ast_bdev(struct ttm_bo_device *bd) | ||
| 35 | { | ||
| 36 | return container_of(bd, struct ast_private, ttm.bdev); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
| 40 | { | ||
| 41 | struct ast_bo *bo; | ||
| 42 | |||
| 43 | bo = container_of(tbo, struct ast_bo, bo); | ||
| 44 | |||
| 45 | drm_gem_object_release(&bo->gem); | ||
| 46 | kfree(bo); | ||
| 47 | } | ||
| 48 | |||
| 49 | static bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo) | ||
| 50 | { | ||
| 51 | if (bo->destroy == &ast_bo_ttm_destroy) | ||
| 52 | return true; | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int | ||
| 57 | ast_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
| 58 | struct ttm_mem_type_manager *man) | ||
| 59 | { | ||
| 60 | switch (type) { | ||
| 61 | case TTM_PL_SYSTEM: | ||
| 62 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 63 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 64 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 65 | break; | ||
| 66 | case TTM_PL_VRAM: | ||
| 67 | man->func = &ttm_bo_manager_func; | ||
| 68 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
| 69 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 70 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
| 71 | TTM_PL_FLAG_WC; | ||
| 72 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | ||
| 76 | return -EINVAL; | ||
| 77 | } | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void | ||
| 82 | ast_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
| 83 | { | ||
| 84 | struct ast_bo *astbo = ast_bo(bo); | ||
| 85 | |||
| 86 | if (!ast_ttm_bo_is_ast_bo(bo)) | ||
| 87 | return; | ||
| 88 | |||
| 89 | ast_ttm_placement(astbo, TTM_PL_FLAG_SYSTEM); | ||
| 90 | *pl = astbo->placement; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | ||
| 94 | { | ||
| 95 | struct ast_bo *astbo = ast_bo(bo); | ||
| 96 | |||
| 97 | return drm_vma_node_verify_access(&astbo->gem.vma_node, | ||
| 98 | filp->private_data); | ||
| 99 | } | ||
| 100 | |||
| 101 | static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 102 | struct ttm_mem_reg *mem) | ||
| 103 | { | ||
| 104 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
| 105 | struct ast_private *ast = ast_bdev(bdev); | ||
| 106 | |||
| 107 | mem->bus.addr = NULL; | ||
| 108 | mem->bus.offset = 0; | ||
| 109 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 110 | mem->bus.base = 0; | ||
| 111 | mem->bus.is_iomem = false; | ||
| 112 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 113 | return -EINVAL; | ||
| 114 | switch (mem->mem_type) { | ||
| 115 | case TTM_PL_SYSTEM: | ||
| 116 | /* system memory */ | ||
| 117 | return 0; | ||
| 118 | case TTM_PL_VRAM: | ||
| 119 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 120 | mem->bus.base = pci_resource_start(ast->dev->pdev, 0); | ||
| 121 | mem->bus.is_iomem = true; | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | return -EINVAL; | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static void ast_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | ||
| 131 | { | ||
| 132 | } | ||
| 133 | |||
| 134 | static void ast_ttm_backend_destroy(struct ttm_tt *tt) | ||
| 135 | { | ||
| 136 | ttm_tt_fini(tt); | ||
| 137 | kfree(tt); | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct ttm_backend_func ast_tt_backend_func = { | ||
| 141 | .destroy = &ast_ttm_backend_destroy, | ||
| 142 | }; | ||
| 143 | |||
| 144 | |||
| 145 | static struct ttm_tt *ast_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 146 | uint32_t page_flags) | ||
| 147 | { | ||
| 148 | struct ttm_tt *tt; | ||
| 149 | |||
| 150 | tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); | ||
| 151 | if (tt == NULL) | ||
| 152 | return NULL; | ||
| 153 | tt->func = &ast_tt_backend_func; | ||
| 154 | if (ttm_tt_init(tt, bo, page_flags)) { | ||
| 155 | kfree(tt); | ||
| 156 | return NULL; | ||
| 157 | } | ||
| 158 | return tt; | ||
| 159 | } | ||
| 160 | |||
| 161 | struct ttm_bo_driver ast_bo_driver = { | ||
| 162 | .ttm_tt_create = ast_ttm_tt_create, | ||
| 163 | .init_mem_type = ast_bo_init_mem_type, | ||
| 164 | .eviction_valuable = ttm_bo_eviction_valuable, | ||
| 165 | .evict_flags = ast_bo_evict_flags, | ||
| 166 | .move = NULL, | ||
| 167 | .verify_access = ast_bo_verify_access, | ||
| 168 | .io_mem_reserve = &ast_ttm_io_mem_reserve, | ||
| 169 | .io_mem_free = &ast_ttm_io_mem_free, | ||
| 170 | }; | ||
| 171 | |||
| 172 | int ast_mm_init(struct ast_private *ast) | 32 | int ast_mm_init(struct ast_private *ast) |
| 173 | { | 33 | { |
| 34 | struct drm_vram_mm *vmm; | ||
| 174 | int ret; | 35 | int ret; |
| 175 | struct drm_device *dev = ast->dev; | 36 | struct drm_device *dev = ast->dev; |
| 176 | struct ttm_bo_device *bdev = &ast->ttm.bdev; | ||
| 177 | |||
| 178 | ret = ttm_bo_device_init(&ast->ttm.bdev, | ||
| 179 | &ast_bo_driver, | ||
| 180 | dev->anon_inode->i_mapping, | ||
| 181 | true); | ||
| 182 | if (ret) { | ||
| 183 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | 37 | ||
| 187 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | 38 | vmm = drm_vram_helper_alloc_mm( |
| 188 | ast->vram_size >> PAGE_SHIFT); | 39 | dev, pci_resource_start(dev->pdev, 0), |
| 189 | if (ret) { | 40 | ast->vram_size, &drm_gem_vram_mm_funcs); |
| 190 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | 41 | if (IS_ERR(vmm)) { |
| 42 | ret = PTR_ERR(vmm); | ||
| 43 | DRM_ERROR("Error initializing VRAM MM; %d\n", ret); | ||
| 191 | return ret; | 44 | return ret; |
| 192 | } | 45 | } |
| 193 | 46 | ||
| @@ -203,148 +56,9 @@ void ast_mm_fini(struct ast_private *ast) · 9 unmodified lines | |||
| 203 | { | 56 | { |
| 204 | struct drm_device *dev = ast->dev; | 57 | struct drm_device *dev = ast->dev; |
| 205 | 58 | ||
| 206 | ttm_bo_device_release(&ast->ttm.bdev); | 59 | drm_vram_helper_release_mm(dev); |
| 207 | 60 | ||
| 208 | arch_phys_wc_del(ast->fb_mtrr); | 61 | arch_phys_wc_del(ast->fb_mtrr); |
| 209 | arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), | 62 | arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), |
| 210 | pci_resource_len(dev->pdev, 0)); | 63 | pci_resource_len(dev->pdev, 0)); |
| 211 | } | 64 | } |
| 212 | |||
| 213 | void ast_ttm_placement(struct ast_bo *bo, int domain) | ||
| 214 | { | ||
| 215 | u32 c = 0; | ||
| 216 | unsigned i; | ||
| 217 | |||
| 218 | bo->placement.placement = bo->placements; | ||
| 219 | bo->placement.busy_placement = bo->placements; | ||
| 220 | if (domain & TTM_PL_FLAG_VRAM) | ||
| 221 | bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
| 222 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
| 223 | bo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; | ||
| 224 | if (!c) | ||
| 225 | bo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; | ||
| 226 | bo->placement.num_placement = c; | ||
| 227 | bo->placement.num_busy_placement = c; | ||
| 228 | for (i = 0; i < c; ++i) { | ||
| 229 | bo->placements[i].fpfn = 0; | ||
| 230 | bo->placements[i].lpfn = 0; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | int ast_bo_create(struct drm_device *dev, int size, int align, | ||
| 235 | uint32_t flags, struct ast_bo **pastbo) | ||
| 236 | { | ||
| 237 | struct ast_private *ast = dev->dev_private; | ||
| 238 | struct ast_bo *astbo; | ||
| 239 | size_t acc_size; | ||
| 240 | int ret; | ||
| 241 | |||
| 242 | astbo = kzalloc(sizeof(struct ast_bo), GFP_KERNEL); | ||
| 243 | if (!astbo) | ||
| 244 | return -ENOMEM; | ||
| 245 | |||
| 246 | ret = drm_gem_object_init(dev, &astbo->gem, size); | ||
| 247 | if (ret) | ||
| 248 | goto error; | ||
| 249 | |||
| 250 | astbo->bo.bdev = &ast->ttm.bdev; | ||
| 251 | |||
| 252 | ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 253 | |||
| 254 | acc_size = ttm_bo_dma_acc_size(&ast->ttm.bdev, size, | ||
| 255 | sizeof(struct ast_bo)); | ||
| 256 | |||
| 257 | ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size, | ||
| 258 | ttm_bo_type_device, &astbo->placement, | ||
| 259 | align >> PAGE_SHIFT, false, acc_size, | ||
| 260 | NULL, NULL, ast_bo_ttm_destroy); | ||
| 261 | if (ret) | ||
| 262 | goto error; | ||
| 263 | |||
| 264 | *pastbo = astbo; | ||
| 265 | return 0; | ||
| 266 | error: | ||
| 267 | kfree(astbo); | ||
| 268 | return ret; | ||
| 269 | } | ||
| 270 | |||
| 271 | static inline u64 ast_bo_gpu_offset(struct ast_bo *bo) | ||
| 272 | { | ||
| 273 | return bo->bo.offset; | ||
| 274 | } | ||
| 275 | |||
| 276 | int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
| 277 | { | ||
| 278 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 279 | int i, ret; | ||
| 280 | |||
| 281 | if (bo->pin_count) { | ||
| 282 | bo->pin_count++; | ||
| 283 | if (gpu_addr) | ||
| 284 | *gpu_addr = ast_bo_gpu_offset(bo); | ||
| 285 | } | ||
| 286 | |||
| 287 | ast_ttm_placement(bo, pl_flag); | ||
| 288 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 289 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 290 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 291 | if (ret) | ||
| 292 | return ret; | ||
| 293 | |||
| 294 | bo->pin_count = 1; | ||
| 295 | if (gpu_addr) | ||
| 296 | *gpu_addr = ast_bo_gpu_offset(bo); | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | int ast_bo_unpin(struct ast_bo *bo) | ||
| 301 | { | ||
| 302 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 303 | int i; | ||
| 304 | if (!bo->pin_count) { | ||
| 305 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | bo->pin_count--; | ||
| 309 | if (bo->pin_count) | ||
| 310 | return 0; | ||
| 311 | |||
| 312 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
| 313 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 314 | return ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 315 | } | ||
| 316 | |||
| 317 | int ast_bo_push_sysram(struct ast_bo *bo) | ||
| 318 | { | ||
| 319 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 320 | int i, ret; | ||
| 321 | if (!bo->pin_count) { | ||
| 322 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | bo->pin_count--; | ||
| 326 | if (bo->pin_count) | ||
| 327 | return 0; | ||
| 328 | |||
| 329 | if (bo->kmap.virtual) | ||
| 330 | ttm_bo_kunmap(&bo->kmap); | ||
| 331 | |||
| 332 | ast_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
| 333 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
| 334 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 335 | |||
| 336 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 337 | if (ret) { | ||
| 338 | DRM_ERROR("pushing to VRAM failed\n"); | ||
| 339 | return ret; | ||
| 340 | } | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | int ast_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 345 | { | ||
| 346 | struct drm_file *file_priv = filp->private_data; | ||
| 347 | struct ast_private *ast = file_priv->minor->dev->dev_private; | ||
| 348 | |||
| 349 | return ttm_bo_mmap(filp, vma, &ast->ttm.bdev); | ||
| 350 | } | ||
| @@ -603,8 +603,6 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, · 602 unmodified lines | |||
| 603 | const struct drm_display_mode *mode; | 603 | const struct drm_display_mode *mode; |
| 604 | struct drm_crtc_state *crtc_state; | 604 | struct drm_crtc_state *crtc_state; |
| 605 | unsigned int tmp; | 605 | unsigned int tmp; |
| 606 | int hsub = 1; | ||
| 607 | int vsub = 1; | ||
| 608 | int ret; | 606 | int ret; |
| 609 | int i; | 607 | int i; |
| 610 | 608 | ||
| @@ -642,13 +640,10 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, · 31 unmodified lines | |||
| 642 | if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES) | 640 | if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES) |
| 643 | return -EINVAL; | 641 | return -EINVAL; |
| 644 | 642 | ||
| 645 | hsub = drm_format_horz_chroma_subsampling(fb->format->format); | ||
| 646 | vsub = drm_format_vert_chroma_subsampling(fb->format->format); | ||
| 647 | |||
| 648 | for (i = 0; i < state->nplanes; i++) { | 643 | for (i = 0; i < state->nplanes; i++) { |
| 649 | unsigned int offset = 0; | 644 | unsigned int offset = 0; |
| 650 | int xdiv = i ? hsub : 1; | 645 | int xdiv = i ? fb->format->hsub : 1; |
| 651 | int ydiv = i ? vsub : 1; | 646 | int ydiv = i ? fb->format->vsub : 1; |
| 652 | 647 | ||
| 653 | state->bpp[i] = fb->format->cpp[i]; | 648 | state->bpp[i] = fb->format->cpp[i]; |
| 654 | if (!state->bpp[i]) | 649 | if (!state->bpp[i]) |
| @@ -3,7 +3,7 @@ config DRM_BOCHS · 2 unmodified lines | |||
| 3 | tristate "DRM Support for bochs dispi vga interface (qemu stdvga)" | 3 | tristate "DRM Support for bochs dispi vga interface (qemu stdvga)" |
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 6 | select DRM_TTM | 6 | select DRM_VRAM_HELPER |
| 7 | help | 7 | help |
| 8 | Choose this option for qemu. | 8 | Choose this option for qemu. |
| 9 | If M is selected the module will be called bochs-drm. | 9 | If M is selected the module will be called bochs-drm. |
| @@ -10,9 +10,9 @@ · 9 unmodified lines | |||
| 10 | #include <drm/drm_simple_kms_helper.h> | 10 | #include <drm/drm_simple_kms_helper.h> |
| 11 | 11 | ||
| 12 | #include <drm/drm_gem.h> | 12 | #include <drm/drm_gem.h> |
| 13 | #include <drm/drm_gem_vram_helper.h> | ||
| 13 | 14 | ||
| 14 | #include <drm/ttm/ttm_bo_driver.h> | 15 | #include <drm/drm_vram_mm_helper.h> |
| 15 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 16 | 16 | ||
| 17 | /* ---------------------------------------------------------------------- */ | 17 | /* ---------------------------------------------------------------------- */ |
| 18 | 18 | ||
| @@ -73,38 +73,8 @@ struct bochs_device { · 54 unmodified lines | |||
| 73 | struct drm_device *dev; | 73 | struct drm_device *dev; |
| 74 | struct drm_simple_display_pipe pipe; | 74 | struct drm_simple_display_pipe pipe; |
| 75 | struct drm_connector connector; | 75 | struct drm_connector connector; |
| 76 | |||
| 77 | /* ttm */ | ||
| 78 | struct { | ||
| 79 | struct ttm_bo_device bdev; | ||
| 80 | bool initialized; | ||
| 81 | } ttm; | ||
| 82 | }; | ||
| 83 | |||
| 84 | struct bochs_bo { | ||
| 85 | struct ttm_buffer_object bo; | ||
| 86 | struct ttm_placement placement; | ||
| 87 | struct ttm_bo_kmap_obj kmap; | ||
| 88 | struct drm_gem_object gem; | ||
| 89 | struct ttm_place placements[3]; | ||
| 90 | int pin_count; | ||
| 91 | }; | 76 | }; |
| 92 | 77 | ||
| 93 | static inline struct bochs_bo *bochs_bo(struct ttm_buffer_object *bo) | ||
| 94 | { | ||
| 95 | return container_of(bo, struct bochs_bo, bo); | ||
| 96 | } | ||
| 97 | |||
| 98 | static inline struct bochs_bo *gem_to_bochs_bo(struct drm_gem_object *gem) | ||
| 99 | { | ||
| 100 | return container_of(gem, struct bochs_bo, gem); | ||
| 101 | } | ||
| 102 | |||
| 103 | static inline u64 bochs_bo_mmap_offset(struct bochs_bo *bo) | ||
| 104 | { | ||
| 105 | return drm_vma_node_offset_addr(&bo->bo.vma_node); | ||
| 106 | } | ||
| 107 | |||
| 108 | /* ---------------------------------------------------------------------- */ | 78 | /* ---------------------------------------------------------------------- */ |
| 109 | 79 | ||
| 110 | /* bochs_hw.c */ | 80 | /* bochs_hw.c */ |
| @@ -122,26 +92,6 @@ int bochs_hw_load_edid(struct bochs_device *bochs); · 11 unmodified lines | |||
| 122 | /* bochs_mm.c */ | 92 | /* bochs_mm.c */ |
| 123 | int bochs_mm_init(struct bochs_device *bochs); | 93 | int bochs_mm_init(struct bochs_device *bochs); |
| 124 | void bochs_mm_fini(struct bochs_device *bochs); | 94 | void bochs_mm_fini(struct bochs_device *bochs); |
| 125 | int bochs_mmap(struct file *filp, struct vm_area_struct *vma); | ||
| 126 | |||
| 127 | int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, | ||
| 128 | struct drm_gem_object **obj); | ||
| 129 | int bochs_gem_init_object(struct drm_gem_object *obj); | ||
| 130 | void bochs_gem_free_object(struct drm_gem_object *obj); | ||
| 131 | int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, | ||
| 132 | struct drm_mode_create_dumb *args); | ||
| 133 | int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, | ||
| 134 | uint32_t handle, uint64_t *offset); | ||
| 135 | |||
| 136 | int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag); | ||
| 137 | int bochs_bo_unpin(struct bochs_bo *bo); | ||
| 138 | |||
| 139 | int bochs_gem_prime_pin(struct drm_gem_object *obj); | ||
| 140 | void bochs_gem_prime_unpin(struct drm_gem_object *obj); | ||
| 141 | void *bochs_gem_prime_vmap(struct drm_gem_object *obj); | ||
| 142 | void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); | ||
| 143 | int bochs_gem_prime_mmap(struct drm_gem_object *obj, | ||
| 144 | struct vm_area_struct *vma); | ||
| 145 | 95 | ||
| 146 | /* bochs_kms.c */ | 96 | /* bochs_kms.c */ |
| 147 | int bochs_kms_init(struct bochs_device *bochs); | 97 | int bochs_kms_init(struct bochs_device *bochs); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <drm/drm_fb_helper.h> | 11 | #include <drm/drm_fb_helper.h> |
| 12 | #include <drm/drm_probe_helper.h> | 12 | #include <drm/drm_probe_helper.h> |
| 13 | #include <drm/drm_atomic_helper.h> | ||
| 13 | 14 | ||
| 14 | #include "bochs.h" | 15 | #include "bochs.h" |
| 15 | 16 | ||
| @@ -63,14 +64,7 @@ err: · 47 unmodified lines | |||
| 63 | 64 | ||
| 64 | static const struct file_operations bochs_fops = { | 65 | static const struct file_operations bochs_fops = { |
| 65 | .owner = THIS_MODULE, | 66 | .owner = THIS_MODULE, |
| 66 | .open = drm_open, | 67 | DRM_VRAM_MM_FILE_OPERATIONS |
| 67 | .release = drm_release, | ||
| 68 | .unlocked_ioctl = drm_ioctl, | ||
| 69 | .compat_ioctl = drm_compat_ioctl, | ||
| 70 | .poll = drm_poll, | ||
| 71 | .read = drm_read, | ||
| 72 | .llseek = no_llseek, | ||
| 73 | .mmap = bochs_mmap, | ||
| 74 | }; | 68 | }; |
| 75 | 69 | ||
| 76 | static struct drm_driver bochs_driver = { | 70 | static struct drm_driver bochs_driver = { |
| @@ -82,17 +76,8 @@ static struct drm_driver bochs_driver = { · 5 unmodified lines | |||
| 82 | .date = "20130925", | 76 | .date = "20130925", |
| 83 | .major = 1, | 77 | .major = 1, |
| 84 | .minor = 0, | 78 | .minor = 0, |
| 85 | .gem_free_object_unlocked = bochs_gem_free_object, | 79 | DRM_GEM_VRAM_DRIVER, |
| 86 | .dumb_create = bochs_dumb_create, | 80 | DRM_GEM_VRAM_DRIVER_PRIME, |
| 87 | .dumb_map_offset = bochs_dumb_mmap_offset, | ||
| 88 | |||
| 89 | .gem_prime_export = drm_gem_prime_export, | ||
| 90 | .gem_prime_import = drm_gem_prime_import, | ||
| 91 | .gem_prime_pin = bochs_gem_prime_pin, | ||
| 92 | .gem_prime_unpin = bochs_gem_prime_unpin, | ||
| 93 | .gem_prime_vmap = bochs_gem_prime_vmap, | ||
| 94 | .gem_prime_vunmap = bochs_gem_prime_vunmap, | ||
| 95 | .gem_prime_mmap = bochs_gem_prime_mmap, | ||
| 96 | }; | 81 | }; |
| 97 | 82 | ||
| 98 | /* ---------------------------------------------------------------------- */ | 83 | /* ---------------------------------------------------------------------- */ |
| @@ -174,6 +159,7 @@ static void bochs_pci_remove(struct pci_dev *pdev) · 75 unmodified lines | |||
| 174 | { | 159 | { |
| 175 | struct drm_device *dev = pci_get_drvdata(pdev); | 160 | struct drm_device *dev = pci_get_drvdata(pdev); |
| 176 | 161 | ||
| 162 | drm_atomic_helper_shutdown(dev); | ||
| 177 | drm_dev_unregister(dev); | 163 | drm_dev_unregister(dev); |
| 178 | bochs_unload(dev); | 164 | bochs_unload(dev); |
| 179 | drm_dev_put(dev); | 165 | drm_dev_put(dev); |
| @@ -30,16 +30,16 @@ static const uint32_t bochs_formats[] = { · 29 unmodified lines | |||
| 30 | static void bochs_plane_update(struct bochs_device *bochs, | 30 | static void bochs_plane_update(struct bochs_device *bochs, |
| 31 | struct drm_plane_state *state) | 31 | struct drm_plane_state *state) |
| 32 | { | 32 | { |
| 33 | struct bochs_bo *bo; | 33 | struct drm_gem_vram_object *gbo; |
| 34 | 34 | ||
| 35 | if (!state->fb || !bochs->stride) | 35 | if (!state->fb || !bochs->stride) |
| 36 | return; | 36 | return; |
| 37 | 37 | ||
| 38 | bo = gem_to_bochs_bo(state->fb->obj[0]); | 38 | gbo = drm_gem_vram_of_gem(state->fb->obj[0]); |
| 39 | bochs_hw_setbase(bochs, | 39 | bochs_hw_setbase(bochs, |
| 40 | state->crtc_x, | 40 | state->crtc_x, |
| 41 | state->crtc_y, | 41 | state->crtc_y, |
| 42 | bo->bo.offset); | 42 | gbo->bo.offset); |
| 43 | bochs_hw_setformat(bochs, state->fb->format); | 43 | bochs_hw_setformat(bochs, state->fb->format); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| @@ -72,23 +72,23 @@ static void bochs_pipe_update(struct drm_simple_display_pipe *pipe, · 26 unmodified lines | |||
| 72 | static int bochs_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, | 72 | static int bochs_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, |
| 73 | struct drm_plane_state *new_state) | 73 | struct drm_plane_state *new_state) |
| 74 | { | 74 | { |
| 75 | struct bochs_bo *bo; | 75 | struct drm_gem_vram_object *gbo; |
| 76 | 76 | ||
| 77 | if (!new_state->fb) | 77 | if (!new_state->fb) |
| 78 | return 0; | 78 | return 0; |
| 79 | bo = gem_to_bochs_bo(new_state->fb->obj[0]); | 79 | gbo = drm_gem_vram_of_gem(new_state->fb->obj[0]); |
| 80 | return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); | 80 | return drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | static void bochs_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, | 83 | static void bochs_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, |
| 84 | struct drm_plane_state *old_state) | 84 | struct drm_plane_state *old_state) |
| 85 | { | 85 | { |
| 86 | struct bochs_bo *bo; | 86 | struct drm_gem_vram_object *gbo; |
| 87 | 87 | ||
| 88 | if (!old_state->fb) | 88 | if (!old_state->fb) |
| 89 | return; | 89 | return; |
| 90 | bo = gem_to_bochs_bo(old_state->fb->obj[0]); | 90 | gbo = drm_gem_vram_of_gem(old_state->fb->obj[0]); |
| 91 | bochs_bo_unpin(bo); | 91 | drm_gem_vram_unpin(gbo); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = { | 94 | static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = { |
| @@ -7,435 +7,22 @@ · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | #include "bochs.h" | 8 | #include "bochs.h" |
| 9 | 9 | ||
| 10 | static void bochs_ttm_placement(struct bochs_bo *bo, int domain); | ||
| 11 | |||
| 12 | /* ---------------------------------------------------------------------- */ | 10 | /* ---------------------------------------------------------------------- */ |
| 13 | 11 | ||
| 14 | static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd) | ||
| 15 | { | ||
| 16 | return container_of(bd, struct bochs_device, ttm.bdev); | ||
| 17 | } | ||
| 18 | |||
| 19 | static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
| 20 | { | ||
| 21 | struct bochs_bo *bo; | ||
| 22 | |||
| 23 | bo = container_of(tbo, struct bochs_bo, bo); | ||
| 24 | drm_gem_object_release(&bo->gem); | ||
| 25 | kfree(bo); | ||
| 26 | } | ||
| 27 | |||
| 28 | static bool bochs_ttm_bo_is_bochs_bo(struct ttm_buffer_object *bo) | ||
| 29 | { | ||
| 30 | if (bo->destroy == &bochs_bo_ttm_destroy) | ||
| 31 | return true; | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | static int bochs_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
| 36 | struct ttm_mem_type_manager *man) | ||
| 37 | { | ||
| 38 | switch (type) { | ||
| 39 | case TTM_PL_SYSTEM: | ||
| 40 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 41 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 42 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 43 | break; | ||
| 44 | case TTM_PL_VRAM: | ||
| 45 | man->func = &ttm_bo_manager_func; | ||
| 46 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
| 47 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 48 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
| 49 | TTM_PL_FLAG_WC; | ||
| 50 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 51 | break; | ||
| 52 | default: | ||
| 53 | DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | ||
| 54 | return -EINVAL; | ||
| 55 | } | ||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void | ||
| 60 | bochs_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
| 61 | { | ||
| 62 | struct bochs_bo *bochsbo = bochs_bo(bo); | ||
| 63 | |||
| 64 | if (!bochs_ttm_bo_is_bochs_bo(bo)) | ||
| 65 | return; | ||
| 66 | |||
| 67 | bochs_ttm_placement(bochsbo, TTM_PL_FLAG_SYSTEM); | ||
| 68 | *pl = bochsbo->placement; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int bochs_bo_verify_access(struct ttm_buffer_object *bo, | ||
| 72 | struct file *filp) | ||
| 73 | { | ||
| 74 | struct bochs_bo *bochsbo = bochs_bo(bo); | ||
| 75 | |||
| 76 | return drm_vma_node_verify_access(&bochsbo->gem.vma_node, | ||
| 77 | filp->private_data); | ||
| 78 | } | ||
| 79 | |||
| 80 | static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 81 | struct ttm_mem_reg *mem) | ||
| 82 | { | ||
| 83 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
| 84 | struct bochs_device *bochs = bochs_bdev(bdev); | ||
| 85 | |||
| 86 | mem->bus.addr = NULL; | ||
| 87 | mem->bus.offset = 0; | ||
| 88 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 89 | mem->bus.base = 0; | ||
| 90 | mem->bus.is_iomem = false; | ||
| 91 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 92 | return -EINVAL; | ||
| 93 | switch (mem->mem_type) { | ||
| 94 | case TTM_PL_SYSTEM: | ||
| 95 | /* system memory */ | ||
| 96 | return 0; | ||
| 97 | case TTM_PL_VRAM: | ||
| 98 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 99 | mem->bus.base = bochs->fb_base; | ||
| 100 | mem->bus.is_iomem = true; | ||
| 101 | break; | ||
| 102 | default: | ||
| 103 | return -EINVAL; | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | static void bochs_ttm_io_mem_free(struct ttm_bo_device *bdev, | ||
| 110 | struct ttm_mem_reg *mem) | ||
| 111 | { | ||
| 112 | } | ||
| 113 | |||
| 114 | static void bochs_ttm_backend_destroy(struct ttm_tt *tt) | ||
| 115 | { | ||
| 116 | ttm_tt_fini(tt); | ||
| 117 | kfree(tt); | ||
| 118 | } | ||
| 119 | |||
| 120 | static struct ttm_backend_func bochs_tt_backend_func = { | ||
| 121 | .destroy = &bochs_ttm_backend_destroy, | ||
| 122 | }; | ||
| 123 | |||
| 124 | static struct ttm_tt *bochs_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 125 | uint32_t page_flags) | ||
| 126 | { | ||
| 127 | struct ttm_tt *tt; | ||
| 128 | |||
| 129 | tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); | ||
| 130 | if (tt == NULL) | ||
| 131 | return NULL; | ||
| 132 | tt->func = &bochs_tt_backend_func; | ||
| 133 | if (ttm_tt_init(tt, bo, page_flags)) { | ||
| 134 | kfree(tt); | ||
| 135 | return NULL; | ||
| 136 | } | ||
| 137 | return tt; | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct ttm_bo_driver bochs_bo_driver = { | ||
| 141 | .ttm_tt_create = bochs_ttm_tt_create, | ||
| 142 | .init_mem_type = bochs_bo_init_mem_type, | ||
| 143 | .eviction_valuable = ttm_bo_eviction_valuable, | ||
| 144 | .evict_flags = bochs_bo_evict_flags, | ||
| 145 | .move = NULL, | ||
| 146 | .verify_access = bochs_bo_verify_access, | ||
| 147 | .io_mem_reserve = &bochs_ttm_io_mem_reserve, | ||
| 148 | .io_mem_free = &bochs_ttm_io_mem_free, | ||
| 149 | }; | ||
| 150 | |||
| 151 | int bochs_mm_init(struct bochs_device *bochs) | 12 | int bochs_mm_init(struct bochs_device *bochs) |
| 152 | { | 13 | { |
| 153 | struct ttm_bo_device *bdev = &bochs->ttm.bdev; | 14 | struct drm_vram_mm *vmm; |
| 154 | int ret; | ||
| 155 | 15 | ||
| 156 | ret = ttm_bo_device_init(&bochs->ttm.bdev, | 16 | vmm = drm_vram_helper_alloc_mm(bochs->dev, bochs->fb_base, |
| 157 | &bochs_bo_driver, | 17 | bochs->fb_size, |
| 158 | bochs->dev->anon_inode->i_mapping, | 18 | &drm_gem_vram_mm_funcs); |
| 159 | true); | 19 | return PTR_ERR_OR_ZERO(vmm); |
| 160 | if (ret) { | ||
| 161 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | ||
| 162 | return ret; | ||
| 163 | } | ||
| 164 | |||
| 165 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | ||
| 166 | bochs->fb_size >> PAGE_SHIFT); | ||
| 167 | if (ret) { | ||
| 168 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | ||
| 169 | return ret; | ||
| 170 | } | ||
| 171 | |||
| 172 | bochs->ttm.initialized = true; | ||
| 173 | return 0; | ||
| 174 | } | 20 | } |
| 175 | 21 | ||
| 176 | void bochs_mm_fini(struct bochs_device *bochs) | 22 | void bochs_mm_fini(struct bochs_device *bochs) |
| 177 | { | 23 | { |
| 178 | if (!bochs->ttm.initialized) | 24 | if (!bochs->dev->vram_mm) |
| 179 | return; | 25 | return; |
| 180 | 26 | ||
| 181 | ttm_bo_device_release(&bochs->ttm.bdev); | 27 | drm_vram_helper_release_mm(bochs->dev); |
| 182 | bochs->ttm.initialized = false; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void bochs_ttm_placement(struct bochs_bo *bo, int domain) | ||
| 186 | { | ||
| 187 | unsigned i; | ||
| 188 | u32 c = 0; | ||
| 189 | bo->placement.placement = bo->placements; | ||
| 190 | bo->placement.busy_placement = bo->placements; | ||
| 191 | if (domain & TTM_PL_FLAG_VRAM) { | ||
| 192 | bo->placements[c++].flags = TTM_PL_FLAG_WC | ||
| 193 | | TTM_PL_FLAG_UNCACHED | ||
| 194 | | TTM_PL_FLAG_VRAM; | ||
| 195 | } | ||
| 196 | if (domain & TTM_PL_FLAG_SYSTEM) { | ||
| 197 | bo->placements[c++].flags = TTM_PL_MASK_CACHING | ||
| 198 | | TTM_PL_FLAG_SYSTEM; | ||
| 199 | } | ||
| 200 | if (!c) { | ||
| 201 | bo->placements[c++].flags = TTM_PL_MASK_CACHING | ||
| 202 | | TTM_PL_FLAG_SYSTEM; | ||
| 203 | } | ||
| 204 | for (i = 0; i < c; ++i) { | ||
| 205 | bo->placements[i].fpfn = 0; | ||
| 206 | bo->placements[i].lpfn = 0; | ||
| 207 | } | ||
| 208 | bo->placement.num_placement = c; | ||
| 209 | bo->placement.num_busy_placement = c; | ||
| 210 | } | ||
| 211 | |||
| 212 | int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag) | ||
| 213 | { | ||
| 214 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 215 | int i, ret; | ||
| 216 | |||
| 217 | if (bo->pin_count) { | ||
| 218 | bo->pin_count++; | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | bochs_ttm_placement(bo, pl_flag); | ||
| 223 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 224 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 225 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
| 226 | if (ret) | ||
| 227 | return ret; | ||
| 228 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 229 | ttm_bo_unreserve(&bo->bo); | ||
| 230 | if (ret) | ||
| 231 | return ret; | ||
| 232 | |||
| 233 | bo->pin_count = 1; | ||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | |||
| 237 | int bochs_bo_unpin(struct bochs_bo *bo) | ||
| 238 | { | ||
| 239 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 240 | int i, ret; | ||
| 241 | |||
| 242 | if (!bo->pin_count) { | ||
| 243 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | bo->pin_count--; | ||
| 247 | |||
| 248 | if (bo->pin_count) | ||
| 249 | return 0; | ||
| 250 | |||
| 251 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 252 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 253 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | ||
| 254 | if (ret) | ||
| 255 | return ret; | ||
| 256 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 257 | ttm_bo_unreserve(&bo->bo); | ||
| 258 | if (ret) | ||
| 259 | return ret; | ||
| 260 | |||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | int bochs_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 265 | { | ||
| 266 | struct drm_file *file_priv = filp->private_data; | ||
| 267 | struct bochs_device *bochs = file_priv->minor->dev->dev_private; | ||
| 268 | |||
| 269 | return ttm_bo_mmap(filp, vma, &bochs->ttm.bdev); | ||
| 270 | } | ||
| 271 | |||
| 272 | /* ---------------------------------------------------------------------- */ | ||
| 273 | |||
| 274 | static int bochs_bo_create(struct drm_device *dev, int size, int align, | ||
| 275 | uint32_t flags, struct bochs_bo **pbochsbo) | ||
| 276 | { | ||
| 277 | struct bochs_device *bochs = dev->dev_private; | ||
| 278 | struct bochs_bo *bochsbo; | ||
| 279 | size_t acc_size; | ||
| 280 | int ret; | ||
| 281 | |||
| 282 | bochsbo = kzalloc(sizeof(struct bochs_bo), GFP_KERNEL); | ||
| 283 | if (!bochsbo) | ||
| 284 | return -ENOMEM; | ||
| 285 | |||
| 286 | ret = drm_gem_object_init(dev, &bochsbo->gem, size); | ||
| 287 | if (ret) { | ||
| 288 | kfree(bochsbo); | ||
| 289 | return ret; | ||
| 290 | } | ||
| 291 | |||
| 292 | bochsbo->bo.bdev = &bochs->ttm.bdev; | ||
| 293 | bochsbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping; | ||
| 294 | |||
| 295 | bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 296 | |||
| 297 | acc_size = ttm_bo_dma_acc_size(&bochs->ttm.bdev, size, | ||
| 298 | sizeof(struct bochs_bo)); | ||
| 299 | |||
| 300 | ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size, | ||
| 301 | ttm_bo_type_device, &bochsbo->placement, | ||
| 302 | align >> PAGE_SHIFT, false, acc_size, | ||
| 303 | NULL, NULL, bochs_bo_ttm_destroy); | ||
| 304 | if (ret) | ||
| 305 | return ret; | ||
| 306 | |||
| 307 | *pbochsbo = bochsbo; | ||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | |||
| 311 | int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, | ||
| 312 | struct drm_gem_object **obj) | ||
| 313 | { | ||
| 314 | struct bochs_bo *bochsbo; | ||
| 315 | int ret; | ||
| 316 | |||
| 317 | *obj = NULL; | ||
| 318 | |||
| 319 | size = PAGE_ALIGN(size); | ||
| 320 | if (size == 0) | ||
| 321 | return -EINVAL; | ||
| 322 | |||
| 323 | ret = bochs_bo_create(dev, size, 0, 0, &bochsbo); | ||
| 324 | if (ret) { | ||
| 325 | if (ret != -ERESTARTSYS) | ||
| 326 | DRM_ERROR("failed to allocate GEM object\n"); | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | *obj = &bochsbo->gem; | ||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, | ||
| 334 | struct drm_mode_create_dumb *args) | ||
| 335 | { | ||
| 336 | struct drm_gem_object *gobj; | ||
| 337 | u32 handle; | ||
| 338 | int ret; | ||
| 339 | |||
| 340 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
| 341 | args->size = args->pitch * args->height; | ||
| 342 | |||
| 343 | ret = bochs_gem_create(dev, args->size, false, | ||
| 344 | &gobj); | ||
| 345 | if (ret) | ||
| 346 | return ret; | ||
| 347 | |||
| 348 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
| 349 | drm_gem_object_put_unlocked(gobj); | ||
| 350 | if (ret) | ||
| 351 | return ret; | ||
| 352 | |||
| 353 | args->handle = handle; | ||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | static void bochs_bo_unref(struct bochs_bo **bo) | ||
| 358 | { | ||
| 359 | struct ttm_buffer_object *tbo; | ||
| 360 | |||
| 361 | if ((*bo) == NULL) | ||
| 362 | return; | ||
| 363 | |||
| 364 | tbo = &((*bo)->bo); | ||
| 365 | ttm_bo_put(tbo); | ||
| 366 | *bo = NULL; | ||
| 367 | } | ||
| 368 | |||
| 369 | void bochs_gem_free_object(struct drm_gem_object *obj) | ||
| 370 | { | ||
| 371 | struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj); | ||
| 372 | |||
| 373 | bochs_bo_unref(&bochs_bo); | ||
| 374 | } | ||
| 375 | |||
| 376 | int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, | ||
| 377 | uint32_t handle, uint64_t *offset) | ||
| 378 | { | ||
| 379 | struct drm_gem_object *obj; | ||
| 380 | struct bochs_bo *bo; | ||
| 381 | |||
| 382 | obj = drm_gem_object_lookup(file, handle); | ||
| 383 | if (obj == NULL) | ||
| 384 | return -ENOENT; | ||
| 385 | |||
| 386 | bo = gem_to_bochs_bo(obj); | ||
| 387 | *offset = bochs_bo_mmap_offset(bo); | ||
| 388 | |||
| 389 | drm_gem_object_put_unlocked(obj); | ||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | /* ---------------------------------------------------------------------- */ | ||
| 394 | |||
| 395 | int bochs_gem_prime_pin(struct drm_gem_object *obj) | ||
| 396 | { | ||
| 397 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
| 398 | |||
| 399 | return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); | ||
| 400 | } | ||
| 401 | |||
| 402 | void bochs_gem_prime_unpin(struct drm_gem_object *obj) | ||
| 403 | { | ||
| 404 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
| 405 | |||
| 406 | bochs_bo_unpin(bo); | ||
| 407 | } | ||
| 408 | |||
| 409 | void *bochs_gem_prime_vmap(struct drm_gem_object *obj) | ||
| 410 | { | ||
| 411 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
| 412 | bool is_iomem; | ||
| 413 | int ret; | ||
| 414 | |||
| 415 | ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM); | ||
| 416 | if (ret) | ||
| 417 | return NULL; | ||
| 418 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
| 419 | if (ret) { | ||
| 420 | bochs_bo_unpin(bo); | ||
| 421 | return NULL; | ||
| 422 | } | ||
| 423 | return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); | ||
| 424 | } | ||
| 425 | |||
| 426 | void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) | ||
| 427 | { | ||
| 428 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
| 429 | |||
| 430 | ttm_bo_kunmap(&bo->kmap); | ||
| 431 | bochs_bo_unpin(bo); | ||
| 432 | } | ||
| 433 | |||
| 434 | int bochs_gem_prime_mmap(struct drm_gem_object *obj, | ||
| 435 | struct vm_area_struct *vma) | ||
| 436 | { | ||
| 437 | struct bochs_bo *bo = gem_to_bochs_bo(obj); | ||
| 438 | |||
| 439 | bo->gem.vma_node.vm_node.start = bo->bo.vma_node.vm_node.start; | ||
| 440 | return drm_gem_prime_mmap(obj, vma); | ||
| 441 | } | 28 | } |
| @@ -9,13 +9,12 @@ · 8 unmodified lines | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <drm/drmP.h> | 11 | #include <drm/drmP.h> |
| 12 | #include <drm/drm_panel.h> | ||
| 13 | #include <drm/drm_atomic_helper.h> | 12 | #include <drm/drm_atomic_helper.h> |
| 14 | #include <drm/drm_connector.h> | 13 | #include <drm/drm_connector.h> |
| 15 | #include <drm/drm_encoder.h> | 14 | #include <drm/drm_encoder.h> |
| 16 | #include <drm/drm_modeset_helper_vtables.h> | 15 | #include <drm/drm_modeset_helper_vtables.h> |
| 17 | #include <drm/drm_probe_helper.h> | ||
| 18 | #include <drm/drm_panel.h> | 16 | #include <drm/drm_panel.h> |
| 17 | #include <drm/drm_probe_helper.h> | ||
| 19 | 18 | ||
| 20 | struct panel_bridge { | 19 | struct panel_bridge { |
| 21 | struct drm_bridge bridge; | 20 | struct drm_bridge bridge; |
| @@ -1,250 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Red Hat | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General | ||
| 5 | * Public License version 2. See the file COPYING in the main | ||
| 6 | * directory of this archive for more details. | ||
| 7 | * | ||
| 8 | * Authors: Matthew Garrett | ||
| 9 | * Dave Airlie | ||
| 10 | */ | ||
| 11 | #ifndef __CIRRUS_DRV_H__ | ||
| 12 | #define __CIRRUS_DRV_H__ | ||
| 13 | |||
| 14 | #include <video/vga.h> | ||
| 15 | |||
| 16 | #include <drm/drm_encoder.h> | ||
| 17 | #include <drm/drm_fb_helper.h> | ||
| 18 | |||
| 19 | #include <drm/ttm/ttm_bo_api.h> | ||
| 20 | #include <drm/ttm/ttm_bo_driver.h> | ||
| 21 | #include <drm/ttm/ttm_placement.h> | ||
| 22 | #include <drm/ttm/ttm_memory.h> | ||
| 23 | #include <drm/ttm/ttm_module.h> | ||
| 24 | |||
| 25 | #include <drm/drm_gem.h> | ||
| 26 | |||
| 27 | #define DRIVER_AUTHOR "Matthew Garrett" | ||
| 28 | |||
| 29 | #define DRIVER_NAME "cirrus" | ||
| 30 | #define DRIVER_DESC "qemu Cirrus emulation" | ||
| 31 | #define DRIVER_DATE "20110418" | ||
| 32 | |||
| 33 | #define DRIVER_MAJOR 1 | ||
| 34 | #define DRIVER_MINOR 0 | ||
| 35 | #define DRIVER_PATCHLEVEL 0 | ||
| 36 | |||
| 37 | #define CIRRUSFB_CONN_LIMIT 1 | ||
| 38 | |||
| 39 | #define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg)) | ||
| 40 | #define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg)) | ||
| 41 | #define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg)) | ||
| 42 | #define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg)) | ||
| 43 | |||
| 44 | #define SEQ_INDEX 4 | ||
| 45 | #define SEQ_DATA 5 | ||
| 46 | |||
| 47 | #define WREG_SEQ(reg, v) \ | ||
| 48 | do { \ | ||
| 49 | WREG8(SEQ_INDEX, reg); \ | ||
| 50 | WREG8(SEQ_DATA, v); \ | ||
| 51 | } while (0) \ | ||
| 52 | |||
| 53 | #define CRT_INDEX 0x14 | ||
| 54 | #define CRT_DATA 0x15 | ||
| 55 | |||
| 56 | #define WREG_CRT(reg, v) \ | ||
| 57 | do { \ | ||
| 58 | WREG8(CRT_INDEX, reg); \ | ||
| 59 | WREG8(CRT_DATA, v); \ | ||
| 60 | } while (0) \ | ||
| 61 | |||
| 62 | #define GFX_INDEX 0xe | ||
| 63 | #define GFX_DATA 0xf | ||
| 64 | |||
| 65 | #define WREG_GFX(reg, v) \ | ||
| 66 | do { \ | ||
| 67 | WREG8(GFX_INDEX, reg); \ | ||
| 68 | WREG8(GFX_DATA, v); \ | ||
| 69 | } while (0) \ | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Cirrus has a "hidden" DAC register that can be accessed by writing to | ||
| 73 | * the pixel mask register to reset the state, then reading from the register | ||
| 74 | * four times. The next write will then pass to the DAC | ||
| 75 | */ | ||
| 76 | #define VGA_DAC_MASK 0x6 | ||
| 77 | |||
| 78 | #define WREG_HDR(v) \ | ||
| 79 | do { \ | ||
| 80 | RREG8(VGA_DAC_MASK); \ | ||
| 81 | RREG8(VGA_DAC_MASK); \ | ||
| 82 | RREG8(VGA_DAC_MASK); \ | ||
| 83 | RREG8(VGA_DAC_MASK); \ | ||
| 84 | WREG8(VGA_DAC_MASK, v); \ | ||
| 85 | } while (0) \ | ||
| 86 | |||
| 87 | |||
| 88 | #define CIRRUS_MAX_FB_HEIGHT 4096 | ||
| 89 | #define CIRRUS_MAX_FB_WIDTH 4096 | ||
| 90 | |||
| 91 | #define CIRRUS_DPMS_CLEARED (-1) | ||
| 92 | |||
| 93 | #define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base) | ||
| 94 | #define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base) | ||
| 95 | |||
| 96 | struct cirrus_crtc { | ||
| 97 | struct drm_crtc base; | ||
| 98 | int last_dpms; | ||
| 99 | bool enabled; | ||
| 100 | }; | ||
| 101 | |||
| 102 | struct cirrus_fbdev; | ||
| 103 | struct cirrus_mode_info { | ||
| 104 | struct cirrus_crtc *crtc; | ||
| 105 | /* pointer to fbdev info structure */ | ||
| 106 | struct cirrus_fbdev *gfbdev; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct cirrus_encoder { | ||
| 110 | struct drm_encoder base; | ||
| 111 | int last_dpms; | ||
| 112 | }; | ||
| 113 | |||
| 114 | struct cirrus_connector { | ||
| 115 | struct drm_connector base; | ||
| 116 | }; | ||
| 117 | |||
| 118 | struct cirrus_mc { | ||
| 119 | resource_size_t vram_size; | ||
| 120 | resource_size_t vram_base; | ||
| 121 | }; | ||
| 122 | |||
| 123 | struct cirrus_device { | ||
| 124 | struct drm_device *dev; | ||
| 125 | unsigned long flags; | ||
| 126 | |||
| 127 | resource_size_t rmmio_base; | ||
| 128 | resource_size_t rmmio_size; | ||
| 129 | void __iomem *rmmio; | ||
| 130 | |||
| 131 | struct cirrus_mc mc; | ||
| 132 | struct cirrus_mode_info mode_info; | ||
| 133 | |||
| 134 | int num_crtc; | ||
| 135 | int fb_mtrr; | ||
| 136 | |||
| 137 | struct { | ||
| 138 | struct ttm_bo_device bdev; | ||
| 139 | } ttm; | ||
| 140 | bool mm_inited; | ||
| 141 | }; | ||
| 142 | |||
| 143 | |||
| 144 | struct cirrus_fbdev { | ||
| 145 | struct drm_fb_helper helper; /* must be first */ | ||
| 146 | struct drm_framebuffer *gfb; | ||
| 147 | void *sysram; | ||
| 148 | int size; | ||
| 149 | int x1, y1, x2, y2; /* dirty rect */ | ||
| 150 | spinlock_t dirty_lock; | ||
| 151 | }; | ||
| 152 | |||
| 153 | struct cirrus_bo { | ||
| 154 | struct ttm_buffer_object bo; | ||
| 155 | struct ttm_placement placement; | ||
| 156 | struct ttm_bo_kmap_obj kmap; | ||
| 157 | struct drm_gem_object gem; | ||
| 158 | struct ttm_place placements[3]; | ||
| 159 | int pin_count; | ||
| 160 | }; | ||
| 161 | #define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem) | ||
| 162 | |||
| 163 | static inline struct cirrus_bo * | ||
| 164 | cirrus_bo(struct ttm_buffer_object *bo) | ||
| 165 | { | ||
| 166 | return container_of(bo, struct cirrus_bo, bo); | ||
| 167 | } | ||
| 168 | |||
| 169 | |||
| 170 | #define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base) | ||
| 171 | |||
| 172 | /* cirrus_main.c */ | ||
| 173 | int cirrus_device_init(struct cirrus_device *cdev, | ||
| 174 | struct drm_device *ddev, | ||
| 175 | struct pci_dev *pdev, | ||
| 176 | uint32_t flags); | ||
| 177 | void cirrus_device_fini(struct cirrus_device *cdev); | ||
| 178 | void cirrus_gem_free_object(struct drm_gem_object *obj); | ||
| 179 | int cirrus_dumb_mmap_offset(struct drm_file *file, | ||
| 180 | struct drm_device *dev, | ||
| 181 | uint32_t handle, | ||
| 182 | uint64_t *offset); | ||
| 183 | int cirrus_gem_create(struct drm_device *dev, | ||
| 184 | u32 size, bool iskernel, | ||
| 185 | struct drm_gem_object **obj); | ||
| 186 | int cirrus_dumb_create(struct drm_file *file, | ||
| 187 | struct drm_device *dev, | ||
| 188 | struct drm_mode_create_dumb *args); | ||
| 189 | |||
| 190 | int cirrus_framebuffer_init(struct drm_device *dev, | ||
| 191 | struct drm_framebuffer *gfb, | ||
| 192 | const struct drm_mode_fb_cmd2 *mode_cmd, | ||
| 193 | struct drm_gem_object *obj); | ||
| 194 | |||
| 195 | bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, | ||
| 196 | int bpp, int pitch); | ||
| 197 | |||
| 198 | /* cirrus_display.c */ | ||
| 199 | int cirrus_modeset_init(struct cirrus_device *cdev); | ||
| 200 | void cirrus_modeset_fini(struct cirrus_device *cdev); | ||
| 201 | |||
| 202 | /* cirrus_fbdev.c */ | ||
| 203 | int cirrus_fbdev_init(struct cirrus_device *cdev); | ||
| 204 | void cirrus_fbdev_fini(struct cirrus_device *cdev); | ||
| 205 | |||
| 206 | |||
| 207 | |||
| 208 | /* cirrus_irq.c */ | ||
| 209 | void cirrus_driver_irq_preinstall(struct drm_device *dev); | ||
| 210 | int cirrus_driver_irq_postinstall(struct drm_device *dev); | ||
| 211 | void cirrus_driver_irq_uninstall(struct drm_device *dev); | ||
| 212 | irqreturn_t cirrus_driver_irq_handler(int irq, void *arg); | ||
| 213 | |||
| 214 | /* cirrus_kms.c */ | ||
| 215 | int cirrus_driver_load(struct drm_device *dev, unsigned long flags); | ||
| 216 | void cirrus_driver_unload(struct drm_device *dev); | ||
| 217 | extern struct drm_ioctl_desc cirrus_ioctls[]; | ||
| 218 | extern int cirrus_max_ioctl; | ||
| 219 | |||
| 220 | int cirrus_mm_init(struct cirrus_device *cirrus); | ||
| 221 | void cirrus_mm_fini(struct cirrus_device *cirrus); | ||
| 222 | void cirrus_ttm_placement(struct cirrus_bo *bo, int domain); | ||
| 223 | int cirrus_bo_create(struct drm_device *dev, int size, int align, | ||
| 224 | uint32_t flags, struct cirrus_bo **pcirrusbo); | ||
| 225 | int cirrus_mmap(struct file *filp, struct vm_area_struct *vma); | ||
| 226 | |||
| 227 | static inline int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) | ||
| 228 | { | ||
| 229 | int ret; | ||
| 230 | |||
| 231 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); | ||
| 232 | if (ret) { | ||
| 233 | if (ret != -ERESTARTSYS && ret != -EBUSY) | ||
| 234 | DRM_ERROR("reserve failed %p\n", bo); | ||
| 235 | return ret; | ||
| 236 | } | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | static inline void cirrus_bo_unreserve(struct cirrus_bo *bo) | ||
| 241 | { | ||
| 242 | ttm_bo_unreserve(&bo->bo); | ||
| 243 | } | ||
| 244 | |||
| 245 | int cirrus_bo_push_sysram(struct cirrus_bo *bo); | ||
| 246 | int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr); | ||
| 247 | |||
| 248 | extern int cirrus_bpp; | ||
| 249 | |||
| 250 | #endif /* __CIRRUS_DRV_H__ */ | ||
| @@ -1,337 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Red Hat Inc. | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the | ||
| 6 | * "Software"), to deal in the Software without restriction, including | ||
| 7 | * without limitation the rights to use, copy, modify, merge, publish, | ||
| 8 | * distribute, sub license, and/or sell copies of the Software, and to | ||
| 9 | * permit persons to whom the Software is furnished to do so, subject to | ||
| 10 | * the following conditions: | ||
| 11 | * | ||
| 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| 15 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
| 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
| 17 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
| 18 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 19 | * | ||
| 20 | * The above copyright notice and this permission notice (including the | ||
| 21 | * next paragraph) shall be included in all copies or substantial portions | ||
| 22 | * of the Software. | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | /* | ||
| 26 | * Authors: Dave Airlie <airlied@redhat.com> | ||
| 27 | */ | ||
| 28 | #include <drm/drmP.h> | ||
| 29 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 30 | |||
| 31 | #include "cirrus_drv.h" | ||
| 32 | |||
| 33 | static inline struct cirrus_device * | ||
| 34 | cirrus_bdev(struct ttm_bo_device *bd) | ||
| 35 | { | ||
| 36 | return container_of(bd, struct cirrus_device, ttm.bdev); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
| 40 | { | ||
| 41 | struct cirrus_bo *bo; | ||
| 42 | |||
| 43 | bo = container_of(tbo, struct cirrus_bo, bo); | ||
| 44 | |||
| 45 | drm_gem_object_release(&bo->gem); | ||
| 46 | kfree(bo); | ||
| 47 | } | ||
| 48 | |||
| 49 | static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo) | ||
| 50 | { | ||
| 51 | if (bo->destroy == &cirrus_bo_ttm_destroy) | ||
| 52 | return true; | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int | ||
| 57 | cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
| 58 | struct ttm_mem_type_manager *man) | ||
| 59 | { | ||
| 60 | switch (type) { | ||
| 61 | case TTM_PL_SYSTEM: | ||
| 62 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 63 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 64 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 65 | break; | ||
| 66 | case TTM_PL_VRAM: | ||
| 67 | man->func = &ttm_bo_manager_func; | ||
| 68 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
| 69 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 70 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
| 71 | TTM_PL_FLAG_WC; | ||
| 72 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | ||
| 76 | return -EINVAL; | ||
| 77 | } | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void | ||
| 82 | cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
| 83 | { | ||
| 84 | struct cirrus_bo *cirrusbo = cirrus_bo(bo); | ||
| 85 | |||
| 86 | if (!cirrus_ttm_bo_is_cirrus_bo(bo)) | ||
| 87 | return; | ||
| 88 | |||
| 89 | cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM); | ||
| 90 | *pl = cirrusbo->placement; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | ||
| 94 | { | ||
| 95 | struct cirrus_bo *cirrusbo = cirrus_bo(bo); | ||
| 96 | |||
| 97 | return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, | ||
| 98 | filp->private_data); | ||
| 99 | } | ||
| 100 | |||
| 101 | static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 102 | struct ttm_mem_reg *mem) | ||
| 103 | { | ||
| 104 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
| 105 | struct cirrus_device *cirrus = cirrus_bdev(bdev); | ||
| 106 | |||
| 107 | mem->bus.addr = NULL; | ||
| 108 | mem->bus.offset = 0; | ||
| 109 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 110 | mem->bus.base = 0; | ||
| 111 | mem->bus.is_iomem = false; | ||
| 112 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 113 | return -EINVAL; | ||
| 114 | switch (mem->mem_type) { | ||
| 115 | case TTM_PL_SYSTEM: | ||
| 116 | /* system memory */ | ||
| 117 | return 0; | ||
| 118 | case TTM_PL_VRAM: | ||
| 119 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 120 | mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0); | ||
| 121 | mem->bus.is_iomem = true; | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | return -EINVAL; | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | ||
| 131 | { | ||
| 132 | } | ||
| 133 | |||
| 134 | static void cirrus_ttm_backend_destroy(struct ttm_tt *tt) | ||
| 135 | { | ||
| 136 | ttm_tt_fini(tt); | ||
| 137 | kfree(tt); | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct ttm_backend_func cirrus_tt_backend_func = { | ||
| 141 | .destroy = &cirrus_ttm_backend_destroy, | ||
| 142 | }; | ||
| 143 | |||
| 144 | |||
| 145 | static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 146 | uint32_t page_flags) | ||
| 147 | { | ||
| 148 | struct ttm_tt *tt; | ||
| 149 | |||
| 150 | tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); | ||
| 151 | if (tt == NULL) | ||
| 152 | return NULL; | ||
| 153 | tt->func = &cirrus_tt_backend_func; | ||
| 154 | if (ttm_tt_init(tt, bo, page_flags)) { | ||
| 155 | kfree(tt); | ||
| 156 | return NULL; | ||
| 157 | } | ||
| 158 | return tt; | ||
| 159 | } | ||
| 160 | |||
| 161 | struct ttm_bo_driver cirrus_bo_driver = { | ||
| 162 | .ttm_tt_create = cirrus_ttm_tt_create, | ||
| 163 | .init_mem_type = cirrus_bo_init_mem_type, | ||
| 164 | .eviction_valuable = ttm_bo_eviction_valuable, | ||
| 165 | .evict_flags = cirrus_bo_evict_flags, | ||
| 166 | .move = NULL, | ||
| 167 | .verify_access = cirrus_bo_verify_access, | ||
| 168 | .io_mem_reserve = &cirrus_ttm_io_mem_reserve, | ||
| 169 | .io_mem_free = &cirrus_ttm_io_mem_free, | ||
| 170 | }; | ||
| 171 | |||
| 172 | int cirrus_mm_init(struct cirrus_device *cirrus) | ||
| 173 | { | ||
| 174 | int ret; | ||
| 175 | struct drm_device *dev = cirrus->dev; | ||
| 176 | struct ttm_bo_device *bdev = &cirrus->ttm.bdev; | ||
| 177 | |||
| 178 | ret = ttm_bo_device_init(&cirrus->ttm.bdev, | ||
| 179 | &cirrus_bo_driver, | ||
| 180 | dev->anon_inode->i_mapping, | ||
| 181 | true); | ||
| 182 | if (ret) { | ||
| 183 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | |||
| 187 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | ||
| 188 | cirrus->mc.vram_size >> PAGE_SHIFT); | ||
| 189 | if (ret) { | ||
| 190 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | ||
| 191 | return ret; | ||
| 192 | } | ||
| 193 | |||
| 194 | arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), | ||
| 195 | pci_resource_len(dev->pdev, 0)); | ||
| 196 | |||
| 197 | cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), | ||
| 198 | pci_resource_len(dev->pdev, 0)); | ||
| 199 | |||
| 200 | cirrus->mm_inited = true; | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | void cirrus_mm_fini(struct cirrus_device *cirrus) | ||
| 205 | { | ||
| 206 | struct drm_device *dev = cirrus->dev; | ||
| 207 | |||
| 208 | if (!cirrus->mm_inited) | ||
| 209 | return; | ||
| 210 | |||
| 211 | ttm_bo_device_release(&cirrus->ttm.bdev); | ||
| 212 | |||
| 213 | arch_phys_wc_del(cirrus->fb_mtrr); | ||
| 214 | cirrus->fb_mtrr = 0; | ||
| 215 | arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), | ||
| 216 | pci_resource_len(dev->pdev, 0)); | ||
| 217 | } | ||
| 218 | |||
| 219 | void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) | ||
| 220 | { | ||
| 221 | u32 c = 0; | ||
| 222 | unsigned i; | ||
| 223 | bo->placement.placement = bo->placements; | ||
| 224 | bo->placement.busy_placement = bo->placements; | ||
| 225 | if (domain & TTM_PL_FLAG_VRAM) | ||
| 226 | bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
| 227 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
| 228 | bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
| 229 | if (!c) | ||
| 230 | bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
| 231 | bo->placement.num_placement = c; | ||
| 232 | bo->placement.num_busy_placement = c; | ||
| 233 | for (i = 0; i < c; ++i) { | ||
| 234 | bo->placements[i].fpfn = 0; | ||
| 235 | bo->placements[i].lpfn = 0; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | int cirrus_bo_create(struct drm_device *dev, int size, int align, | ||
| 240 | uint32_t flags, struct cirrus_bo **pcirrusbo) | ||
| 241 | { | ||
| 242 | struct cirrus_device *cirrus = dev->dev_private; | ||
| 243 | struct cirrus_bo *cirrusbo; | ||
| 244 | size_t acc_size; | ||
| 245 | int ret; | ||
| 246 | |||
| 247 | cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL); | ||
| 248 | if (!cirrusbo) | ||
| 249 | return -ENOMEM; | ||
| 250 | |||
| 251 | ret = drm_gem_object_init(dev, &cirrusbo->gem, size); | ||
| 252 | if (ret) { | ||
| 253 | kfree(cirrusbo); | ||
| 254 | return ret; | ||
| 255 | } | ||
| 256 | |||
| 257 | cirrusbo->bo.bdev = &cirrus->ttm.bdev; | ||
| 258 | |||
| 259 | cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 260 | |||
| 261 | acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size, | ||
| 262 | sizeof(struct cirrus_bo)); | ||
| 263 | |||
| 264 | ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size, | ||
| 265 | ttm_bo_type_device, &cirrusbo->placement, | ||
| 266 | align >> PAGE_SHIFT, false, acc_size, | ||
| 267 | NULL, NULL, cirrus_bo_ttm_destroy); | ||
| 268 | if (ret) | ||
| 269 | return ret; | ||
| 270 | |||
| 271 | *pcirrusbo = cirrusbo; | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo) | ||
| 276 | { | ||
| 277 | return bo->bo.offset; | ||
| 278 | } | ||
| 279 | |||
| 280 | int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
| 281 | { | ||
| 282 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 283 | int i, ret; | ||
| 284 | |||
| 285 | if (bo->pin_count) { | ||
| 286 | bo->pin_count++; | ||
| 287 | if (gpu_addr) | ||
| 288 | *gpu_addr = cirrus_bo_gpu_offset(bo); | ||
| 289 | } | ||
| 290 | |||
| 291 | cirrus_ttm_placement(bo, pl_flag); | ||
| 292 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 293 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 294 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 295 | if (ret) | ||
| 296 | return ret; | ||
| 297 | |||
| 298 | bo->pin_count = 1; | ||
| 299 | if (gpu_addr) | ||
| 300 | *gpu_addr = cirrus_bo_gpu_offset(bo); | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | int cirrus_bo_push_sysram(struct cirrus_bo *bo) | ||
| 305 | { | ||
| 306 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 307 | int i, ret; | ||
| 308 | if (!bo->pin_count) { | ||
| 309 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | bo->pin_count--; | ||
| 313 | if (bo->pin_count) | ||
| 314 | return 0; | ||
| 315 | |||
| 316 | if (bo->kmap.virtual) | ||
| 317 | ttm_bo_kunmap(&bo->kmap); | ||
| 318 | |||
| 319 | cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
| 320 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
| 321 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 322 | |||
| 323 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 324 | if (ret) { | ||
| 325 | DRM_ERROR("pushing to VRAM failed\n"); | ||
| 326 | return ret; | ||
| 327 | } | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | int cirrus_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 332 | { | ||
| 333 | struct drm_file *file_priv = filp->private_data; | ||
| 334 | struct cirrus_device *cirrus = file_priv->minor->dev->dev_private; | ||
| 335 | |||
| 336 | return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev); | ||
| 337 | } | ||
| @@ -1423,7 +1423,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, · 1422 unmodified lines | |||
| 1423 | ret = wait_event_timeout(dev->vblank[i].queue, | 1423 | ret = wait_event_timeout(dev->vblank[i].queue, |
| 1424 | old_state->crtcs[i].last_vblank_count != | 1424 | old_state->crtcs[i].last_vblank_count != |
| 1425 | drm_crtc_vblank_count(crtc), | 1425 | drm_crtc_vblank_count(crtc), |
| 1426 | msecs_to_jiffies(50)); | 1426 | msecs_to_jiffies(100)); |
| 1427 | 1427 | ||
| 1428 | WARN(!ret, "[CRTC:%d:%s] vblank wait timed out\n", | 1428 | WARN(!ret, "[CRTC:%d:%s] vblank wait timed out\n", |
| 1429 | crtc->base.id, crtc->name); | 1429 | crtc->base.id, crtc->name); |
| @@ -56,6 +56,29 @@ · 55 unmodified lines | |||
| 56 | * for these functions. | 56 | * for these functions. |
| 57 | */ | 57 | */ |
| 58 | 58 | ||
| 59 | /** | ||
| 60 | * __drm_atomic_helper_crtc_reset - reset state on CRTC | ||
| 61 | * @crtc: drm CRTC | ||
| 62 | * @crtc_state: CRTC state to assign | ||
| 63 | * | ||
| 64 | * Initializes the newly allocated @crtc_state and assigns it to | ||
| 65 | * the &drm_crtc->state pointer of @crtc, usually required when | ||
| 66 | * initializing the drivers or when called from the &drm_crtc_funcs.reset | ||
| 67 | * hook. | ||
| 68 | * | ||
| 69 | * This is useful for drivers that subclass the CRTC state. | ||
| 70 | */ | ||
| 71 | void | ||
| 72 | __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, | ||
| 73 | struct drm_crtc_state *crtc_state) | ||
| 74 | { | ||
| 75 | if (crtc_state) | ||
| 76 | crtc_state->crtc = crtc; | ||
| 77 | |||
| 78 | crtc->state = crtc_state; | ||
| 79 | } | ||
| 80 | EXPORT_SYMBOL(__drm_atomic_helper_crtc_reset); | ||
| 81 | |||
| 59 | /** | 82 | /** |
| 60 | * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs | 83 | * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs |
| 61 | * @crtc: drm CRTC | 84 | * @crtc: drm CRTC |
| @@ -65,14 +88,13 @@ · 3 unmodified lines | |||
| 65 | */ | 88 | */ |
| 66 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) | 89 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) |
| 67 | { | 90 | { |
| 68 | if (crtc->state) | 91 | struct drm_crtc_state *crtc_state = |
| 69 | __drm_atomic_helper_crtc_destroy_state(crtc->state); | 92 | kzalloc(sizeof(*crtc->state), GFP_KERNEL); |
| 70 | |||
| 71 | kfree(crtc->state); | ||
| 72 | crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); | ||
| 73 | 93 | ||
| 74 | if (crtc->state) | 94 | if (crtc->state) |
| 75 | crtc->state->crtc = crtc; | 95 | crtc->funcs->atomic_destroy_state(crtc, crtc->state); |
| 96 | |||
| 97 | __drm_atomic_helper_crtc_reset(crtc, crtc_state); | ||
| 76 | } | 98 | } |
| 77 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); | 99 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); |
| 78 | 100 | ||
| @@ -314,7 +336,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); · 235 unmodified lines | |||
| 314 | * @conn_state: connector state to assign | 336 | * @conn_state: connector state to assign |
| 315 | * | 337 | * |
| 316 | * Initializes the newly allocated @conn_state and assigns it to | 338 | * Initializes the newly allocated @conn_state and assigns it to |
| 317 | * the &drm_conector->state pointer of @connector, usually required when | 339 | * the &drm_connector->state pointer of @connector, usually required when |
| 318 | * initializing the drivers or when called from the &drm_connector_funcs.reset | 340 | * initializing the drivers or when called from the &drm_connector_funcs.reset |
| 319 | * hook. | 341 | * hook. |
| 320 | * | 342 | * |
| @@ -369,6 +391,9 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, · 48 unmodified lines | |||
| 369 | drm_connector_get(connector); | 391 | drm_connector_get(connector); |
| 370 | state->commit = NULL; | 392 | state->commit = NULL; |
| 371 | 393 | ||
| 394 | if (state->hdr_output_metadata) | ||
| 395 | drm_property_blob_get(state->hdr_output_metadata); | ||
| 396 | |||
| 372 | /* Don't copy over a writeback job, they are used only once */ | 397 | /* Don't copy over a writeback job, they are used only once */ |
| 373 | state->writeback_job = NULL; | 398 | state->writeback_job = NULL; |
| 374 | } | 399 | } |
| @@ -416,6 +441,8 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) · 41 unmodified lines | |||
| 416 | 441 | ||
| 417 | if (state->writeback_job) | 442 | if (state->writeback_job) |
| 418 | drm_writeback_cleanup_job(state->writeback_job); | 443 | drm_writeback_cleanup_job(state->writeback_job); |
| 444 | |||
| 445 | drm_property_blob_put(state->hdr_output_metadata); | ||
| 419 | } | 446 | } |
| 420 | EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); | 447 | EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); |
| 421 | 448 | ||
| @@ -676,6 +676,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, · 675 unmodified lines | |||
| 676 | { | 676 | { |
| 677 | struct drm_device *dev = connector->dev; | 677 | struct drm_device *dev = connector->dev; |
| 678 | struct drm_mode_config *config = &dev->mode_config; | 678 | struct drm_mode_config *config = &dev->mode_config; |
| 679 | bool replaced = false; | ||
| 680 | int ret; | ||
| 679 | 681 | ||
| 680 | if (property == config->prop_crtc_id) { | 682 | if (property == config->prop_crtc_id) { |
| 681 | struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val); | 683 | struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val); |
| @@ -726,6 +728,13 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, · 44 unmodified lines | |||
| 726 | */ | 728 | */ |
| 727 | if (state->link_status != DRM_LINK_STATUS_GOOD) | 729 | if (state->link_status != DRM_LINK_STATUS_GOOD) |
| 728 | state->link_status = val; | 730 | state->link_status = val; |
| 731 | } else if (property == config->hdr_output_metadata_property) { | ||
| 732 | ret = drm_atomic_replace_property_blob_from_id(dev, | ||
| 733 | &state->hdr_output_metadata, | ||
| 734 | val, | ||
| 735 | sizeof(struct hdr_output_metadata), -1, | ||
| 736 | &replaced); | ||
| 737 | return ret; | ||
| 729 | } else if (property == config->aspect_ratio_property) { | 738 | } else if (property == config->aspect_ratio_property) { |
| 730 | state->picture_aspect_ratio = val; | 739 | state->picture_aspect_ratio = val; |
| 731 | } else if (property == config->content_type_property) { | 740 | } else if (property == config->content_type_property) { |
| @@ -814,6 +823,9 @@ drm_atomic_connector_get_property(struct drm_connector *connector, · 82 unmodified lines | |||
| 814 | *val = state->colorspace; | 823 | *val = state->colorspace; |
| 815 | } else if (property == connector->scaling_mode_property) { | 824 | } else if (property == connector->scaling_mode_property) { |
| 816 | *val = state->scaling_mode; | 825 | *val = state->scaling_mode; |
| 826 | } else if (property == config->hdr_output_metadata_property) { | ||
| 827 | *val = state->hdr_output_metadata ? | ||
| 828 | state->hdr_output_metadata->base.id : 0; | ||
| 817 | } else if (property == connector->content_protection_property) { | 829 | } else if (property == connector->content_protection_property) { |
| 818 | *val = state->content_protection; | 830 | *val = state->content_protection; |
| 819 | } else if (property == config->writeback_fb_id_property) { | 831 | } else if (property == config->writeback_fb_id_property) { |
| @@ -351,3 +351,23 @@ void drm_master_put(struct drm_master **master) · 350 unmodified lines | |||
| 351 | *master = NULL; | 351 | *master = NULL; |
| 352 | } | 352 | } |
| 353 | EXPORT_SYMBOL(drm_master_put); | 353 | EXPORT_SYMBOL(drm_master_put); |
| 354 | |||
| 355 | /* Used by drm_client and drm_fb_helper */ | ||
| 356 | bool drm_master_internal_acquire(struct drm_device *dev) | ||
| 357 | { | ||
| 358 | mutex_lock(&dev->master_mutex); | ||
| 359 | if (dev->master) { | ||
| 360 | mutex_unlock(&dev->master_mutex); | ||
| 361 | return false; | ||
| 362 | } | ||
| 363 | |||
| 364 | return true; | ||
| 365 | } | ||
| 366 | EXPORT_SYMBOL(drm_master_internal_acquire); | ||
| 367 | |||
| 368 | /* Used by drm_client and drm_fb_helper */ | ||
| 369 | void drm_master_internal_release(struct drm_device *dev) | ||
| 370 | { | ||
| 371 | mutex_unlock(&dev->master_mutex); | ||
| 372 | } | ||
| 373 | EXPORT_SYMBOL(drm_master_internal_release); | ||
| @@ -243,6 +243,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) · 242 unmodified lines | |||
| 243 | static struct drm_client_buffer * | 243 | static struct drm_client_buffer * |
| 244 | drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) | 244 | drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) |
| 245 | { | 245 | { |
| 246 | const struct drm_format_info *info = drm_format_info(format); | ||
| 246 | struct drm_mode_create_dumb dumb_args = { }; | 247 | struct drm_mode_create_dumb dumb_args = { }; |
| 247 | struct drm_device *dev = client->dev; | 248 | struct drm_device *dev = client->dev; |
| 248 | struct drm_client_buffer *buffer; | 249 | struct drm_client_buffer *buffer; |
| @@ -258,7 +259,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u · 9 unmodified lines | |||
| 258 | 259 | ||
| 259 | dumb_args.width = width; | 260 | dumb_args.width = width; |
| 260 | dumb_args.height = height; | 261 | dumb_args.height = height; |
| 261 | dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8; | 262 | dumb_args.bpp = info->cpp[0] * 8; |
| 262 | ret = drm_mode_create_dumb(dev, &dumb_args, client->file); | 263 | ret = drm_mode_create_dumb(dev, &dumb_args, client->file); |
| 263 | if (ret) | 264 | if (ret) |
| 264 | goto err_delete; | 265 | goto err_delete; |
| @@ -1058,6 +1058,12 @@ int drm_connector_create_standard_properties(struct drm_device *dev) · 1057 unmodified lines | |||
| 1058 | return -ENOMEM; | 1058 | return -ENOMEM; |
| 1059 | dev->mode_config.non_desktop_property = prop; | 1059 | dev->mode_config.non_desktop_property = prop; |
| 1060 | 1060 | ||
| 1061 | prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, | ||
| 1062 | "HDR_OUTPUT_METADATA", 0); | ||
| 1063 | if (!prop) | ||
| 1064 | return -ENOMEM; | ||
| 1065 | dev->mode_config.hdr_output_metadata_property = prop; | ||
| 1066 | |||
| 1061 | return 0; | 1067 | return 0; |
| 1062 | } | 1068 | } |
| 1063 | 1069 | ||
| @@ -27,15 +27,17 @@ · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
| 29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
| 32 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
| 33 | #include <linux/module.h> | 32 | #include <linux/module.h> |
| 33 | #include <linux/sched/signal.h> | ||
| 34 | #include <linux/slab.h> | ||
| 34 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
| 35 | #include <linux/uio.h> | 36 | #include <linux/uio.h> |
| 36 | #include <drm/drm_dp_helper.h> | 37 | |
| 37 | #include <drm/drm_crtc.h> | 38 | #include <drm/drm_crtc.h> |
| 38 | #include <drm/drmP.h> | 39 | #include <drm/drm_dp_helper.h> |
| 40 | #include <drm/drm_print.h> | ||
| 39 | 41 | ||
| 40 | #include "drm_crtc_helper_internal.h" | 42 | #include "drm_crtc_helper_internal.h" |
| 41 | 43 | ||
| @@ -20,13 +20,15 @@ · 19 unmodified lines | |||
| 20 | * OTHER DEALINGS IN THE SOFTWARE. | 20 | * OTHER DEALINGS IN THE SOFTWARE. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/delay.h> | ||
| 23 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| 24 | #include <linux/export.h> | 25 | #include <linux/export.h> |
| 25 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
| 26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 27 | #include <linux/string.h> | 28 | #include <linux/string.h> |
| 29 | |||
| 28 | #include <drm/drm_dp_dual_mode_helper.h> | 30 | #include <drm/drm_dp_dual_mode_helper.h> |
| 29 | #include <drm/drmP.h> | 31 | #include <drm/drm_print.h> |
| 30 | 32 | ||
| 31 | /** | 33 | /** |
| 32 | * DOC: dp dual mode helpers | 34 | * DOC: dp dual mode helpers |
| @@ -20,16 +20,18 @@ · 19 unmodified lines | |||
| 20 | * OF THIS SOFTWARE. | 20 | * OF THIS SOFTWARE. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| 28 | #include <linux/sched.h> | ||
| 29 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/sched.h> | ||
| 30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
| 31 | |||
| 31 | #include <drm/drm_dp_helper.h> | 32 | #include <drm/drm_dp_helper.h> |
| 32 | #include <drm/drmP.h> | 33 | #include <drm/drm_print.h> |
| 34 | #include <drm/drm_vblank.h> | ||
| 33 | 35 | ||
| 34 | #include "drm_crtc_helper_internal.h" | 36 | #include "drm_crtc_helper_internal.h" |
| 35 | 37 | ||
| @@ -20,19 +20,20 @@ · 19 unmodified lines | |||
| 20 | * OF THIS SOFTWARE. | 20 | * OF THIS SOFTWARE. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 27 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
| 28 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
| 29 | #include <linux/i2c.h> | ||
| 30 | #include <drm/drm_dp_mst_helper.h> | ||
| 31 | #include <drm/drmP.h> | ||
| 32 | 30 | ||
| 33 | #include <drm/drm_fixed.h> | ||
| 34 | #include <drm/drm_atomic.h> | 31 | #include <drm/drm_atomic.h> |
| 35 | #include <drm/drm_atomic_helper.h> | 32 | #include <drm/drm_atomic_helper.h> |
| 33 | #include <drm/drm_dp_mst_helper.h> | ||
| 34 | #include <drm/drm_drv.h> | ||
| 35 | #include <drm/drm_fixed.h> | ||
| 36 | #include <drm/drm_print.h> | ||
| 36 | #include <drm/drm_probe_helper.h> | 37 | #include <drm/drm_probe_helper.h> |
| 37 | 38 | ||
| 38 | /** | 39 | /** |
| @@ -27,16 +27,19 @@ · 26 unmodified lines | |||
| 27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 28 | * DEALINGS IN THE SOFTWARE. | 28 | * DEALINGS IN THE SOFTWARE. |
| 29 | */ | 29 | */ |
| 30 | #include <linux/kernel.h> | 30 | |
| 31 | #include <linux/slab.h> | ||
| 32 | #include <linux/hdmi.h> | 31 | #include <linux/hdmi.h> |
| 33 | #include <linux/i2c.h> | 32 | #include <linux/i2c.h> |
| 33 | #include <linux/kernel.h> | ||
| 34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
| 35 | #include <linux/slab.h> | ||
| 35 | #include <linux/vga_switcheroo.h> | 36 | #include <linux/vga_switcheroo.h> |
| 36 | #include <drm/drmP.h> | 37 | |
| 38 | #include <drm/drm_displayid.h> | ||
| 39 | #include <drm/drm_drv.h> | ||
| 37 | #include <drm/drm_edid.h> | 40 | #include <drm/drm_edid.h> |
| 38 | #include <drm/drm_encoder.h> | 41 | #include <drm/drm_encoder.h> |
| 39 | #include <drm/drm_displayid.h> | 42 | #include <drm/drm_print.h> |
| 40 | #include <drm/drm_scdc_helper.h> | 43 | #include <drm/drm_scdc_helper.h> |
| 41 | 44 | ||
| 42 | #include "drm_crtc_internal.h" | 45 | #include "drm_crtc_internal.h" |
| @@ -2849,6 +2852,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, · 2806 unmodified lines | |||
| 2849 | #define VIDEO_BLOCK 0x02 | 2852 | #define VIDEO_BLOCK 0x02 |
| 2850 | #define VENDOR_BLOCK 0x03 | 2853 | #define VENDOR_BLOCK 0x03 |
| 2851 | #define SPEAKER_BLOCK 0x04 | 2854 | #define SPEAKER_BLOCK 0x04 |
| 2855 | #define HDR_STATIC_METADATA_BLOCK 0x6 | ||
| 2852 | #define USE_EXTENDED_TAG 0x07 | 2856 | #define USE_EXTENDED_TAG 0x07 |
| 2853 | #define EXT_VIDEO_CAPABILITY_BLOCK 0x00 | 2857 | #define EXT_VIDEO_CAPABILITY_BLOCK 0x00 |
| 2854 | #define EXT_VIDEO_DATA_BLOCK_420 0x0E | 2858 | #define EXT_VIDEO_DATA_BLOCK_420 0x0E |
| @@ -3831,6 +3835,55 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) · 976 unmodified lines | |||
| 3831 | mode->clock = clock; | 3835 | mode->clock = clock; |
| 3832 | } | 3836 | } |
| 3833 | 3837 | ||
| 3838 | static bool cea_db_is_hdmi_hdr_metadata_block(const u8 *db) | ||
| 3839 | { | ||
| 3840 | if (cea_db_tag(db) != USE_EXTENDED_TAG) | ||
| 3841 | return false; | ||
| 3842 | |||
| 3843 | if (db[1] != HDR_STATIC_METADATA_BLOCK) | ||
| 3844 | return false; | ||
| 3845 | |||
| 3846 | if (cea_db_payload_len(db) < 3) | ||
| 3847 | return false; | ||
| 3848 | |||
| 3849 | return true; | ||
| 3850 | } | ||
| 3851 | |||
| 3852 | static uint8_t eotf_supported(const u8 *edid_ext) | ||
| 3853 | { | ||
| 3854 | return edid_ext[2] & | ||
| 3855 | (BIT(HDMI_EOTF_TRADITIONAL_GAMMA_SDR) | | ||
| 3856 | BIT(HDMI_EOTF_TRADITIONAL_GAMMA_HDR) | | ||
| 3857 | BIT(HDMI_EOTF_SMPTE_ST2084) | | ||
| 3858 | BIT(HDMI_EOTF_BT_2100_HLG)); | ||
| 3859 | } | ||
| 3860 | |||
| 3861 | static uint8_t hdr_metadata_type(const u8 *edid_ext) | ||
| 3862 | { | ||
| 3863 | return edid_ext[3] & | ||
| 3864 | BIT(HDMI_STATIC_METADATA_TYPE1); | ||
| 3865 | } | ||
| 3866 | |||
| 3867 | static void | ||
| 3868 | drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db) | ||
| 3869 | { | ||
| 3870 | u16 len; | ||
| 3871 | |||
| 3872 | len = cea_db_payload_len(db); | ||
| 3873 | |||
| 3874 | connector->hdr_sink_metadata.hdmi_type1.eotf = | ||
| 3875 | eotf_supported(db); | ||
| 3876 | connector->hdr_sink_metadata.hdmi_type1.metadata_type = | ||
| 3877 | hdr_metadata_type(db); | ||
| 3878 | |||
| 3879 | if (len >= 4) | ||
| 3880 | connector->hdr_sink_metadata.hdmi_type1.max_cll = db[4]; | ||
| 3881 | if (len >= 5) | ||
| 3882 | connector->hdr_sink_metadata.hdmi_type1.max_fall = db[5]; | ||
| 3883 | if (len >= 6) | ||
| 3884 | connector->hdr_sink_metadata.hdmi_type1.min_cll = db[6]; | ||
| 3885 | } | ||
| 3886 | |||
| 3834 | static void | 3887 | static void |
| 3835 | drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) | 3888 | drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) |
| 3836 | { | 3889 | { |
| @@ -4458,6 +4511,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, · 621 unmodified lines | |||
| 4458 | drm_parse_y420cmdb_bitmap(connector, db); | 4511 | drm_parse_y420cmdb_bitmap(connector, db); |
| 4459 | if (cea_db_is_vcdb(db)) | 4512 | if (cea_db_is_vcdb(db)) |
| 4460 | drm_parse_vcdb(connector, db); | 4513 | drm_parse_vcdb(connector, db); |
| 4514 | if (cea_db_is_hdmi_hdr_metadata_block(db)) | ||
| 4515 | drm_parse_hdr_metadata_block(connector, db); | ||
| 4461 | } | 4516 | } |
| 4462 | } | 4517 | } |
| 4463 | 4518 | ||
| @@ -4850,6 +4905,78 @@ static bool is_hdmi2_sink(struct drm_connector *connector) · 386 unmodified lines | |||
| 4850 | connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; | 4905 | connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; |
| 4851 | } | 4906 | } |
| 4852 | 4907 | ||
| 4908 | static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) | ||
| 4909 | { | ||
| 4910 | return sink_eotf & BIT(output_eotf); | ||
| 4911 | } | ||
| 4912 | |||
| 4913 | /** | ||
| 4914 | * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI DRM infoframe with | ||
| 4915 | * HDR metadata from userspace | ||
| 4916 | * @frame: HDMI DRM infoframe | ||
| 4917 | * @conn_state: Connector state containing HDR metadata | ||
| 4918 | * | ||
| 4919 | * Return: 0 on success or a negative error code on failure. | ||
| 4920 | */ | ||
| 4921 | int | ||
| 4922 | drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, | ||
| 4923 | const struct drm_connector_state *conn_state) | ||
| 4924 | { | ||
| 4925 | struct drm_connector *connector; | ||
| 4926 | struct hdr_output_metadata *hdr_metadata; | ||
| 4927 | int err; | ||
| 4928 | |||
| 4929 | if (!frame || !conn_state) | ||
| 4930 | return -EINVAL; | ||
| 4931 | |||
| 4932 | connector = conn_state->connector; | ||
| 4933 | |||
| 4934 | if (!conn_state->hdr_output_metadata) | ||
| 4935 | return -EINVAL; | ||
| 4936 | |||
| 4937 | hdr_metadata = conn_state->hdr_output_metadata->data; | ||
| 4938 | |||
| 4939 | if (!hdr_metadata || !connector) | ||
| 4940 | return -EINVAL; | ||
| 4941 | |||
| 4942 | /* Sink EOTF is Bit map while infoframe is absolute values */ | ||
| 4943 | if (!is_eotf_supported(hdr_metadata->hdmi_metadata_type1.eotf, | ||
| 4944 | connector->hdr_sink_metadata.hdmi_type1.eotf)) { | ||
| 4945 | DRM_DEBUG_KMS("EOTF Not Supported\n"); | ||
| 4946 | return -EINVAL; | ||
| 4947 | } | ||
| 4948 | |||
| 4949 | err = hdmi_drm_infoframe_init(frame); | ||
| 4950 | if (err < 0) | ||
| 4951 | return err; | ||
| 4952 | |||
| 4953 | frame->eotf = hdr_metadata->hdmi_metadata_type1.eotf; | ||
| 4954 | frame->metadata_type = hdr_metadata->hdmi_metadata_type1.metadata_type; | ||
| 4955 | |||
| 4956 | BUILD_BUG_ON(sizeof(frame->display_primaries) != | ||
| 4957 | sizeof(hdr_metadata->hdmi_metadata_type1.display_primaries)); | ||
| 4958 | BUILD_BUG_ON(sizeof(frame->white_point) != | ||
| 4959 | sizeof(hdr_metadata->hdmi_metadata_type1.white_point)); | ||
| 4960 | |||
| 4961 | memcpy(&frame->display_primaries, | ||
| 4962 | &hdr_metadata->hdmi_metadata_type1.display_primaries, | ||
| 4963 | sizeof(frame->display_primaries)); | ||
| 4964 | |||
| 4965 | memcpy(&frame->white_point, | ||
| 4966 | &hdr_metadata->hdmi_metadata_type1.white_point, | ||
| 4967 | sizeof(frame->white_point)); | ||
| 4968 | |||
| 4969 | frame->max_display_mastering_luminance = | ||
| 4970 | hdr_metadata->hdmi_metadata_type1.max_display_mastering_luminance; | ||
| 4971 | frame->min_display_mastering_luminance = | ||
| 4972 | hdr_metadata->hdmi_metadata_type1.min_display_mastering_luminance; | ||
| 4973 | frame->max_fall = hdr_metadata->hdmi_metadata_type1.max_fall; | ||
| 4974 | frame->max_cll = hdr_metadata->hdmi_metadata_type1.max_cll; | ||
| 4975 | |||
| 4976 | return 0; | ||
| 4977 | } | ||
| 4978 | EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); | ||
| 4979 | |||
| 4853 | /** | 4980 | /** |
| 4854 | * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with | 4981 | * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with |
| 4855 | * data from a DRM display mode | 4982 | * data from a DRM display mode |
| @@ -7,12 +7,15 @@ · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/firmware.h> | 10 | #include <linux/firmware.h> |
| 12 | #include <drm/drmP.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/platform_device.h> | ||
| 13 | |||
| 13 | #include <drm/drm_crtc.h> | 14 | #include <drm/drm_crtc.h> |
| 14 | #include <drm/drm_crtc_helper.h> | 15 | #include <drm/drm_crtc_helper.h> |
| 16 | #include <drm/drm_drv.h> | ||
| 15 | #include <drm/drm_edid.h> | 17 | #include <drm/drm_edid.h> |
| 18 | #include <drm/drm_print.h> | ||
| 16 | 19 | ||
| 17 | static char edid_firmware[PATH_MAX]; | 20 | static char edid_firmware[PATH_MAX]; |
| 18 | module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); | 21 | module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); |
| @@ -44,6 +44,7 @@ · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | #include "drm_crtc_internal.h" | 45 | #include "drm_crtc_internal.h" |
| 46 | #include "drm_crtc_helper_internal.h" | 46 | #include "drm_crtc_helper_internal.h" |
| 47 | #include "drm_internal.h" | ||
| 47 | 48 | ||
| 48 | static bool drm_fbdev_emulation = true; | 49 | static bool drm_fbdev_emulation = true; |
| 49 | module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); | 50 | module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); |
| @@ -387,6 +388,49 @@ int drm_fb_helper_debug_leave(struct fb_info *info) · 337 unmodified lines | |||
| 387 | } | 388 | } |
| 388 | EXPORT_SYMBOL(drm_fb_helper_debug_leave); | 389 | EXPORT_SYMBOL(drm_fb_helper_debug_leave); |
| 389 | 390 | ||
| 391 | /* Check if the plane can hw rotate to match panel orientation */ | ||
| 392 | static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset, | ||
| 393 | unsigned int *rotation) | ||
| 394 | { | ||
| 395 | struct drm_connector *connector = modeset->connectors[0]; | ||
| 396 | struct drm_plane *plane = modeset->crtc->primary; | ||
| 397 | u64 valid_mask = 0; | ||
| 398 | unsigned int i; | ||
| 399 | |||
| 400 | if (!modeset->num_connectors) | ||
| 401 | return false; | ||
| 402 | |||
| 403 | switch (connector->display_info.panel_orientation) { | ||
| 404 | case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP: | ||
| 405 | *rotation = DRM_MODE_ROTATE_180; | ||
| 406 | break; | ||
| 407 | case DRM_MODE_PANEL_ORIENTATION_LEFT_UP: | ||
| 408 | *rotation = DRM_MODE_ROTATE_90; | ||
| 409 | break; | ||
| 410 | case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP: | ||
| 411 | *rotation = DRM_MODE_ROTATE_270; | ||
| 412 | break; | ||
| 413 | default: | ||
| 414 | *rotation = DRM_MODE_ROTATE_0; | ||
| 415 | } | ||
| 416 | |||
| 417 | /* | ||
| 418 | * TODO: support 90 / 270 degree hardware rotation, | ||
| 419 | * depending on the hardware this may require the framebuffer | ||
| 420 | * to be in a specific tiling format. | ||
| 421 | */ | ||
| 422 | if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) | ||
| 423 | return false; | ||
| 424 | |||
| 425 | for (i = 0; i < plane->rotation_property->num_values; i++) | ||
| 426 | valid_mask |= (1ULL << plane->rotation_property->values[i]); | ||
| 427 | |||
| 428 | if (!(*rotation & valid_mask)) | ||
| 429 | return false; | ||
| 430 | |||
| 431 | return true; | ||
| 432 | } | ||
| 433 | |||
| 390 | static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active) | 434 | static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active) |
| 391 | { | 435 | { |
| 392 | struct drm_device *dev = fb_helper->dev; | 436 | struct drm_device *dev = fb_helper->dev; |
| @@ -427,10 +471,13 @@ retry: · 34 unmodified lines | |||
| 427 | for (i = 0; i < fb_helper->crtc_count; i++) { | 471 | for (i = 0; i < fb_helper->crtc_count; i++) { |
| 428 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; | 472 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; |
| 429 | struct drm_plane *primary = mode_set->crtc->primary; | 473 | struct drm_plane *primary = mode_set->crtc->primary; |
| 474 | unsigned int rotation; | ||
| 430 | 475 | ||
| 431 | /* Cannot fail as we've already gotten the plane state above */ | 476 | if (drm_fb_helper_panel_rotation(mode_set, &rotation)) { |
| 432 | plane_state = drm_atomic_get_new_plane_state(state, primary); | 477 | /* Cannot fail as we've already gotten the plane state above */ |
| 433 | plane_state->rotation = fb_helper->crtc_info[i].rotation; | 478 | plane_state = drm_atomic_get_new_plane_state(state, primary); |
| 479 | plane_state->rotation = rotation; | ||
| 480 | } | ||
| 434 | 481 | ||
| 435 | ret = __drm_atomic_helper_set_config(mode_set, state); | 482 | ret = __drm_atomic_helper_set_config(mode_set, state); |
| 436 | if (ret != 0) | 483 | if (ret != 0) |
| @@ -509,7 +556,7 @@ out: · 72 unmodified lines | |||
| 509 | return ret; | 556 | return ret; |
| 510 | } | 557 | } |
| 511 | 558 | ||
| 512 | static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) | 559 | static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper) |
| 513 | { | 560 | { |
| 514 | struct drm_device *dev = fb_helper->dev; | 561 | struct drm_device *dev = fb_helper->dev; |
| 515 | 562 | ||
| @@ -519,6 +566,21 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) · 3 unmodified lines | |||
| 519 | return restore_fbdev_mode_legacy(fb_helper); | 566 | return restore_fbdev_mode_legacy(fb_helper); |
| 520 | } | 567 | } |
| 521 | 568 | ||
| 569 | static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) | ||
| 570 | { | ||
| 571 | struct drm_device *dev = fb_helper->dev; | ||
| 572 | int ret; | ||
| 573 | |||
| 574 | if (!drm_master_internal_acquire(dev)) | ||
| 575 | return -EBUSY; | ||
| 576 | |||
| 577 | ret = restore_fbdev_mode_force(fb_helper); | ||
| 578 | |||
| 579 | drm_master_internal_release(dev); | ||
| 580 | |||
| 581 | return ret; | ||
| 582 | } | ||
| 583 | |||
| 522 | /** | 584 | /** |
| 523 | * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration | 585 | * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration |
| 524 | * @fb_helper: driver-allocated fbdev helper, can be NULL | 586 | * @fb_helper: driver-allocated fbdev helper, can be NULL |
| @@ -542,7 +604,17 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) · 17 unmodified lines | |||
| 542 | return 0; | 604 | return 0; |
| 543 | 605 | ||
| 544 | mutex_lock(&fb_helper->lock); | 606 | mutex_lock(&fb_helper->lock); |
| 545 | ret = restore_fbdev_mode(fb_helper); | 607 | /* |
| 608 | * TODO: | ||
| 609 | * We should bail out here if there is a master by dropping _force. | ||
| 610 | * Currently these igt tests fail if we do that: | ||
| 611 | * - kms_fbcon_fbt@psr | ||
| 612 | * - kms_fbcon_fbt@psr-suspend | ||
| 613 | * | ||
| 614 | * So first these tests need to be fixed so they drop master or don't | ||
| 615 | * have an fd open. | ||
| 616 | */ | ||
| 617 | ret = restore_fbdev_mode_force(fb_helper); | ||
| 546 | 618 | ||
| 547 | do_delayed = fb_helper->delayed_hotplug; | 619 | do_delayed = fb_helper->delayed_hotplug; |
| 548 | if (do_delayed) | 620 | if (do_delayed) |
| @@ -556,34 +628,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) · 7 unmodified lines | |||
| 556 | } | 628 | } |
| 557 | EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); | 629 | EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); |
| 558 | 630 | ||
| 559 | static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) | ||
| 560 | { | ||
| 561 | struct drm_device *dev = fb_helper->dev; | ||
| 562 | struct drm_crtc *crtc; | ||
| 563 | int bound = 0, crtcs_bound = 0; | ||
| 564 | |||
| 565 | /* | ||
| 566 | * Sometimes user space wants everything disabled, so don't steal the | ||
| 567 | * display if there's a master. | ||
| 568 | */ | ||
| 569 | if (READ_ONCE(dev->master)) | ||
| 570 | return false; | ||
| 571 | |||
| 572 | drm_for_each_crtc(crtc, dev) { | ||
| 573 | drm_modeset_lock(&crtc->mutex, NULL); | ||
| 574 | if (crtc->primary->fb) | ||
| 575 | crtcs_bound++; | ||
| 576 | if (crtc->primary->fb == fb_helper->fb) | ||
| 577 | bound++; | ||
| 578 | drm_modeset_unlock(&crtc->mutex); | ||
| 579 | } | ||
| 580 | |||
| 581 | if (bound < crtcs_bound) | ||
| 582 | return false; | ||
| 583 | |||
| 584 | return true; | ||
| 585 | } | ||
| 586 | |||
| 587 | #ifdef CONFIG_MAGIC_SYSRQ | 631 | #ifdef CONFIG_MAGIC_SYSRQ |
| 588 | /* | 632 | /* |
| 589 | * restore fbcon display for all kms driver's using this helper, used for sysrq | 633 | * restore fbcon display for all kms driver's using this helper, used for sysrq |
| @@ -604,7 +648,7 @@ static bool drm_fb_helper_force_kernel_mode(void) · 14 unmodified lines | |||
| 604 | continue; | 648 | continue; |
| 605 | 649 | ||
| 606 | mutex_lock(&helper->lock); | 650 | mutex_lock(&helper->lock); |
| 607 | ret = restore_fbdev_mode(helper); | 651 | ret = restore_fbdev_mode_force(helper); |
| 608 | if (ret) | 652 | if (ret) |
| 609 | error = true; | 653 | error = true; |
| 610 | mutex_unlock(&helper->lock); | 654 | mutex_unlock(&helper->lock); |
| @@ -663,20 +707,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode) · 52 unmodified lines | |||
| 663 | static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) | 707 | static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) |
| 664 | { | 708 | { |
| 665 | struct drm_fb_helper *fb_helper = info->par; | 709 | struct drm_fb_helper *fb_helper = info->par; |
| 710 | struct drm_device *dev = fb_helper->dev; | ||
| 666 | 711 | ||
| 667 | /* | 712 | /* |
| 668 | * For each CRTC in this fb, turn the connectors on/off. | 713 | * For each CRTC in this fb, turn the connectors on/off. |
| 669 | */ | 714 | */ |
| 670 | mutex_lock(&fb_helper->lock); | 715 | mutex_lock(&fb_helper->lock); |
| 671 | if (!drm_fb_helper_is_bound(fb_helper)) { | 716 | if (!drm_master_internal_acquire(dev)) |
| 672 | mutex_unlock(&fb_helper->lock); | 717 | goto unlock; |
| 673 | return; | ||
| 674 | } | ||
| 675 | 718 | ||
| 676 | if (drm_drv_uses_atomic_modeset(fb_helper->dev)) | 719 | if (drm_drv_uses_atomic_modeset(dev)) |
| 677 | restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON); | 720 | restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON); |
| 678 | else | 721 | else |
| 679 | dpms_legacy(fb_helper, dpms_mode); | 722 | dpms_legacy(fb_helper, dpms_mode); |
| 723 | |||
| 724 | drm_master_internal_release(dev); | ||
| 725 | unlock: | ||
| 680 | mutex_unlock(&fb_helper->lock); | 726 | mutex_unlock(&fb_helper->lock); |
| 681 | } | 727 | } |
| 682 | 728 | ||
| @@ -767,7 +813,7 @@ static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper, · 84 unmodified lines | |||
| 767 | struct drm_clip_rect *clip) | 813 | struct drm_clip_rect *clip) |
| 768 | { | 814 | { |
| 769 | struct drm_framebuffer *fb = fb_helper->fb; | 815 | struct drm_framebuffer *fb = fb_helper->fb; |
| 770 | unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); | 816 | unsigned int cpp = fb->format->cpp[0]; |
| 771 | size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp; | 817 | size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp; |
| 772 | void *src = fb_helper->fbdev->screen_buffer + offset; | 818 | void *src = fb_helper->fbdev->screen_buffer + offset; |
| 773 | void *dst = fb_helper->buffer->vaddr + offset; | 819 | void *dst = fb_helper->buffer->vaddr + offset; |
| @@ -881,7 +927,6 @@ int drm_fb_helper_init(struct drm_device *dev, · 107 unmodified lines | |||
| 881 | if (!fb_helper->crtc_info[i].mode_set.connectors) | 927 | if (!fb_helper->crtc_info[i].mode_set.connectors) |
| 882 | goto out_free; | 928 | goto out_free; |
| 883 | fb_helper->crtc_info[i].mode_set.num_connectors = 0; | 929 | fb_helper->crtc_info[i].mode_set.num_connectors = 0; |
| 884 | fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0; | ||
| 885 | } | 930 | } |
| 886 | 931 | ||
| 887 | i = 0; | 932 | i = 0; |
| @@ -1509,6 +1554,7 @@ backoff: · 621 unmodified lines | |||
| 1509 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) | 1554 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
| 1510 | { | 1555 | { |
| 1511 | struct drm_fb_helper *fb_helper = info->par; | 1556 | struct drm_fb_helper *fb_helper = info->par; |
| 1557 | struct drm_device *dev = fb_helper->dev; | ||
| 1512 | int ret; | 1558 | int ret; |
| 1513 | 1559 | ||
| 1514 | if (oops_in_progress) | 1560 | if (oops_in_progress) |
| @@ -1516,9 +1562,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) · 1 unmodified line | |||
| 1516 | 1562 | ||
| 1517 | mutex_lock(&fb_helper->lock); | 1563 | mutex_lock(&fb_helper->lock); |
| 1518 | 1564 | ||
| 1519 | if (!drm_fb_helper_is_bound(fb_helper)) { | 1565 | if (!drm_master_internal_acquire(dev)) { |
| 1520 | ret = -EBUSY; | 1566 | ret = -EBUSY; |
| 1521 | goto out; | 1567 | goto unlock; |
| 1522 | } | 1568 | } |
| 1523 | 1569 | ||
| 1524 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) | 1570 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) |
| @@ -1528,7 +1574,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) · 3 unmodified lines | |||
| 1528 | else | 1574 | else |
| 1529 | ret = setcmap_legacy(cmap, info); | 1575 | ret = setcmap_legacy(cmap, info); |
| 1530 | 1576 | ||
| 1531 | out: | 1577 | drm_master_internal_release(dev); |
| 1578 | unlock: | ||
| 1532 | mutex_unlock(&fb_helper->lock); | 1579 | mutex_unlock(&fb_helper->lock); |
| 1533 | 1580 | ||
| 1534 | return ret; | 1581 | return ret; |
| @@ -1548,12 +1595,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, · 13 unmodified lines | |||
| 1548 | unsigned long arg) | 1595 | unsigned long arg) |
| 1549 | { | 1596 | { |
| 1550 | struct drm_fb_helper *fb_helper = info->par; | 1597 | struct drm_fb_helper *fb_helper = info->par; |
| 1598 | struct drm_device *dev = fb_helper->dev; | ||
| 1551 | struct drm_mode_set *mode_set; | 1599 | struct drm_mode_set *mode_set; |
| 1552 | struct drm_crtc *crtc; | 1600 | struct drm_crtc *crtc; |
| 1553 | int ret = 0; | 1601 | int ret = 0; |
| 1554 | 1602 | ||
| 1555 | mutex_lock(&fb_helper->lock); | 1603 | mutex_lock(&fb_helper->lock); |
| 1556 | if (!drm_fb_helper_is_bound(fb_helper)) { | 1604 | if (!drm_master_internal_acquire(dev)) { |
| 1557 | ret = -EBUSY; | 1605 | ret = -EBUSY; |
| 1558 | goto unlock; | 1606 | goto unlock; |
| 1559 | } | 1607 | } |
| @@ -1591,11 +1639,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, · 31 unmodified lines | |||
| 1591 | } | 1639 | } |
| 1592 | 1640 | ||
| 1593 | ret = 0; | 1641 | ret = 0; |
| 1594 | goto unlock; | 1642 | break; |
| 1595 | default: | 1643 | default: |
| 1596 | ret = -ENOTTY; | 1644 | ret = -ENOTTY; |
| 1597 | } | 1645 | } |
| 1598 | 1646 | ||
| 1647 | drm_master_internal_release(dev); | ||
| 1599 | unlock: | 1648 | unlock: |
| 1600 | mutex_unlock(&fb_helper->lock); | 1649 | mutex_unlock(&fb_helper->lock); |
| 1601 | return ret; | 1650 | return ret; |
| @@ -1847,15 +1896,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, · 245 unmodified lines | |||
| 1847 | return -EBUSY; | 1896 | return -EBUSY; |
| 1848 | 1897 | ||
| 1849 | mutex_lock(&fb_helper->lock); | 1898 | mutex_lock(&fb_helper->lock); |
| 1850 | if (!drm_fb_helper_is_bound(fb_helper)) { | 1899 | if (!drm_master_internal_acquire(dev)) { |
| 1851 | mutex_unlock(&fb_helper->lock); | 1900 | ret = -EBUSY; |
| 1852 | return -EBUSY; | 1901 | goto unlock; |
| 1853 | } | 1902 | } |
| 1854 | 1903 | ||
| 1855 | if (drm_drv_uses_atomic_modeset(dev)) | 1904 | if (drm_drv_uses_atomic_modeset(dev)) |
| 1856 | ret = pan_display_atomic(var, info); | 1905 | ret = pan_display_atomic(var, info); |
| 1857 | else | 1906 | else |
| 1858 | ret = pan_display_legacy(var, info); | 1907 | ret = pan_display_legacy(var, info); |
| 1908 | |||
| 1909 | drm_master_internal_release(dev); | ||
| 1910 | unlock: | ||
| 1859 | mutex_unlock(&fb_helper->lock); | 1911 | mutex_unlock(&fb_helper->lock); |
| 1860 | 1912 | ||
| 1861 | return ret; | 1913 | return ret; |
| @@ -1979,16 +2031,16 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, · 117 unmodified lines | |||
| 1979 | */ | 2031 | */ |
| 1980 | bool lastv = true, lasth = true; | 2032 | bool lastv = true, lasth = true; |
| 1981 | 2033 | ||
| 1982 | desired_mode = fb_helper->crtc_info[i].desired_mode; | ||
| 1983 | mode_set = &fb_helper->crtc_info[i].mode_set; | 2034 | mode_set = &fb_helper->crtc_info[i].mode_set; |
| 2035 | desired_mode = mode_set->mode; | ||
| 1984 | 2036 | ||
| 1985 | if (!desired_mode) | 2037 | if (!desired_mode) |
| 1986 | continue; | 2038 | continue; |
| 1987 | 2039 | ||
| 1988 | crtc_count++; | 2040 | crtc_count++; |
| 1989 | 2041 | ||
| 1990 | x = fb_helper->crtc_info[i].x; | 2042 | x = mode_set->x; |
| 1991 | y = fb_helper->crtc_info[i].y; | 2043 | y = mode_set->y; |
| 1992 | 2044 | ||
| 1993 | sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width); | 2045 | sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width); |
| 1994 | sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height); | 2046 | sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height); |
| @@ -2014,7 +2066,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, · 19 unmodified lines | |||
| 2014 | DRM_INFO("Cannot find any crtc or sizes\n"); | 2066 | DRM_INFO("Cannot find any crtc or sizes\n"); |
| 2015 | 2067 | ||
| 2016 | /* First time: disable all crtc's.. */ | 2068 | /* First time: disable all crtc's.. */ |
| 2017 | if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master)) | 2069 | if (!fb_helper->deferred_setup) |
| 2018 | restore_fbdev_mode(fb_helper); | 2070 | restore_fbdev_mode(fb_helper); |
| 2019 | return -EAGAIN; | 2071 | return -EAGAIN; |
| 2020 | } | 2072 | } |
| @@ -2503,62 +2555,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, · 482 unmodified lines | |||
| 2503 | return best_score; | 2555 | return best_score; |
| 2504 | } | 2556 | } |
| 2505 | 2557 | ||
| 2506 | /* | ||
| 2507 | * This function checks if rotation is necessary because of panel orientation | ||
| 2508 | * and if it is, if it is supported. | ||
| 2509 | * If rotation is necessary and supported, it gets set in fb_crtc.rotation. | ||
| 2510 | * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets | ||
| 2511 | * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only | ||
| 2512 | * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do | ||
| 2513 | * the unsupported rotation. | ||
| 2514 | */ | ||
| 2515 | static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, | ||
| 2516 | struct drm_fb_helper_crtc *fb_crtc, | ||
| 2517 | struct drm_connector *connector) | ||
| 2518 | { | ||
| 2519 | struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; | ||
| 2520 | uint64_t valid_mask = 0; | ||
| 2521 | int i, rotation; | ||
| 2522 | |||
| 2523 | fb_crtc->rotation = DRM_MODE_ROTATE_0; | ||
| 2524 | |||
| 2525 | switch (connector->display_info.panel_orientation) { | ||
| 2526 | case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP: | ||
| 2527 | rotation = DRM_MODE_ROTATE_180; | ||
| 2528 | break; | ||
| 2529 | case DRM_MODE_PANEL_ORIENTATION_LEFT_UP: | ||
| 2530 | rotation = DRM_MODE_ROTATE_90; | ||
| 2531 | break; | ||
| 2532 | case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP: | ||
| 2533 | rotation = DRM_MODE_ROTATE_270; | ||
| 2534 | break; | ||
| 2535 | default: | ||
| 2536 | rotation = DRM_MODE_ROTATE_0; | ||
| 2537 | } | ||
| 2538 | |||
| 2539 | /* | ||
| 2540 | * TODO: support 90 / 270 degree hardware rotation, | ||
| 2541 | * depending on the hardware this may require the framebuffer | ||
| 2542 | * to be in a specific tiling format. | ||
| 2543 | */ | ||
| 2544 | if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) { | ||
| 2545 | fb_helper->sw_rotations |= rotation; | ||
| 2546 | return; | ||
| 2547 | } | ||
| 2548 | |||
| 2549 | for (i = 0; i < plane->rotation_property->num_values; i++) | ||
| 2550 | valid_mask |= (1ULL << plane->rotation_property->values[i]); | ||
| 2551 | |||
| 2552 | if (!(rotation & valid_mask)) { | ||
| 2553 | fb_helper->sw_rotations |= rotation; | ||
| 2554 | return; | ||
| 2555 | } | ||
| 2556 | |||
| 2557 | fb_crtc->rotation = rotation; | ||
| 2558 | /* Rotating in hardware, fbcon should not rotate */ | ||
| 2559 | fb_helper->sw_rotations |= DRM_MODE_ROTATE_0; | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | static struct drm_fb_helper_crtc * | 2558 | static struct drm_fb_helper_crtc * |
| 2563 | drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) | 2559 | drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) |
| 2564 | { | 2560 | { |
| @@ -2805,7 +2801,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, · 240 unmodified lines | |||
| 2805 | drm_fb_helper_modeset_release(fb_helper, | 2801 | drm_fb_helper_modeset_release(fb_helper, |
| 2806 | &fb_helper->crtc_info[i].mode_set); | 2802 | &fb_helper->crtc_info[i].mode_set); |
| 2807 | 2803 | ||
| 2808 | fb_helper->sw_rotations = 0; | ||
| 2809 | drm_fb_helper_for_each_connector(fb_helper, i) { | 2804 | drm_fb_helper_for_each_connector(fb_helper, i) { |
| 2810 | struct drm_display_mode *mode = modes[i]; | 2805 | struct drm_display_mode *mode = modes[i]; |
| 2811 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; | 2806 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
| @@ -2819,13 +2814,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, · 7 unmodified lines | |||
| 2819 | DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", | 2814 | DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", |
| 2820 | mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); | 2815 | mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); |
| 2821 | 2816 | ||
| 2822 | fb_crtc->desired_mode = mode; | 2817 | modeset->mode = drm_mode_duplicate(dev, mode); |
| 2823 | fb_crtc->x = offset->x; | ||
| 2824 | fb_crtc->y = offset->y; | ||
| 2825 | modeset->mode = drm_mode_duplicate(dev, | ||
| 2826 | fb_crtc->desired_mode); | ||
| 2827 | drm_connector_get(connector); | 2818 | drm_connector_get(connector); |
| 2828 | drm_setup_crtc_rotation(fb_helper, fb_crtc, connector); | ||
| 2829 | modeset->connectors[modeset->num_connectors++] = connector; | 2819 | modeset->connectors[modeset->num_connectors++] = connector; |
| 2830 | modeset->x = offset->x; | 2820 | modeset->x = offset->x; |
| 2831 | modeset->y = offset->y; | 2821 | modeset->y = offset->y; |
| @@ -2848,11 +2838,23 @@ out: · 16 unmodified lines | |||
| 2848 | static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) | 2838 | static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) |
| 2849 | { | 2839 | { |
| 2850 | struct fb_info *info = fb_helper->fbdev; | 2840 | struct fb_info *info = fb_helper->fbdev; |
| 2841 | unsigned int rotation, sw_rotations = 0; | ||
| 2851 | int i; | 2842 | int i; |
| 2852 | 2843 | ||
| 2853 | for (i = 0; i < fb_helper->crtc_count; i++) | 2844 | for (i = 0; i < fb_helper->crtc_count; i++) { |
| 2854 | if (fb_helper->crtc_info[i].mode_set.num_connectors) | 2845 | struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set; |
| 2855 | fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; | 2846 | |
| 2847 | if (!modeset->num_connectors) | ||
| 2848 | continue; | ||
| 2849 | |||
| 2850 | modeset->fb = fb_helper->fb; | ||
| 2851 | |||
| 2852 | if (drm_fb_helper_panel_rotation(modeset, &rotation)) | ||
| 2853 | /* Rotating in hardware, fbcon should not rotate */ | ||
| 2854 | sw_rotations |= DRM_MODE_ROTATE_0; | ||
| 2855 | else | ||
| 2856 | sw_rotations |= rotation; | ||
| 2857 | } | ||
| 2856 | 2858 | ||
| 2857 | mutex_lock(&fb_helper->dev->mode_config.mutex); | 2859 | mutex_lock(&fb_helper->dev->mode_config.mutex); |
| 2858 | drm_fb_helper_for_each_connector(fb_helper, i) { | 2860 | drm_fb_helper_for_each_connector(fb_helper, i) { |
| @@ -2868,7 +2870,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) · 9 unmodified lines | |||
| 2868 | } | 2870 | } |
| 2869 | mutex_unlock(&fb_helper->dev->mode_config.mutex); | 2871 | mutex_unlock(&fb_helper->dev->mode_config.mutex); |
| 2870 | 2872 | ||
| 2871 | switch (fb_helper->sw_rotations) { | 2873 | switch (sw_rotations) { |
| 2872 | case DRM_MODE_ROTATE_0: | 2874 | case DRM_MODE_ROTATE_0: |
| 2873 | info->fbcon_rotate_hint = FB_ROTATE_UR; | 2875 | info->fbcon_rotate_hint = FB_ROTATE_UR; |
| 2874 | break; | 2876 | break; |
| @@ -3041,12 +3043,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) · 166 unmodified lines | |||
| 3041 | return err; | 3043 | return err; |
| 3042 | } | 3044 | } |
| 3043 | 3045 | ||
| 3044 | if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) { | 3046 | if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) { |
| 3045 | fb_helper->delayed_hotplug = true; | 3047 | fb_helper->delayed_hotplug = true; |
| 3046 | mutex_unlock(&fb_helper->lock); | 3048 | mutex_unlock(&fb_helper->lock); |
| 3047 | return err; | 3049 | return err; |
| 3048 | } | 3050 | } |
| 3049 | 3051 | ||
| 3052 | drm_master_internal_release(fb_helper->dev); | ||
| 3053 | |||
| 3050 | DRM_DEBUG_KMS("\n"); | 3054 | DRM_DEBUG_KMS("\n"); |
| 3051 | 3055 | ||
| 3052 | drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height); | 3056 | drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height); |
| @@ -100,8 +100,6 @@ DEFINE_MUTEX(drm_global_mutex); · 99 unmodified lines | |||
| 100 | * :ref:`IOCTL support in the userland interfaces chapter<drm_driver_ioctl>`. | 100 | * :ref:`IOCTL support in the userland interfaces chapter<drm_driver_ioctl>`. |
| 101 | */ | 101 | */ |
| 102 | 102 | ||
| 103 | static int drm_open_helper(struct file *filp, struct drm_minor *minor); | ||
| 104 | |||
| 105 | /** | 103 | /** |
| 106 | * drm_file_alloc - allocate file context | 104 | * drm_file_alloc - allocate file context |
| 107 | * @minor: minor to allocate on | 105 | * @minor: minor to allocate on |
| @@ -273,76 +271,6 @@ static void drm_close_helper(struct file *filp) · 165 unmodified lines | |||
| 273 | drm_file_free(file_priv); | 271 | drm_file_free(file_priv); |
| 274 | } | 272 | } |
| 275 | 273 | ||
| 276 | static int drm_setup(struct drm_device * dev) | ||
| 277 | { | ||
| 278 | int ret; | ||
| 279 | |||
| 280 | if (dev->driver->firstopen && | ||
| 281 | drm_core_check_feature(dev, DRIVER_LEGACY)) { | ||
| 282 | ret = dev->driver->firstopen(dev); | ||
| 283 | if (ret != 0) | ||
| 284 | return ret; | ||
| 285 | } | ||
| 286 | |||
| 287 | ret = drm_legacy_dma_setup(dev); | ||
| 288 | if (ret < 0) | ||
| 289 | return ret; | ||
| 290 | |||
| 291 | |||
| 292 | DRM_DEBUG("\n"); | ||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | /** | ||
| 297 | * drm_open - open method for DRM file | ||
| 298 | * @inode: device inode | ||
| 299 | * @filp: file pointer. | ||
| 300 | * | ||
| 301 | * This function must be used by drivers as their &file_operations.open method. | ||
| 302 | * It looks up the correct DRM device and instantiates all the per-file | ||
| 303 | * resources for it. It also calls the &drm_driver.open driver callback. | ||
| 304 | * | ||
| 305 | * RETURNS: | ||
| 306 | * | ||
| 307 | * 0 on success or negative errno value on falure. | ||
| 308 | */ | ||
| 309 | int drm_open(struct inode *inode, struct file *filp) | ||
| 310 | { | ||
| 311 | struct drm_device *dev; | ||
| 312 | struct drm_minor *minor; | ||
| 313 | int retcode; | ||
| 314 | int need_setup = 0; | ||
| 315 | |||
| 316 | minor = drm_minor_acquire(iminor(inode)); | ||
| 317 | if (IS_ERR(minor)) | ||
| 318 | return PTR_ERR(minor); | ||
| 319 | |||
| 320 | dev = minor->dev; | ||
| 321 | if (!dev->open_count++) | ||
| 322 | need_setup = 1; | ||
| 323 | |||
| 324 | /* share address_space across all char-devs of a single device */ | ||
| 325 | filp->f_mapping = dev->anon_inode->i_mapping; | ||
| 326 | |||
| 327 | retcode = drm_open_helper(filp, minor); | ||
| 328 | if (retcode) | ||
| 329 | goto err_undo; | ||
| 330 | if (need_setup) { | ||
| 331 | retcode = drm_setup(dev); | ||
| 332 | if (retcode) { | ||
| 333 | drm_close_helper(filp); | ||
| 334 | goto err_undo; | ||
| 335 | } | ||
| 336 | } | ||
| 337 | return 0; | ||
| 338 | |||
| 339 | err_undo: | ||
| 340 | dev->open_count--; | ||
| 341 | drm_minor_release(minor); | ||
| 342 | return retcode; | ||
| 343 | } | ||
| 344 | EXPORT_SYMBOL(drm_open); | ||
| 345 | |||
| 346 | /* | 274 | /* |
| 347 | * Check whether DRI will run on this CPU. | 275 | * Check whether DRI will run on this CPU. |
| 348 | * | 276 | * |
| @@ -424,6 +352,56 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) · 75 unmodified lines | |||
| 424 | return 0; | 352 | return 0; |
| 425 | } | 353 | } |
| 426 | 354 | ||
| 355 | /** | ||
| 356 | * drm_open - open method for DRM file | ||
| 357 | * @inode: device inode | ||
| 358 | * @filp: file pointer. | ||
| 359 | * | ||
| 360 | * This function must be used by drivers as their &file_operations.open method. | ||
| 361 | * It looks up the correct DRM device and instantiates all the per-file | ||
| 362 | * resources for it. It also calls the &drm_driver.open driver callback. | ||
| 363 | * | ||
| 364 | * RETURNS: | ||
| 365 | * | ||
| 366 | * 0 on success or negative errno value on falure. | ||
| 367 | */ | ||
| 368 | int drm_open(struct inode *inode, struct file *filp) | ||
| 369 | { | ||
| 370 | struct drm_device *dev; | ||
| 371 | struct drm_minor *minor; | ||
| 372 | int retcode; | ||
| 373 | int need_setup = 0; | ||
| 374 | |||
| 375 | minor = drm_minor_acquire(iminor(inode)); | ||
| 376 | if (IS_ERR(minor)) | ||
| 377 | return PTR_ERR(minor); | ||
| 378 | |||
| 379 | dev = minor->dev; | ||
| 380 | if (!dev->open_count++) | ||
| 381 | need_setup = 1; | ||
| 382 | |||
| 383 | /* share address_space across all char-devs of a single device */ | ||
| 384 | filp->f_mapping = dev->anon_inode->i_mapping; | ||
| 385 | |||
| 386 | retcode = drm_open_helper(filp, minor); | ||
| 387 | if (retcode) | ||
| 388 | goto err_undo; | ||
| 389 | if (need_setup) { | ||
| 390 | retcode = drm_legacy_setup(dev); | ||
| 391 | if (retcode) { | ||
| 392 | drm_close_helper(filp); | ||
| 393 | goto err_undo; | ||
| 394 | } | ||
| 395 | } | ||
| 396 | return 0; | ||
| 397 | |||
| 398 | err_undo: | ||
| 399 | dev->open_count--; | ||
| 400 | drm_minor_release(minor); | ||
| 401 | return retcode; | ||
| 402 | } | ||
| 403 | EXPORT_SYMBOL(drm_open); | ||
| 404 | |||
| 427 | void drm_lastclose(struct drm_device * dev) | 405 | void drm_lastclose(struct drm_device * dev) |
| 428 | { | 406 | { |
| 429 | DRM_DEBUG("\n"); | 407 | DRM_DEBUG("\n"); |
| @@ -36,7 +36,7 @@ static unsigned int clip_offset(struct drm_rect *clip, · 35 unmodified lines | |||
| 36 | void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, | 36 | void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, |
| 37 | struct drm_rect *clip) | 37 | struct drm_rect *clip) |
| 38 | { | 38 | { |
| 39 | unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); | 39 | unsigned int cpp = fb->format->cpp[0]; |
| 40 | size_t len = (clip->x2 - clip->x1) * cpp; | 40 | size_t len = (clip->x2 - clip->x1) * cpp; |
| 41 | unsigned int y, lines = clip->y2 - clip->y1; | 41 | unsigned int y, lines = clip->y2 - clip->y1; |
| 42 | 42 | ||
| @@ -63,7 +63,7 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, · 20 unmodified lines | |||
| 63 | struct drm_framebuffer *fb, | 63 | struct drm_framebuffer *fb, |
| 64 | struct drm_rect *clip) | 64 | struct drm_rect *clip) |
| 65 | { | 65 | { |
| 66 | unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); | 66 | unsigned int cpp = fb->format->cpp[0]; |
| 67 | unsigned int offset = clip_offset(clip, fb->pitches[0], cpp); | 67 | unsigned int offset = clip_offset(clip, fb->pitches[0], cpp); |
| 68 | size_t len = (clip->x2 - clip->x1) * cpp; | 68 | size_t len = (clip->x2 - clip->x1) * cpp; |
| 69 | unsigned int y, lines = clip->y2 - clip->y1; | 69 | unsigned int y, lines = clip->y2 - clip->y1; |
| @@ -332,124 +332,6 @@ drm_get_format_info(struct drm_device *dev, · 331 unmodified lines | |||
| 332 | } | 332 | } |
| 333 | EXPORT_SYMBOL(drm_get_format_info); | 333 | EXPORT_SYMBOL(drm_get_format_info); |
| 334 | 334 | ||
| 335 | /** | ||
| 336 | * drm_format_num_planes - get the number of planes for format | ||
| 337 | * @format: pixel format (DRM_FORMAT_*) | ||
| 338 | * | ||
| 339 | * Returns: | ||
| 340 | * The number of planes used by the specified pixel format. | ||
| 341 | */ | ||
| 342 | int drm_format_num_planes(uint32_t format) | ||
| 343 | { | ||
| 344 | const struct drm_format_info *info; | ||
| 345 | |||
| 346 | info = drm_format_info(format); | ||
| 347 | return info ? info->num_planes : 1; | ||
| 348 | } | ||
| 349 | EXPORT_SYMBOL(drm_format_num_planes); | ||
| 350 | |||
| 351 | /** | ||
| 352 | * drm_format_plane_cpp - determine the bytes per pixel value | ||
| 353 | * @format: pixel format (DRM_FORMAT_*) | ||
| 354 | * @plane: plane index | ||
| 355 | * | ||
| 356 | * Returns: | ||
| 357 | * The bytes per pixel value for the specified plane. | ||
| 358 | */ | ||
| 359 | int drm_format_plane_cpp(uint32_t format, int plane) | ||
| 360 | { | ||
| 361 | const struct drm_format_info *info; | ||
| 362 | |||
| 363 | info = drm_format_info(format); | ||
| 364 | if (!info || plane >= info->num_planes) | ||
| 365 | return 0; | ||
| 366 | |||
| 367 | return info->cpp[plane]; | ||
| 368 | } | ||
| 369 | EXPORT_SYMBOL(drm_format_plane_cpp); | ||
| 370 | |||
| 371 | /** | ||
| 372 | * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor | ||
| 373 | * @format: pixel format (DRM_FORMAT_*) | ||
| 374 | * | ||
| 375 | * Returns: | ||
| 376 | * The horizontal chroma subsampling factor for the | ||
| 377 | * specified pixel format. | ||
| 378 | */ | ||
| 379 | int drm_format_horz_chroma_subsampling(uint32_t format) | ||
| 380 | { | ||
| 381 | const struct drm_format_info *info; | ||
| 382 | |||
| 383 | info = drm_format_info(format); | ||
| 384 | return info ? info->hsub : 1; | ||
| 385 | } | ||
| 386 | EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); | ||
| 387 | |||
| 388 | /** | ||
| 389 | * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor | ||
| 390 | * @format: pixel format (DRM_FORMAT_*) | ||
| 391 | * | ||
| 392 | * Returns: | ||
| 393 | * The vertical chroma subsampling factor for the | ||
| 394 | * specified pixel format. | ||
| 395 | */ | ||
| 396 | int drm_format_vert_chroma_subsampling(uint32_t format) | ||
| 397 | { | ||
| 398 | const struct drm_format_info *info; | ||
| 399 | |||
| 400 | info = drm_format_info(format); | ||
| 401 | return info ? info->vsub : 1; | ||
| 402 | } | ||
| 403 | EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); | ||
| 404 | |||
| 405 | /** | ||
| 406 | * drm_format_plane_width - width of the plane given the first plane | ||
| 407 | * @width: width of the first plane | ||
| 408 | * @format: pixel format | ||
| 409 | * @plane: plane index | ||
| 410 | * | ||
| 411 | * Returns: | ||
| 412 | * The width of @plane, given that the width of the first plane is @width. | ||
| 413 | */ | ||
| 414 | int drm_format_plane_width(int width, uint32_t format, int plane) | ||
| 415 | { | ||
| 416 | const struct drm_format_info *info; | ||
| 417 | |||
| 418 | info = drm_format_info(format); | ||
| 419 | if (!info || plane >= info->num_planes) | ||
| 420 | return 0; | ||
| 421 | |||
| 422 | if (plane == 0) | ||
| 423 | return width; | ||
| 424 | |||
| 425 | return width / info->hsub; | ||
| 426 | } | ||
| 427 | EXPORT_SYMBOL(drm_format_plane_width); | ||
| 428 | |||
| 429 | /** | ||
| 430 | * drm_format_plane_height - height of the plane given the first plane | ||
| 431 | * @height: height of the first plane | ||
| 432 | * @format: pixel format | ||
| 433 | * @plane: plane index | ||
| 434 | * | ||
| 435 | * Returns: | ||
| 436 | * The height of @plane, given that the height of the first plane is @height. | ||
| 437 | */ | ||
| 438 | int drm_format_plane_height(int height, uint32_t format, int plane) | ||
| 439 | { | ||
| 440 | const struct drm_format_info *info; | ||
| 441 | |||
| 442 | info = drm_format_info(format); | ||
| 443 | if (!info || plane >= info->num_planes) | ||
| 444 | return 0; | ||
| 445 | |||
| 446 | if (plane == 0) | ||
| 447 | return height; | ||
| 448 | |||
| 449 | return height / info->vsub; | ||
| 450 | } | ||
| 451 | EXPORT_SYMBOL(drm_format_plane_height); | ||
| 452 | |||
| 453 | /** | 335 | /** |
| 454 | * drm_format_info_block_width - width in pixels of block. | 336 | * drm_format_info_block_width - width in pixels of block. |
| 455 | * @info: pixel format info | 337 | * @info: pixel format info |
| @@ -0,0 +1,772 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | |||
| 3 | #include <drm/drm_gem_vram_helper.h> | ||
| 4 | #include <drm/drm_device.h> | ||
| 5 | #include <drm/drm_mode.h> | ||
| 6 | #include <drm/drm_prime.h> | ||
| 7 | #include <drm/drm_vram_mm_helper.h> | ||
| 8 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 9 | |||
| 10 | /** | ||
| 11 | * DOC: overview | ||
| 12 | * | ||
| 13 | * This library provides a GEM buffer object that is backed by video RAM | ||
| 14 | * (VRAM). It can be used for framebuffer devices with dedicated memory. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Buffer-objects helpers | ||
| 19 | */ | ||
| 20 | |||
| 21 | static void drm_gem_vram_cleanup(struct drm_gem_vram_object *gbo) | ||
| 22 | { | ||
| 23 | /* We got here via ttm_bo_put(), which means that the | ||
| 24 | * TTM buffer object in 'bo' has already been cleaned | ||
| 25 | * up; only release the GEM object. | ||
| 26 | */ | ||
| 27 | drm_gem_object_release(&gbo->gem); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void drm_gem_vram_destroy(struct drm_gem_vram_object *gbo) | ||
| 31 | { | ||
| 32 | drm_gem_vram_cleanup(gbo); | ||
| 33 | kfree(gbo); | ||
| 34 | } | ||
| 35 | |||
| 36 | static void ttm_buffer_object_destroy(struct ttm_buffer_object *bo) | ||
| 37 | { | ||
| 38 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_bo(bo); | ||
| 39 | |||
| 40 | drm_gem_vram_destroy(gbo); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, | ||
| 44 | unsigned long pl_flag) | ||
| 45 | { | ||
| 46 | unsigned int i; | ||
| 47 | unsigned int c = 0; | ||
| 48 | |||
| 49 | gbo->placement.placement = gbo->placements; | ||
| 50 | gbo->placement.busy_placement = gbo->placements; | ||
| 51 | |||
| 52 | if (pl_flag & TTM_PL_FLAG_VRAM) | ||
| 53 | gbo->placements[c++].flags = TTM_PL_FLAG_WC | | ||
| 54 | TTM_PL_FLAG_UNCACHED | | ||
| 55 | TTM_PL_FLAG_VRAM; | ||
| 56 | |||
| 57 | if (pl_flag & TTM_PL_FLAG_SYSTEM) | ||
| 58 | gbo->placements[c++].flags = TTM_PL_MASK_CACHING | | ||
| 59 | TTM_PL_FLAG_SYSTEM; | ||
| 60 | |||
| 61 | if (!c) | ||
| 62 | gbo->placements[c++].flags = TTM_PL_MASK_CACHING | | ||
| 63 | TTM_PL_FLAG_SYSTEM; | ||
| 64 | |||
| 65 | gbo->placement.num_placement = c; | ||
| 66 | gbo->placement.num_busy_placement = c; | ||
| 67 | |||
| 68 | for (i = 0; i < c; ++i) { | ||
| 69 | gbo->placements[i].fpfn = 0; | ||
| 70 | gbo->placements[i].lpfn = 0; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | static int drm_gem_vram_init(struct drm_device *dev, | ||
| 75 | struct ttm_bo_device *bdev, | ||
| 76 | struct drm_gem_vram_object *gbo, | ||
| 77 | size_t size, unsigned long pg_align, | ||
| 78 | bool interruptible) | ||
| 79 | { | ||
| 80 | int ret; | ||
| 81 | size_t acc_size; | ||
| 82 | |||
| 83 | ret = drm_gem_object_init(dev, &gbo->gem, size); | ||
| 84 | if (ret) | ||
| 85 | return ret; | ||
| 86 | |||
| 87 | acc_size = ttm_bo_dma_acc_size(bdev, size, sizeof(*gbo)); | ||
| 88 | |||
| 89 | gbo->bo.bdev = bdev; | ||
| 90 | drm_gem_vram_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 91 | |||
| 92 | ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device, | ||
| 93 | &gbo->placement, pg_align, interruptible, acc_size, | ||
| 94 | NULL, NULL, ttm_buffer_object_destroy); | ||
| 95 | if (ret) | ||
| 96 | goto err_drm_gem_object_release; | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | |||
| 100 | err_drm_gem_object_release: | ||
| 101 | drm_gem_object_release(&gbo->gem); | ||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | /** | ||
| 106 | * drm_gem_vram_create() - Creates a VRAM-backed GEM object | ||
| 107 | * @dev: the DRM device | ||
| 108 | * @bdev: the TTM BO device backing the object | ||
| 109 | * @size: the buffer size in bytes | ||
| 110 | * @pg_align: the buffer's alignment in multiples of the page size | ||
| 111 | * @interruptible: sleep interruptible if waiting for memory | ||
| 112 | * | ||
| 113 | * Returns: | ||
| 114 | * A new instance of &struct drm_gem_vram_object on success, or | ||
| 115 | * an ERR_PTR()-encoded error code otherwise. | ||
| 116 | */ | ||
| 117 | struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, | ||
| 118 | struct ttm_bo_device *bdev, | ||
| 119 | size_t size, | ||
| 120 | unsigned long pg_align, | ||
| 121 | bool interruptible) | ||
| 122 | { | ||
| 123 | struct drm_gem_vram_object *gbo; | ||
| 124 | int ret; | ||
| 125 | |||
| 126 | gbo = kzalloc(sizeof(*gbo), GFP_KERNEL); | ||
| 127 | if (!gbo) | ||
| 128 | return ERR_PTR(-ENOMEM); | ||
| 129 | |||
| 130 | ret = drm_gem_vram_init(dev, bdev, gbo, size, pg_align, interruptible); | ||
| 131 | if (ret < 0) | ||
| 132 | goto err_kfree; | ||
| 133 | |||
| 134 | return gbo; | ||
| 135 | |||
| 136 | err_kfree: | ||
| 137 | kfree(gbo); | ||
| 138 | return ERR_PTR(ret); | ||
| 139 | } | ||
| 140 | EXPORT_SYMBOL(drm_gem_vram_create); | ||
| 141 | |||
| 142 | /** | ||
| 143 | * drm_gem_vram_put() - Releases a reference to a VRAM-backed GEM object | ||
| 144 | * @gbo: the GEM VRAM object | ||
| 145 | * | ||
| 146 | * See ttm_bo_put() for more information. | ||
| 147 | */ | ||
| 148 | void drm_gem_vram_put(struct drm_gem_vram_object *gbo) | ||
| 149 | { | ||
| 150 | ttm_bo_put(&gbo->bo); | ||
| 151 | } | ||
| 152 | EXPORT_SYMBOL(drm_gem_vram_put); | ||
| 153 | |||
| 154 | /** | ||
| 155 | * drm_gem_vram_lock() - Locks a VRAM-backed GEM object | ||
| 156 | * @gbo: the GEM VRAM object | ||
| 157 | * @no_wait: don't wait for buffer object to become available | ||
| 158 | * | ||
| 159 | * See ttm_bo_reserve() for more information. | ||
| 160 | * | ||
| 161 | * Returns: | ||
| 162 | * 0 on success, or | ||
| 163 | * a negative error code otherwise | ||
| 164 | */ | ||
| 165 | int drm_gem_vram_lock(struct drm_gem_vram_object *gbo, bool no_wait) | ||
| 166 | { | ||
| 167 | return ttm_bo_reserve(&gbo->bo, true, no_wait, NULL); | ||
| 168 | } | ||
| 169 | EXPORT_SYMBOL(drm_gem_vram_lock); | ||
| 170 | |||
| 171 | /** | ||
| 172 | * drm_gem_vram_unlock() - \ | ||
| 173 | Release a reservation acquired by drm_gem_vram_lock() | ||
| 174 | * @gbo: the GEM VRAM object | ||
| 175 | * | ||
| 176 | * See ttm_bo_unreserve() for more information. | ||
| 177 | */ | ||
| 178 | void drm_gem_vram_unlock(struct drm_gem_vram_object *gbo) | ||
| 179 | { | ||
| 180 | ttm_bo_unreserve(&gbo->bo); | ||
| 181 | } | ||
| 182 | EXPORT_SYMBOL(drm_gem_vram_unlock); | ||
| 183 | |||
| 184 | /** | ||
| 185 | * drm_gem_vram_mmap_offset() - Returns a GEM VRAM object's mmap offset | ||
| 186 | * @gbo: the GEM VRAM object | ||
| 187 | * | ||
| 188 | * See drm_vma_node_offset_addr() for more information. | ||
| 189 | * | ||
| 190 | * Returns: | ||
| 191 | * The buffer object's offset for userspace mappings on success, or | ||
| 192 | * 0 if no offset is allocated. | ||
| 193 | */ | ||
| 194 | u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo) | ||
| 195 | { | ||
| 196 | return drm_vma_node_offset_addr(&gbo->bo.vma_node); | ||
| 197 | } | ||
| 198 | EXPORT_SYMBOL(drm_gem_vram_mmap_offset); | ||
| 199 | |||
| 200 | /** | ||
| 201 | * drm_gem_vram_offset() - \ | ||
| 202 | Returns a GEM VRAM object's offset in video memory | ||
| 203 | * @gbo: the GEM VRAM object | ||
| 204 | * | ||
| 205 | * This function returns the buffer object's offset in the device's video | ||
| 206 | * memory. The buffer object has to be pinned to %TTM_PL_VRAM. | ||
| 207 | * | ||
| 208 | * Returns: | ||
| 209 | * The buffer object's offset in video memory on success, or | ||
| 210 | * a negative errno code otherwise. | ||
| 211 | */ | ||
| 212 | s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo) | ||
| 213 | { | ||
| 214 | if (WARN_ON_ONCE(!gbo->pin_count)) | ||
| 215 | return (s64)-ENODEV; | ||
| 216 | return gbo->bo.offset; | ||
| 217 | } | ||
| 218 | EXPORT_SYMBOL(drm_gem_vram_offset); | ||
| 219 | |||
| 220 | /** | ||
| 221 | * drm_gem_vram_pin() - Pins a GEM VRAM object in a region. | ||
| 222 | * @gbo: the GEM VRAM object | ||
| 223 | * @pl_flag: a bitmask of possible memory regions | ||
| 224 | * | ||
| 225 | * Pinning a buffer object ensures that it is not evicted from | ||
| 226 | * a memory region. A pinned buffer object has to be unpinned before | ||
| 227 | * it can be pinned to another region. | ||
| 228 | * | ||
| 229 | * Returns: | ||
| 230 | * 0 on success, or | ||
| 231 | * a negative error code otherwise. | ||
| 232 | */ | ||
| 233 | int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag) | ||
| 234 | { | ||
| 235 | int i, ret; | ||
| 236 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 237 | |||
| 238 | ret = ttm_bo_reserve(&gbo->bo, true, false, NULL); | ||
| 239 | if (ret < 0) | ||
| 240 | return ret; | ||
| 241 | |||
| 242 | if (gbo->pin_count) | ||
| 243 | goto out; | ||
| 244 | |||
| 245 | drm_gem_vram_placement(gbo, pl_flag); | ||
| 246 | for (i = 0; i < gbo->placement.num_placement; ++i) | ||
| 247 | gbo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 248 | |||
| 249 | ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx); | ||
| 250 | if (ret < 0) | ||
| 251 | goto err_ttm_bo_unreserve; | ||
| 252 | |||
| 253 | out: | ||
| 254 | ++gbo->pin_count; | ||
| 255 | ttm_bo_unreserve(&gbo->bo); | ||
| 256 | |||
| 257 | return 0; | ||
| 258 | |||
| 259 | err_ttm_bo_unreserve: | ||
| 260 | ttm_bo_unreserve(&gbo->bo); | ||
| 261 | return ret; | ||
| 262 | } | ||
| 263 | EXPORT_SYMBOL(drm_gem_vram_pin); | ||
| 264 | |||
| 265 | /** | ||
| 266 | * drm_gem_vram_pin_locked() - Pins a GEM VRAM object in a region. | ||
| 267 | * @gbo: the GEM VRAM object | ||
| 268 | * @pl_flag: a bitmask of possible memory regions | ||
| 269 | * | ||
| 270 | * Pinning a buffer object ensures that it is not evicted from | ||
| 271 | * a memory region. A pinned buffer object has to be unpinned before | ||
| 272 | * it can be pinned to another region. | ||
| 273 | * | ||
| 274 | * This function pins a GEM VRAM object that has already been | ||
| 275 | * locked. Use drm_gem_vram_pin() if possible. | ||
| 276 | * | ||
| 277 | * Returns: | ||
| 278 | * 0 on success, or | ||
| 279 | * a negative error code otherwise. | ||
| 280 | */ | ||
| 281 | int drm_gem_vram_pin_locked(struct drm_gem_vram_object *gbo, | ||
| 282 | unsigned long pl_flag) | ||
| 283 | { | ||
| 284 | int i, ret; | ||
| 285 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 286 | |||
| 287 | lockdep_assert_held(&gbo->bo.resv->lock.base); | ||
| 288 | |||
| 289 | if (gbo->pin_count) { | ||
| 290 | ++gbo->pin_count; | ||
| 291 | return 0; | ||
| 292 | } | ||
| 293 | |||
| 294 | drm_gem_vram_placement(gbo, pl_flag); | ||
| 295 | for (i = 0; i < gbo->placement.num_placement; ++i) | ||
| 296 | gbo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 297 | |||
| 298 | ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx); | ||
| 299 | if (ret < 0) | ||
| 300 | return ret; | ||
| 301 | |||
| 302 | gbo->pin_count = 1; | ||
| 303 | |||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | EXPORT_SYMBOL(drm_gem_vram_pin_locked); | ||
| 307 | |||
| 308 | /** | ||
| 309 | * drm_gem_vram_unpin() - Unpins a GEM VRAM object | ||
| 310 | * @gbo: the GEM VRAM object | ||
| 311 | * | ||
| 312 | * Returns: | ||
| 313 | * 0 on success, or | ||
| 314 | * a negative error code otherwise. | ||
| 315 | */ | ||
| 316 | int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo) | ||
| 317 | { | ||
| 318 | int i, ret; | ||
| 319 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 320 | |||
| 321 | ret = ttm_bo_reserve(&gbo->bo, true, false, NULL); | ||
| 322 | if (ret < 0) | ||
| 323 | return ret; | ||
| 324 | |||
| 325 | if (WARN_ON_ONCE(!gbo->pin_count)) | ||
| 326 | goto out; | ||
| 327 | |||
| 328 | --gbo->pin_count; | ||
| 329 | if (gbo->pin_count) | ||
| 330 | goto out; | ||
| 331 | |||
| 332 | for (i = 0; i < gbo->placement.num_placement ; ++i) | ||
| 333 | gbo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 334 | |||
| 335 | ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx); | ||
| 336 | if (ret < 0) | ||
| 337 | goto err_ttm_bo_unreserve; | ||
| 338 | |||
| 339 | out: | ||
| 340 | ttm_bo_unreserve(&gbo->bo); | ||
| 341 | |||
| 342 | return 0; | ||
| 343 | |||
| 344 | err_ttm_bo_unreserve: | ||
| 345 | ttm_bo_unreserve(&gbo->bo); | ||
| 346 | return ret; | ||
| 347 | } | ||
| 348 | EXPORT_SYMBOL(drm_gem_vram_unpin); | ||
| 349 | |||
| 350 | /** | ||
| 351 | * drm_gem_vram_unpin_locked() - Unpins a GEM VRAM object | ||
| 352 | * @gbo: the GEM VRAM object | ||
| 353 | * | ||
| 354 | * This function unpins a GEM VRAM object that has already been | ||
| 355 | * locked. Use drm_gem_vram_unpin() if possible. | ||
| 356 | * | ||
| 357 | * Returns: | ||
| 358 | * 0 on success, or | ||
| 359 | * a negative error code otherwise. | ||
| 360 | */ | ||
| 361 | int drm_gem_vram_unpin_locked(struct drm_gem_vram_object *gbo) | ||
| 362 | { | ||
| 363 | int i, ret; | ||
| 364 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 365 | |||
| 366 | lockdep_assert_held(&gbo->bo.resv->lock.base); | ||
| 367 | |||
| 368 | if (WARN_ON_ONCE(!gbo->pin_count)) | ||
| 369 | return 0; | ||
| 370 | |||
| 371 | --gbo->pin_count; | ||
| 372 | if (gbo->pin_count) | ||
| 373 | return 0; | ||
| 374 | |||
| 375 | for (i = 0; i < gbo->placement.num_placement ; ++i) | ||
| 376 | gbo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 377 | |||
| 378 | ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx); | ||
| 379 | if (ret < 0) | ||
| 380 | return ret; | ||
| 381 | |||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | EXPORT_SYMBOL(drm_gem_vram_unpin_locked); | ||
| 385 | |||
| 386 | /** | ||
| 387 | * drm_gem_vram_kmap_at() - Maps a GEM VRAM object into kernel address space | ||
| 388 | * @gbo: the GEM VRAM object | ||
| 389 | * @map: establish a mapping if necessary | ||
| 390 | * @is_iomem: returns true if the mapped memory is I/O memory, or false \ | ||
| 391 | otherwise; can be NULL | ||
| 392 | * @kmap: the mapping's kmap object | ||
| 393 | * | ||
| 394 | * This function maps the buffer object into the kernel's address space | ||
| 395 | * or returns the current mapping. If the parameter map is false, the | ||
| 396 | * function only queries the current mapping, but does not establish a | ||
| 397 | * new one. | ||
| 398 | * | ||
| 399 | * Returns: | ||
| 400 | * The buffers virtual address if mapped, or | ||
| 401 | * NULL if not mapped, or | ||
| 402 | * an ERR_PTR()-encoded error code otherwise. | ||
| 403 | */ | ||
| 404 | void *drm_gem_vram_kmap_at(struct drm_gem_vram_object *gbo, bool map, | ||
| 405 | bool *is_iomem, struct ttm_bo_kmap_obj *kmap) | ||
| 406 | { | ||
| 407 | int ret; | ||
| 408 | |||
| 409 | if (kmap->virtual || !map) | ||
| 410 | goto out; | ||
| 411 | |||
| 412 | ret = ttm_bo_kmap(&gbo->bo, 0, gbo->bo.num_pages, kmap); | ||
| 413 | if (ret) | ||
| 414 | return ERR_PTR(ret); | ||
| 415 | |||
| 416 | out: | ||
| 417 | if (!is_iomem) | ||
| 418 | return kmap->virtual; | ||
| 419 | if (!kmap->virtual) { | ||
| 420 | *is_iomem = false; | ||
| 421 | return NULL; | ||
| 422 | } | ||
| 423 | return ttm_kmap_obj_virtual(kmap, is_iomem); | ||
| 424 | } | ||
| 425 | EXPORT_SYMBOL(drm_gem_vram_kmap_at); | ||
| 426 | |||
| 427 | /** | ||
| 428 | * drm_gem_vram_kmap() - Maps a GEM VRAM object into kernel address space | ||
| 429 | * @gbo: the GEM VRAM object | ||
| 430 | * @map: establish a mapping if necessary | ||
| 431 | * @is_iomem: returns true if the mapped memory is I/O memory, or false \ | ||
| 432 | otherwise; can be NULL | ||
| 433 | * | ||
| 434 | * This function maps the buffer object into the kernel's address space | ||
| 435 | * or returns the current mapping. If the parameter map is false, the | ||
| 436 | * function only queries the current mapping, but does not establish a | ||
| 437 | * new one. | ||
| 438 | * | ||
| 439 | * Returns: | ||
| 440 | * The buffers virtual address if mapped, or | ||
| 441 | * NULL if not mapped, or | ||
| 442 | * an ERR_PTR()-encoded error code otherwise. | ||
| 443 | */ | ||
| 444 | void *drm_gem_vram_kmap(struct drm_gem_vram_object *gbo, bool map, | ||
| 445 | bool *is_iomem) | ||
| 446 | { | ||
| 447 | return drm_gem_vram_kmap_at(gbo, map, is_iomem, &gbo->kmap); | ||
| 448 | } | ||
| 449 | EXPORT_SYMBOL(drm_gem_vram_kmap); | ||
| 450 | |||
| 451 | /** | ||
| 452 | * drm_gem_vram_kunmap_at() - Unmaps a GEM VRAM object | ||
| 453 | * @gbo: the GEM VRAM object | ||
| 454 | * @kmap: the mapping's kmap object | ||
| 455 | */ | ||
| 456 | void drm_gem_vram_kunmap_at(struct drm_gem_vram_object *gbo, | ||
| 457 | struct ttm_bo_kmap_obj *kmap) | ||
| 458 | { | ||
| 459 | if (!kmap->virtual) | ||
| 460 | return; | ||
| 461 | |||
| 462 | ttm_bo_kunmap(kmap); | ||
| 463 | kmap->virtual = NULL; | ||
| 464 | } | ||
| 465 | EXPORT_SYMBOL(drm_gem_vram_kunmap_at); | ||
| 466 | |||
| 467 | /** | ||
| 468 | * drm_gem_vram_kunmap() - Unmaps a GEM VRAM object | ||
| 469 | * @gbo: the GEM VRAM object | ||
| 470 | */ | ||
| 471 | void drm_gem_vram_kunmap(struct drm_gem_vram_object *gbo) | ||
| 472 | { | ||
| 473 | drm_gem_vram_kunmap_at(gbo, &gbo->kmap); | ||
| 474 | } | ||
| 475 | EXPORT_SYMBOL(drm_gem_vram_kunmap); | ||
| 476 | |||
| 477 | /** | ||
| 478 | * drm_gem_vram_fill_create_dumb() - \ | ||
| 479 | Helper for implementing &struct drm_driver.dumb_create | ||
| 480 | * @file: the DRM file | ||
| 481 | * @dev: the DRM device | ||
| 482 | * @bdev: the TTM BO device managing the buffer object | ||
| 483 | * @pg_align: the buffer's alignment in multiples of the page size | ||
| 484 | * @interruptible: sleep interruptible if waiting for memory | ||
| 485 | * @args: the arguments as provided to \ | ||
| 486 | &struct drm_driver.dumb_create | ||
| 487 | * | ||
| 488 | * This helper function fills &struct drm_mode_create_dumb, which is used | ||
| 489 | * by &struct drm_driver.dumb_create. Implementations of this interface | ||
| 490 | * should forwards their arguments to this helper, plus the driver-specific | ||
| 491 | * parameters. | ||
| 492 | * | ||
| 493 | * Returns: | ||
| 494 | * 0 on success, or | ||
| 495 | * a negative error code otherwise. | ||
| 496 | */ | ||
| 497 | int drm_gem_vram_fill_create_dumb(struct drm_file *file, | ||
| 498 | struct drm_device *dev, | ||
| 499 | struct ttm_bo_device *bdev, | ||
| 500 | unsigned long pg_align, | ||
| 501 | bool interruptible, | ||
| 502 | struct drm_mode_create_dumb *args) | ||
| 503 | { | ||
| 504 | size_t pitch, size; | ||
| 505 | struct drm_gem_vram_object *gbo; | ||
| 506 | int ret; | ||
| 507 | u32 handle; | ||
| 508 | |||
| 509 | pitch = args->width * ((args->bpp + 7) / 8); | ||
| 510 | size = pitch * args->height; | ||
| 511 | |||
| 512 | size = roundup(size, PAGE_SIZE); | ||
| 513 | if (!size) | ||
| 514 | return -EINVAL; | ||
| 515 | |||
| 516 | gbo = drm_gem_vram_create(dev, bdev, size, pg_align, interruptible); | ||
| 517 | if (IS_ERR(gbo)) | ||
| 518 | return PTR_ERR(gbo); | ||
| 519 | |||
| 520 | ret = drm_gem_handle_create(file, &gbo->gem, &handle); | ||
| 521 | if (ret) | ||
| 522 | goto err_drm_gem_object_put_unlocked; | ||
| 523 | |||
| 524 | drm_gem_object_put_unlocked(&gbo->gem); | ||
| 525 | |||
| 526 | args->pitch = pitch; | ||
| 527 | args->size = size; | ||
| 528 | args->handle = handle; | ||
| 529 | |||
| 530 | return 0; | ||
| 531 | |||
| 532 | err_drm_gem_object_put_unlocked: | ||
| 533 | drm_gem_object_put_unlocked(&gbo->gem); | ||
| 534 | return ret; | ||
| 535 | } | ||
| 536 | EXPORT_SYMBOL(drm_gem_vram_fill_create_dumb); | ||
| 537 | |||
| 538 | /* | ||
| 539 | * Helpers for struct ttm_bo_driver | ||
| 540 | */ | ||
| 541 | |||
| 542 | static bool drm_is_gem_vram(struct ttm_buffer_object *bo) | ||
| 543 | { | ||
| 544 | return (bo->destroy == ttm_buffer_object_destroy); | ||
| 545 | } | ||
| 546 | |||
| 547 | /** | ||
| 548 | * drm_gem_vram_bo_driver_evict_flags() - \ | ||
| 549 | Implements &struct ttm_bo_driver.evict_flags | ||
| 550 | * @bo: TTM buffer object. Refers to &struct drm_gem_vram_object.bo | ||
| 551 | * @pl: TTM placement information. | ||
| 552 | */ | ||
| 553 | void drm_gem_vram_bo_driver_evict_flags(struct ttm_buffer_object *bo, | ||
| 554 | struct ttm_placement *pl) | ||
| 555 | { | ||
| 556 | struct drm_gem_vram_object *gbo; | ||
| 557 | |||
| 558 | /* TTM may pass BOs that are not GEM VRAM BOs. */ | ||
| 559 | if (!drm_is_gem_vram(bo)) | ||
| 560 | return; | ||
| 561 | |||
| 562 | gbo = drm_gem_vram_of_bo(bo); | ||
| 563 | drm_gem_vram_placement(gbo, TTM_PL_FLAG_SYSTEM); | ||
| 564 | *pl = gbo->placement; | ||
| 565 | } | ||
| 566 | EXPORT_SYMBOL(drm_gem_vram_bo_driver_evict_flags); | ||
| 567 | |||
| 568 | /** | ||
| 569 | * drm_gem_vram_bo_driver_verify_access() - \ | ||
| 570 | Implements &struct ttm_bo_driver.verify_access | ||
| 571 | * @bo: TTM buffer object. Refers to &struct drm_gem_vram_object.bo | ||
| 572 | * @filp: File pointer. | ||
| 573 | * | ||
| 574 | * Returns: | ||
| 575 | * 0 on success, or | ||
| 576 | * a negative errno code otherwise. | ||
| 577 | */ | ||
| 578 | int drm_gem_vram_bo_driver_verify_access(struct ttm_buffer_object *bo, | ||
| 579 | struct file *filp) | ||
| 580 | { | ||
| 581 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_bo(bo); | ||
| 582 | |||
| 583 | return drm_vma_node_verify_access(&gbo->gem.vma_node, | ||
| 584 | filp->private_data); | ||
| 585 | } | ||
| 586 | EXPORT_SYMBOL(drm_gem_vram_bo_driver_verify_access); | ||
| 587 | |||
| 588 | /** | ||
| 589 | * drm_gem_vram_mm_funcs - Functions for &struct drm_vram_mm | ||
| 590 | * | ||
| 591 | * Most users of @struct drm_gem_vram_object will also use | ||
| 592 | * @struct drm_vram_mm. This instance of &struct drm_vram_mm_funcs | ||
| 593 | * can be used to connect both. | ||
| 594 | */ | ||
| 595 | const struct drm_vram_mm_funcs drm_gem_vram_mm_funcs = { | ||
| 596 | .evict_flags = drm_gem_vram_bo_driver_evict_flags, | ||
| 597 | .verify_access = drm_gem_vram_bo_driver_verify_access | ||
| 598 | }; | ||
| 599 | EXPORT_SYMBOL(drm_gem_vram_mm_funcs); | ||
| 600 | |||
| 601 | /* | ||
| 602 | * Helpers for struct drm_driver | ||
| 603 | */ | ||
| 604 | |||
| 605 | /** | ||
| 606 | * drm_gem_vram_driver_gem_free_object_unlocked() - \ | ||
| 607 | Implements &struct drm_driver.gem_free_object_unlocked | ||
| 608 | * @gem: GEM object. Refers to &struct drm_gem_vram_object.gem | ||
| 609 | */ | ||
| 610 | void drm_gem_vram_driver_gem_free_object_unlocked(struct drm_gem_object *gem) | ||
| 611 | { | ||
| 612 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | ||
| 613 | |||
| 614 | drm_gem_vram_put(gbo); | ||
| 615 | } | ||
| 616 | EXPORT_SYMBOL(drm_gem_vram_driver_gem_free_object_unlocked); | ||
| 617 | |||
| 618 | /** | ||
| 619 | * drm_gem_vram_driver_create_dumb() - \ | ||
| 620 | Implements &struct drm_driver.dumb_create | ||
| 621 | * @file: the DRM file | ||
| 622 | * @dev: the DRM device | ||
| 623 | * @args: the arguments as provided to \ | ||
| 624 | &struct drm_driver.dumb_create | ||
| 625 | * | ||
| 626 | * This function requires the driver to use @drm_device.vram_mm for its | ||
| 627 | * instance of VRAM MM. | ||
| 628 | * | ||
| 629 | * Returns: | ||
| 630 | * 0 on success, or | ||
| 631 | * a negative error code otherwise. | ||
| 632 | */ | ||
| 633 | int drm_gem_vram_driver_dumb_create(struct drm_file *file, | ||
| 634 | struct drm_device *dev, | ||
| 635 | struct drm_mode_create_dumb *args) | ||
| 636 | { | ||
| 637 | if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) | ||
| 638 | return -EINVAL; | ||
| 639 | |||
| 640 | return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, 0, | ||
| 641 | false, args); | ||
| 642 | } | ||
| 643 | EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); | ||
| 644 | |||
| 645 | /** | ||
| 646 | * drm_gem_vram_driver_dumb_mmap_offset() - \ | ||
| 647 | Implements &struct drm_driver.dumb_mmap_offset | ||
| 648 | * @file: DRM file pointer. | ||
| 649 | * @dev: DRM device. | ||
| 650 | * @handle: GEM handle | ||
| 651 | * @offset: Returns the mapping's memory offset on success | ||
| 652 | * | ||
| 653 | * Returns: | ||
| 654 | * 0 on success, or | ||
| 655 | * a negative errno code otherwise. | ||
| 656 | */ | ||
| 657 | int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, | ||
| 658 | struct drm_device *dev, | ||
| 659 | uint32_t handle, uint64_t *offset) | ||
| 660 | { | ||
| 661 | struct drm_gem_object *gem; | ||
| 662 | struct drm_gem_vram_object *gbo; | ||
| 663 | |||
| 664 | gem = drm_gem_object_lookup(file, handle); | ||
| 665 | if (!gem) | ||
| 666 | return -ENOENT; | ||
| 667 | |||
| 668 | gbo = drm_gem_vram_of_gem(gem); | ||
| 669 | *offset = drm_gem_vram_mmap_offset(gbo); | ||
| 670 | |||
| 671 | drm_gem_object_put_unlocked(gem); | ||
| 672 | |||
| 673 | return 0; | ||
| 674 | } | ||
| 675 | EXPORT_SYMBOL(drm_gem_vram_driver_dumb_mmap_offset); | ||
| 676 | |||
| 677 | /* | ||
| 678 | * PRIME helpers for struct drm_driver | ||
| 679 | */ | ||
| 680 | |||
| 681 | /** | ||
| 682 | * drm_gem_vram_driver_gem_prime_pin() - \ | ||
| 683 | Implements &struct drm_driver.gem_prime_pin | ||
| 684 | * @gem: The GEM object to pin | ||
| 685 | * | ||
| 686 | * Returns: | ||
| 687 | * 0 on success, or | ||
| 688 | * a negative errno code otherwise. | ||
| 689 | */ | ||
| 690 | int drm_gem_vram_driver_gem_prime_pin(struct drm_gem_object *gem) | ||
| 691 | { | ||
| 692 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | ||
| 693 | |||
| 694 | return drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); | ||
| 695 | } | ||
| 696 | EXPORT_SYMBOL(drm_gem_vram_driver_gem_prime_pin); | ||
| 697 | |||
| 698 | /** | ||
| 699 | * drm_gem_vram_driver_gem_prime_unpin() - \ | ||
| 700 | Implements &struct drm_driver.gem_prime_unpin | ||
| 701 | * @gem: The GEM object to unpin | ||
| 702 | */ | ||
| 703 | void drm_gem_vram_driver_gem_prime_unpin(struct drm_gem_object *gem) | ||
| 704 | { | ||
| 705 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | ||
| 706 | |||
| 707 | drm_gem_vram_unpin(gbo); | ||
| 708 | } | ||
| 709 | EXPORT_SYMBOL(drm_gem_vram_driver_gem_prime_unpin); | ||
| 710 | |||
| 711 | /** | ||
| 712 | * drm_gem_vram_driver_gem_prime_vmap() - \ | ||
| 713 | Implements &struct drm_driver.gem_prime_vmap | ||
| 714 | * @gem: The GEM object to map | ||
| 715 | * | ||
| 716 | * Returns: | ||
| 717 | * The buffers virtual address on success, or | ||
| 718 | * NULL otherwise. | ||
| 719 | */ | ||
| 720 | void *drm_gem_vram_driver_gem_prime_vmap(struct drm_gem_object *gem) | ||
| 721 | { | ||
| 722 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | ||
| 723 | int ret; | ||
| 724 | void *base; | ||
| 725 | |||
| 726 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); | ||
| 727 | if (ret) | ||
| 728 | return NULL; | ||
| 729 | base = drm_gem_vram_kmap(gbo, true, NULL); | ||
| 730 | if (IS_ERR(base)) { | ||
| 731 | drm_gem_vram_unpin(gbo); | ||
| 732 | return NULL; | ||
| 733 | } | ||
| 734 | return base; | ||
| 735 | } | ||
| 736 | EXPORT_SYMBOL(drm_gem_vram_driver_gem_prime_vmap); | ||
| 737 | |||
| 738 | /** | ||
| 739 | * drm_gem_vram_driver_gem_prime_vunmap() - \ | ||
| 740 | Implements &struct drm_driver.gem_prime_vunmap | ||
| 741 | * @gem: The GEM object to unmap | ||
| 742 | * @vaddr: The mapping's base address | ||
| 743 | */ | ||
| 744 | void drm_gem_vram_driver_gem_prime_vunmap(struct drm_gem_object *gem, | ||
| 745 | void *vaddr) | ||
| 746 | { | ||
| 747 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | ||
| 748 | |||
| 749 | drm_gem_vram_kunmap(gbo); | ||
| 750 | drm_gem_vram_unpin(gbo); | ||
| 751 | } | ||
| 752 | EXPORT_SYMBOL(drm_gem_vram_driver_gem_prime_vunmap); | ||
| 753 | |||
| 754 | /** | ||
| 755 | * drm_gem_vram_driver_gem_prime_mmap() - \ | ||
| 756 | Implements &struct drm_driver.gem_prime_mmap | ||
| 757 | * @gem: The GEM object to map | ||
| 758 | * @vma: The VMA describing the mapping | ||
| 759 | * | ||
| 760 | * Returns: | ||
| 761 | * 0 on success, or | ||
| 762 | * a negative errno code otherwise. | ||
| 763 | */ | ||
| 764 | int drm_gem_vram_driver_gem_prime_mmap(struct drm_gem_object *gem, | ||
| 765 | struct vm_area_struct *vma) | ||
| 766 | { | ||
| 767 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | ||
| 768 | |||
| 769 | gbo->gem.vma_node.vm_node.start = gbo->bo.vma_node.vm_node.start; | ||
| 770 | return drm_gem_prime_mmap(gem, vma); | ||
| 771 | } | ||
| 772 | EXPORT_SYMBOL(drm_gem_vram_driver_gem_prime_mmap); | ||
| @@ -93,6 +93,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, · 92 unmodified lines | |||
| 93 | struct drm_file *file_priv); | 93 | struct drm_file *file_priv); |
| 94 | int drm_master_open(struct drm_file *file_priv); | 94 | int drm_master_open(struct drm_file *file_priv); |
| 95 | void drm_master_release(struct drm_file *file_priv); | 95 | void drm_master_release(struct drm_file *file_priv); |
| 96 | bool drm_master_internal_acquire(struct drm_device *dev); | ||
| 97 | void drm_master_internal_release(struct drm_device *dev); | ||
| 96 | 98 | ||
| 97 | /* drm_sysfs.c */ | 99 | /* drm_sysfs.c */ |
| 98 | extern struct class *drm_class; | 100 | extern struct class *drm_class; |
| @@ -187,10 +187,12 @@ int drm_legacy_sg_free(struct drm_device *dev, void *data, · 186 unmodified lines | |||
| 187 | void drm_legacy_init_members(struct drm_device *dev); | 187 | void drm_legacy_init_members(struct drm_device *dev); |
| 188 | void drm_legacy_destroy_members(struct drm_device *dev); | 188 | void drm_legacy_destroy_members(struct drm_device *dev); |
| 189 | void drm_legacy_dev_reinit(struct drm_device *dev); | 189 | void drm_legacy_dev_reinit(struct drm_device *dev); |
| 190 | int drm_legacy_setup(struct drm_device * dev); | ||
| 190 | #else | 191 | #else |
| 191 | static inline void drm_legacy_init_members(struct drm_device *dev) {} | 192 | static inline void drm_legacy_init_members(struct drm_device *dev) {} |
| 192 | static inline void drm_legacy_destroy_members(struct drm_device *dev) {} | 193 | static inline void drm_legacy_destroy_members(struct drm_device *dev) {} |
| 193 | static inline void drm_legacy_dev_reinit(struct drm_device *dev) {} | 194 | static inline void drm_legacy_dev_reinit(struct drm_device *dev) {} |
| 195 | static inline int drm_legacy_setup(struct drm_device * dev) { return 0; } | ||
| 194 | #endif | 196 | #endif |
| 195 | 197 | ||
| 196 | #if IS_ENABLED(CONFIG_DRM_LEGACY) | 198 | #if IS_ENABLED(CONFIG_DRM_LEGACY) |
| @@ -51,6 +51,26 @@ void drm_legacy_destroy_members(struct drm_device *dev) · 50 unmodified lines | |||
| 51 | mutex_destroy(&dev->ctxlist_mutex); | 51 | mutex_destroy(&dev->ctxlist_mutex); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | int drm_legacy_setup(struct drm_device * dev) | ||
| 55 | { | ||
| 56 | int ret; | ||
| 57 | |||
| 58 | if (dev->driver->firstopen && | ||
| 59 | drm_core_check_feature(dev, DRIVER_LEGACY)) { | ||
| 60 | ret = dev->driver->firstopen(dev); | ||
| 61 | if (ret != 0) | ||
| 62 | return ret; | ||
| 63 | } | ||
| 64 | |||
| 65 | ret = drm_legacy_dma_setup(dev); | ||
| 66 | if (ret < 0) | ||
| 67 | return ret; | ||
| 68 | |||
| 69 | |||
| 70 | DRM_DEBUG("\n"); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 54 | void drm_legacy_dev_reinit(struct drm_device *dev) | 74 | void drm_legacy_dev_reinit(struct drm_device *dev) |
| 55 | { | 75 | { |
| 56 | if (dev->irq_enabled) | 76 | if (dev->irq_enabled) |
| @@ -86,11 +86,6 @@ struct drm_prime_member { · 85 unmodified lines | |||
| 86 | struct rb_node handle_rb; | 86 | struct rb_node handle_rb; |
| 87 | }; | 87 | }; |
| 88 | 88 | ||
| 89 | struct drm_prime_attachment { | ||
| 90 | struct sg_table *sgt; | ||
| 91 | enum dma_data_direction dir; | ||
| 92 | }; | ||
| 93 | |||
| 94 | static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, | 89 | static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, |
| 95 | struct dma_buf *dma_buf, uint32_t handle) | 90 | struct dma_buf *dma_buf, uint32_t handle) |
| 96 | { | 91 | { |
| @@ -188,25 +183,16 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri · 91 unmodified lines | |||
| 188 | * @dma_buf: buffer to attach device to | 183 | * @dma_buf: buffer to attach device to |
| 189 | * @attach: buffer attachment data | 184 | * @attach: buffer attachment data |
| 190 | * | 185 | * |
| 191 | * Allocates &drm_prime_attachment and calls &drm_driver.gem_prime_pin for | 186 | * Calls &drm_driver.gem_prime_pin for device specific handling. This can be |
| 192 | * device specific attachment. This can be used as the &dma_buf_ops.attach | 187 | * used as the &dma_buf_ops.attach callback. |
| 193 | * callback. | ||
| 194 | * | 188 | * |
| 195 | * Returns 0 on success, negative error code on failure. | 189 | * Returns 0 on success, negative error code on failure. |
| 196 | */ | 190 | */ |
| 197 | int drm_gem_map_attach(struct dma_buf *dma_buf, | 191 | int drm_gem_map_attach(struct dma_buf *dma_buf, |
| 198 | struct dma_buf_attachment *attach) | 192 | struct dma_buf_attachment *attach) |
| 199 | { | 193 | { |
| 200 | struct drm_prime_attachment *prime_attach; | ||
| 201 | struct drm_gem_object *obj = dma_buf->priv; | 194 | struct drm_gem_object *obj = dma_buf->priv; |
| 202 | 195 | ||
| 203 | prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL); | ||
| 204 | if (!prime_attach) | ||
| 205 | return -ENOMEM; | ||
| 206 | |||
| 207 | prime_attach->dir = DMA_NONE; | ||
| 208 | attach->priv = prime_attach; | ||
| 209 | |||
| 210 | return drm_gem_pin(obj); | 196 | return drm_gem_pin(obj); |
| 211 | } | 197 | } |
| 212 | EXPORT_SYMBOL(drm_gem_map_attach); | 198 | EXPORT_SYMBOL(drm_gem_map_attach); |
| @@ -222,26 +208,8 @@ EXPORT_SYMBOL(drm_gem_map_attach); · 9 unmodified lines | |||
| 222 | void drm_gem_map_detach(struct dma_buf *dma_buf, | 208 | void drm_gem_map_detach(struct dma_buf *dma_buf, |
| 223 | struct dma_buf_attachment *attach) | 209 | struct dma_buf_attachment *attach) |
| 224 | { | 210 | { |
| 225 | struct drm_prime_attachment *prime_attach = attach->priv; | ||
| 226 | struct drm_gem_object *obj = dma_buf->priv; | 211 | struct drm_gem_object *obj = dma_buf->priv; |
| 227 | 212 | ||
| 228 | if (prime_attach) { | ||
| 229 | struct sg_table *sgt = prime_attach->sgt; | ||
| 230 | |||
| 231 | if (sgt) { | ||
| 232 | if (prime_attach->dir != DMA_NONE) | ||
| 233 | dma_unmap_sg_attrs(attach->dev, sgt->sgl, | ||
| 234 | sgt->nents, | ||
| 235 | prime_attach->dir, | ||
| 236 | DMA_ATTR_SKIP_CPU_SYNC); | ||
| 237 | sg_free_table(sgt); | ||
| 238 | } | ||
| 239 | |||
| 240 | kfree(sgt); | ||
| 241 | kfree(prime_attach); | ||
| 242 | attach->priv = NULL; | ||
| 243 | } | ||
| 244 | |||
| 245 | drm_gem_unpin(obj); | 213 | drm_gem_unpin(obj); |
| 246 | } | 214 | } |
| 247 | EXPORT_SYMBOL(drm_gem_map_detach); | 215 | EXPORT_SYMBOL(drm_gem_map_detach); |
| @@ -286,39 +254,22 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr · 38 unmodified lines | |||
| 286 | struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | 254 | struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, |
| 287 | enum dma_data_direction dir) | 255 | enum dma_data_direction dir) |
| 288 | { | 256 | { |
| 289 | struct drm_prime_attachment *prime_attach = attach->priv; | ||
| 290 | struct drm_gem_object *obj = attach->dmabuf->priv; | 257 | struct drm_gem_object *obj = attach->dmabuf->priv; |
| 291 | struct sg_table *sgt; | 258 | struct sg_table *sgt; |
| 292 | 259 | ||
| 293 | if (WARN_ON(dir == DMA_NONE || !prime_attach)) | 260 | if (WARN_ON(dir == DMA_NONE)) |
| 294 | return ERR_PTR(-EINVAL); | 261 | return ERR_PTR(-EINVAL); |
| 295 | 262 | ||
| 296 | /* return the cached mapping when possible */ | ||
| 297 | if (prime_attach->dir == dir) | ||
| 298 | return prime_attach->sgt; | ||
| 299 | |||
| 300 | /* | ||
| 301 | * two mappings with different directions for the same attachment are | ||
| 302 | * not allowed | ||
| 303 | */ | ||
| 304 | if (WARN_ON(prime_attach->dir != DMA_NONE)) | ||
| 305 | return ERR_PTR(-EBUSY); | ||
| 306 | |||
| 307 | if (obj->funcs) | 263 | if (obj->funcs) |
| 308 | sgt = obj->funcs->get_sg_table(obj); | 264 | sgt = obj->funcs->get_sg_table(obj); |
| 309 | else | 265 | else |
| 310 | sgt = obj->dev->driver->gem_prime_get_sg_table(obj); | 266 | sgt = obj->dev->driver->gem_prime_get_sg_table(obj); |
| 311 | 267 | ||
| 312 | if (!IS_ERR(sgt)) { | 268 | if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, |
| 313 | if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, | 269 | DMA_ATTR_SKIP_CPU_SYNC)) { |
| 314 | DMA_ATTR_SKIP_CPU_SYNC)) { | 270 | sg_free_table(sgt); |
| 315 | sg_free_table(sgt); | 271 | kfree(sgt); |
| 316 | kfree(sgt); | 272 | sgt = ERR_PTR(-ENOMEM); |
| 317 | sgt = ERR_PTR(-ENOMEM); | ||
| 318 | } else { | ||
| 319 | prime_attach->sgt = sgt; | ||
| 320 | prime_attach->dir = dir; | ||
| 321 | } | ||
| 322 | } | 273 | } |
| 323 | 274 | ||
| 324 | return sgt; | 275 | return sgt; |
| @@ -331,14 +282,19 @@ EXPORT_SYMBOL(drm_gem_map_dma_buf); · 6 unmodified lines | |||
| 331 | * @sgt: scatterlist info of the buffer to unmap | 282 | * @sgt: scatterlist info of the buffer to unmap |
| 332 | * @dir: direction of DMA transfer | 283 | * @dir: direction of DMA transfer |
| 333 | * | 284 | * |
| 334 | * Not implemented. The unmap is done at drm_gem_map_detach(). This can be | 285 | * This can be used as the &dma_buf_ops.unmap_dma_buf callback. |
| 335 | * used as the &dma_buf_ops.unmap_dma_buf callback. | ||
| 336 | */ | 286 | */ |
| 337 | void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, | 287 | void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, |
| 338 | struct sg_table *sgt, | 288 | struct sg_table *sgt, |
| 339 | enum dma_data_direction dir) | 289 | enum dma_data_direction dir) |
| 340 | { | 290 | { |
| 341 | /* nothing to be done here */ | 291 | if (!sgt) |
| 292 | return; | ||
| 293 | |||
| 294 | dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, | ||
| 295 | DMA_ATTR_SKIP_CPU_SYNC); | ||
| 296 | sg_free_table(sgt); | ||
| 297 | kfree(sgt); | ||
| 342 | } | 298 | } |
| 343 | EXPORT_SYMBOL(drm_gem_unmap_dma_buf); | 299 | EXPORT_SYMBOL(drm_gem_unmap_dma_buf); |
| 344 | 300 | ||
| @@ -452,6 +408,7 @@ int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) · 107 unmodified lines | |||
| 452 | EXPORT_SYMBOL(drm_gem_dmabuf_mmap); | 408 | EXPORT_SYMBOL(drm_gem_dmabuf_mmap); |
| 453 | 409 | ||
| 454 | static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { | 410 | static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { |
| 411 | .cache_sgt_mapping = true, | ||
| 455 | .attach = drm_gem_map_attach, | 412 | .attach = drm_gem_map_attach, |
| 456 | .detach = drm_gem_map_detach, | 413 | .detach = drm_gem_map_detach, |
| 457 | .map_dma_buf = drm_gem_map_dma_buf, | 414 | .map_dma_buf = drm_gem_map_dma_buf, |
| @@ -0,0 +1,96 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | |||
| 3 | #include <linux/module.h> | ||
| 4 | |||
| 5 | /** | ||
| 6 | * DOC: overview | ||
| 7 | * | ||
| 8 | * This library provides &struct drm_gem_vram_object (GEM VRAM), a GEM | ||
| 9 | * buffer object that is backed by video RAM. It can be used for | ||
| 10 | * framebuffer devices with dedicated memory. The video RAM can be | ||
| 11 | * managed with &struct drm_vram_mm (VRAM MM). Both data structures are | ||
| 12 | * supposed to be used together, but can also be used individually. | ||
| 13 | * | ||
| 14 | * With the GEM interface userspace applications create, manage and destroy | ||
| 15 | * graphics buffers, such as an on-screen framebuffer. GEM does not provide | ||
| 16 | * an implementation of these interfaces. It's up to the DRM driver to | ||
| 17 | * provide an implementation that suits the hardware. If the hardware device | ||
| 18 | * contains dedicated video memory, the DRM driver can use the VRAM helper | ||
| 19 | * library. Each active buffer object is stored in video RAM. Active | ||
| 20 | * buffer are used for drawing the current frame, typically something like | ||
| 21 | * the frame's scanout buffer or the cursor image. If there's no more space | ||
| 22 | * left in VRAM, inactive GEM objects can be moved to system memory. | ||
| 23 | * | ||
| 24 | * The easiest way to use the VRAM helper library is to call | ||
| 25 | * drm_vram_helper_alloc_mm(). The function allocates and initializes an | ||
| 26 | * instance of &struct drm_vram_mm in &struct drm_device.vram_mm . Use | ||
| 27 | * &DRM_GEM_VRAM_DRIVER to initialize &struct drm_driver and | ||
| 28 | * &DRM_VRAM_MM_FILE_OPERATIONS to initialize &struct file_operations; | ||
| 29 | * as illustrated below. | ||
| 30 | * | ||
| 31 | * .. code-block:: c | ||
| 32 | * | ||
| 33 | * struct file_operations fops ={ | ||
| 34 | * .owner = THIS_MODULE, | ||
| 35 | * DRM_VRAM_MM_FILE_OPERATION | ||
| 36 | * }; | ||
| 37 | * struct drm_driver drv = { | ||
| 38 | * .driver_feature = DRM_ ... , | ||
| 39 | * .fops = &fops, | ||
| 40 | * DRM_GEM_VRAM_DRIVER | ||
| 41 | * }; | ||
| 42 | * | ||
| 43 | * int init_drm_driver() | ||
| 44 | * { | ||
| 45 | * struct drm_device *dev; | ||
| 46 | * uint64_t vram_base; | ||
| 47 | * unsigned long vram_size; | ||
| 48 | * int ret; | ||
| 49 | * | ||
| 50 | * // setup device, vram base and size | ||
| 51 | * // ... | ||
| 52 | * | ||
| 53 | * ret = drm_vram_helper_alloc_mm(dev, vram_base, vram_size, | ||
| 54 | * &drm_gem_vram_mm_funcs); | ||
| 55 | * if (ret) | ||
| 56 | * return ret; | ||
| 57 | * return 0; | ||
| 58 | * } | ||
| 59 | * | ||
| 60 | * This creates an instance of &struct drm_vram_mm, exports DRM userspace | ||
| 61 | * interfaces for GEM buffer management and initializes file operations to | ||
| 62 | * allow for accessing created GEM buffers. With this setup, the DRM driver | ||
| 63 | * manages an area of video RAM with VRAM MM and provides GEM VRAM objects | ||
| 64 | * to userspace. | ||
| 65 | * | ||
| 66 | * To clean up the VRAM memory management, call drm_vram_helper_release_mm() | ||
| 67 | * in the driver's clean-up code. | ||
| 68 | * | ||
| 69 | * .. code-block:: c | ||
| 70 | * | ||
| 71 | * void fini_drm_driver() | ||
| 72 | * { | ||
| 73 | * struct drm_device *dev = ...; | ||
| 74 | * | ||
| 75 | * drm_vram_helper_release_mm(dev); | ||
| 76 | * } | ||
| 77 | * | ||
| 78 | * For drawing or scanout operations, buffer object have to be pinned in video | ||
| 79 | * RAM. Call drm_gem_vram_pin() with &DRM_GEM_VRAM_PL_FLAG_VRAM or | ||
| 80 | * &DRM_GEM_VRAM_PL_FLAG_SYSTEM to pin a buffer object in video RAM or system | ||
| 81 | * memory. Call drm_gem_vram_unpin() to release the pinned object afterwards. | ||
| 82 | * | ||
| 83 | * A buffer object that is pinned in video RAM has a fixed address within that | ||
| 84 | * memory region. Call drm_gem_vram_offset() to retrieve this value. Typically | ||
| 85 | * it's used to program the hardware's scanout engine for framebuffers, set | ||
| 86 | * the cursor overlay's image for a mouse cursor, or use it as input to the | ||
| 87 | * hardware's draing engine. | ||
| 88 | * | ||
| 89 | * To access a buffer object's memory from the DRM driver, call | ||
| 90 | * drm_gem_vram_kmap(). It (optionally) maps the buffer into kernel address | ||
| 91 | * space and returns the memory address. Use drm_gem_vram_kunmap() to | ||
| 92 | * release the mapping. | ||
| 93 | */ | ||
| 94 | |||
| 95 | MODULE_DESCRIPTION("DRM VRAM memory-management helpers"); | ||
| 96 | MODULE_LICENSE("GPL"); | ||
| @@ -0,0 +1,295 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | |||
| 3 | #include <drm/drm_vram_mm_helper.h> | ||
| 4 | #include <drm/drmP.h> | ||
| 5 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 6 | |||
| 7 | /** | ||
| 8 | * DOC: overview | ||
| 9 | * | ||
| 10 | * The data structure &struct drm_vram_mm and its helpers implement a memory | ||
| 11 | * manager for simple framebuffer devices with dedicated video memory. Buffer | ||
| 12 | * objects are either placed in video RAM or evicted to system memory. These | ||
| 13 | * helper functions work well with &struct drm_gem_vram_object. | ||
| 14 | */ | ||
| 15 | |||
| 16 | /* | ||
| 17 | * TTM TT | ||
| 18 | */ | ||
| 19 | |||
| 20 | static void backend_func_destroy(struct ttm_tt *tt) | ||
| 21 | { | ||
| 22 | ttm_tt_fini(tt); | ||
| 23 | kfree(tt); | ||
| 24 | } | ||
| 25 | |||
| 26 | static struct ttm_backend_func backend_func = { | ||
| 27 | .destroy = backend_func_destroy | ||
| 28 | }; | ||
| 29 | |||
| 30 | /* | ||
| 31 | * TTM BO device | ||
| 32 | */ | ||
| 33 | |||
| 34 | static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 35 | uint32_t page_flags) | ||
| 36 | { | ||
| 37 | struct ttm_tt *tt; | ||
| 38 | int ret; | ||
| 39 | |||
| 40 | tt = kzalloc(sizeof(*tt), GFP_KERNEL); | ||
| 41 | if (!tt) | ||
| 42 | return NULL; | ||
| 43 | |||
| 44 | tt->func = &backend_func; | ||
| 45 | |||
| 46 | ret = ttm_tt_init(tt, bo, page_flags); | ||
| 47 | if (ret < 0) | ||
| 48 | goto err_ttm_tt_init; | ||
| 49 | |||
| 50 | return tt; | ||
| 51 | |||
| 52 | err_ttm_tt_init: | ||
| 53 | kfree(tt); | ||
| 54 | return NULL; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
| 58 | struct ttm_mem_type_manager *man) | ||
| 59 | { | ||
| 60 | switch (type) { | ||
| 61 | case TTM_PL_SYSTEM: | ||
| 62 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 63 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 64 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 65 | break; | ||
| 66 | case TTM_PL_VRAM: | ||
| 67 | man->func = &ttm_bo_manager_func; | ||
| 68 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
| 69 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 70 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
| 71 | TTM_PL_FLAG_WC; | ||
| 72 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | return -EINVAL; | ||
| 76 | } | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static void bo_driver_evict_flags(struct ttm_buffer_object *bo, | ||
| 81 | struct ttm_placement *placement) | ||
| 82 | { | ||
| 83 | struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bo->bdev); | ||
| 84 | |||
| 85 | if (vmm->funcs && vmm->funcs->evict_flags) | ||
| 86 | vmm->funcs->evict_flags(bo, placement); | ||
| 87 | } | ||
| 88 | |||
| 89 | static int bo_driver_verify_access(struct ttm_buffer_object *bo, | ||
| 90 | struct file *filp) | ||
| 91 | { | ||
| 92 | struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bo->bdev); | ||
| 93 | |||
| 94 | if (!vmm->funcs || !vmm->funcs->verify_access) | ||
| 95 | return 0; | ||
| 96 | return vmm->funcs->verify_access(bo, filp); | ||
| 97 | } | ||
| 98 | |||
| 99 | static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 100 | struct ttm_mem_reg *mem) | ||
| 101 | { | ||
| 102 | struct ttm_mem_type_manager *man = bdev->man + mem->mem_type; | ||
| 103 | struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev); | ||
| 104 | |||
| 105 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 106 | return -EINVAL; | ||
| 107 | |||
| 108 | mem->bus.addr = NULL; | ||
| 109 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 110 | |||
| 111 | switch (mem->mem_type) { | ||
| 112 | case TTM_PL_SYSTEM: /* nothing to do */ | ||
| 113 | mem->bus.offset = 0; | ||
| 114 | mem->bus.base = 0; | ||
| 115 | mem->bus.is_iomem = false; | ||
| 116 | break; | ||
| 117 | case TTM_PL_VRAM: | ||
| 118 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 119 | mem->bus.base = vmm->vram_base; | ||
| 120 | mem->bus.is_iomem = true; | ||
| 121 | break; | ||
| 122 | default: | ||
| 123 | return -EINVAL; | ||
| 124 | } | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static void bo_driver_io_mem_free(struct ttm_bo_device *bdev, | ||
| 130 | struct ttm_mem_reg *mem) | ||
| 131 | { } | ||
| 132 | |||
| 133 | static struct ttm_bo_driver bo_driver = { | ||
| 134 | .ttm_tt_create = bo_driver_ttm_tt_create, | ||
| 135 | .ttm_tt_populate = ttm_pool_populate, | ||
| 136 | .ttm_tt_unpopulate = ttm_pool_unpopulate, | ||
| 137 | .init_mem_type = bo_driver_init_mem_type, | ||
| 138 | .eviction_valuable = ttm_bo_eviction_valuable, | ||
| 139 | .evict_flags = bo_driver_evict_flags, | ||
| 140 | .verify_access = bo_driver_verify_access, | ||
| 141 | .io_mem_reserve = bo_driver_io_mem_reserve, | ||
| 142 | .io_mem_free = bo_driver_io_mem_free, | ||
| 143 | }; | ||
| 144 | |||
| 145 | /* | ||
| 146 | * struct drm_vram_mm | ||
| 147 | */ | ||
| 148 | |||
| 149 | /** | ||
| 150 | * drm_vram_mm_init() - Initialize an instance of VRAM MM. | ||
| 151 | * @vmm: the VRAM MM instance to initialize | ||
| 152 | * @dev: the DRM device | ||
| 153 | * @vram_base: the base address of the video memory | ||
| 154 | * @vram_size: the size of the video memory in bytes | ||
| 155 | * @funcs: callback functions for buffer objects | ||
| 156 | * | ||
| 157 | * Returns: | ||
| 158 | * 0 on success, or | ||
| 159 | * a negative error code otherwise. | ||
| 160 | */ | ||
| 161 | int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, | ||
| 162 | uint64_t vram_base, size_t vram_size, | ||
| 163 | const struct drm_vram_mm_funcs *funcs) | ||
| 164 | { | ||
| 165 | int ret; | ||
| 166 | |||
| 167 | vmm->vram_base = vram_base; | ||
| 168 | vmm->vram_size = vram_size; | ||
| 169 | vmm->funcs = funcs; | ||
| 170 | |||
| 171 | ret = ttm_bo_device_init(&vmm->bdev, &bo_driver, | ||
| 172 | dev->anon_inode->i_mapping, | ||
| 173 | true); | ||
| 174 | if (ret) | ||
| 175 | return ret; | ||
| 176 | |||
| 177 | ret = ttm_bo_init_mm(&vmm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT); | ||
| 178 | if (ret) | ||
| 179 | return ret; | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | EXPORT_SYMBOL(drm_vram_mm_init); | ||
| 184 | |||
| 185 | /** | ||
| 186 | * drm_vram_mm_cleanup() - Cleans up an initialized instance of VRAM MM. | ||
| 187 | * @vmm: the VRAM MM instance to clean up | ||
| 188 | */ | ||
| 189 | void drm_vram_mm_cleanup(struct drm_vram_mm *vmm) | ||
| 190 | { | ||
| 191 | ttm_bo_device_release(&vmm->bdev); | ||
| 192 | } | ||
| 193 | EXPORT_SYMBOL(drm_vram_mm_cleanup); | ||
| 194 | |||
| 195 | /** | ||
| 196 | * drm_vram_mm_mmap() - Helper for implementing &struct file_operations.mmap() | ||
| 197 | * @filp: the mapping's file structure | ||
| 198 | * @vma: the mapping's memory area | ||
| 199 | * @vmm: the VRAM MM instance | ||
| 200 | * | ||
| 201 | * Returns: | ||
| 202 | * 0 on success, or | ||
| 203 | * a negative error code otherwise. | ||
| 204 | */ | ||
| 205 | int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma, | ||
| 206 | struct drm_vram_mm *vmm) | ||
| 207 | { | ||
| 208 | return ttm_bo_mmap(filp, vma, &vmm->bdev); | ||
| 209 | } | ||
| 210 | EXPORT_SYMBOL(drm_vram_mm_mmap); | ||
| 211 | |||
| 212 | /* | ||
| 213 | * Helpers for integration with struct drm_device | ||
| 214 | */ | ||
| 215 | |||
| 216 | /** | ||
| 217 | * drm_vram_helper_alloc_mm - Allocates a device's instance of \ | ||
| 218 | &struct drm_vram_mm | ||
| 219 | * @dev: the DRM device | ||
| 220 | * @vram_base: the base address of the video memory | ||
| 221 | * @vram_size: the size of the video memory in bytes | ||
| 222 | * @funcs: callback functions for buffer objects | ||
| 223 | * | ||
| 224 | * Returns: | ||
| 225 | * The new instance of &struct drm_vram_mm on success, or | ||
| 226 | * an ERR_PTR()-encoded errno code otherwise. | ||
| 227 | */ | ||
| 228 | struct drm_vram_mm *drm_vram_helper_alloc_mm( | ||
| 229 | struct drm_device *dev, uint64_t vram_base, size_t vram_size, | ||
| 230 | const struct drm_vram_mm_funcs *funcs) | ||
| 231 | { | ||
| 232 | int ret; | ||
| 233 | |||
| 234 | if (WARN_ON(dev->vram_mm)) | ||
| 235 | return dev->vram_mm; | ||
| 236 | |||
| 237 | dev->vram_mm = kzalloc(sizeof(*dev->vram_mm), GFP_KERNEL); | ||
| 238 | if (!dev->vram_mm) | ||
| 239 | return ERR_PTR(-ENOMEM); | ||
| 240 | |||
| 241 | ret = drm_vram_mm_init(dev->vram_mm, dev, vram_base, vram_size, funcs); | ||
| 242 | if (ret) | ||
| 243 | goto err_kfree; | ||
| 244 | |||
| 245 | return dev->vram_mm; | ||
| 246 | |||
| 247 | err_kfree: | ||
| 248 | kfree(dev->vram_mm); | ||
| 249 | dev->vram_mm = NULL; | ||
| 250 | return ERR_PTR(ret); | ||
| 251 | } | ||
| 252 | EXPORT_SYMBOL(drm_vram_helper_alloc_mm); | ||
| 253 | |||
| 254 | /** | ||
| 255 | * drm_vram_helper_release_mm - Releases a device's instance of \ | ||
| 256 | &struct drm_vram_mm | ||
| 257 | * @dev: the DRM device | ||
| 258 | */ | ||
| 259 | void drm_vram_helper_release_mm(struct drm_device *dev) | ||
| 260 | { | ||
| 261 | if (!dev->vram_mm) | ||
| 262 | return; | ||
| 263 | |||
| 264 | drm_vram_mm_cleanup(dev->vram_mm); | ||
| 265 | kfree(dev->vram_mm); | ||
| 266 | dev->vram_mm = NULL; | ||
| 267 | } | ||
| 268 | EXPORT_SYMBOL(drm_vram_helper_release_mm); | ||
| 269 | |||
| 270 | /* | ||
| 271 | * Helpers for &struct file_operations | ||
| 272 | */ | ||
| 273 | |||
| 274 | /** | ||
| 275 | * drm_vram_mm_file_operations_mmap() - \ | ||
| 276 | Implements &struct file_operations.mmap() | ||
| 277 | * @filp: the mapping's file structure | ||
| 278 | * @vma: the mapping's memory area | ||
| 279 | * | ||
| 280 | * Returns: | ||
| 281 | * 0 on success, or | ||
| 282 | * a negative error code otherwise. | ||
| 283 | */ | ||
| 284 | int drm_vram_mm_file_operations_mmap( | ||
| 285 | struct file *filp, struct vm_area_struct *vma) | ||
| 286 | { | ||
| 287 | struct drm_file *file_priv = filp->private_data; | ||
| 288 | struct drm_device *dev = file_priv->minor->dev; | ||
| 289 | |||
| 290 | if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) | ||
| 291 | return -EINVAL; | ||
| 292 | |||
| 293 | return drm_vram_mm_mmap(filp, vma, dev->vram_mm); | ||
| 294 | } | ||
| 295 | EXPORT_SYMBOL(drm_vram_mm_file_operations_mmap); | ||
| @@ -118,7 +118,6 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) · 117 unmodified lines | |||
| 118 | unsigned int n_obj, n_bomap_pages; | 118 | unsigned int n_obj, n_bomap_pages; |
| 119 | size_t file_size, mmu_size; | 119 | size_t file_size, mmu_size; |
| 120 | __le64 *bomap, *bomap_start; | 120 | __le64 *bomap, *bomap_start; |
| 121 | unsigned long flags; | ||
| 122 | 121 | ||
| 123 | /* Only catch the first event, or when manually re-armed */ | 122 | /* Only catch the first event, or when manually re-armed */ |
| 124 | if (!etnaviv_dump_core) | 123 | if (!etnaviv_dump_core) |
| @@ -135,13 +134,11 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) · 10 unmodified lines | |||
| 135 | mmu_size + gpu->buffer.size; | 134 | mmu_size + gpu->buffer.size; |
| 136 | 135 | ||
| 137 | /* Add in the active command buffers */ | 136 | /* Add in the active command buffers */ |
| 138 | spin_lock_irqsave(&gpu->sched.job_list_lock, flags); | ||
| 139 | list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { | 137 | list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { |
| 140 | submit = to_etnaviv_submit(s_job); | 138 | submit = to_etnaviv_submit(s_job); |
| 141 | file_size += submit->cmdbuf.size; | 139 | file_size += submit->cmdbuf.size; |
| 142 | n_obj++; | 140 | n_obj++; |
| 143 | } | 141 | } |
| 144 | spin_unlock_irqrestore(&gpu->sched.job_list_lock, flags); | ||
| 145 | 142 | ||
| 146 | /* Add in the active buffer objects */ | 143 | /* Add in the active buffer objects */ |
| 147 | list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { | 144 | list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { |
| @@ -183,14 +180,12 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) · 35 unmodified lines | |||
| 183 | gpu->buffer.size, | 180 | gpu->buffer.size, |
| 184 | etnaviv_cmdbuf_get_va(&gpu->buffer)); | 181 | etnaviv_cmdbuf_get_va(&gpu->buffer)); |
| 185 | 182 | ||
| 186 | spin_lock_irqsave(&gpu->sched.job_list_lock, flags); | ||
| 187 | list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { | 183 | list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) { |
| 188 | submit = to_etnaviv_submit(s_job); | 184 | submit = to_etnaviv_submit(s_job); |
| 189 | etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, | 185 | etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, |
| 190 | submit->cmdbuf.vaddr, submit->cmdbuf.size, | 186 | submit->cmdbuf.vaddr, submit->cmdbuf.size, |
| 191 | etnaviv_cmdbuf_get_va(&submit->cmdbuf)); | 187 | etnaviv_cmdbuf_get_va(&submit->cmdbuf)); |
| 192 | } | 188 | } |
| 193 | spin_unlock_irqrestore(&gpu->sched.job_list_lock, flags); | ||
| 194 | 189 | ||
| 195 | /* Reserve space for the bomap */ | 190 | /* Reserve space for the bomap */ |
| 196 | if (n_bomap_pages) { | 191 | if (n_bomap_pages) { |
| @@ -109,7 +109,7 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job) · 108 unmodified lines | |||
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | /* block scheduler */ | 111 | /* block scheduler */ |
| 112 | drm_sched_stop(&gpu->sched); | 112 | drm_sched_stop(&gpu->sched, sched_job); |
| 113 | 113 | ||
| 114 | if(sched_job) | 114 | if(sched_job) |
| 115 | drm_sched_increase_karma(sched_job); | 115 | drm_sched_increase_karma(sched_job); |
| @@ -20,24 +20,24 @@ · 19 unmodified lines | |||
| 20 | * | 20 | * |
| 21 | **************************************************************************/ | 21 | **************************************************************************/ |
| 22 | 22 | ||
| 23 | #include <linux/module.h> | 23 | #include <linux/console.h> |
| 24 | #include <linux/kernel.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
| 26 | #include <linux/string.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/kernel.h> | ||
| 27 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
| 28 | #include <linux/tty.h> | 29 | #include <linux/module.h> |
| 29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 30 | #include <linux/delay.h> | 31 | #include <linux/string.h> |
| 31 | #include <linux/init.h> | 32 | #include <linux/tty.h> |
| 32 | #include <linux/console.h> | ||
| 33 | 33 | ||
| 34 | #include <drm/drmP.h> | ||
| 35 | #include <drm/drm.h> | 34 | #include <drm/drm.h> |
| 36 | #include <drm/drm_crtc.h> | 35 | #include <drm/drm_crtc.h> |
| 36 | #include <drm/drm_fourcc.h> | ||
| 37 | 37 | ||
| 38 | #include "framebuffer.h" | ||
| 38 | #include "psb_drv.h" | 39 | #include "psb_drv.h" |
| 39 | #include "psb_reg.h" | 40 | #include "psb_reg.h" |
| 40 | #include "framebuffer.h" | ||
| 41 | 41 | ||
| 42 | /** | 42 | /** |
| 43 | * psb_spank - reset the 2D engine | 43 | * psb_spank - reset the 2D engine |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | |||
| 17 | #ifndef __BLITTER_H | 17 | #ifndef __BLITTER_H |
| 18 | #define __BLITTER_H | 18 | #define __BLITTER_H |
| 19 | 19 | ||
| 20 | struct drm_psb_private; | ||
| 21 | |||
| 20 | extern int gma_blt_wait_idle(struct drm_psb_private *dev_priv); | 22 | extern int gma_blt_wait_idle(struct drm_psb_private *dev_priv); |
| 21 | 23 | ||
| 22 | #endif | 24 | #endif |
| @@ -18,15 +18,16 @@ · 17 unmodified lines | |||
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | #include <linux/backlight.h> | 20 | #include <linux/backlight.h> |
| 21 | #include <drm/drmP.h> | 21 | #include <linux/delay.h> |
| 22 | |||
| 22 | #include <drm/drm.h> | 23 | #include <drm/drm.h> |
| 23 | #include <drm/gma_drm.h> | 24 | |
| 24 | #include "psb_drv.h" | ||
| 25 | #include "psb_reg.h" | ||
| 26 | #include "psb_intel_reg.h" | ||
| 27 | #include "intel_bios.h" | ||
| 28 | #include "cdv_device.h" | 25 | #include "cdv_device.h" |
| 29 | #include "gma_device.h" | 26 | #include "gma_device.h" |
| 27 | #include "intel_bios.h" | ||
| 28 | #include "psb_drv.h" | ||
| 29 | #include "psb_intel_reg.h" | ||
| 30 | #include "psb_reg.h" | ||
| 30 | 31 | ||
| 31 | #define VGA_SR_INDEX 0x3c4 | 32 | #define VGA_SR_INDEX 0x3c4 |
| 32 | #define VGA_SR_DATA 0x3c5 | 33 | #define VGA_SR_DATA 0x3c5 |
| @@ -15,6 +15,10 @@ · 14 unmodified lines | |||
| 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | struct drm_crtc; | ||
| 19 | struct drm_device; | ||
| 20 | struct psb_intel_mode_device; | ||
| 21 | |||
| 18 | extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; | 22 | extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; |
| 19 | extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; | 23 | extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; |
| 20 | extern const struct gma_clock_funcs cdv_clock_funcs; | 24 | extern const struct gma_clock_funcs cdv_clock_funcs; |
| @@ -24,16 +24,16 @@ · 23 unmodified lines | |||
| 24 | * Eric Anholt <eric@anholt.net> | 24 | * Eric Anholt <eric@anholt.net> |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <linux/delay.h> | ||
| 27 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
| 28 | #include <drm/drmP.h> | 29 | #include <linux/pm_runtime.h> |
| 29 | 30 | ||
| 31 | #include "cdv_device.h" | ||
| 30 | #include "intel_bios.h" | 32 | #include "intel_bios.h" |
| 33 | #include "power.h" | ||
| 31 | #include "psb_drv.h" | 34 | #include "psb_drv.h" |
| 32 | #include "psb_intel_drv.h" | 35 | #include "psb_intel_drv.h" |
| 33 | #include "psb_intel_reg.h" | 36 | #include "psb_intel_reg.h" |
| 34 | #include "power.h" | ||
| 35 | #include "cdv_device.h" | ||
| 36 | #include <linux/pm_runtime.h> | ||
| 37 | 37 | ||
| 38 | 38 | ||
| 39 | static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) | 39 | static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) |
| @@ -18,16 +18,18 @@ · 17 unmodified lines | |||
| 18 | * Eric Anholt <eric@anholt.net> | 18 | * Eric Anholt <eric@anholt.net> |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/delay.h> | ||
| 21 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
| 22 | 23 | ||
| 23 | #include <drm/drmP.h> | 24 | #include <drm/drm_crtc.h> |
| 25 | |||
| 26 | #include "cdv_device.h" | ||
| 24 | #include "framebuffer.h" | 27 | #include "framebuffer.h" |
| 28 | #include "gma_display.h" | ||
| 29 | #include "power.h" | ||
| 25 | #include "psb_drv.h" | 30 | #include "psb_drv.h" |
| 26 | #include "psb_intel_drv.h" | 31 | #include "psb_intel_drv.h" |
| 27 | #include "psb_intel_reg.h" | 32 | #include "psb_intel_reg.h" |
| 28 | #include "gma_display.h" | ||
| 29 | #include "power.h" | ||
| 30 | #include "cdv_device.h" | ||
| 31 | 33 | ||
| 32 | static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, | 34 | static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, |
| 33 | struct drm_crtc *crtc, int target, | 35 | struct drm_crtc *crtc, int target, |
| @@ -26,16 +26,17 @@ · 25 unmodified lines | |||
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 31 | #include <drm/drmP.h> | 30 | #include <linux/slab.h> |
| 31 | |||
| 32 | #include <drm/drm_crtc.h> | 32 | #include <drm/drm_crtc.h> |
| 33 | #include <drm/drm_crtc_helper.h> | 33 | #include <drm/drm_crtc_helper.h> |
| 34 | #include <drm/drm_dp_helper.h> | ||
| 35 | |||
| 36 | #include "gma_display.h" | ||
| 34 | #include "psb_drv.h" | 37 | #include "psb_drv.h" |
| 35 | #include "psb_intel_drv.h" | 38 | #include "psb_intel_drv.h" |
| 36 | #include "psb_intel_reg.h" | 39 | #include "psb_intel_reg.h" |
| 37 | #include "gma_display.h" | ||
| 38 | #include <drm/drm_dp_helper.h> | ||
| 39 | 40 | ||
| 40 | /** | 41 | /** |
| 41 | * struct i2c_algo_dp_aux_data - driver interface structure for i2c over dp | 42 | * struct i2c_algo_dp_aux_data - driver interface structure for i2c over dp |
| @@ -27,15 +27,16 @@ · 26 unmodified lines | |||
| 27 | * We should probably make this generic and share it with Medfield | 27 | * We should probably make this generic and share it with Medfield |
| 28 | */ | 28 | */ |
| 29 | 29 | ||
| 30 | #include <drm/drmP.h> | 30 | #include <linux/pm_runtime.h> |
| 31 | |||
| 31 | #include <drm/drm.h> | 32 | #include <drm/drm.h> |
| 32 | #include <drm/drm_crtc.h> | 33 | #include <drm/drm_crtc.h> |
| 33 | #include <drm/drm_edid.h> | 34 | #include <drm/drm_edid.h> |
| 34 | #include "psb_intel_drv.h" | 35 | |
| 36 | #include "cdv_device.h" | ||
| 35 | #include "psb_drv.h" | 37 | #include "psb_drv.h" |
| 38 | #include "psb_intel_drv.h" | ||
| 36 | #include "psb_intel_reg.h" | 39 | #include "psb_intel_reg.h" |
| 37 | #include "cdv_device.h" | ||
| 38 | #include <linux/pm_runtime.h> | ||
| 39 | 40 | ||
| 40 | /* hdmi control bits */ | 41 | /* hdmi control bits */ |
| 41 | #define HDMI_NULL_PACKETS_DURING_VSYNC (1 << 9) | 42 | #define HDMI_NULL_PACKETS_DURING_VSYNC (1 << 9) |
| @@ -20,17 +20,16 @@ · 19 unmodified lines | |||
| 20 | * Jesse Barnes <jesse.barnes@intel.com> | 20 | * Jesse Barnes <jesse.barnes@intel.com> |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/i2c.h> | ||
| 24 | #include <linux/dmi.h> | 23 | #include <linux/dmi.h> |
| 25 | #include <drm/drmP.h> | 24 | #include <linux/i2c.h> |
| 25 | #include <linux/pm_runtime.h> | ||
| 26 | 26 | ||
| 27 | #include "cdv_device.h" | ||
| 27 | #include "intel_bios.h" | 28 | #include "intel_bios.h" |
| 29 | #include "power.h" | ||
| 28 | #include "psb_drv.h" | 30 | #include "psb_drv.h" |
| 29 | #include "psb_intel_drv.h" | 31 | #include "psb_intel_drv.h" |
| 30 | #include "psb_intel_reg.h" | 32 | #include "psb_intel_reg.h" |
| 31 | #include "power.h" | ||
| 32 | #include <linux/pm_runtime.h> | ||
| 33 | #include "cdv_device.h" | ||
| 34 | 33 | ||
| 35 | /** | 34 | /** |
| 36 | * LVDS I2C backlight control macros | 35 | * LVDS I2C backlight control macros |
| @@ -17,29 +17,29 @@ · 16 unmodified lines | |||
| 17 | * | 17 | * |
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | #include <linux/module.h> | 20 | #include <linux/console.h> |
| 21 | #include <linux/kernel.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
| 23 | #include <linux/string.h> | 23 | #include <linux/init.h> |
| 24 | #include <linux/pfn_t.h> | 24 | #include <linux/kernel.h> |
| 25 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
| 26 | #include <linux/tty.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/pfn_t.h> | ||
| 27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 28 | #include <linux/delay.h> | 29 | #include <linux/string.h> |
| 29 | #include <linux/init.h> | 30 | #include <linux/tty.h> |
| 30 | #include <linux/console.h> | ||
| 31 | 31 | ||
| 32 | #include <drm/drmP.h> | ||
| 33 | #include <drm/drm.h> | 32 | #include <drm/drm.h> |
| 34 | #include <drm/drm_crtc.h> | 33 | #include <drm/drm_crtc.h> |
| 35 | #include <drm/drm_fb_helper.h> | 34 | #include <drm/drm_fb_helper.h> |
| 35 | #include <drm/drm_fourcc.h> | ||
| 36 | #include <drm/drm_gem_framebuffer_helper.h> | 36 | #include <drm/drm_gem_framebuffer_helper.h> |
| 37 | 37 | ||
| 38 | #include "psb_drv.h" | ||
| 39 | #include "psb_intel_reg.h" | ||
| 40 | #include "psb_intel_drv.h" | ||
| 41 | #include "framebuffer.h" | 38 | #include "framebuffer.h" |
| 42 | #include "gtt.h" | 39 | #include "gtt.h" |
| 40 | #include "psb_drv.h" | ||
| 41 | #include "psb_intel_drv.h" | ||
| 42 | #include "psb_intel_reg.h" | ||
| 43 | 43 | ||
| 44 | static const struct drm_framebuffer_funcs psb_fb_funcs = { | 44 | static const struct drm_framebuffer_funcs psb_fb_funcs = { |
| 45 | .destroy = drm_gem_fb_destroy, | 45 | .destroy = drm_gem_fb_destroy, |
| @@ -232,7 +232,7 @@ static int psb_framebuffer_init(struct drm_device *dev, · 186 unmodified lines | |||
| 232 | * Reject unknown formats, YUV formats, and formats with more than | 232 | * Reject unknown formats, YUV formats, and formats with more than |
| 233 | * 4 bytes per pixel. | 233 | * 4 bytes per pixel. |
| 234 | */ | 234 | */ |
| 235 | info = drm_format_info(mode_cmd->pixel_format); | 235 | info = drm_get_format_info(dev, mode_cmd); |
| 236 | if (!info || !info->depth || info->cpp[0] > 4) | 236 | if (!info || !info->depth || info->cpp[0] > 4) |
| 237 | return -EINVAL; | 237 | return -EINVAL; |
| 238 | 238 | ||
| @@ -22,7 +22,6 @@ · 21 unmodified lines | |||
| 22 | #ifndef _FRAMEBUFFER_H_ | 22 | #ifndef _FRAMEBUFFER_H_ |
| 23 | #define _FRAMEBUFFER_H_ | 23 | #define _FRAMEBUFFER_H_ |
| 24 | 24 | ||
| 25 | #include <drm/drmP.h> | ||
| 26 | #include <drm/drm_fb_helper.h> | 25 | #include <drm/drm_fb_helper.h> |
| 27 | 26 | ||
| 28 | #include "psb_drv.h" | 27 | #include "psb_drv.h" |
| @@ -23,10 +23,11 @@ · 22 unmodified lines | |||
| 23 | * accelerated operations on a GEM object) | 23 | * accelerated operations on a GEM object) |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <drm/drmP.h> | 26 | #include <linux/pagemap.h> |
| 27 | |||
| 27 | #include <drm/drm.h> | 28 | #include <drm/drm.h> |
| 28 | #include <drm/gma_drm.h> | ||
| 29 | #include <drm/drm_vma_manager.h> | 29 | #include <drm/drm_vma_manager.h> |
| 30 | |||
| 30 | #include "psb_drv.h" | 31 | #include "psb_drv.h" |
| 31 | 32 | ||
| 32 | void psb_gem_free_object(struct drm_gem_object *obj) | 33 | void psb_gem_free_object(struct drm_gem_object *obj) |
| @@ -13,7 +13,6 @@ · 12 unmodified lines | |||
| 13 | * | 13 | * |
| 14 | **************************************************************************/ | 14 | **************************************************************************/ |
| 15 | 15 | ||
| 16 | #include <drm/drmP.h> | ||
| 17 | #include "psb_drv.h" | 16 | #include "psb_drv.h" |
| 18 | 17 | ||
| 19 | void gma_get_core_freq(struct drm_device *dev) | 18 | void gma_get_core_freq(struct drm_device *dev) |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | #ifndef _GMA_DEVICE_H | 16 | #ifndef _GMA_DEVICE_H |
| 17 | #define _GMA_DEVICE_H | 17 | #define _GMA_DEVICE_H |
| 18 | struct drm_device; | ||
| 18 | 19 | ||
| 19 | extern void gma_get_core_freq(struct drm_device *dev); | 20 | extern void gma_get_core_freq(struct drm_device *dev); |
| 20 | 21 | ||
| @@ -19,12 +19,18 @@ · 18 unmodified lines | |||
| 19 | * Patrik Jakobsson <patrik.r.jakobsson@gmail.com> | 19 | * Patrik Jakobsson <patrik.r.jakobsson@gmail.com> |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <drm/drmP.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/highmem.h> | ||
| 24 | |||
| 25 | #include <drm/drm_crtc.h> | ||
| 26 | #include <drm/drm_fourcc.h> | ||
| 27 | #include <drm/drm_vblank.h> | ||
| 28 | |||
| 29 | #include "framebuffer.h" | ||
| 23 | #include "gma_display.h" | 30 | #include "gma_display.h" |
| 31 | #include "psb_drv.h" | ||
| 24 | #include "psb_intel_drv.h" | 32 | #include "psb_intel_drv.h" |
| 25 | #include "psb_intel_reg.h" | 33 | #include "psb_intel_reg.h" |
| 26 | #include "psb_drv.h" | ||
| 27 | #include "framebuffer.h" | ||
| 28 | 34 | ||
| 29 | /** | 35 | /** |
| 30 | * Returns whether any output on the specified pipe is of the specified type | 36 | * Returns whether any output on the specified pipe is of the specified type |
| @@ -24,6 +24,9 @@ · 23 unmodified lines | |||
| 24 | 24 | ||
| 25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
| 26 | 26 | ||
| 27 | struct drm_encoder; | ||
| 28 | struct drm_mode_set; | ||
| 29 | |||
| 27 | struct gma_clock_t { | 30 | struct gma_clock_t { |
| 28 | /* given values */ | 31 | /* given values */ |
| 29 | int n; | 32 | int n; |
| @@ -19,11 +19,12 @@ · 18 unmodified lines | |||
| 19 | * Alan Cox <alan@linux.intel.com> | 19 | * Alan Cox <alan@linux.intel.com> |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <drm/drmP.h> | ||
| 23 | #include <linux/shmem_fs.h> | 22 | #include <linux/shmem_fs.h> |
| 23 | |||
| 24 | #include <asm/set_memory.h> | 24 | #include <asm/set_memory.h> |
| 25 | #include "psb_drv.h" | 25 | |
| 26 | #include "blitter.h" | 26 | #include "blitter.h" |
| 27 | #include "psb_drv.h" | ||
| 27 | 28 | ||
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | #ifndef _PSB_GTT_H_ | 20 | #ifndef _PSB_GTT_H_ |
| 21 | #define _PSB_GTT_H_ | 21 | #define _PSB_GTT_H_ |
| 22 | 22 | ||
| 23 | #include <drm/drmP.h> | ||
| 24 | #include <drm/drm_gem.h> | 23 | #include <drm/drm_gem.h> |
| 25 | 24 | ||
| 26 | /* This wants cleaning up with respect to the psb_dev and un-needed stuff */ | 25 | /* This wants cleaning up with respect to the psb_dev and un-needed stuff */ |
| @@ -18,13 +18,13 @@ · 17 unmodified lines | |||
| 18 | * Eric Anholt <eric@anholt.net> | 18 | * Eric Anholt <eric@anholt.net> |
| 19 | * | 19 | * |
| 20 | */ | 20 | */ |
| 21 | #include <drm/drmP.h> | ||
| 22 | #include <drm/drm.h> | 21 | #include <drm/drm.h> |
| 23 | #include <drm/gma_drm.h> | 22 | #include <drm/drm_dp_helper.h> |
| 23 | |||
| 24 | #include "intel_bios.h" | ||
| 24 | #include "psb_drv.h" | 25 | #include "psb_drv.h" |
| 25 | #include "psb_intel_drv.h" | 26 | #include "psb_intel_drv.h" |
| 26 | #include "psb_intel_reg.h" | 27 | #include "psb_intel_reg.h" |
| 27 | #include "intel_bios.h" | ||
| 28 | 28 | ||
| 29 | #define SLAVE_ADDR1 0x70 | 29 | #define SLAVE_ADDR1 0x70 |
| 30 | #define SLAVE_ADDR2 0x72 | 30 | #define SLAVE_ADDR2 0x72 |
| @@ -22,8 +22,7 @@ · 21 unmodified lines | |||
| 22 | #ifndef _INTEL_BIOS_H_ | 22 | #ifndef _INTEL_BIOS_H_ |
| 23 | #define _INTEL_BIOS_H_ | 23 | #define _INTEL_BIOS_H_ |
| 24 | 24 | ||
| 25 | #include <drm/drmP.h> | 25 | struct drm_device; |
| 26 | #include <drm/drm_dp_helper.h> | ||
| 27 | 26 | ||
| 28 | struct vbt_header { | 27 | struct vbt_header { |
| 29 | u8 signature[20]; /**< Always starts with 'VBT$' */ | 28 | u8 signature[20]; /**< Always starts with 'VBT$' */ |
| @@ -26,13 +26,14 @@ · 25 unmodified lines | |||
| 26 | * Eric Anholt <eric@anholt.net> | 26 | * Eric Anholt <eric@anholt.net> |
| 27 | * Chris Wilson <chris@chris-wilson.co.uk> | 27 | * Chris Wilson <chris@chris-wilson.co.uk> |
| 28 | */ | 28 | */ |
| 29 | #include <linux/module.h> | 29 | |
| 30 | #include <linux/i2c.h> | 30 | #include <linux/delay.h> |
| 31 | #include <linux/i2c-algo-bit.h> | 31 | #include <linux/i2c-algo-bit.h> |
| 32 | #include <drm/drmP.h> | 32 | #include <linux/i2c.h> |
| 33 | #include "psb_intel_drv.h" | 33 | #include <linux/module.h> |
| 34 | #include <drm/gma_drm.h> | 34 | |
| 35 | #include "psb_drv.h" | 35 | #include "psb_drv.h" |
| 36 | #include "psb_intel_drv.h" | ||
| 36 | #include "psb_intel_reg.h" | 37 | #include "psb_intel_reg.h" |
| 37 | 38 | ||
| 38 | #define _wait_for(COND, MS, W) ({ \ | 39 | #define _wait_for(COND, MS, W) ({ \ |
| @@ -17,9 +17,11 @@ · 16 unmodified lines | |||
| 17 | * Authors: | 17 | * Authors: |
| 18 | * Eric Anholt <eric@anholt.net> | 18 | * Eric Anholt <eric@anholt.net> |
| 19 | */ | 19 | */ |
| 20 | |||
| 21 | #include <linux/delay.h> | ||
| 20 | #include <linux/export.h> | 22 | #include <linux/export.h> |
| 21 | #include <linux/i2c.h> | ||
| 22 | #include <linux/i2c-algo-bit.h> | 23 | #include <linux/i2c-algo-bit.h> |
| 24 | #include <linux/i2c.h> | ||
| 23 | 25 | ||
| 24 | #include "psb_drv.h" | 26 | #include "psb_drv.h" |
| 25 | #include "psb_intel_reg.h" | 27 | #include "psb_intel_reg.h" |
| @@ -17,14 +17,16 @@ · 16 unmodified lines | |||
| 17 | * | 17 | * |
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | #include "psb_drv.h" | 20 | #include <linux/delay.h> |
| 21 | #include "mid_bios.h" | ||
| 22 | #include "mdfld_output.h" | ||
| 23 | #include "mdfld_dsi_output.h" | ||
| 24 | #include "tc35876x-dsi-lvds.h" | ||
| 25 | 21 | ||
| 26 | #include <asm/intel_scu_ipc.h> | 22 | #include <asm/intel_scu_ipc.h> |
| 27 | 23 | ||
| 24 | #include "mdfld_dsi_output.h" | ||
| 25 | #include "mdfld_output.h" | ||
| 26 | #include "mid_bios.h" | ||
| 27 | #include "psb_drv.h" | ||
| 28 | #include "tc35876x-dsi-lvds.h" | ||
| 29 | |||
| 28 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | 30 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE |
| 29 | 31 | ||
| 30 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF | 32 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF |
| @@ -342,7 +344,7 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum) · 311 unmodified lines | |||
| 342 | 344 | ||
| 343 | if (pipenum == 1) { | 345 | if (pipenum == 1) { |
| 344 | /* restore palette (gamma) */ | 346 | /* restore palette (gamma) */ |
| 345 | /*DRM_UDELAY(50000); */ | 347 | /* udelay(50000); */ |
| 346 | for (i = 0; i < 256; i++) | 348 | for (i = 0; i < 256; i++) |
| 347 | PSB_WVDC32(pipe->palette[i], map->palette + (i << 2)); | 349 | PSB_WVDC32(pipe->palette[i], map->palette + (i << 2)); |
| 348 | 350 | ||
| @@ -404,7 +406,7 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum) · 55 unmodified lines | |||
| 404 | PSB_WVDC32(pipe->conf, map->conf); | 406 | PSB_WVDC32(pipe->conf, map->conf); |
| 405 | 407 | ||
| 406 | /* restore palette (gamma) */ | 408 | /* restore palette (gamma) */ |
| 407 | /*DRM_UDELAY(50000); */ | 409 | /* udelay(50000); */ |
| 408 | for (i = 0; i < 256; i++) | 410 | for (i = 0; i < 256; i++) |
| 409 | PSB_WVDC32(pipe->palette[i], map->palette + (i << 2)); | 411 | PSB_WVDC32(pipe->palette[i], map->palette + (i << 2)); |
| 410 | 412 | ||
| @@ -25,9 +25,11 @@ · 24 unmodified lines | |||
| 25 | * Jackie Li<yaodong.li@intel.com> | 25 | * Jackie Li<yaodong.li@intel.com> |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/delay.h> | ||
| 29 | |||
| 28 | #include "mdfld_dsi_dpi.h" | 30 | #include "mdfld_dsi_dpi.h" |
| 29 | #include "mdfld_output.h" | ||
| 30 | #include "mdfld_dsi_pkg_sender.h" | 31 | #include "mdfld_dsi_pkg_sender.h" |
| 32 | #include "mdfld_output.h" | ||
| 31 | #include "psb_drv.h" | 33 | #include "psb_drv.h" |
| 32 | #include "tc35876x-dsi-lvds.h" | 34 | #include "tc35876x-dsi-lvds.h" |
| 33 | 35 | ||
| @@ -25,15 +25,17 @@ · 24 unmodified lines | |||
| 25 | * Jackie Li<yaodong.li@intel.com> | 25 | * Jackie Li<yaodong.li@intel.com> |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/module.h> | 28 | #include <linux/delay.h> |
| 29 | #include <linux/moduleparam.h> | ||
| 30 | #include <linux/pm_runtime.h> | ||
| 31 | |||
| 32 | #include <asm/intel_scu_ipc.h> | ||
| 29 | 33 | ||
| 30 | #include "mdfld_dsi_output.h" | ||
| 31 | #include "mdfld_dsi_dpi.h" | 34 | #include "mdfld_dsi_dpi.h" |
| 32 | #include "mdfld_output.h" | 35 | #include "mdfld_dsi_output.h" |
| 33 | #include "mdfld_dsi_pkg_sender.h" | 36 | #include "mdfld_dsi_pkg_sender.h" |
| 37 | #include "mdfld_output.h" | ||
| 34 | #include "tc35876x-dsi-lvds.h" | 38 | #include "tc35876x-dsi-lvds.h" |
| 35 | #include <linux/pm_runtime.h> | ||
| 36 | #include <asm/intel_scu_ipc.h> | ||
| 37 | 39 | ||
| 38 | /* get the LABC from command line. */ | 40 | /* get the LABC from command line. */ |
| 39 | static int LABC_control = 1; | 41 | static int LABC_control = 1; |
| @@ -29,17 +29,17 @@ · 28 unmodified lines | |||
| 29 | #define __MDFLD_DSI_OUTPUT_H__ | 29 | #define __MDFLD_DSI_OUTPUT_H__ |
| 30 | 30 | ||
| 31 | #include <linux/backlight.h> | 31 | #include <linux/backlight.h> |
| 32 | #include <drm/drmP.h> | 32 | |
| 33 | #include <asm/intel-mid.h> | ||
| 34 | |||
| 33 | #include <drm/drm.h> | 35 | #include <drm/drm.h> |
| 34 | #include <drm/drm_crtc.h> | 36 | #include <drm/drm_crtc.h> |
| 35 | #include <drm/drm_edid.h> | 37 | #include <drm/drm_edid.h> |
| 36 | 38 | ||
| 39 | #include "mdfld_output.h" | ||
| 37 | #include "psb_drv.h" | 40 | #include "psb_drv.h" |
| 38 | #include "psb_intel_drv.h" | 41 | #include "psb_intel_drv.h" |
| 39 | #include "psb_intel_reg.h" | 42 | #include "psb_intel_reg.h" |
| 40 | #include "mdfld_output.h" | ||
| 41 | |||
| 42 | #include <asm/intel-mid.h> | ||
| 43 | 43 | ||
| 44 | #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) | 44 | #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) |
| 45 | #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) | 45 | #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) |
| @@ -24,12 +24,14 @@ · 23 unmodified lines | |||
| 24 | * Jackie Li<yaodong.li@intel.com> | 24 | * Jackie Li<yaodong.li@intel.com> |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <linux/delay.h> | ||
| 27 | #include <linux/freezer.h> | 28 | #include <linux/freezer.h> |
| 29 | |||
| 28 | #include <video/mipi_display.h> | 30 | #include <video/mipi_display.h> |
| 29 | 31 | ||
| 32 | #include "mdfld_dsi_dpi.h" | ||
| 30 | #include "mdfld_dsi_output.h" | 33 | #include "mdfld_dsi_output.h" |
| 31 | #include "mdfld_dsi_pkg_sender.h" | 34 | #include "mdfld_dsi_pkg_sender.h" |
| 32 | #include "mdfld_dsi_dpi.h" | ||
| 33 | 35 | ||
| 34 | #define MDFLD_DSI_READ_MAX_COUNT 5000 | 36 | #define MDFLD_DSI_READ_MAX_COUNT 5000 |
| 35 | 37 | ||
| @@ -18,15 +18,18 @@ · 17 unmodified lines | |||
| 18 | * Eric Anholt <eric@anholt.net> | 18 | * Eric Anholt <eric@anholt.net> |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/delay.h> | ||
| 21 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
| 22 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
| 23 | 24 | ||
| 24 | #include <drm/drmP.h> | 25 | #include <drm/drm_crtc.h> |
| 25 | #include "psb_intel_reg.h" | 26 | #include <drm/drm_fourcc.h> |
| 26 | #include "gma_display.h" | 27 | |
| 27 | #include "framebuffer.h" | 28 | #include "framebuffer.h" |
| 28 | #include "mdfld_output.h" | 29 | #include "gma_display.h" |
| 29 | #include "mdfld_dsi_output.h" | 30 | #include "mdfld_dsi_output.h" |
| 31 | #include "mdfld_output.h" | ||
| 32 | #include "psb_intel_reg.h" | ||
| 30 | 33 | ||
| 31 | /* Hardcoded currently */ | 34 | /* Hardcoded currently */ |
| 32 | static int ksel = KSEL_CRYSTAL_19; | 35 | static int ksel = KSEL_CRYSTAL_19; |
| @@ -27,6 +27,8 @@ · 26 unmodified lines | |||
| 27 | * Scott Rowe <scott.m.rowe@intel.com> | 27 | * Scott Rowe <scott.m.rowe@intel.com> |
| 28 | */ | 28 | */ |
| 29 | 29 | ||
| 30 | #include <linux/delay.h> | ||
| 31 | |||
| 30 | #include "mdfld_dsi_dpi.h" | 32 | #include "mdfld_dsi_dpi.h" |
| 31 | #include "mdfld_dsi_pkg_sender.h" | 33 | #include "mdfld_dsi_pkg_sender.h" |
| 32 | 34 | ||
| @@ -23,11 +23,10 @@ · 22 unmodified lines | |||
| 23 | * - Check ioremap failures | 23 | * - Check ioremap failures |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <drm/drmP.h> | ||
| 27 | #include <drm/drm.h> | 26 | #include <drm/drm.h> |
| 28 | #include <drm/gma_drm.h> | 27 | |
| 29 | #include "psb_drv.h" | ||
| 30 | #include "mid_bios.h" | 28 | #include "mid_bios.h" |
| 29 | #include "psb_drv.h" | ||
| 31 | 30 | ||
| 32 | static void mid_get_fuse_settings(struct drm_device *dev) | 31 | static void mid_get_fuse_settings(struct drm_device *dev) |
| 33 | { | 32 | { |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | |||
| 16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 17 | * | 17 | * |
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | struct drm_device; | ||
| 19 | 20 | ||
| 20 | extern int mid_chip_setup(struct drm_device *dev); | 21 | extern int mid_chip_setup(struct drm_device *dev); |
| 21 | 22 | ||
| @@ -15,10 +15,12 @@ · 14 unmodified lines | |||
| 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 16 | * | 16 | * |
| 17 | **************************************************************************/ | 17 | **************************************************************************/ |
| 18 | #include <drm/drmP.h> | 18 | |
| 19 | #include <linux/highmem.h> | ||
| 20 | |||
| 21 | #include "mmu.h" | ||
| 19 | #include "psb_drv.h" | 22 | #include "psb_drv.h" |
| 20 | #include "psb_reg.h" | 23 | #include "psb_reg.h" |
| 21 | #include "mmu.h" | ||
| 22 | 24 | ||
| 23 | /* | 25 | /* |
| 24 | * Code for the SGX MMU: | 26 | * Code for the SGX MMU: |
| @@ -17,6 +17,8 @@ · 16 unmodified lines | |||
| 17 | * | 17 | * |
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | struct psb_intel_mode_device; | ||
| 21 | |||
| 20 | /* MID device specific descriptors */ | 22 | /* MID device specific descriptors */ |
| 21 | 23 | ||
| 22 | struct oaktrail_timing_info { | 24 | struct oaktrail_timing_info { |
| @@ -15,16 +15,18 @@ · 14 unmodified lines | |||
| 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/delay.h> | ||
| 18 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
| 19 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
| 20 | 21 | ||
| 21 | #include <drm/drmP.h> | 22 | #include <drm/drm_fourcc.h> |
| 23 | |||
| 22 | #include "framebuffer.h" | 24 | #include "framebuffer.h" |
| 25 | #include "gma_display.h" | ||
| 26 | #include "power.h" | ||
| 23 | #include "psb_drv.h" | 27 | #include "psb_drv.h" |
| 24 | #include "psb_intel_drv.h" | 28 | #include "psb_intel_drv.h" |
| 25 | #include "psb_intel_reg.h" | 29 | #include "psb_intel_reg.h" |
| 26 | #include "gma_display.h" | ||
| 27 | #include "power.h" | ||
| 28 | 30 | ||
| 29 | #define MRST_LIMIT_LVDS_100L 0 | 31 | #define MRST_LIMIT_LVDS_100L 0 |
| 30 | #define MRST_LIMIT_LVDS_83 1 | 32 | #define MRST_LIMIT_LVDS_83 1 |
| @@ -18,18 +18,20 @@ · 17 unmodified lines | |||
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | #include <linux/backlight.h> | 20 | #include <linux/backlight.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/dmi.h> | 22 | #include <linux/dmi.h> |
| 23 | #include <drm/drmP.h> | 23 | #include <linux/module.h> |
| 24 | #include <drm/drm.h> | 24 | |
| 25 | #include <drm/gma_drm.h> | ||
| 26 | #include "psb_drv.h" | ||
| 27 | #include "psb_reg.h" | ||
| 28 | #include "psb_intel_reg.h" | ||
| 29 | #include <asm/intel-mid.h> | 25 | #include <asm/intel-mid.h> |
| 30 | #include <asm/intel_scu_ipc.h> | 26 | #include <asm/intel_scu_ipc.h> |
| 31 | #include "mid_bios.h" | 27 | |
| 28 | #include <drm/drm.h> | ||
| 29 | |||
| 32 | #include "intel_bios.h" | 30 | #include "intel_bios.h" |
| 31 | #include "mid_bios.h" | ||
| 32 | #include "psb_drv.h" | ||
| 33 | #include "psb_intel_reg.h" | ||
| 34 | #include "psb_reg.h" | ||
| 33 | 35 | ||
| 34 | static int oaktrail_output_init(struct drm_device *dev) | 36 | static int oaktrail_output_init(struct drm_device *dev) |
| 35 | { | 37 | { |
| @@ -327,7 +329,7 @@ static int oaktrail_restore_display_registers(struct drm_device *dev) · 291 unmodified lines | |||
| 327 | 329 | ||
| 328 | /* Actually enable it */ | 330 | /* Actually enable it */ |
| 329 | PSB_WVDC32(p->dpll, MRST_DPLL_A); | 331 | PSB_WVDC32(p->dpll, MRST_DPLL_A); |
| 330 | DRM_UDELAY(150); | 332 | udelay(150); |
| 331 | 333 | ||
| 332 | /* Restore mode */ | 334 | /* Restore mode */ |
| 333 | PSB_WVDC32(p->htotal, HTOTAL_A); | 335 | PSB_WVDC32(p->htotal, HTOTAL_A); |
| @@ -24,11 +24,13 @@ · 23 unmodified lines | |||
| 24 | * Li Peng <peng.li@intel.com> | 24 | * Li Peng <peng.li@intel.com> |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <drm/drmP.h> | 27 | #include <linux/delay.h> |
| 28 | |||
| 28 | #include <drm/drm.h> | 29 | #include <drm/drm.h> |
| 30 | |||
| 31 | #include "psb_drv.h" | ||
| 29 | #include "psb_intel_drv.h" | 32 | #include "psb_intel_drv.h" |
| 30 | #include "psb_intel_reg.h" | 33 | #include "psb_intel_reg.h" |
| 31 | #include "psb_drv.h" | ||
| 32 | 34 | ||
| 33 | #define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) | 35 | #define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) |
| 34 | #define HDMI_WRITE(reg, val) writel(val, hdmi_dev->regs + (reg)) | 36 | #define HDMI_WRITE(reg, val) writel(val, hdmi_dev->regs + (reg)) |
| @@ -815,7 +817,7 @@ void oaktrail_hdmi_restore(struct drm_device *dev) · 780 unmodified lines | |||
| 815 | PSB_WVDC32(hdmi_dev->saveDPLL_ADJUST, DPLL_ADJUST); | 817 | PSB_WVDC32(hdmi_dev->saveDPLL_ADJUST, DPLL_ADJUST); |
| 816 | PSB_WVDC32(hdmi_dev->saveDPLL_UPDATE, DPLL_UPDATE); | 818 | PSB_WVDC32(hdmi_dev->saveDPLL_UPDATE, DPLL_UPDATE); |
| 817 | PSB_WVDC32(hdmi_dev->saveDPLL_CLK_ENABLE, DPLL_CLK_ENABLE); | 819 | PSB_WVDC32(hdmi_dev->saveDPLL_CLK_ENABLE, DPLL_CLK_ENABLE); |
| 818 | DRM_UDELAY(150); | 820 | udelay(150); |
| 819 | 821 | ||
| 820 | /* pipe */ | 822 | /* pipe */ |
| 821 | PSB_WVDC32(pipeb->src, PIPEBSRC); | 823 | PSB_WVDC32(pipeb->src, PIPEBSRC); |
| @@ -21,15 +21,15 @@ · 20 unmodified lines | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
| 24 | #include <drm/drmP.h> | 24 | #include <linux/pm_runtime.h> |
| 25 | |||
| 25 | #include <asm/intel-mid.h> | 26 | #include <asm/intel-mid.h> |
| 26 | 27 | ||
| 27 | #include "intel_bios.h" | 28 | #include "intel_bios.h" |
| 29 | #include "power.h" | ||
| 28 | #include "psb_drv.h" | 30 | #include "psb_drv.h" |
| 29 | #include "psb_intel_drv.h" | 31 | #include "psb_intel_drv.h" |
| 30 | #include "psb_intel_reg.h" | 32 | #include "psb_intel_reg.h" |
| 31 | #include "power.h" | ||
| 32 | #include <linux/pm_runtime.h> | ||
| 33 | 33 | ||
| 34 | /* The max/min PWM frequency in BPCR[31:17] - */ | 34 | /* The max/min PWM frequency in BPCR[31:17] - */ |
| 35 | /* The smallest number is 1 (not 0) that can fit in the | 35 | /* The smallest number is 1 (not 0) that can fit in the |
| @@ -23,17 +23,16 @@ · 22 unmodified lines | |||
| 23 | * | 23 | * |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/i2c-algo-bit.h> | ||
| 28 | #include <linux/i2c.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/io.h> | ||
| 26 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
| 27 | #include <linux/module.h> | 32 | #include <linux/module.h> |
| 28 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
| 29 | #include <linux/types.h> | 34 | #include <linux/types.h> |
| 30 | #include <linux/i2c.h> | ||
| 31 | #include <linux/i2c-algo-bit.h> | ||
| 32 | #include <linux/init.h> | ||
| 33 | #include <linux/io.h> | ||
| 34 | #include <linux/delay.h> | ||
| 35 | 35 | ||
| 36 | #include <drm/drmP.h> | ||
| 37 | #include "psb_drv.h" | 36 | #include "psb_drv.h" |
| 38 | #include "psb_intel_reg.h" | 37 | #include "psb_intel_reg.h" |
| 39 | 38 | ||
| @@ -31,7 +31,9 @@ · 30 unmodified lines | |||
| 31 | #define _PSB_POWERMGMT_H_ | 31 | #define _PSB_POWERMGMT_H_ |
| 32 | 32 | ||
| 33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
| 34 | #include <drm/drmP.h> | 34 | |
| 35 | struct device; | ||
| 36 | struct drm_device; | ||
| 35 | 37 | ||
| 36 | void gma_power_init(struct drm_device *dev); | 38 | void gma_power_init(struct drm_device *dev); |
| 37 | void gma_power_uninit(struct drm_device *dev); | 39 | void gma_power_uninit(struct drm_device *dev); |
| @@ -18,15 +18,15 @@ · 17 unmodified lines | |||
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | #include <linux/backlight.h> | 20 | #include <linux/backlight.h> |
| 21 | #include <drm/drmP.h> | 21 | |
| 22 | #include <drm/drm.h> | 22 | #include <drm/drm.h> |
| 23 | #include <drm/gma_drm.h> | 23 | |
| 24 | #include "psb_drv.h" | 24 | #include "gma_device.h" |
| 25 | #include "psb_reg.h" | ||
| 26 | #include "psb_intel_reg.h" | ||
| 27 | #include "intel_bios.h" | 25 | #include "intel_bios.h" |
| 28 | #include "psb_device.h" | 26 | #include "psb_device.h" |
| 29 | #include "gma_device.h" | 27 | #include "psb_drv.h" |
| 28 | #include "psb_intel_reg.h" | ||
| 29 | #include "psb_reg.h" | ||
| 30 | 30 | ||
| 31 | static int psb_output_init(struct drm_device *dev) | 31 | static int psb_output_init(struct drm_device *dev) |
| 32 | { | 32 | { |
| @@ -19,23 +19,32 @@ · 18 unmodified lines | |||
| 19 | * | 19 | * |
| 20 | **************************************************************************/ | 20 | **************************************************************************/ |
| 21 | 21 | ||
| 22 | #include <drm/drmP.h> | 22 | #include <linux/cpu.h> |
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/notifier.h> | ||
| 25 | #include <linux/pm_runtime.h> | ||
| 26 | #include <linux/spinlock.h> | ||
| 27 | |||
| 28 | #include <asm/set_memory.h> | ||
| 29 | |||
| 30 | #include <acpi/video.h> | ||
| 31 | |||
| 23 | #include <drm/drm.h> | 32 | #include <drm/drm.h> |
| 24 | #include "psb_drv.h" | 33 | #include <drm/drm_drv.h> |
| 34 | #include <drm/drm_file.h> | ||
| 35 | #include <drm/drm_ioctl.h> | ||
| 36 | #include <drm/drm_irq.h> | ||
| 37 | #include <drm/drm_pci.h> | ||
| 38 | #include <drm/drm_pciids.h> | ||
| 39 | #include <drm/drm_vblank.h> | ||
| 40 | |||
| 25 | #include "framebuffer.h" | 41 | #include "framebuffer.h" |
| 26 | #include "psb_reg.h" | ||
| 27 | #include "psb_intel_reg.h" | ||
| 28 | #include "intel_bios.h" | 42 | #include "intel_bios.h" |
| 29 | #include "mid_bios.h" | 43 | #include "mid_bios.h" |
| 30 | #include <drm/drm_pciids.h> | ||
| 31 | #include "power.h" | 44 | #include "power.h" |
| 32 | #include <linux/cpu.h> | 45 | #include "psb_drv.h" |
| 33 | #include <linux/notifier.h> | 46 | #include "psb_intel_reg.h" |
| 34 | #include <linux/spinlock.h> | 47 | #include "psb_reg.h" |
| 35 | #include <linux/pm_runtime.h> | ||
| 36 | #include <acpi/video.h> | ||
| 37 | #include <linux/module.h> | ||
| 38 | #include <asm/set_memory.h> | ||
| 39 | 48 | ||
| 40 | static struct drm_driver driver; | 49 | static struct drm_driver driver; |
| 41 | static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | 50 | static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); |
| @@ -23,17 +23,17 @@ · 22 unmodified lines | |||
| 23 | #include <linux/kref.h> | 23 | #include <linux/kref.h> |
| 24 | #include <linux/mm_types.h> | 24 | #include <linux/mm_types.h> |
| 25 | 25 | ||
| 26 | #include <drm/drmP.h> | 26 | #include <drm/drm_device.h> |
| 27 | #include <drm/gma_drm.h> | 27 | |
| 28 | #include "psb_reg.h" | ||
| 29 | #include "psb_intel_drv.h" | ||
| 30 | #include "gma_display.h" | 28 | #include "gma_display.h" |
| 31 | #include "intel_bios.h" | ||
| 32 | #include "gtt.h" | 29 | #include "gtt.h" |
| 33 | #include "power.h" | 30 | #include "intel_bios.h" |
| 34 | #include "opregion.h" | ||
| 35 | #include "oaktrail.h" | ||
| 36 | #include "mmu.h" | 31 | #include "mmu.h" |
| 32 | #include "oaktrail.h" | ||
| 33 | #include "opregion.h" | ||
| 34 | #include "power.h" | ||
| 35 | #include "psb_intel_drv.h" | ||
| 36 | #include "psb_reg.h" | ||
| 37 | 37 | ||
| 38 | #define DRIVER_AUTHOR "Alan Cox <alan@linux.intel.com> and others" | 38 | #define DRIVER_AUTHOR "Alan Cox <alan@linux.intel.com> and others" |
| 39 | 39 | ||
| @@ -18,16 +18,17 @@ · 17 unmodified lines | |||
| 18 | * Eric Anholt <eric@anholt.net> | 18 | * Eric Anholt <eric@anholt.net> |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/delay.h> | ||
| 21 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
| 22 | 23 | ||
| 23 | #include <drm/drmP.h> | ||
| 24 | #include <drm/drm_plane_helper.h> | 24 | #include <drm/drm_plane_helper.h> |
| 25 | |||
| 25 | #include "framebuffer.h" | 26 | #include "framebuffer.h" |
| 27 | #include "gma_display.h" | ||
| 28 | #include "power.h" | ||
| 26 | #include "psb_drv.h" | 29 | #include "psb_drv.h" |
| 27 | #include "psb_intel_drv.h" | 30 | #include "psb_intel_drv.h" |
| 28 | #include "psb_intel_reg.h" | 31 | #include "psb_intel_reg.h" |
| 29 | #include "gma_display.h" | ||
| 30 | #include "power.h" | ||
| 31 | 32 | ||
| 32 | #define INTEL_LIMIT_I9XX_SDVO_DAC 0 | 33 | #define INTEL_LIMIT_I9XX_SDVO_DAC 0 |
| 33 | #define INTEL_LIMIT_I9XX_LVDS 1 | 34 | #define INTEL_LIMIT_I9XX_LVDS 1 |
| @@ -21,14 +21,13 @@ · 20 unmodified lines | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
| 24 | #include <drm/drmP.h> | 24 | #include <linux/pm_runtime.h> |
| 25 | 25 | ||
| 26 | #include "intel_bios.h" | 26 | #include "intel_bios.h" |
| 27 | #include "power.h" | ||
| 27 | #include "psb_drv.h" | 28 | #include "psb_drv.h" |
| 28 | #include "psb_intel_drv.h" | 29 | #include "psb_intel_drv.h" |
| 29 | #include "psb_intel_reg.h" | 30 | #include "psb_intel_reg.h" |
| 30 | #include "power.h" | ||
| 31 | #include <linux/pm_runtime.h> | ||
| 32 | 31 | ||
| 33 | /* | 32 | /* |
| 34 | * LVDS I2C backlight control macros | 33 | * LVDS I2C backlight control macros |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | |||
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
| 21 | #include <drm/drmP.h> | 21 | |
| 22 | #include "psb_intel_drv.h" | 22 | #include "psb_intel_drv.h" |
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| @@ -25,19 +25,20 @@ · 24 unmodified lines | |||
| 25 | * Authors: | 25 | * Authors: |
| 26 | * Eric Anholt <eric@anholt.net> | 26 | * Eric Anholt <eric@anholt.net> |
| 27 | */ | 27 | */ |
| 28 | #include <linux/module.h> | 28 | |
| 29 | #include <linux/delay.h> | ||
| 29 | #include <linux/i2c.h> | 30 | #include <linux/i2c.h> |
| 31 | #include <linux/kernel.h> | ||
| 32 | #include <linux/module.h> | ||
| 30 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 31 | #include <linux/delay.h> | 34 | |
| 32 | #include <drm/drmP.h> | ||
| 33 | #include <drm/drm_crtc.h> | 35 | #include <drm/drm_crtc.h> |
| 34 | #include <drm/drm_edid.h> | 36 | #include <drm/drm_edid.h> |
| 35 | #include "psb_intel_drv.h" | 37 | |
| 36 | #include <drm/gma_drm.h> | ||
| 37 | #include "psb_drv.h" | 38 | #include "psb_drv.h" |
| 38 | #include "psb_intel_sdvo_regs.h" | 39 | #include "psb_intel_drv.h" |
| 39 | #include "psb_intel_reg.h" | 40 | #include "psb_intel_reg.h" |
| 40 | #include <linux/kernel.h> | 41 | #include "psb_intel_sdvo_regs.h" |
| 41 | 42 | ||
| 42 | #define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) | 43 | #define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) |
| 43 | #define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) | 44 | #define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) |
| @@ -22,13 +22,14 @@ · 21 unmodified lines | |||
| 22 | /* | 22 | /* |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <drm/drmP.h> | 25 | #include <drm/drm_vblank.h> |
| 26 | |||
| 27 | #include "mdfld_output.h" | ||
| 28 | #include "power.h" | ||
| 26 | #include "psb_drv.h" | 29 | #include "psb_drv.h" |
| 27 | #include "psb_reg.h" | ||
| 28 | #include "psb_intel_reg.h" | 30 | #include "psb_intel_reg.h" |
| 29 | #include "power.h" | ||
| 30 | #include "psb_irq.h" | 31 | #include "psb_irq.h" |
| 31 | #include "mdfld_output.h" | 32 | #include "psb_reg.h" |
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * inline functions | 35 | * inline functions |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | |||
| 24 | #ifndef _PSB_IRQ_H_ | 24 | #ifndef _PSB_IRQ_H_ |
| 25 | #define _PSB_IRQ_H_ | 25 | #define _PSB_IRQ_H_ |
| 26 | 26 | ||
| 27 | #include <drm/drmP.h> | 27 | struct drm_device; |
| 28 | 28 | ||
| 29 | bool sysirq_init(struct drm_device *dev); | 29 | bool sysirq_init(struct drm_device *dev); |
| 30 | void sysirq_uninit(struct drm_device *dev); | 30 | void sysirq_uninit(struct drm_device *dev); |
| @@ -17,11 +17,11 @@ · 16 unmodified lines | |||
| 17 | * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | 17 | * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
| 18 | **************************************************************************/ | 18 | **************************************************************************/ |
| 19 | 19 | ||
| 20 | #include <drm/drmP.h> | 20 | #include <linux/spinlock.h> |
| 21 | |||
| 21 | #include "psb_drv.h" | 22 | #include "psb_drv.h" |
| 22 | #include "psb_reg.h" | ||
| 23 | #include "psb_intel_reg.h" | 23 | #include "psb_intel_reg.h" |
| 24 | #include <linux/spinlock.h> | 24 | #include "psb_reg.h" |
| 25 | 25 | ||
| 26 | static void psb_lid_timer_func(struct timer_list *t) | 26 | static void psb_lid_timer_func(struct timer_list *t) |
| 27 | { | 27 | { |
| @@ -22,15 +22,18 @@ · 21 unmodified lines | |||
| 22 | * | 22 | * |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include "mdfld_dsi_dpi.h" | 25 | #include <linux/delay.h> |
| 26 | #include "mdfld_output.h" | ||
| 27 | #include "mdfld_dsi_pkg_sender.h" | ||
| 28 | #include "tc35876x-dsi-lvds.h" | ||
| 29 | #include <linux/platform_data/tc35876x.h> | ||
| 30 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 31 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 28 | #include <linux/platform_data/tc35876x.h> | ||
| 29 | |||
| 32 | #include <asm/intel_scu_ipc.h> | 30 | #include <asm/intel_scu_ipc.h> |
| 33 | 31 | ||
| 32 | #include "mdfld_dsi_dpi.h" | ||
| 33 | #include "mdfld_dsi_pkg_sender.h" | ||
| 34 | #include "mdfld_output.h" | ||
| 35 | #include "tc35876x-dsi-lvds.h" | ||
| 36 | |||
| 34 | static struct i2c_client *tc35876x_client; | 37 | static struct i2c_client *tc35876x_client; |
| 35 | static struct i2c_client *cmi_lcd_i2c_client; | 38 | static struct i2c_client *cmi_lcd_i2c_client; |
| 36 | 39 | ||
| @@ -3,7 +3,7 @@ config DRM_HISI_HIBMC · 2 unmodified lines | |||
| 3 | tristate "DRM Support for Hisilicon Hibmc" | 3 | tristate "DRM Support for Hisilicon Hibmc" |
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 6 | select DRM_TTM | 6 | select DRM_VRAM_HELPER |
| 7 | 7 | ||
| 8 | help | 8 | help |
| 9 | Choose this option if you have a Hisilicon Hibmc soc chipset. | 9 | Choose this option if you have a Hisilicon Hibmc soc chipset. |
| @@ -96,27 +96,26 @@ static void hibmc_plane_atomic_update(struct drm_plane *plane, · 95 unmodified lines | |||
| 96 | struct drm_plane_state *state = plane->state; | 96 | struct drm_plane_state *state = plane->state; |
| 97 | u32 reg; | 97 | u32 reg; |
| 98 | int ret; | 98 | int ret; |
| 99 | u64 gpu_addr = 0; | 99 | s64 gpu_addr = 0; |
| 100 | unsigned int line_l; | 100 | unsigned int line_l; |
| 101 | struct hibmc_drm_private *priv = plane->dev->dev_private; | 101 | struct hibmc_drm_private *priv = plane->dev->dev_private; |
| 102 | struct hibmc_framebuffer *hibmc_fb; | 102 | struct hibmc_framebuffer *hibmc_fb; |
| 103 | struct hibmc_bo *bo; | 103 | struct drm_gem_vram_object *gbo; |
| 104 | 104 | ||
| 105 | if (!state->fb) | 105 | if (!state->fb) |
| 106 | return; | 106 | return; |
| 107 | 107 | ||
| 108 | hibmc_fb = to_hibmc_framebuffer(state->fb); | 108 | hibmc_fb = to_hibmc_framebuffer(state->fb); |
| 109 | bo = gem_to_hibmc_bo(hibmc_fb->obj); | 109 | gbo = drm_gem_vram_of_gem(hibmc_fb->obj); |
| 110 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | 110 | |
| 111 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); | ||
| 111 | if (ret) { | 112 | if (ret) { |
| 112 | DRM_ERROR("failed to reserve ttm_bo: %d", ret); | 113 | DRM_ERROR("failed to pin bo: %d", ret); |
| 113 | return; | 114 | return; |
| 114 | } | 115 | } |
| 115 | 116 | gpu_addr = drm_gem_vram_offset(gbo); | |
| 116 | ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | 117 | if (gpu_addr < 0) { |
| 117 | ttm_bo_unreserve(&bo->bo); | 118 | drm_gem_vram_unpin(gbo); |
| 118 | if (ret) { | ||
| 119 | DRM_ERROR("failed to pin hibmc_bo: %d", ret); | ||
| 120 | return; | 119 | return; |
| 121 | } | 120 | } |
| 122 | 121 | ||
| @@ -27,14 +27,7 @@ · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | static const struct file_operations hibmc_fops = { | 28 | static const struct file_operations hibmc_fops = { |
| 29 | .owner = THIS_MODULE, | 29 | .owner = THIS_MODULE, |
| 30 | .open = drm_open, | 30 | DRM_VRAM_MM_FILE_OPERATIONS |
| 31 | .release = drm_release, | ||
| 32 | .unlocked_ioctl = drm_ioctl, | ||
| 33 | .compat_ioctl = drm_compat_ioctl, | ||
| 34 | .mmap = hibmc_mmap, | ||
| 35 | .poll = drm_poll, | ||
| 36 | .read = drm_read, | ||
| 37 | .llseek = no_llseek, | ||
| 38 | }; | 31 | }; |
| 39 | 32 | ||
| 40 | static irqreturn_t hibmc_drm_interrupt(int irq, void *arg) | 33 | static irqreturn_t hibmc_drm_interrupt(int irq, void *arg) |
| @@ -63,9 +56,10 @@ static struct drm_driver hibmc_driver = { · 22 unmodified lines | |||
| 63 | .desc = "hibmc drm driver", | 56 | .desc = "hibmc drm driver", |
| 64 | .major = 1, | 57 | .major = 1, |
| 65 | .minor = 0, | 58 | .minor = 0, |
| 66 | .gem_free_object_unlocked = hibmc_gem_free_object, | 59 | .gem_free_object_unlocked = |
| 60 | drm_gem_vram_driver_gem_free_object_unlocked, | ||
| 67 | .dumb_create = hibmc_dumb_create, | 61 | .dumb_create = hibmc_dumb_create, |
| 68 | .dumb_map_offset = hibmc_dumb_mmap_offset, | 62 | .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, |
| 69 | .irq_handler = hibmc_drm_interrupt, | 63 | .irq_handler = hibmc_drm_interrupt, |
| 70 | }; | 64 | }; |
| 71 | 65 | ||
| @@ -23,7 +23,8 @@ · 22 unmodified lines | |||
| 23 | #include <drm/drm_atomic.h> | 23 | #include <drm/drm_atomic.h> |
| 24 | #include <drm/drm_fb_helper.h> | 24 | #include <drm/drm_fb_helper.h> |
| 25 | #include <drm/drm_gem.h> | 25 | #include <drm/drm_gem.h> |
| 26 | #include <drm/ttm/ttm_bo_driver.h> | 26 | #include <drm/drm_gem_vram_helper.h> |
| 27 | #include <drm/drm_vram_mm_helper.h> | ||
| 27 | 28 | ||
| 28 | struct hibmc_framebuffer { | 29 | struct hibmc_framebuffer { |
| 29 | struct drm_framebuffer fb; | 30 | struct drm_framebuffer fb; |
| @@ -48,36 +49,12 @@ struct hibmc_drm_private { · 18 unmodified lines | |||
| 48 | struct drm_device *dev; | 49 | struct drm_device *dev; |
| 49 | bool mode_config_initialized; | 50 | bool mode_config_initialized; |
| 50 | 51 | ||
| 51 | /* ttm */ | ||
| 52 | struct ttm_bo_device bdev; | ||
| 53 | bool initialized; | ||
| 54 | |||
| 55 | /* fbdev */ | 52 | /* fbdev */ |
| 56 | struct hibmc_fbdev *fbdev; | 53 | struct hibmc_fbdev *fbdev; |
| 57 | bool mm_inited; | ||
| 58 | }; | 54 | }; |
| 59 | 55 | ||
| 60 | #define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb) | 56 | #define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb) |
| 61 | 57 | ||
| 62 | struct hibmc_bo { | ||
| 63 | struct ttm_buffer_object bo; | ||
| 64 | struct ttm_placement placement; | ||
| 65 | struct ttm_bo_kmap_obj kmap; | ||
| 66 | struct drm_gem_object gem; | ||
| 67 | struct ttm_place placements[3]; | ||
| 68 | int pin_count; | ||
| 69 | }; | ||
| 70 | |||
| 71 | static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo) | ||
| 72 | { | ||
| 73 | return container_of(bo, struct hibmc_bo, bo); | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem) | ||
| 77 | { | ||
| 78 | return container_of(gem, struct hibmc_bo, gem); | ||
| 79 | } | ||
| 80 | |||
| 81 | void hibmc_set_power_mode(struct hibmc_drm_private *priv, | 58 | void hibmc_set_power_mode(struct hibmc_drm_private *priv, |
| 82 | unsigned int power_mode); | 59 | unsigned int power_mode); |
| 83 | void hibmc_set_current_gate(struct hibmc_drm_private *priv, | 60 | void hibmc_set_current_gate(struct hibmc_drm_private *priv, |
| @@ -97,14 +74,8 @@ hibmc_framebuffer_init(struct drm_device *dev, · 13 unmodified lines | |||
| 97 | 74 | ||
| 98 | int hibmc_mm_init(struct hibmc_drm_private *hibmc); | 75 | int hibmc_mm_init(struct hibmc_drm_private *hibmc); |
| 99 | void hibmc_mm_fini(struct hibmc_drm_private *hibmc); | 76 | void hibmc_mm_fini(struct hibmc_drm_private *hibmc); |
| 100 | int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr); | ||
| 101 | int hibmc_bo_unpin(struct hibmc_bo *bo); | ||
| 102 | void hibmc_gem_free_object(struct drm_gem_object *obj); | ||
| 103 | int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, | 77 | int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, |
| 104 | struct drm_mode_create_dumb *args); | 78 | struct drm_mode_create_dumb *args); |
| 105 | int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, | ||
| 106 | u32 handle, u64 *offset); | ||
| 107 | int hibmc_mmap(struct file *filp, struct vm_area_struct *vma); | ||
| 108 | 79 | ||
| 109 | extern const struct drm_mode_config_funcs hibmc_mode_funcs; | 80 | extern const struct drm_mode_config_funcs hibmc_mode_funcs; |
| 110 | 81 | ||
| @@ -63,10 +63,10 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, · 62 unmodified lines | |||
| 63 | struct drm_mode_fb_cmd2 mode_cmd; | 63 | struct drm_mode_fb_cmd2 mode_cmd; |
| 64 | struct drm_gem_object *gobj = NULL; | 64 | struct drm_gem_object *gobj = NULL; |
| 65 | int ret = 0; | 65 | int ret = 0; |
| 66 | int ret1; | ||
| 67 | size_t size; | 66 | size_t size; |
| 68 | unsigned int bytes_per_pixel; | 67 | unsigned int bytes_per_pixel; |
| 69 | struct hibmc_bo *bo = NULL; | 68 | struct drm_gem_vram_object *gbo = NULL; |
| 69 | void *base; | ||
| 70 | 70 | ||
| 71 | DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", | 71 | DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", |
| 72 | sizes->surface_width, sizes->surface_height, | 72 | sizes->surface_width, sizes->surface_height, |
| @@ -88,26 +88,20 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, · 15 unmodified lines | |||
| 88 | return -ENOMEM; | 88 | return -ENOMEM; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | bo = gem_to_hibmc_bo(gobj); | 91 | gbo = drm_gem_vram_of_gem(gobj); |
| 92 | 92 | ||
| 93 | ret = ttm_bo_reserve(&bo->bo, true, false, NULL); | 93 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 94 | if (ret) { | ||
| 95 | DRM_ERROR("failed to reserve ttm_bo: %d\n", ret); | ||
| 96 | goto out_unref_gem; | ||
| 97 | } | ||
| 98 | |||
| 99 | ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); | ||
| 100 | if (ret) { | 94 | if (ret) { |
| 101 | DRM_ERROR("failed to pin fbcon: %d\n", ret); | 95 | DRM_ERROR("failed to pin fbcon: %d\n", ret); |
| 102 | goto out_unreserve_ttm_bo; | 96 | goto out_unref_gem; |
| 103 | } | 97 | } |
| 104 | 98 | ||
| 105 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 99 | base = drm_gem_vram_kmap(gbo, true, NULL); |
| 106 | if (ret) { | 100 | if (IS_ERR(base)) { |
| 101 | ret = PTR_ERR(base); | ||
| 107 | DRM_ERROR("failed to kmap fbcon: %d\n", ret); | 102 | DRM_ERROR("failed to kmap fbcon: %d\n", ret); |
| 108 | goto out_unpin_bo; | 103 | goto out_unpin_bo; |
| 109 | } | 104 | } |
| 110 | ttm_bo_unreserve(&bo->bo); | ||
| 111 | 105 | ||
| 112 | info = drm_fb_helper_alloc_fbi(helper); | 106 | info = drm_fb_helper_alloc_fbi(helper); |
| 113 | if (IS_ERR(info)) { | 107 | if (IS_ERR(info)) { |
| @@ -131,24 +125,17 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, · 17 unmodified lines | |||
| 131 | 125 | ||
| 132 | drm_fb_helper_fill_info(info, &priv->fbdev->helper, sizes); | 126 | drm_fb_helper_fill_info(info, &priv->fbdev->helper, sizes); |
| 133 | 127 | ||
| 134 | info->screen_base = bo->kmap.virtual; | 128 | info->screen_base = base; |
| 135 | info->screen_size = size; | 129 | info->screen_size = size; |
| 136 | 130 | ||
| 137 | info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base; | 131 | info->fix.smem_start = gbo->bo.mem.bus.offset + gbo->bo.mem.bus.base; |
| 138 | info->fix.smem_len = size; | 132 | info->fix.smem_len = size; |
| 139 | return 0; | 133 | return 0; |
| 140 | 134 | ||
| 141 | out_release_fbi: | 135 | out_release_fbi: |
| 142 | ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL); | 136 | drm_gem_vram_kunmap(gbo); |
| 143 | if (ret1) { | ||
| 144 | DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1); | ||
| 145 | goto out_unref_gem; | ||
| 146 | } | ||
| 147 | ttm_bo_kunmap(&bo->kmap); | ||
| 148 | out_unpin_bo: | 137 | out_unpin_bo: |
| 149 | hibmc_bo_unpin(bo); | 138 | drm_gem_vram_unpin(gbo); |
| 150 | out_unreserve_ttm_bo: | ||
| 151 | ttm_bo_unreserve(&bo->bo); | ||
| 152 | out_unref_gem: | 139 | out_unref_gem: |
| 153 | drm_gem_object_put_unlocked(gobj); | 140 | drm_gem_object_put_unlocked(gobj); |
| 154 | 141 | ||
| @@ -17,335 +17,55 @@ · 16 unmodified lines | |||
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <drm/drm_atomic_helper.h> | 19 | #include <drm/drm_atomic_helper.h> |
| 20 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 21 | 20 | ||
| 22 | #include "hibmc_drm_drv.h" | 21 | #include "hibmc_drm_drv.h" |
| 23 | 22 | ||
| 24 | static inline struct hibmc_drm_private * | ||
| 25 | hibmc_bdev(struct ttm_bo_device *bd) | ||
| 26 | { | ||
| 27 | return container_of(bd, struct hibmc_drm_private, bdev); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
| 31 | { | ||
| 32 | struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo); | ||
| 33 | |||
| 34 | drm_gem_object_release(&bo->gem); | ||
| 35 | kfree(bo); | ||
| 36 | } | ||
| 37 | |||
| 38 | static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo) | ||
| 39 | { | ||
| 40 | return bo->destroy == &hibmc_bo_ttm_destroy; | ||
| 41 | } | ||
| 42 | |||
| 43 | static int | ||
| 44 | hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type, | ||
| 45 | struct ttm_mem_type_manager *man) | ||
| 46 | { | ||
| 47 | switch (type) { | ||
| 48 | case TTM_PL_SYSTEM: | ||
| 49 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 50 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 51 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 52 | break; | ||
| 53 | case TTM_PL_VRAM: | ||
| 54 | man->func = &ttm_bo_manager_func; | ||
| 55 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
| 56 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 57 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
| 58 | TTM_PL_FLAG_WC; | ||
| 59 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 60 | break; | ||
| 61 | default: | ||
| 62 | DRM_ERROR("unsupported memory type %u\n", type); | ||
| 63 | return -EINVAL; | ||
| 64 | } | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | void hibmc_ttm_placement(struct hibmc_bo *bo, int domain) | ||
| 69 | { | ||
| 70 | u32 count = 0; | ||
| 71 | u32 i; | ||
| 72 | |||
| 73 | bo->placement.placement = bo->placements; | ||
| 74 | bo->placement.busy_placement = bo->placements; | ||
| 75 | if (domain & TTM_PL_FLAG_VRAM) | ||
| 76 | bo->placements[count++].flags = TTM_PL_FLAG_WC | | ||
| 77 | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
| 78 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
| 79 | bo->placements[count++].flags = TTM_PL_MASK_CACHING | | ||
| 80 | TTM_PL_FLAG_SYSTEM; | ||
| 81 | if (!count) | ||
| 82 | bo->placements[count++].flags = TTM_PL_MASK_CACHING | | ||
| 83 | TTM_PL_FLAG_SYSTEM; | ||
| 84 | |||
| 85 | bo->placement.num_placement = count; | ||
| 86 | bo->placement.num_busy_placement = count; | ||
| 87 | for (i = 0; i < count; i++) { | ||
| 88 | bo->placements[i].fpfn = 0; | ||
| 89 | bo->placements[i].lpfn = 0; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | static void | ||
| 94 | hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
| 95 | { | ||
| 96 | struct hibmc_bo *hibmcbo = hibmc_bo(bo); | ||
| 97 | |||
| 98 | if (!hibmc_ttm_bo_is_hibmc_bo(bo)) | ||
| 99 | return; | ||
| 100 | |||
| 101 | hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM); | ||
| 102 | *pl = hibmcbo->placement; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int hibmc_bo_verify_access(struct ttm_buffer_object *bo, | ||
| 106 | struct file *filp) | ||
| 107 | { | ||
| 108 | struct hibmc_bo *hibmcbo = hibmc_bo(bo); | ||
| 109 | |||
| 110 | return drm_vma_node_verify_access(&hibmcbo->gem.vma_node, | ||
| 111 | filp->private_data); | ||
| 112 | } | ||
| 113 | |||
| 114 | static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 115 | struct ttm_mem_reg *mem) | ||
| 116 | { | ||
| 117 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
| 118 | struct hibmc_drm_private *hibmc = hibmc_bdev(bdev); | ||
| 119 | |||
| 120 | mem->bus.addr = NULL; | ||
| 121 | mem->bus.offset = 0; | ||
| 122 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 123 | mem->bus.base = 0; | ||
| 124 | mem->bus.is_iomem = false; | ||
| 125 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 126 | return -EINVAL; | ||
| 127 | switch (mem->mem_type) { | ||
| 128 | case TTM_PL_SYSTEM: | ||
| 129 | /* system memory */ | ||
| 130 | return 0; | ||
| 131 | case TTM_PL_VRAM: | ||
| 132 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 133 | mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0); | ||
| 134 | mem->bus.is_iomem = true; | ||
| 135 | break; | ||
| 136 | default: | ||
| 137 | return -EINVAL; | ||
| 138 | } | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void hibmc_ttm_backend_destroy(struct ttm_tt *tt) | ||
| 143 | { | ||
| 144 | ttm_tt_fini(tt); | ||
| 145 | kfree(tt); | ||
| 146 | } | ||
| 147 | |||
| 148 | static struct ttm_backend_func hibmc_tt_backend_func = { | ||
| 149 | .destroy = &hibmc_ttm_backend_destroy, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 153 | u32 page_flags) | ||
| 154 | { | ||
| 155 | struct ttm_tt *tt; | ||
| 156 | int ret; | ||
| 157 | |||
| 158 | tt = kzalloc(sizeof(*tt), GFP_KERNEL); | ||
| 159 | if (!tt) { | ||
| 160 | DRM_ERROR("failed to allocate ttm_tt\n"); | ||
| 161 | return NULL; | ||
| 162 | } | ||
| 163 | tt->func = &hibmc_tt_backend_func; | ||
| 164 | ret = ttm_tt_init(tt, bo, page_flags); | ||
| 165 | if (ret) { | ||
| 166 | DRM_ERROR("failed to initialize ttm_tt: %d\n", ret); | ||
| 167 | kfree(tt); | ||
| 168 | return NULL; | ||
| 169 | } | ||
| 170 | return tt; | ||
| 171 | } | ||
| 172 | |||
| 173 | struct ttm_bo_driver hibmc_bo_driver = { | ||
| 174 | .ttm_tt_create = hibmc_ttm_tt_create, | ||
| 175 | .init_mem_type = hibmc_bo_init_mem_type, | ||
| 176 | .evict_flags = hibmc_bo_evict_flags, | ||
| 177 | .move = NULL, | ||
| 178 | .verify_access = hibmc_bo_verify_access, | ||
| 179 | .io_mem_reserve = &hibmc_ttm_io_mem_reserve, | ||
| 180 | .io_mem_free = NULL, | ||
| 181 | }; | ||
| 182 | |||
| 183 | int hibmc_mm_init(struct hibmc_drm_private *hibmc) | 23 | int hibmc_mm_init(struct hibmc_drm_private *hibmc) |
| 184 | { | 24 | { |
| 25 | struct drm_vram_mm *vmm; | ||
| 185 | int ret; | 26 | int ret; |
| 186 | struct drm_device *dev = hibmc->dev; | 27 | struct drm_device *dev = hibmc->dev; |
| 187 | struct ttm_bo_device *bdev = &hibmc->bdev; | ||
| 188 | 28 | ||
| 189 | ret = ttm_bo_device_init(&hibmc->bdev, | 29 | vmm = drm_vram_helper_alloc_mm(dev, |
| 190 | &hibmc_bo_driver, | 30 | pci_resource_start(dev->pdev, 0), |
| 191 | dev->anon_inode->i_mapping, | 31 | hibmc->fb_size, &drm_gem_vram_mm_funcs); |
| 192 | true); | 32 | if (IS_ERR(vmm)) { |
| 193 | if (ret) { | 33 | ret = PTR_ERR(vmm); |
| 194 | DRM_ERROR("error initializing bo driver: %d\n", ret); | 34 | DRM_ERROR("Error initializing VRAM MM; %d\n", ret); |
| 195 | return ret; | 35 | return ret; |
| 196 | } | 36 | } |
| 197 | 37 | ||
| 198 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | ||
| 199 | hibmc->fb_size >> PAGE_SHIFT); | ||
| 200 | if (ret) { | ||
| 201 | DRM_ERROR("failed ttm VRAM init: %d\n", ret); | ||
| 202 | return ret; | ||
| 203 | } | ||
| 204 | |||
| 205 | hibmc->mm_inited = true; | ||
| 206 | return 0; | 38 | return 0; |
| 207 | } | 39 | } |
| 208 | 40 | ||
| 209 | void hibmc_mm_fini(struct hibmc_drm_private *hibmc) | 41 | void hibmc_mm_fini(struct hibmc_drm_private *hibmc) |
| 210 | { | 42 | { |
| 211 | if (!hibmc->mm_inited) | 43 | if (!hibmc->dev->vram_mm) |
| 212 | return; | ||
| 213 | |||
| 214 | ttm_bo_device_release(&hibmc->bdev); | ||
| 215 | hibmc->mm_inited = false; | ||
| 216 | } | ||
| 217 | |||
| 218 | static void hibmc_bo_unref(struct hibmc_bo **bo) | ||
| 219 | { | ||
| 220 | struct ttm_buffer_object *tbo; | ||
| 221 | |||
| 222 | if ((*bo) == NULL) | ||
| 223 | return; | 44 | return; |
| 224 | 45 | ||
| 225 | tbo = &((*bo)->bo); | 46 | drm_vram_helper_release_mm(hibmc->dev); |
| 226 | ttm_bo_put(tbo); | ||
| 227 | *bo = NULL; | ||
| 228 | } | ||
| 229 | |||
| 230 | int hibmc_bo_create(struct drm_device *dev, int size, int align, | ||
| 231 | u32 flags, struct hibmc_bo **phibmcbo) | ||
| 232 | { | ||
| 233 | struct hibmc_drm_private *hibmc = dev->dev_private; | ||
| 234 | struct hibmc_bo *hibmcbo; | ||
| 235 | size_t acc_size; | ||
| 236 | int ret; | ||
| 237 | |||
| 238 | hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL); | ||
| 239 | if (!hibmcbo) { | ||
| 240 | DRM_ERROR("failed to allocate hibmcbo\n"); | ||
| 241 | return -ENOMEM; | ||
| 242 | } | ||
| 243 | ret = drm_gem_object_init(dev, &hibmcbo->gem, size); | ||
| 244 | if (ret) { | ||
| 245 | DRM_ERROR("failed to initialize drm gem object: %d\n", ret); | ||
| 246 | kfree(hibmcbo); | ||
| 247 | return ret; | ||
| 248 | } | ||
| 249 | |||
| 250 | hibmcbo->bo.bdev = &hibmc->bdev; | ||
| 251 | |||
| 252 | hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 253 | |||
| 254 | acc_size = ttm_bo_dma_acc_size(&hibmc->bdev, size, | ||
| 255 | sizeof(struct hibmc_bo)); | ||
| 256 | |||
| 257 | ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size, | ||
| 258 | ttm_bo_type_device, &hibmcbo->placement, | ||
| 259 | align >> PAGE_SHIFT, false, acc_size, | ||
| 260 | NULL, NULL, hibmc_bo_ttm_destroy); | ||
| 261 | if (ret) { | ||
| 262 | hibmc_bo_unref(&hibmcbo); | ||
| 263 | DRM_ERROR("failed to initialize ttm_bo: %d\n", ret); | ||
| 264 | return ret; | ||
| 265 | } | ||
| 266 | |||
| 267 | *phibmcbo = hibmcbo; | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
| 272 | { | ||
| 273 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 274 | int i, ret; | ||
| 275 | |||
| 276 | if (bo->pin_count) { | ||
| 277 | bo->pin_count++; | ||
| 278 | if (gpu_addr) | ||
| 279 | *gpu_addr = bo->bo.offset; | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | hibmc_ttm_placement(bo, pl_flag); | ||
| 284 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 285 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 286 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 287 | if (ret) | ||
| 288 | return ret; | ||
| 289 | |||
| 290 | bo->pin_count = 1; | ||
| 291 | if (gpu_addr) | ||
| 292 | *gpu_addr = bo->bo.offset; | ||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | int hibmc_bo_unpin(struct hibmc_bo *bo) | ||
| 297 | { | ||
| 298 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 299 | int i, ret; | ||
| 300 | |||
| 301 | if (!bo->pin_count) { | ||
| 302 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | bo->pin_count--; | ||
| 306 | if (bo->pin_count) | ||
| 307 | return 0; | ||
| 308 | |||
| 309 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
| 310 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 311 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 312 | if (ret) { | ||
| 313 | DRM_ERROR("validate failed for unpin: %d\n", ret); | ||
| 314 | return ret; | ||
| 315 | } | ||
| 316 | |||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | int hibmc_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 321 | { | ||
| 322 | struct drm_file *file_priv = filp->private_data; | ||
| 323 | struct hibmc_drm_private *hibmc = file_priv->minor->dev->dev_private; | ||
| 324 | |||
| 325 | return ttm_bo_mmap(filp, vma, &hibmc->bdev); | ||
| 326 | } | 47 | } |
| 327 | 48 | ||
| 328 | int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, | 49 | int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, |
| 329 | struct drm_gem_object **obj) | 50 | struct drm_gem_object **obj) |
| 330 | { | 51 | { |
| 331 | struct hibmc_bo *hibmcbo; | 52 | struct drm_gem_vram_object *gbo; |
| 332 | int ret; | 53 | int ret; |
| 333 | 54 | ||
| 334 | *obj = NULL; | 55 | *obj = NULL; |
| 335 | 56 | ||
| 336 | size = PAGE_ALIGN(size); | 57 | size = roundup(size, PAGE_SIZE); |
| 337 | if (size == 0) { | 58 | if (size == 0) |
| 338 | DRM_ERROR("error: zero size\n"); | ||
| 339 | return -EINVAL; | 59 | return -EINVAL; |
| 340 | } | ||
| 341 | 60 | ||
| 342 | ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo); | 61 | gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); |
| 343 | if (ret) { | 62 | if (IS_ERR(gbo)) { |
| 63 | ret = PTR_ERR(gbo); | ||
| 344 | if (ret != -ERESTARTSYS) | 64 | if (ret != -ERESTARTSYS) |
| 345 | DRM_ERROR("failed to allocate GEM object: %d\n", ret); | 65 | DRM_ERROR("failed to allocate GEM object: %d\n", ret); |
| 346 | return ret; | 66 | return ret; |
| 347 | } | 67 | } |
| 348 | *obj = &hibmcbo->gem; | 68 | *obj = &gbo->gem; |
| 349 | return 0; | 69 | return 0; |
| 350 | } | 70 | } |
| 351 | 71 | ||
| @@ -377,35 +97,6 @@ int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, · 25 unmodified lines | |||
| 377 | return 0; | 97 | return 0; |
| 378 | } | 98 | } |
| 379 | 99 | ||
| 380 | void hibmc_gem_free_object(struct drm_gem_object *obj) | ||
| 381 | { | ||
| 382 | struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj); | ||
| 383 | |||
| 384 | hibmc_bo_unref(&hibmcbo); | ||
| 385 | } | ||
| 386 | |||
| 387 | static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo) | ||
| 388 | { | ||
| 389 | return drm_vma_node_offset_addr(&bo->bo.vma_node); | ||
| 390 | } | ||
| 391 | |||
| 392 | int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, | ||
| 393 | u32 handle, u64 *offset) | ||
| 394 | { | ||
| 395 | struct drm_gem_object *obj; | ||
| 396 | struct hibmc_bo *bo; | ||
| 397 | |||
| 398 | obj = drm_gem_object_lookup(file, handle); | ||
| 399 | if (!obj) | ||
| 400 | return -ENOENT; | ||
| 401 | |||
| 402 | bo = gem_to_hibmc_bo(obj); | ||
| 403 | *offset = hibmc_bo_mmap_offset(bo); | ||
| 404 | |||
| 405 | drm_gem_object_put_unlocked(obj); | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb) | 100 | static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb) |
| 410 | { | 101 | { |
| 411 | struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb); | 102 | struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb); |
| @@ -14605,9 +14605,8 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) · 14604 unmodified lines | |||
| 14605 | ret = -ENOMEM; | 14605 | ret = -ENOMEM; |
| 14606 | goto fail; | 14606 | goto fail; |
| 14607 | } | 14607 | } |
| 14608 | __drm_atomic_helper_crtc_reset(&intel_crtc->base, &crtc_state->base); | ||
| 14608 | intel_crtc->config = crtc_state; | 14609 | intel_crtc->config = crtc_state; |
| 14609 | intel_crtc->base.state = &crtc_state->base; | ||
| 14610 | crtc_state->base.crtc = &intel_crtc->base; | ||
| 14611 | 14610 | ||
| 14612 | primary = intel_primary_plane_create(dev_priv, pipe); | 14611 | primary = intel_primary_plane_create(dev_priv, pipe); |
| 14613 | if (IS_ERR(primary)) { | 14612 | if (IS_ERR(primary)) { |
| @@ -16149,7 +16148,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) · 1535 unmodified lines | |||
| 16149 | 16148 | ||
| 16150 | __drm_atomic_helper_crtc_destroy_state(&crtc_state->base); | 16149 | __drm_atomic_helper_crtc_destroy_state(&crtc_state->base); |
| 16151 | memset(crtc_state, 0, sizeof(*crtc_state)); | 16150 | memset(crtc_state, 0, sizeof(*crtc_state)); |
| 16152 | crtc_state->base.crtc = &crtc->base; | 16151 | __drm_atomic_helper_crtc_reset(&crtc->base, &crtc_state->base); |
| 16153 | 16152 | ||
| 16154 | crtc_state->base.active = crtc_state->base.enable = | 16153 | crtc_state->base.active = crtc_state->base.enable = |
| 16155 | dev_priv->display.get_pipe_config(crtc, crtc_state); | 16154 | dev_priv->display.get_pipe_config(crtc, crtc_state); |
| @@ -325,7 +325,8 @@ skl_plane_max_stride(struct intel_plane *plane, · 324 unmodified lines | |||
| 325 | u32 pixel_format, u64 modifier, | 325 | u32 pixel_format, u64 modifier, |
| 326 | unsigned int rotation) | 326 | unsigned int rotation) |
| 327 | { | 327 | { |
| 328 | int cpp = drm_format_plane_cpp(pixel_format, 0); | 328 | const struct drm_format_info *info = drm_format_info(pixel_format); |
| 329 | int cpp = info->cpp[0]; | ||
| 329 | 330 | ||
| 330 | /* | 331 | /* |
| 331 | * "The stride in bytes must not exceed the | 332 | * "The stride in bytes must not exceed the |
| @@ -115,8 +115,8 @@ drm_plane_state_to_ubo(struct drm_plane_state *state) · 114 unmodified lines | |||
| 115 | cma_obj = drm_fb_cma_get_gem_obj(fb, 1); | 115 | cma_obj = drm_fb_cma_get_gem_obj(fb, 1); |
| 116 | BUG_ON(!cma_obj); | 116 | BUG_ON(!cma_obj); |
| 117 | 117 | ||
| 118 | x /= drm_format_horz_chroma_subsampling(fb->format->format); | 118 | x /= fb->format->hsub; |
| 119 | y /= drm_format_vert_chroma_subsampling(fb->format->format); | 119 | y /= fb->format->vsub; |
| 120 | 120 | ||
| 121 | return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y + | 121 | return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y + |
| 122 | fb->format->cpp[1] * x - eba; | 122 | fb->format->cpp[1] * x - eba; |
| @@ -134,8 +134,8 @@ drm_plane_state_to_vbo(struct drm_plane_state *state) · 11 unmodified lines | |||
| 134 | cma_obj = drm_fb_cma_get_gem_obj(fb, 2); | 134 | cma_obj = drm_fb_cma_get_gem_obj(fb, 2); |
| 135 | BUG_ON(!cma_obj); | 135 | BUG_ON(!cma_obj); |
| 136 | 136 | ||
| 137 | x /= drm_format_horz_chroma_subsampling(fb->format->format); | 137 | x /= fb->format->hsub; |
| 138 | y /= drm_format_vert_chroma_subsampling(fb->format->format); | 138 | y /= fb->format->vsub; |
| 139 | 139 | ||
| 140 | return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y + | 140 | return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y + |
| 141 | fb->format->cpp[2] * x - eba; | 141 | fb->format->cpp[2] * x - eba; |
| @@ -352,7 +352,6 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, · 210 unmodified lines | |||
| 352 | struct drm_framebuffer *old_fb = old_state->fb; | 352 | struct drm_framebuffer *old_fb = old_state->fb; |
| 353 | unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba; | 353 | unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba; |
| 354 | bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); | 354 | bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); |
| 355 | int hsub, vsub; | ||
| 356 | int ret; | 355 | int ret; |
| 357 | 356 | ||
| 358 | /* Ok to disable */ | 357 | /* Ok to disable */ |
| @@ -471,10 +470,8 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, · 112 unmodified lines | |||
| 471 | * The x/y offsets must be even in case of horizontal/vertical | 470 | * The x/y offsets must be even in case of horizontal/vertical |
| 472 | * chroma subsampling. | 471 | * chroma subsampling. |
| 473 | */ | 472 | */ |
| 474 | hsub = drm_format_horz_chroma_subsampling(fb->format->format); | 473 | if (((state->src.x1 >> 16) & (fb->format->hsub - 1)) || |
| 475 | vsub = drm_format_vert_chroma_subsampling(fb->format->format); | 474 | ((state->src.y1 >> 16) & (fb->format->vsub - 1))) |
| 476 | if (((state->src.x1 >> 16) & (hsub - 1)) || | ||
| 477 | ((state->src.y1 >> 16) & (vsub - 1))) | ||
| 478 | return -EINVAL; | 475 | return -EINVAL; |
| 479 | break; | 476 | break; |
| 480 | case DRM_FORMAT_RGB565_A8: | 477 | case DRM_FORMAT_RGB565_A8: |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | int lima_sched_timeout_ms; | 18 | int lima_sched_timeout_ms; |
| 19 | 19 | ||
| 20 | MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms (0 = no timeout (default))"); | 20 | MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); |
| 21 | module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); | 21 | module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); |
| 22 | 22 | ||
| 23 | static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) | 23 | static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) |
| @@ -64,7 +64,13 @@ static irqreturn_t lima_pp_bcast_irq_handler(int irq, void *data) · 63 unmodified lines | |||
| 64 | struct lima_ip *pp_bcast = data; | 64 | struct lima_ip *pp_bcast = data; |
| 65 | struct lima_device *dev = pp_bcast->dev; | 65 | struct lima_device *dev = pp_bcast->dev; |
| 66 | struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; | 66 | struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; |
| 67 | struct drm_lima_m450_pp_frame *frame = pipe->current_task->frame; | 67 | struct drm_lima_m450_pp_frame *frame; |
| 68 | |||
| 69 | /* for shared irq case */ | ||
| 70 | if (!pipe->current_task) | ||
| 71 | return IRQ_NONE; | ||
| 72 | |||
| 73 | frame = pipe->current_task->frame; | ||
| 68 | 74 | ||
| 69 | for (i = 0; i < frame->num_pp; i++) { | 75 | for (i = 0; i < frame->num_pp; i++) { |
| 70 | struct lima_ip *ip = pipe->processor[i]; | 76 | struct lima_ip *ip = pipe->processor[i]; |
| @@ -258,7 +258,7 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) · 257 unmodified lines | |||
| 258 | static void lima_sched_handle_error_task(struct lima_sched_pipe *pipe, | 258 | static void lima_sched_handle_error_task(struct lima_sched_pipe *pipe, |
| 259 | struct lima_sched_task *task) | 259 | struct lima_sched_task *task) |
| 260 | { | 260 | { |
| 261 | drm_sched_stop(&pipe->base); | 261 | drm_sched_stop(&pipe->base, &task->base); |
| 262 | 262 | ||
| 263 | if (task) | 263 | if (task) |
| 264 | drm_sched_increase_karma(&task->base); | 264 | drm_sched_increase_karma(&task->base); |
| @@ -329,19 +329,16 @@ static void lima_sched_error_work(struct work_struct *work) · 64 unmodified lines | |||
| 329 | 329 | ||
| 330 | int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) | 330 | int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) |
| 331 | { | 331 | { |
| 332 | long timeout; | 332 | unsigned int timeout = lima_sched_timeout_ms > 0 ? |
| 333 | 333 | lima_sched_timeout_ms : 500; | |
| 334 | if (lima_sched_timeout_ms <= 0) | ||
| 335 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
| 336 | else | ||
| 337 | timeout = msecs_to_jiffies(lima_sched_timeout_ms); | ||
| 338 | 334 | ||
| 339 | pipe->fence_context = dma_fence_context_alloc(1); | 335 | pipe->fence_context = dma_fence_context_alloc(1); |
| 340 | spin_lock_init(&pipe->fence_lock); | 336 | spin_lock_init(&pipe->fence_lock); |
| 341 | 337 | ||
| 342 | INIT_WORK(&pipe->error_work, lima_sched_error_work); | 338 | INIT_WORK(&pipe->error_work, lima_sched_error_work); |
| 343 | 339 | ||
| 344 | return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, timeout, name); | 340 | return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, |
| 341 | msecs_to_jiffies(timeout), name); | ||
| 345 | } | 342 | } |
| 346 | 343 | ||
| 347 | void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) | 344 | void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) |
| @@ -32,10 +32,11 @@ static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev, · 31 unmodified lines | |||
| 32 | const struct drm_mode_fb_cmd2 *mode, | 32 | const struct drm_mode_fb_cmd2 *mode, |
| 33 | struct drm_gem_object *obj) | 33 | struct drm_gem_object *obj) |
| 34 | { | 34 | { |
| 35 | const struct drm_format_info *info = drm_get_format_info(dev, mode); | ||
| 35 | struct drm_framebuffer *fb; | 36 | struct drm_framebuffer *fb; |
| 36 | int ret; | 37 | int ret; |
| 37 | 38 | ||
| 38 | if (drm_format_num_planes(mode->pixel_format) != 1) | 39 | if (info->num_planes != 1) |
| 39 | return ERR_PTR(-EINVAL); | 40 | return ERR_PTR(-EINVAL); |
| 40 | 41 | ||
| 41 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); | 42 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); |
| @@ -88,6 +89,7 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, · 46 unmodified lines | |||
| 88 | struct drm_file *file, | 89 | struct drm_file *file, |
| 89 | const struct drm_mode_fb_cmd2 *cmd) | 90 | const struct drm_mode_fb_cmd2 *cmd) |
| 90 | { | 91 | { |
| 92 | const struct drm_format_info *info = drm_get_format_info(dev, cmd); | ||
| 91 | struct drm_framebuffer *fb; | 93 | struct drm_framebuffer *fb; |
| 92 | struct drm_gem_object *gem; | 94 | struct drm_gem_object *gem; |
| 93 | unsigned int width = cmd->width; | 95 | unsigned int width = cmd->width; |
| @@ -95,14 +97,14 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, · 1 unmodified line | |||
| 95 | unsigned int size, bpp; | 97 | unsigned int size, bpp; |
| 96 | int ret; | 98 | int ret; |
| 97 | 99 | ||
| 98 | if (drm_format_num_planes(cmd->pixel_format) != 1) | 100 | if (info->num_planes != 1) |
| 99 | return ERR_PTR(-EINVAL); | 101 | return ERR_PTR(-EINVAL); |
| 100 | 102 | ||
| 101 | gem = drm_gem_object_lookup(file, cmd->handles[0]); | 103 | gem = drm_gem_object_lookup(file, cmd->handles[0]); |
| 102 | if (!gem) | 104 | if (!gem) |
| 103 | return ERR_PTR(-ENOENT); | 105 | return ERR_PTR(-ENOENT); |
| 104 | 106 | ||
| 105 | bpp = drm_format_plane_cpp(cmd->pixel_format, 0); | 107 | bpp = info->cpp[0]; |
| 106 | size = (height - 1) * cmd->pitches[0] + width * bpp; | 108 | size = (height - 1) * cmd->pitches[0] + width * bpp; |
| 107 | size += cmd->offsets[0]; | 109 | size += cmd->offsets[0]; |
| 108 | 110 | ||
| @@ -341,6 +341,9 @@ static void mtk_hdmi_hw_send_info_frame(struct mtk_hdmi *hdmi, u8 *buffer, · 340 unmodified lines | |||
| 341 | ctrl_frame_en = VS_EN; | 341 | ctrl_frame_en = VS_EN; |
| 342 | ctrl_reg = GRL_ACP_ISRC_CTRL; | 342 | ctrl_reg = GRL_ACP_ISRC_CTRL; |
| 343 | break; | 343 | break; |
| 344 | default: | ||
| 345 | dev_err(hdmi->dev, "Unknown infoframe type %d\n", frame_type); | ||
| 346 | return; | ||
| 344 | } | 347 | } |
| 345 | mtk_hdmi_clear_bits(hdmi, ctrl_reg, ctrl_frame_en); | 348 | mtk_hdmi_clear_bits(hdmi, ctrl_reg, ctrl_frame_en); |
| 346 | mtk_hdmi_write(hdmi, GRL_INFOFRM_TYPE, frame_type); | 349 | mtk_hdmi_write(hdmi, GRL_INFOFRM_TYPE, frame_type); |
| @@ -458,7 +458,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, · 457 unmodified lines | |||
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | /* Update Canvas with buffer address */ | 460 | /* Update Canvas with buffer address */ |
| 461 | priv->viu.vd1_planes = drm_format_num_planes(fb->format->format); | 461 | priv->viu.vd1_planes = fb->format->num_planes; |
| 462 | 462 | ||
| 463 | switch (priv->viu.vd1_planes) { | 463 | switch (priv->viu.vd1_planes) { |
| 464 | case 3: | 464 | case 3: |
| @@ -466,8 +466,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, · 1 unmodified line | |||
| 466 | priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2]; | 466 | priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2]; |
| 467 | priv->viu.vd1_stride2 = fb->pitches[2]; | 467 | priv->viu.vd1_stride2 = fb->pitches[2]; |
| 468 | priv->viu.vd1_height2 = | 468 | priv->viu.vd1_height2 = |
| 469 | drm_format_plane_height(fb->height, | 469 | drm_format_info_plane_height(fb->format, |
| 470 | fb->format->format, 2); | 470 | fb->height, 2); |
| 471 | DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n", | 471 | DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n", |
| 472 | priv->viu.vd1_addr2, | 472 | priv->viu.vd1_addr2, |
| 473 | priv->viu.vd1_stride2, | 473 | priv->viu.vd1_stride2, |
| @@ -478,8 +478,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, · 4 unmodified lines | |||
| 478 | priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1]; | 478 | priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1]; |
| 479 | priv->viu.vd1_stride1 = fb->pitches[1]; | 479 | priv->viu.vd1_stride1 = fb->pitches[1]; |
| 480 | priv->viu.vd1_height1 = | 480 | priv->viu.vd1_height1 = |
| 481 | drm_format_plane_height(fb->height, | 481 | drm_format_info_plane_height(fb->format, |
| 482 | fb->format->format, 1); | 482 | fb->height, 1); |
| 483 | DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n", | 483 | DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n", |
| 484 | priv->viu.vd1_addr1, | 484 | priv->viu.vd1_addr1, |
| 485 | priv->viu.vd1_stride1, | 485 | priv->viu.vd1_stride1, |
| @@ -490,8 +490,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, · 4 unmodified lines | |||
| 490 | priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0]; | 490 | priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0]; |
| 491 | priv->viu.vd1_stride0 = fb->pitches[0]; | 491 | priv->viu.vd1_stride0 = fb->pitches[0]; |
| 492 | priv->viu.vd1_height0 = | 492 | priv->viu.vd1_height0 = |
| 493 | drm_format_plane_height(fb->height, | 493 | drm_format_info_plane_height(fb->format, |
| 494 | fb->format->format, 0); | 494 | fb->height, 0); |
| 495 | DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n", | 495 | DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n", |
| 496 | priv->viu.vd1_addr0, | 496 | priv->viu.vd1_addr0, |
| 497 | priv->viu.vd1_stride0, | 497 | priv->viu.vd1_stride0, |
| @@ -3,7 +3,7 @@ config DRM_MGAG200 · 2 unmodified lines | |||
| 3 | tristate "Kernel modesetting driver for MGA G200 server engines" | 3 | tristate "Kernel modesetting driver for MGA G200 server engines" |
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 6 | select DRM_TTM | 6 | select DRM_VRAM_HELPER |
| 7 | help | 7 | help |
| 8 | This is a KMS driver for the MGA G200 server chips, it | 8 | This is a KMS driver for the MGA G200 server chips, it |
| 9 | does not support the original MGA G200 or any of the desktop | 9 | does not support the original MGA G200 or any of the desktop |
| @@ -23,9 +23,9 @@ static void mga_hide_cursor(struct mga_device *mdev) · 22 unmodified lines | |||
| 23 | WREG8(MGA_CURPOSXL, 0); | 23 | WREG8(MGA_CURPOSXL, 0); |
| 24 | WREG8(MGA_CURPOSXH, 0); | 24 | WREG8(MGA_CURPOSXH, 0); |
| 25 | if (mdev->cursor.pixels_1->pin_count) | 25 | if (mdev->cursor.pixels_1->pin_count) |
| 26 | mgag200_bo_unpin(mdev->cursor.pixels_1); | 26 | drm_gem_vram_unpin_locked(mdev->cursor.pixels_1); |
| 27 | if (mdev->cursor.pixels_2->pin_count) | 27 | if (mdev->cursor.pixels_2->pin_count) |
| 28 | mgag200_bo_unpin(mdev->cursor.pixels_2); | 28 | drm_gem_vram_unpin_locked(mdev->cursor.pixels_2); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | int mga_crtc_cursor_set(struct drm_crtc *crtc, | 31 | int mga_crtc_cursor_set(struct drm_crtc *crtc, |
| @@ -36,13 +36,14 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, · 4 unmodified lines | |||
| 36 | { | 36 | { |
| 37 | struct drm_device *dev = crtc->dev; | 37 | struct drm_device *dev = crtc->dev; |
| 38 | struct mga_device *mdev = (struct mga_device *)dev->dev_private; | 38 | struct mga_device *mdev = (struct mga_device *)dev->dev_private; |
| 39 | struct mgag200_bo *pixels_1 = mdev->cursor.pixels_1; | 39 | struct drm_gem_vram_object *pixels_1 = mdev->cursor.pixels_1; |
| 40 | struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2; | 40 | struct drm_gem_vram_object *pixels_2 = mdev->cursor.pixels_2; |
| 41 | struct mgag200_bo *pixels_current = mdev->cursor.pixels_current; | 41 | struct drm_gem_vram_object *pixels_current = mdev->cursor.pixels_current; |
| 42 | struct mgag200_bo *pixels_prev = mdev->cursor.pixels_prev; | 42 | struct drm_gem_vram_object *pixels_prev = mdev->cursor.pixels_prev; |
| 43 | struct drm_gem_object *obj; | 43 | struct drm_gem_object *obj; |
| 44 | struct mgag200_bo *bo = NULL; | 44 | struct drm_gem_vram_object *gbo = NULL; |
| 45 | int ret = 0; | 45 | int ret = 0; |
| 46 | u8 *src, *dst; | ||
| 46 | unsigned int i, row, col; | 47 | unsigned int i, row, col; |
| 47 | uint32_t colour_set[16]; | 48 | uint32_t colour_set[16]; |
| 48 | uint32_t *next_space = &colour_set[0]; | 49 | uint32_t *next_space = &colour_set[0]; |
| @@ -50,7 +51,7 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, · 1 unmodified line | |||
| 50 | uint32_t this_colour; | 51 | uint32_t this_colour; |
| 51 | bool found = false; | 52 | bool found = false; |
| 52 | int colour_count = 0; | 53 | int colour_count = 0; |
| 53 | u64 gpu_addr; | 54 | s64 gpu_addr; |
| 54 | u8 reg_index; | 55 | u8 reg_index; |
| 55 | u8 this_row[48]; | 56 | u8 this_row[48]; |
| 56 | 57 | ||
| @@ -79,54 +80,66 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, · 22 unmodified lines | |||
| 79 | if (!obj) | 80 | if (!obj) |
| 80 | return -ENOENT; | 81 | return -ENOENT; |
| 81 | 82 | ||
| 82 | ret = mgag200_bo_reserve(pixels_1, true); | 83 | ret = drm_gem_vram_lock(pixels_1, true); |
| 83 | if (ret) { | 84 | if (ret) { |
| 84 | WREG8(MGA_CURPOSXL, 0); | 85 | WREG8(MGA_CURPOSXL, 0); |
| 85 | WREG8(MGA_CURPOSXH, 0); | 86 | WREG8(MGA_CURPOSXH, 0); |
| 86 | goto out_unref; | 87 | goto out_unref; |
| 87 | } | 88 | } |
| 88 | ret = mgag200_bo_reserve(pixels_2, true); | 89 | ret = drm_gem_vram_lock(pixels_2, true); |
| 89 | if (ret) { | 90 | if (ret) { |
| 90 | WREG8(MGA_CURPOSXL, 0); | 91 | WREG8(MGA_CURPOSXL, 0); |
| 91 | WREG8(MGA_CURPOSXH, 0); | 92 | WREG8(MGA_CURPOSXH, 0); |
| 92 | mgag200_bo_unreserve(pixels_1); | 93 | drm_gem_vram_unlock(pixels_1); |
| 93 | goto out_unreserve1; | 94 | goto out_unlock1; |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | /* Move cursor buffers into VRAM if they aren't already */ | 97 | /* Move cursor buffers into VRAM if they aren't already */ |
| 97 | if (!pixels_1->pin_count) { | 98 | if (!pixels_1->pin_count) { |
| 98 | ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM, | 99 | ret = drm_gem_vram_pin_locked(pixels_1, |
| 99 | &mdev->cursor.pixels_1_gpu_addr); | 100 | DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 100 | if (ret) | 101 | if (ret) |
| 101 | goto out1; | 102 | goto out1; |
| 103 | gpu_addr = drm_gem_vram_offset(pixels_1); | ||
| 104 | if (gpu_addr < 0) { | ||
| 105 | drm_gem_vram_unpin_locked(pixels_1); | ||
| 106 | goto out1; | ||
| 107 | } | ||
| 108 | mdev->cursor.pixels_1_gpu_addr = gpu_addr; | ||
| 102 | } | 109 | } |
| 103 | if (!pixels_2->pin_count) { | 110 | if (!pixels_2->pin_count) { |
| 104 | ret = mgag200_bo_pin(pixels_2, TTM_PL_FLAG_VRAM, | 111 | ret = drm_gem_vram_pin_locked(pixels_2, |
| 105 | &mdev->cursor.pixels_2_gpu_addr); | 112 | DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 106 | if (ret) { | 113 | if (ret) { |
| 107 | mgag200_bo_unpin(pixels_1); | 114 | drm_gem_vram_unpin_locked(pixels_1); |
| 108 | goto out1; | 115 | goto out1; |
| 109 | } | 116 | } |
| 117 | gpu_addr = drm_gem_vram_offset(pixels_2); | ||
| 118 | if (gpu_addr < 0) { | ||
| 119 | drm_gem_vram_unpin_locked(pixels_1); | ||
| 120 | drm_gem_vram_unpin_locked(pixels_2); | ||
| 121 | goto out1; | ||
| 122 | } | ||
| 123 | mdev->cursor.pixels_2_gpu_addr = gpu_addr; | ||
| 110 | } | 124 | } |
| 111 | 125 | ||
| 112 | bo = gem_to_mga_bo(obj); | 126 | gbo = drm_gem_vram_of_gem(obj); |
| 113 | ret = mgag200_bo_reserve(bo, true); | 127 | ret = drm_gem_vram_lock(gbo, true); |
| 114 | if (ret) { | 128 | if (ret) { |
| 115 | dev_err(&dev->pdev->dev, "failed to reserve user bo\n"); | 129 | dev_err(&dev->pdev->dev, "failed to lock user bo\n"); |
| 116 | goto out1; | 130 | goto out1; |
| 117 | } | 131 | } |
| 118 | if (!bo->kmap.virtual) { | 132 | src = drm_gem_vram_kmap(gbo, true, NULL); |
| 119 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 133 | if (IS_ERR(src)) { |
| 120 | if (ret) { | 134 | ret = PTR_ERR(src); |
| 121 | dev_err(&dev->pdev->dev, "failed to kmap user buffer updates\n"); | 135 | dev_err(&dev->pdev->dev, "failed to kmap user buffer updates\n"); |
| 122 | goto out2; | 136 | goto out2; |
| 123 | } | ||
| 124 | } | 137 | } |
| 125 | 138 | ||
| 126 | memset(&colour_set[0], 0, sizeof(uint32_t)*16); | 139 | memset(&colour_set[0], 0, sizeof(uint32_t)*16); |
| 127 | /* width*height*4 = 16384 */ | 140 | /* width*height*4 = 16384 */ |
| 128 | for (i = 0; i < 16384; i += 4) { | 141 | for (i = 0; i < 16384; i += 4) { |
| 129 | this_colour = ioread32(bo->kmap.virtual + i); | 142 | this_colour = ioread32(src + i); |
| 130 | /* No transparency */ | 143 | /* No transparency */ |
| 131 | if (this_colour>>24 != 0xff && | 144 | if (this_colour>>24 != 0xff && |
| 132 | this_colour>>24 != 0x0) { | 145 | this_colour>>24 != 0x0) { |
| @@ -178,21 +191,18 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, · 45 unmodified lines | |||
| 178 | } | 191 | } |
| 179 | 192 | ||
| 180 | /* Map up-coming buffer to write colour indices */ | 193 | /* Map up-coming buffer to write colour indices */ |
| 181 | if (!pixels_prev->kmap.virtual) { | 194 | dst = drm_gem_vram_kmap(pixels_prev, true, NULL); |
| 182 | ret = ttm_bo_kmap(&pixels_prev->bo, 0, | 195 | if (IS_ERR(dst)) { |
| 183 | pixels_prev->bo.num_pages, | 196 | ret = PTR_ERR(dst); |
| 184 | &pixels_prev->kmap); | 197 | dev_err(&dev->pdev->dev, "failed to kmap cursor updates\n"); |
| 185 | if (ret) { | 198 | goto out3; |
| 186 | dev_err(&dev->pdev->dev, "failed to kmap cursor updates\n"); | ||
| 187 | goto out3; | ||
| 188 | } | ||
| 189 | } | 199 | } |
| 190 | 200 | ||
| 191 | /* now write colour indices into hardware cursor buffer */ | 201 | /* now write colour indices into hardware cursor buffer */ |
| 192 | for (row = 0; row < 64; row++) { | 202 | for (row = 0; row < 64; row++) { |
| 193 | memset(&this_row[0], 0, 48); | 203 | memset(&this_row[0], 0, 48); |
| 194 | for (col = 0; col < 64; col++) { | 204 | for (col = 0; col < 64; col++) { |
| 195 | this_colour = ioread32(bo->kmap.virtual + 4*(col + 64*row)); | 205 | this_colour = ioread32(src + 4*(col + 64*row)); |
| 196 | /* write transparent pixels */ | 206 | /* write transparent pixels */ |
| 197 | if (this_colour>>24 == 0x0) { | 207 | if (this_colour>>24 == 0x0) { |
| 198 | this_row[47 - col/8] |= 0x80>>(col%8); | 208 | this_row[47 - col/8] |= 0x80>>(col%8); |
| @@ -210,7 +220,7 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, · 11 unmodified lines | |||
| 210 | } | 220 | } |
| 211 | } | 221 | } |
| 212 | } | 222 | } |
| 213 | memcpy_toio(pixels_prev->kmap.virtual + row*48, &this_row[0], 48); | 223 | memcpy_toio(dst + row*48, &this_row[0], 48); |
| 214 | } | 224 | } |
| 215 | 225 | ||
| 216 | /* Program gpu address of cursor buffer */ | 226 | /* Program gpu address of cursor buffer */ |
| @@ -236,17 +246,17 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, · 19 unmodified lines | |||
| 236 | } | 246 | } |
| 237 | ret = 0; | 247 | ret = 0; |
| 238 | 248 | ||
| 239 | ttm_bo_kunmap(&pixels_prev->kmap); | 249 | drm_gem_vram_kunmap(pixels_prev); |
| 240 | out3: | 250 | out3: |
| 241 | ttm_bo_kunmap(&bo->kmap); | 251 | drm_gem_vram_kunmap(gbo); |
| 242 | out2: | 252 | out2: |
| 243 | mgag200_bo_unreserve(bo); | 253 | drm_gem_vram_unlock(gbo); |
| 244 | out1: | 254 | out1: |
| 245 | if (ret) | 255 | if (ret) |
| 246 | mga_hide_cursor(mdev); | 256 | mga_hide_cursor(mdev); |
| 247 | mgag200_bo_unreserve(pixels_1); | 257 | drm_gem_vram_unlock(pixels_1); |
| 248 | out_unreserve1: | 258 | out_unlock1: |
| 249 | mgag200_bo_unreserve(pixels_2); | 259 | drm_gem_vram_unlock(pixels_2); |
| 250 | out_unref: | 260 | out_unref: |
| 251 | drm_gem_object_put_unlocked(obj); | 261 | drm_gem_object_put_unlocked(obj); |
| 252 | 262 | ||
| @@ -59,13 +59,7 @@ static void mga_pci_remove(struct pci_dev *pdev) · 58 unmodified lines | |||
| 59 | 59 | ||
| 60 | static const struct file_operations mgag200_driver_fops = { | 60 | static const struct file_operations mgag200_driver_fops = { |
| 61 | .owner = THIS_MODULE, | 61 | .owner = THIS_MODULE, |
| 62 | .open = drm_open, | 62 | DRM_VRAM_MM_FILE_OPERATIONS |
| 63 | .release = drm_release, | ||
| 64 | .unlocked_ioctl = drm_ioctl, | ||
| 65 | .mmap = mgag200_mmap, | ||
| 66 | .poll = drm_poll, | ||
| 67 | .compat_ioctl = drm_compat_ioctl, | ||
| 68 | .read = drm_read, | ||
| 69 | }; | 63 | }; |
| 70 | 64 | ||
| 71 | static struct drm_driver driver = { | 65 | static struct drm_driver driver = { |
| @@ -79,10 +73,7 @@ static struct drm_driver driver = { · 7 unmodified lines | |||
| 79 | .major = DRIVER_MAJOR, | 73 | .major = DRIVER_MAJOR, |
| 80 | .minor = DRIVER_MINOR, | 74 | .minor = DRIVER_MINOR, |
| 81 | .patchlevel = DRIVER_PATCHLEVEL, | 75 | .patchlevel = DRIVER_PATCHLEVEL, |
| 82 | 76 | DRM_GEM_VRAM_DRIVER | |
| 83 | .gem_free_object_unlocked = mgag200_gem_free_object, | ||
| 84 | .dumb_create = mgag200_dumb_create, | ||
| 85 | .dumb_map_offset = mgag200_dumb_mmap_offset, | ||
| 86 | }; | 77 | }; |
| 87 | 78 | ||
| 88 | static struct pci_driver mgag200_pci_driver = { | 79 | static struct pci_driver mgag200_pci_driver = { |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2010 Matt Turner. | 2 | * Copyright 2010 Matt Turner. |
| 3 | * Copyright 2012 Red Hat | 3 | * Copyright 2012 Red Hat |
| 4 | * | 4 | * |
| 5 | * This file is subject to the terms and conditions of the GNU General | 5 | * This file is subject to the terms and conditions of the GNU General |
| 6 | * Public License version 2. See the file COPYING in the main | 6 | * Public License version 2. See the file COPYING in the main |
| @@ -17,13 +17,11 @@ · 10 unmodified lines | |||
| 17 | 17 | ||
| 18 | #include <drm/drm_encoder.h> | 18 | #include <drm/drm_encoder.h> |
| 19 | #include <drm/drm_fb_helper.h> | 19 | #include <drm/drm_fb_helper.h> |
| 20 | #include <drm/ttm/ttm_bo_api.h> | ||
| 21 | #include <drm/ttm/ttm_bo_driver.h> | ||
| 22 | #include <drm/ttm/ttm_placement.h> | ||
| 23 | #include <drm/ttm/ttm_memory.h> | ||
| 24 | #include <drm/ttm/ttm_module.h> | ||
| 25 | 20 | ||
| 26 | #include <drm/drm_gem.h> | 21 | #include <drm/drm_gem.h> |
| 22 | #include <drm/drm_gem_vram_helper.h> | ||
| 23 | |||
| 24 | #include <drm/drm_vram_mm_helper.h> | ||
| 27 | 25 | ||
| 28 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
| 29 | #include <linux/i2c-algo-bit.h> | 27 | #include <linux/i2c-algo-bit.h> |
| @@ -117,7 +115,6 @@ struct mga_fbdev { · 87 unmodified lines | |||
| 117 | struct mga_framebuffer mfb; | 115 | struct mga_framebuffer mfb; |
| 118 | void *sysram; | 116 | void *sysram; |
| 119 | int size; | 117 | int size; |
| 120 | struct ttm_bo_kmap_obj mapping; | ||
| 121 | int x1, y1, x2, y2; /* dirty rect */ | 118 | int x1, y1, x2, y2; /* dirty rect */ |
| 122 | spinlock_t dirty_lock; | 119 | spinlock_t dirty_lock; |
| 123 | }; | 120 | }; |
| @@ -159,13 +156,13 @@ struct mga_cursor { · 35 unmodified lines | |||
| 159 | If either of these is NULL, then don't do hardware cursors, and | 156 | If either of these is NULL, then don't do hardware cursors, and |
| 160 | fall back to software. | 157 | fall back to software. |
| 161 | */ | 158 | */ |
| 162 | struct mgag200_bo *pixels_1; | 159 | struct drm_gem_vram_object *pixels_1; |
| 163 | struct mgag200_bo *pixels_2; | 160 | struct drm_gem_vram_object *pixels_2; |
| 164 | u64 pixels_1_gpu_addr, pixels_2_gpu_addr; | 161 | u64 pixels_1_gpu_addr, pixels_2_gpu_addr; |
| 165 | /* The currently displayed icon, this points to one of pixels_1, or pixels_2 */ | 162 | /* The currently displayed icon, this points to one of pixels_1, or pixels_2 */ |
| 166 | struct mgag200_bo *pixels_current; | 163 | struct drm_gem_vram_object *pixels_current; |
| 167 | /* The previously displayed icon */ | 164 | /* The previously displayed icon */ |
| 168 | struct mgag200_bo *pixels_prev; | 165 | struct drm_gem_vram_object *pixels_prev; |
| 169 | }; | 166 | }; |
| 170 | 167 | ||
| 171 | struct mga_mc { | 168 | struct mga_mc { |
| @@ -211,31 +208,10 @@ struct mga_device { · 39 unmodified lines | |||
| 211 | 208 | ||
| 212 | int fb_mtrr; | 209 | int fb_mtrr; |
| 213 | 210 | ||
| 214 | struct { | ||
| 215 | struct ttm_bo_device bdev; | ||
| 216 | } ttm; | ||
| 217 | |||
| 218 | /* SE model number stored in reg 0x1e24 */ | 211 | /* SE model number stored in reg 0x1e24 */ |
| 219 | u32 unique_rev_id; | 212 | u32 unique_rev_id; |
| 220 | }; | 213 | }; |
| 221 | 214 | ||
| 222 | |||
| 223 | struct mgag200_bo { | ||
| 224 | struct ttm_buffer_object bo; | ||
| 225 | struct ttm_placement placement; | ||
| 226 | struct ttm_bo_kmap_obj kmap; | ||
| 227 | struct drm_gem_object gem; | ||
| 228 | struct ttm_place placements[3]; | ||
| 229 | int pin_count; | ||
| 230 | }; | ||
| 231 | #define gem_to_mga_bo(gobj) container_of((gobj), struct mgag200_bo, gem) | ||
| 232 | |||
| 233 | static inline struct mgag200_bo * | ||
| 234 | mgag200_bo(struct ttm_buffer_object *bo) | ||
| 235 | { | ||
| 236 | return container_of(bo, struct mgag200_bo, bo); | ||
| 237 | } | ||
| 238 | |||
| 239 | /* mgag200_mode.c */ | 215 | /* mgag200_mode.c */ |
| 240 | int mgag200_modeset_init(struct mga_device *mdev); | 216 | int mgag200_modeset_init(struct mga_device *mdev); |
| 241 | void mgag200_modeset_fini(struct mga_device *mdev); | 217 | void mgag200_modeset_fini(struct mga_device *mdev); |
| @@ -259,45 +235,15 @@ int mgag200_gem_create(struct drm_device *dev, · 17 unmodified lines | |||
| 259 | int mgag200_dumb_create(struct drm_file *file, | 235 | int mgag200_dumb_create(struct drm_file *file, |
| 260 | struct drm_device *dev, | 236 | struct drm_device *dev, |
| 261 | struct drm_mode_create_dumb *args); | 237 | struct drm_mode_create_dumb *args); |
| 262 | void mgag200_gem_free_object(struct drm_gem_object *obj); | 238 | |
| 263 | int | ||
| 264 | mgag200_dumb_mmap_offset(struct drm_file *file, | ||
| 265 | struct drm_device *dev, | ||
| 266 | uint32_t handle, | ||
| 267 | uint64_t *offset); | ||
| 268 | /* mgag200_i2c.c */ | 239 | /* mgag200_i2c.c */ |
| 269 | struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev); | 240 | struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev); |
| 270 | void mgag200_i2c_destroy(struct mga_i2c_chan *i2c); | 241 | void mgag200_i2c_destroy(struct mga_i2c_chan *i2c); |
| 271 | 242 | ||
| 272 | void mgag200_ttm_placement(struct mgag200_bo *bo, int domain); | ||
| 273 | |||
| 274 | static inline int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait) | ||
| 275 | { | ||
| 276 | int ret; | ||
| 277 | |||
| 278 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); | ||
| 279 | if (ret) { | ||
| 280 | if (ret != -ERESTARTSYS && ret != -EBUSY) | ||
| 281 | DRM_ERROR("reserve failed %p\n", bo); | ||
| 282 | return ret; | ||
| 283 | } | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static inline void mgag200_bo_unreserve(struct mgag200_bo *bo) | ||
| 288 | { | ||
| 289 | ttm_bo_unreserve(&bo->bo); | ||
| 290 | } | ||
| 291 | |||
| 292 | int mgag200_bo_create(struct drm_device *dev, int size, int align, | ||
| 293 | uint32_t flags, struct mgag200_bo **pastbo); | ||
| 294 | int mgag200_mm_init(struct mga_device *mdev); | 243 | int mgag200_mm_init(struct mga_device *mdev); |
| 295 | void mgag200_mm_fini(struct mga_device *mdev); | 244 | void mgag200_mm_fini(struct mga_device *mdev); |
| 296 | int mgag200_mmap(struct file *filp, struct vm_area_struct *vma); | 245 | int mgag200_mmap(struct file *filp, struct vm_area_struct *vma); |
| 297 | int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr); | 246 | |
| 298 | int mgag200_bo_unpin(struct mgag200_bo *bo); | ||
| 299 | int mgag200_bo_push_sysram(struct mgag200_bo *bo); | ||
| 300 | /* mgag200_cursor.c */ | ||
| 301 | int mga_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | 247 | int mga_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, |
| 302 | uint32_t handle, uint32_t width, uint32_t height); | 248 | uint32_t handle, uint32_t width, uint32_t height); |
| 303 | int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); | 249 | int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); |
| @@ -23,25 +23,25 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev, · 22 unmodified lines | |||
| 23 | { | 23 | { |
| 24 | int i; | 24 | int i; |
| 25 | struct drm_gem_object *obj; | 25 | struct drm_gem_object *obj; |
| 26 | struct mgag200_bo *bo; | 26 | struct drm_gem_vram_object *gbo; |
| 27 | int src_offset, dst_offset; | 27 | int src_offset, dst_offset; |
| 28 | int bpp = mfbdev->mfb.base.format->cpp[0]; | 28 | int bpp = mfbdev->mfb.base.format->cpp[0]; |
| 29 | int ret = -EBUSY; | 29 | int ret = -EBUSY; |
| 30 | u8 *dst; | ||
| 30 | bool unmap = false; | 31 | bool unmap = false; |
| 31 | bool store_for_later = false; | 32 | bool store_for_later = false; |
| 32 | int x2, y2; | 33 | int x2, y2; |
| 33 | unsigned long flags; | 34 | unsigned long flags; |
| 34 | 35 | ||
| 35 | obj = mfbdev->mfb.obj; | 36 | obj = mfbdev->mfb.obj; |
| 36 | bo = gem_to_mga_bo(obj); | 37 | gbo = drm_gem_vram_of_gem(obj); |
| 37 | 38 | ||
| 38 | /* | 39 | /* Try to lock the BO. If we fail with -EBUSY then |
| 39 | * try and reserve the BO, if we fail with busy | 40 | * the BO is being moved and we should store up the |
| 40 | * then the BO is being moved and we should | 41 | * damage until later. |
| 41 | * store up the damage until later. | ||
| 42 | */ | 42 | */ |
| 43 | if (drm_can_sleep()) | 43 | if (drm_can_sleep()) |
| 44 | ret = mgag200_bo_reserve(bo, true); | 44 | ret = drm_gem_vram_lock(gbo, true); |
| 45 | if (ret) { | 45 | if (ret) { |
| 46 | if (ret != -EBUSY) | 46 | if (ret != -EBUSY) |
| 47 | return; | 47 | return; |
| @@ -75,25 +75,32 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev, · 27 unmodified lines | |||
| 75 | mfbdev->x2 = mfbdev->y2 = 0; | 75 | mfbdev->x2 = mfbdev->y2 = 0; |
| 76 | spin_unlock_irqrestore(&mfbdev->dirty_lock, flags); | 76 | spin_unlock_irqrestore(&mfbdev->dirty_lock, flags); |
| 77 | 77 | ||
| 78 | if (!bo->kmap.virtual) { | 78 | dst = drm_gem_vram_kmap(gbo, false, NULL); |
| 79 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 79 | if (IS_ERR(dst)) { |
| 80 | if (ret) { | 80 | DRM_ERROR("failed to kmap fb updates\n"); |
| 81 | goto out; | ||
| 82 | } else if (!dst) { | ||
| 83 | dst = drm_gem_vram_kmap(gbo, true, NULL); | ||
| 84 | if (IS_ERR(dst)) { | ||
| 81 | DRM_ERROR("failed to kmap fb updates\n"); | 85 | DRM_ERROR("failed to kmap fb updates\n"); |
| 82 | mgag200_bo_unreserve(bo); | 86 | goto out; |
| 83 | return; | ||
| 84 | } | 87 | } |
| 85 | unmap = true; | 88 | unmap = true; |
| 86 | } | 89 | } |
| 90 | |||
| 87 | for (i = y; i <= y2; i++) { | 91 | for (i = y; i <= y2; i++) { |
| 88 | /* assume equal stride for now */ | 92 | /* assume equal stride for now */ |
| 89 | src_offset = dst_offset = i * mfbdev->mfb.base.pitches[0] + (x * bpp); | 93 | src_offset = dst_offset = |
| 90 | memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, (x2 - x + 1) * bpp); | 94 | i * mfbdev->mfb.base.pitches[0] + (x * bpp); |
| 91 | 95 | memcpy_toio(dst + dst_offset, mfbdev->sysram + src_offset, | |
| 96 | (x2 - x + 1) * bpp); | ||
| 92 | } | 97 | } |
| 98 | |||
| 93 | if (unmap) | 99 | if (unmap) |
| 94 | ttm_bo_kunmap(&bo->kmap); | 100 | drm_gem_vram_kunmap(gbo); |
| 95 | 101 | ||
| 96 | mgag200_bo_unreserve(bo); | 102 | out: |
| 103 | drm_gem_vram_unlock(gbo); | ||
| 97 | } | 104 | } |
| 98 | 105 | ||
| 99 | static void mga_fillrect(struct fb_info *info, | 106 | static void mga_fillrect(struct fb_info *info, |
| @@ -230,11 +230,13 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags) · 229 unmodified lines | |||
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | /* Make small buffers to store a hardware cursor (double buffered icon updates) */ | 232 | /* Make small buffers to store a hardware cursor (double buffered icon updates) */ |
| 233 | mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0, | 233 | mdev->cursor.pixels_1 = drm_gem_vram_create(dev, &dev->vram_mm->bdev, |
| 234 | &mdev->cursor.pixels_1); | 234 | roundup(48*64, PAGE_SIZE), |
| 235 | mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0, | 235 | 0, 0); |
| 236 | &mdev->cursor.pixels_2); | 236 | mdev->cursor.pixels_2 = drm_gem_vram_create(dev, &dev->vram_mm->bdev, |
| 237 | if (!mdev->cursor.pixels_2 || !mdev->cursor.pixels_1) { | 237 | roundup(48*64, PAGE_SIZE), |
| 238 | 0, 0); | ||
| 239 | if (IS_ERR(mdev->cursor.pixels_2) || IS_ERR(mdev->cursor.pixels_1)) { | ||
| 238 | mdev->cursor.pixels_1 = NULL; | 240 | mdev->cursor.pixels_1 = NULL; |
| 239 | mdev->cursor.pixels_2 = NULL; | 241 | mdev->cursor.pixels_2 = NULL; |
| 240 | dev_warn(&dev->pdev->dev, | 242 | dev_warn(&dev->pdev->dev, |
| @@ -272,7 +274,7 @@ int mgag200_gem_create(struct drm_device *dev, · 31 unmodified lines | |||
| 272 | u32 size, bool iskernel, | 274 | u32 size, bool iskernel, |
| 273 | struct drm_gem_object **obj) | 275 | struct drm_gem_object **obj) |
| 274 | { | 276 | { |
| 275 | struct mgag200_bo *astbo; | 277 | struct drm_gem_vram_object *gbo; |
| 276 | int ret; | 278 | int ret; |
| 277 | 279 | ||
| 278 | *obj = NULL; | 280 | *obj = NULL; |
| @@ -281,78 +283,13 @@ int mgag200_gem_create(struct drm_device *dev, · 2 unmodified lines | |||
| 281 | if (size == 0) | 283 | if (size == 0) |
| 282 | return -EINVAL; | 284 | return -EINVAL; |
| 283 | 285 | ||
| 284 | ret = mgag200_bo_create(dev, size, 0, 0, &astbo); | 286 | gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); |
| 285 | if (ret) { | 287 | if (IS_ERR(gbo)) { |
| 288 | ret = PTR_ERR(gbo); | ||
| 286 | if (ret != -ERESTARTSYS) | 289 | if (ret != -ERESTARTSYS) |
| 287 | DRM_ERROR("failed to allocate GEM object\n"); | 290 | DRM_ERROR("failed to allocate GEM object\n"); |
| 288 | return ret; | 291 | return ret; |
| 289 | } | 292 | } |
| 290 | *obj = &astbo->gem; | 293 | *obj = &gbo->gem; |
| 291 | return 0; | ||
| 292 | } | ||
| 293 | |||
| 294 | int mgag200_dumb_create(struct drm_file *file, | ||
| 295 | struct drm_device *dev, | ||
| 296 | struct drm_mode_create_dumb *args) | ||
| 297 | { | ||
| 298 | int ret; | ||
| 299 | struct drm_gem_object *gobj; | ||
| 300 | u32 handle; | ||
| 301 | |||
| 302 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
| 303 | args->size = args->pitch * args->height; | ||
| 304 | |||
| 305 | ret = mgag200_gem_create(dev, args->size, false, | ||
| 306 | &gobj); | ||
| 307 | if (ret) | ||
| 308 | return ret; | ||
| 309 | |||
| 310 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
| 311 | drm_gem_object_put_unlocked(gobj); | ||
| 312 | if (ret) | ||
| 313 | return ret; | ||
| 314 | |||
| 315 | args->handle = handle; | ||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | static void mgag200_bo_unref(struct mgag200_bo **bo) | ||
| 320 | { | ||
| 321 | if ((*bo) == NULL) | ||
| 322 | return; | ||
| 323 | ttm_bo_put(&((*bo)->bo)); | ||
| 324 | *bo = NULL; | ||
| 325 | } | ||
| 326 | |||
| 327 | void mgag200_gem_free_object(struct drm_gem_object *obj) | ||
| 328 | { | ||
| 329 | struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj); | ||
| 330 | |||
| 331 | mgag200_bo_unref(&mgag200_bo); | ||
| 332 | } | ||
| 333 | |||
| 334 | |||
| 335 | static inline u64 mgag200_bo_mmap_offset(struct mgag200_bo *bo) | ||
| 336 | { | ||
| 337 | return drm_vma_node_offset_addr(&bo->bo.vma_node); | ||
| 338 | } | ||
| 339 | |||
| 340 | int | ||
| 341 | mgag200_dumb_mmap_offset(struct drm_file *file, | ||
| 342 | struct drm_device *dev, | ||
| 343 | uint32_t handle, | ||
| 344 | uint64_t *offset) | ||
| 345 | { | ||
| 346 | struct drm_gem_object *obj; | ||
| 347 | struct mgag200_bo *bo; | ||
| 348 | |||
| 349 | obj = drm_gem_object_lookup(file, handle); | ||
| 350 | if (obj == NULL) | ||
| 351 | return -ENOENT; | ||
| 352 | |||
| 353 | bo = gem_to_mga_bo(obj); | ||
| 354 | *offset = mgag200_bo_mmap_offset(bo); | ||
| 355 | |||
| 356 | drm_gem_object_put_unlocked(obj); | ||
| 357 | return 0; | 294 | return 0; |
| 358 | } | 295 | } |
| @@ -858,8 +858,6 @@ static void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) · 857 unmodified lines | |||
| 858 | WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0); | 858 | WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0); |
| 859 | } | 859 | } |
| 860 | 860 | ||
| 861 | |||
| 862 | /* ast is different - we will force move buffers out of VRAM */ | ||
| 863 | static int mga_crtc_do_set_base(struct drm_crtc *crtc, | 861 | static int mga_crtc_do_set_base(struct drm_crtc *crtc, |
| 864 | struct drm_framebuffer *fb, | 862 | struct drm_framebuffer *fb, |
| 865 | int x, int y, int atomic) | 863 | int x, int y, int atomic) |
| @@ -867,48 +865,51 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc, · 1 unmodified line | |||
| 867 | struct mga_device *mdev = crtc->dev->dev_private; | 865 | struct mga_device *mdev = crtc->dev->dev_private; |
| 868 | struct drm_gem_object *obj; | 866 | struct drm_gem_object *obj; |
| 869 | struct mga_framebuffer *mga_fb; | 867 | struct mga_framebuffer *mga_fb; |
| 870 | struct mgag200_bo *bo; | 868 | struct drm_gem_vram_object *gbo; |
| 871 | int ret; | 869 | int ret; |
| 872 | u64 gpu_addr; | 870 | s64 gpu_addr; |
| 871 | void *base; | ||
| 873 | 872 | ||
| 874 | /* push the previous fb to system ram */ | ||
| 875 | if (!atomic && fb) { | 873 | if (!atomic && fb) { |
| 876 | mga_fb = to_mga_framebuffer(fb); | 874 | mga_fb = to_mga_framebuffer(fb); |
| 877 | obj = mga_fb->obj; | 875 | obj = mga_fb->obj; |
| 878 | bo = gem_to_mga_bo(obj); | 876 | gbo = drm_gem_vram_of_gem(obj); |
| 879 | ret = mgag200_bo_reserve(bo, false); | 877 | |
| 880 | if (ret) | 878 | /* unmap if console */ |
| 881 | return ret; | 879 | if (&mdev->mfbdev->mfb == mga_fb) |
| 882 | mgag200_bo_push_sysram(bo); | 880 | drm_gem_vram_kunmap(gbo); |
| 883 | mgag200_bo_unreserve(bo); | 881 | drm_gem_vram_unpin(gbo); |
| 884 | } | 882 | } |
| 885 | 883 | ||
| 886 | mga_fb = to_mga_framebuffer(crtc->primary->fb); | 884 | mga_fb = to_mga_framebuffer(crtc->primary->fb); |
| 887 | obj = mga_fb->obj; | 885 | obj = mga_fb->obj; |
| 888 | bo = gem_to_mga_bo(obj); | 886 | gbo = drm_gem_vram_of_gem(obj); |
| 889 | 887 | ||
| 890 | ret = mgag200_bo_reserve(bo, false); | 888 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 891 | if (ret) | 889 | if (ret) |
| 892 | return ret; | 890 | return ret; |
| 893 | 891 | gpu_addr = drm_gem_vram_offset(gbo); | |
| 894 | ret = mgag200_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | 892 | if (gpu_addr < 0) { |
| 895 | if (ret) { | 893 | ret = (int)gpu_addr; |
| 896 | mgag200_bo_unreserve(bo); | 894 | goto err_drm_gem_vram_unpin; |
| 897 | return ret; | ||
| 898 | } | 895 | } |
| 899 | 896 | ||
| 900 | if (&mdev->mfbdev->mfb == mga_fb) { | 897 | if (&mdev->mfbdev->mfb == mga_fb) { |
| 901 | /* if pushing console in kmap it */ | 898 | /* if pushing console in kmap it */ |
| 902 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 899 | base = drm_gem_vram_kmap(gbo, true, NULL); |
| 903 | if (ret) | 900 | if (IS_ERR(base)) { |
| 901 | ret = PTR_ERR(base); | ||
| 904 | DRM_ERROR("failed to kmap fbcon\n"); | 902 | DRM_ERROR("failed to kmap fbcon\n"); |
| 905 | 903 | } | |
| 906 | } | 904 | } |
| 907 | mgag200_bo_unreserve(bo); | ||
| 908 | 905 | ||
| 909 | mga_set_start_address(crtc, (u32)gpu_addr); | 906 | mga_set_start_address(crtc, (u32)gpu_addr); |
| 910 | 907 | ||
| 911 | return 0; | 908 | return 0; |
| 909 | |||
| 910 | err_drm_gem_vram_unpin: | ||
| 911 | drm_gem_vram_unpin(gbo); | ||
| 912 | return ret; | ||
| 912 | } | 913 | } |
| 913 | 914 | ||
| 914 | static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | 915 | static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, |
| @@ -1422,18 +1423,18 @@ static void mga_crtc_destroy(struct drm_crtc *crtc) · 507 unmodified lines | |||
| 1422 | 1423 | ||
| 1423 | static void mga_crtc_disable(struct drm_crtc *crtc) | 1424 | static void mga_crtc_disable(struct drm_crtc *crtc) |
| 1424 | { | 1425 | { |
| 1425 | int ret; | ||
| 1426 | DRM_DEBUG_KMS("\n"); | 1426 | DRM_DEBUG_KMS("\n"); |
| 1427 | mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 1427 | mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
| 1428 | if (crtc->primary->fb) { | 1428 | if (crtc->primary->fb) { |
| 1429 | struct mga_device *mdev = crtc->dev->dev_private; | ||
| 1429 | struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->primary->fb); | 1430 | struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->primary->fb); |
| 1430 | struct drm_gem_object *obj = mga_fb->obj; | 1431 | struct drm_gem_object *obj = mga_fb->obj; |
| 1431 | struct mgag200_bo *bo = gem_to_mga_bo(obj); | 1432 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(obj); |
| 1432 | ret = mgag200_bo_reserve(bo, false); | 1433 | |
| 1433 | if (ret) | 1434 | /* unmap if console */ |
| 1434 | return; | 1435 | if (&mdev->mfbdev->mfb == mga_fb) |
| 1435 | mgag200_bo_push_sysram(bo); | 1436 | drm_gem_vram_kunmap(gbo); |
| 1436 | mgag200_bo_unreserve(bo); | 1437 | drm_gem_vram_unpin(gbo); |
| 1437 | } | 1438 | } |
| 1438 | crtc->primary->fb = NULL; | 1439 | crtc->primary->fb = NULL; |
| 1439 | } | 1440 | } |
| @@ -26,167 +26,21 @@ · 25 unmodified lines | |||
| 26 | * Authors: Dave Airlie <airlied@redhat.com> | 26 | * Authors: Dave Airlie <airlied@redhat.com> |
| 27 | */ | 27 | */ |
| 28 | #include <drm/drmP.h> | 28 | #include <drm/drmP.h> |
| 29 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 30 | 29 | ||
| 31 | #include "mgag200_drv.h" | 30 | #include "mgag200_drv.h" |
| 32 | 31 | ||
| 33 | static inline struct mga_device * | ||
| 34 | mgag200_bdev(struct ttm_bo_device *bd) | ||
| 35 | { | ||
| 36 | return container_of(bd, struct mga_device, ttm.bdev); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
| 40 | { | ||
| 41 | struct mgag200_bo *bo; | ||
| 42 | |||
| 43 | bo = container_of(tbo, struct mgag200_bo, bo); | ||
| 44 | |||
| 45 | drm_gem_object_release(&bo->gem); | ||
| 46 | kfree(bo); | ||
| 47 | } | ||
| 48 | |||
| 49 | static bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo) | ||
| 50 | { | ||
| 51 | if (bo->destroy == &mgag200_bo_ttm_destroy) | ||
| 52 | return true; | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int | ||
| 57 | mgag200_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | ||
| 58 | struct ttm_mem_type_manager *man) | ||
| 59 | { | ||
| 60 | switch (type) { | ||
| 61 | case TTM_PL_SYSTEM: | ||
| 62 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 63 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 64 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 65 | break; | ||
| 66 | case TTM_PL_VRAM: | ||
| 67 | man->func = &ttm_bo_manager_func; | ||
| 68 | man->flags = TTM_MEMTYPE_FLAG_FIXED | | ||
| 69 | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 70 | man->available_caching = TTM_PL_FLAG_UNCACHED | | ||
| 71 | TTM_PL_FLAG_WC; | ||
| 72 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | ||
| 76 | return -EINVAL; | ||
| 77 | } | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void | ||
| 82 | mgag200_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
| 83 | { | ||
| 84 | struct mgag200_bo *mgabo = mgag200_bo(bo); | ||
| 85 | |||
| 86 | if (!mgag200_ttm_bo_is_mgag200_bo(bo)) | ||
| 87 | return; | ||
| 88 | |||
| 89 | mgag200_ttm_placement(mgabo, TTM_PL_FLAG_SYSTEM); | ||
| 90 | *pl = mgabo->placement; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) | ||
| 94 | { | ||
| 95 | struct mgag200_bo *mgabo = mgag200_bo(bo); | ||
| 96 | |||
| 97 | return drm_vma_node_verify_access(&mgabo->gem.vma_node, | ||
| 98 | filp->private_data); | ||
| 99 | } | ||
| 100 | |||
| 101 | static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 102 | struct ttm_mem_reg *mem) | ||
| 103 | { | ||
| 104 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
| 105 | struct mga_device *mdev = mgag200_bdev(bdev); | ||
| 106 | |||
| 107 | mem->bus.addr = NULL; | ||
| 108 | mem->bus.offset = 0; | ||
| 109 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 110 | mem->bus.base = 0; | ||
| 111 | mem->bus.is_iomem = false; | ||
| 112 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 113 | return -EINVAL; | ||
| 114 | switch (mem->mem_type) { | ||
| 115 | case TTM_PL_SYSTEM: | ||
| 116 | /* system memory */ | ||
| 117 | return 0; | ||
| 118 | case TTM_PL_VRAM: | ||
| 119 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 120 | mem->bus.base = pci_resource_start(mdev->dev->pdev, 0); | ||
| 121 | mem->bus.is_iomem = true; | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | return -EINVAL; | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static void mgag200_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | ||
| 131 | { | ||
| 132 | } | ||
| 133 | |||
| 134 | static void mgag200_ttm_backend_destroy(struct ttm_tt *tt) | ||
| 135 | { | ||
| 136 | ttm_tt_fini(tt); | ||
| 137 | kfree(tt); | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct ttm_backend_func mgag200_tt_backend_func = { | ||
| 141 | .destroy = &mgag200_ttm_backend_destroy, | ||
| 142 | }; | ||
| 143 | |||
| 144 | |||
| 145 | static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 146 | uint32_t page_flags) | ||
| 147 | { | ||
| 148 | struct ttm_tt *tt; | ||
| 149 | |||
| 150 | tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); | ||
| 151 | if (tt == NULL) | ||
| 152 | return NULL; | ||
| 153 | tt->func = &mgag200_tt_backend_func; | ||
| 154 | if (ttm_tt_init(tt, bo, page_flags)) { | ||
| 155 | kfree(tt); | ||
| 156 | return NULL; | ||
| 157 | } | ||
| 158 | return tt; | ||
| 159 | } | ||
| 160 | |||
| 161 | struct ttm_bo_driver mgag200_bo_driver = { | ||
| 162 | .ttm_tt_create = mgag200_ttm_tt_create, | ||
| 163 | .init_mem_type = mgag200_bo_init_mem_type, | ||
| 164 | .eviction_valuable = ttm_bo_eviction_valuable, | ||
| 165 | .evict_flags = mgag200_bo_evict_flags, | ||
| 166 | .move = NULL, | ||
| 167 | .verify_access = mgag200_bo_verify_access, | ||
| 168 | .io_mem_reserve = &mgag200_ttm_io_mem_reserve, | ||
| 169 | .io_mem_free = &mgag200_ttm_io_mem_free, | ||
| 170 | }; | ||
| 171 | |||
| 172 | int mgag200_mm_init(struct mga_device *mdev) | 32 | int mgag200_mm_init(struct mga_device *mdev) |
| 173 | { | 33 | { |
| 34 | struct drm_vram_mm *vmm; | ||
| 174 | int ret; | 35 | int ret; |
| 175 | struct drm_device *dev = mdev->dev; | 36 | struct drm_device *dev = mdev->dev; |
| 176 | struct ttm_bo_device *bdev = &mdev->ttm.bdev; | ||
| 177 | |||
| 178 | ret = ttm_bo_device_init(&mdev->ttm.bdev, | ||
| 179 | &mgag200_bo_driver, | ||
| 180 | dev->anon_inode->i_mapping, | ||
| 181 | true); | ||
| 182 | if (ret) { | ||
| 183 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | 37 | ||
| 187 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, mdev->mc.vram_size >> PAGE_SHIFT); | 38 | vmm = drm_vram_helper_alloc_mm(dev, pci_resource_start(dev->pdev, 0), |
| 188 | if (ret) { | 39 | mdev->mc.vram_size, |
| 189 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | 40 | &drm_gem_vram_mm_funcs); |
| 41 | if (IS_ERR(vmm)) { | ||
| 42 | ret = PTR_ERR(vmm); | ||
| 43 | DRM_ERROR("Error initializing VRAM MM; %d\n", ret); | ||
| 190 | return ret; | 44 | return ret; |
| 191 | } | 45 | } |
| 192 | 46 | ||
| @@ -203,149 +57,10 @@ void mgag200_mm_fini(struct mga_device *mdev) · 10 unmodified lines | |||
| 203 | { | 57 | { |
| 204 | struct drm_device *dev = mdev->dev; | 58 | struct drm_device *dev = mdev->dev; |
| 205 | 59 | ||
| 206 | ttm_bo_device_release(&mdev->ttm.bdev); | 60 | drm_vram_helper_release_mm(dev); |
| 207 | 61 | ||
| 208 | arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), | 62 | arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), |
| 209 | pci_resource_len(dev->pdev, 0)); | 63 | pci_resource_len(dev->pdev, 0)); |
| 210 | arch_phys_wc_del(mdev->fb_mtrr); | 64 | arch_phys_wc_del(mdev->fb_mtrr); |
| 211 | mdev->fb_mtrr = 0; | 65 | mdev->fb_mtrr = 0; |
| 212 | } | 66 | } |
| 213 | |||
| 214 | void mgag200_ttm_placement(struct mgag200_bo *bo, int domain) | ||
| 215 | { | ||
| 216 | u32 c = 0; | ||
| 217 | unsigned i; | ||
| 218 | |||
| 219 | bo->placement.placement = bo->placements; | ||
| 220 | bo->placement.busy_placement = bo->placements; | ||
| 221 | if (domain & TTM_PL_FLAG_VRAM) | ||
| 222 | bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
| 223 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
| 224 | bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
| 225 | if (!c) | ||
| 226 | bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
| 227 | bo->placement.num_placement = c; | ||
| 228 | bo->placement.num_busy_placement = c; | ||
| 229 | for (i = 0; i < c; ++i) { | ||
| 230 | bo->placements[i].fpfn = 0; | ||
| 231 | bo->placements[i].lpfn = 0; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | int mgag200_bo_create(struct drm_device *dev, int size, int align, | ||
| 236 | uint32_t flags, struct mgag200_bo **pmgabo) | ||
| 237 | { | ||
| 238 | struct mga_device *mdev = dev->dev_private; | ||
| 239 | struct mgag200_bo *mgabo; | ||
| 240 | size_t acc_size; | ||
| 241 | int ret; | ||
| 242 | |||
| 243 | mgabo = kzalloc(sizeof(struct mgag200_bo), GFP_KERNEL); | ||
| 244 | if (!mgabo) | ||
| 245 | return -ENOMEM; | ||
| 246 | |||
| 247 | ret = drm_gem_object_init(dev, &mgabo->gem, size); | ||
| 248 | if (ret) { | ||
| 249 | kfree(mgabo); | ||
| 250 | return ret; | ||
| 251 | } | ||
| 252 | |||
| 253 | mgabo->bo.bdev = &mdev->ttm.bdev; | ||
| 254 | |||
| 255 | mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 256 | |||
| 257 | acc_size = ttm_bo_dma_acc_size(&mdev->ttm.bdev, size, | ||
| 258 | sizeof(struct mgag200_bo)); | ||
| 259 | |||
| 260 | ret = ttm_bo_init(&mdev->ttm.bdev, &mgabo->bo, size, | ||
| 261 | ttm_bo_type_device, &mgabo->placement, | ||
| 262 | align >> PAGE_SHIFT, false, acc_size, | ||
| 263 | NULL, NULL, mgag200_bo_ttm_destroy); | ||
| 264 | if (ret) | ||
| 265 | return ret; | ||
| 266 | |||
| 267 | *pmgabo = mgabo; | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | static inline u64 mgag200_bo_gpu_offset(struct mgag200_bo *bo) | ||
| 272 | { | ||
| 273 | return bo->bo.offset; | ||
| 274 | } | ||
| 275 | |||
| 276 | int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr) | ||
| 277 | { | ||
| 278 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 279 | int i, ret; | ||
| 280 | |||
| 281 | if (bo->pin_count) { | ||
| 282 | bo->pin_count++; | ||
| 283 | if (gpu_addr) | ||
| 284 | *gpu_addr = mgag200_bo_gpu_offset(bo); | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | mgag200_ttm_placement(bo, pl_flag); | ||
| 289 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 290 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 291 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 292 | if (ret) | ||
| 293 | return ret; | ||
| 294 | |||
| 295 | bo->pin_count = 1; | ||
| 296 | if (gpu_addr) | ||
| 297 | *gpu_addr = mgag200_bo_gpu_offset(bo); | ||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | int mgag200_bo_unpin(struct mgag200_bo *bo) | ||
| 302 | { | ||
| 303 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 304 | int i; | ||
| 305 | if (!bo->pin_count) { | ||
| 306 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | bo->pin_count--; | ||
| 310 | if (bo->pin_count) | ||
| 311 | return 0; | ||
| 312 | |||
| 313 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
| 314 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 315 | return ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 316 | } | ||
| 317 | |||
| 318 | int mgag200_bo_push_sysram(struct mgag200_bo *bo) | ||
| 319 | { | ||
| 320 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 321 | int i, ret; | ||
| 322 | if (!bo->pin_count) { | ||
| 323 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 324 | return 0; | ||
| 325 | } | ||
| 326 | bo->pin_count--; | ||
| 327 | if (bo->pin_count) | ||
| 328 | return 0; | ||
| 329 | |||
| 330 | if (bo->kmap.virtual) | ||
| 331 | ttm_bo_kunmap(&bo->kmap); | ||
| 332 | |||
| 333 | mgag200_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
| 334 | for (i = 0; i < bo->placement.num_placement ; i++) | ||
| 335 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 336 | |||
| 337 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 338 | if (ret) { | ||
| 339 | DRM_ERROR("pushing to VRAM failed\n"); | ||
| 340 | return ret; | ||
| 341 | } | ||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | int mgag200_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 346 | { | ||
| 347 | struct drm_file *file_priv = filp->private_data; | ||
| 348 | struct mga_device *mdev = file_priv->minor->dev->dev_private; | ||
| 349 | |||
| 350 | return ttm_bo_mmap(filp, vma, &mdev->ttm.bdev); | ||
| 351 | } | ||
| @@ -694,14 +694,12 @@ end: · 693 unmodified lines | |||
| 694 | 694 | ||
| 695 | static void dpu_crtc_reset(struct drm_crtc *crtc) | 695 | static void dpu_crtc_reset(struct drm_crtc *crtc) |
| 696 | { | 696 | { |
| 697 | struct dpu_crtc_state *cstate; | 697 | struct dpu_crtc_state *cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); |
| 698 | 698 | ||
| 699 | if (crtc->state) | 699 | if (crtc->state) |
| 700 | dpu_crtc_destroy_state(crtc, crtc->state); | 700 | dpu_crtc_destroy_state(crtc, crtc->state); |
| 701 | 701 | ||
| 702 | crtc->state = kzalloc(sizeof(*cstate), GFP_KERNEL); | 702 | __drm_atomic_helper_crtc_reset(crtc, &cstate->base); |
| 703 | if (crtc->state) | ||
| 704 | crtc->state->crtc = crtc; | ||
| 705 | } | 703 | } |
| 706 | 704 | ||
| 707 | /** | 705 | /** |
| @@ -1040,10 +1040,11 @@ int dpu_format_check_modified_format( · 1039 unmodified lines | |||
| 1040 | const struct drm_mode_fb_cmd2 *cmd, | 1040 | const struct drm_mode_fb_cmd2 *cmd, |
| 1041 | struct drm_gem_object **bos) | 1041 | struct drm_gem_object **bos) |
| 1042 | { | 1042 | { |
| 1043 | int ret, i, num_base_fmt_planes; | 1043 | const struct drm_format_info *info; |
| 1044 | const struct dpu_format *fmt; | 1044 | const struct dpu_format *fmt; |
| 1045 | struct dpu_hw_fmt_layout layout; | 1045 | struct dpu_hw_fmt_layout layout; |
| 1046 | uint32_t bos_total_size = 0; | 1046 | uint32_t bos_total_size = 0; |
| 1047 | int ret, i; | ||
| 1047 | 1048 | ||
| 1048 | if (!msm_fmt || !cmd || !bos) { | 1049 | if (!msm_fmt || !cmd || !bos) { |
| 1049 | DRM_ERROR("invalid arguments\n"); | 1050 | DRM_ERROR("invalid arguments\n"); |
| @@ -1051,14 +1052,16 @@ int dpu_format_check_modified_format( · 1 unmodified line | |||
| 1051 | } | 1052 | } |
| 1052 | 1053 | ||
| 1053 | fmt = to_dpu_format(msm_fmt); | 1054 | fmt = to_dpu_format(msm_fmt); |
| 1054 | num_base_fmt_planes = drm_format_num_planes(fmt->base.pixel_format); | 1055 | info = drm_format_info(fmt->base.pixel_format); |
| 1056 | if (!info) | ||
| 1057 | return -EINVAL; | ||
| 1055 | 1058 | ||
| 1056 | ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height, | 1059 | ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height, |
| 1057 | &layout, cmd->pitches); | 1060 | &layout, cmd->pitches); |
| 1058 | if (ret) | 1061 | if (ret) |
| 1059 | return ret; | 1062 | return ret; |
| 1060 | 1063 | ||
| 1061 | for (i = 0; i < num_base_fmt_planes; i++) { | 1064 | for (i = 0; i < info->num_planes; i++) { |
| 1062 | if (!bos[i]) { | 1065 | if (!bos[i]) { |
| 1063 | DRM_ERROR("invalid handle for plane %d\n", i); | 1066 | DRM_ERROR("invalid handle for plane %d\n", i); |
| 1064 | return -EINVAL; | 1067 | return -EINVAL; |
| @@ -557,14 +557,9 @@ static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu, · 556 unmodified lines | |||
| 557 | struct dpu_plane_state *pstate, | 557 | struct dpu_plane_state *pstate, |
| 558 | const struct dpu_format *fmt, bool color_fill) | 558 | const struct dpu_format *fmt, bool color_fill) |
| 559 | { | 559 | { |
| 560 | uint32_t chroma_subsmpl_h, chroma_subsmpl_v; | 560 | const struct drm_format_info *info = drm_format_info(fmt->base.pixel_format); |
| 561 | 561 | ||
| 562 | /* don't chroma subsample if decimating */ | 562 | /* don't chroma subsample if decimating */ |
| 563 | chroma_subsmpl_h = | ||
| 564 | drm_format_horz_chroma_subsampling(fmt->base.pixel_format); | ||
| 565 | chroma_subsmpl_v = | ||
| 566 | drm_format_vert_chroma_subsampling(fmt->base.pixel_format); | ||
| 567 | |||
| 568 | /* update scaler. calculate default config for QSEED3 */ | 563 | /* update scaler. calculate default config for QSEED3 */ |
| 569 | _dpu_plane_setup_scaler3(pdpu, pstate, | 564 | _dpu_plane_setup_scaler3(pdpu, pstate, |
| 570 | drm_rect_width(&pdpu->pipe_cfg.src_rect), | 565 | drm_rect_width(&pdpu->pipe_cfg.src_rect), |
| @@ -572,7 +567,7 @@ static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu, · 1 unmodified line | |||
| 572 | drm_rect_width(&pdpu->pipe_cfg.dst_rect), | 567 | drm_rect_width(&pdpu->pipe_cfg.dst_rect), |
| 573 | drm_rect_height(&pdpu->pipe_cfg.dst_rect), | 568 | drm_rect_height(&pdpu->pipe_cfg.dst_rect), |
| 574 | &pstate->scaler3_cfg, fmt, | 569 | &pstate->scaler3_cfg, fmt, |
| 575 | chroma_subsmpl_h, chroma_subsmpl_v); | 570 | info->hsub, info->vsub); |
| 576 | } | 571 | } |
| 577 | 572 | ||
| 578 | /** | 573 | /** |
| @@ -782,6 +782,7 @@ static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h) · 781 unmodified lines | |||
| 782 | 782 | ||
| 783 | static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) | 783 | static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) |
| 784 | { | 784 | { |
| 785 | const struct drm_format_info *info = drm_format_info(DRM_FORMAT_ARGB8888); | ||
| 785 | struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); | 786 | struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); |
| 786 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); | 787 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); |
| 787 | struct mdp5_kms *mdp5_kms = get_kms(crtc); | 788 | struct mdp5_kms *mdp5_kms = get_kms(crtc); |
| @@ -800,7 +801,7 @@ static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) · 12 unmodified lines | |||
| 800 | width = mdp5_crtc->cursor.width; | 801 | width = mdp5_crtc->cursor.width; |
| 801 | height = mdp5_crtc->cursor.height; | 802 | height = mdp5_crtc->cursor.height; |
| 802 | 803 | ||
| 803 | stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0); | 804 | stride = width * info->cpp[0]; |
| 804 | 805 | ||
| 805 | get_roi(crtc, &roi_w, &roi_h); | 806 | get_roi(crtc, &roi_w, &roi_h); |
| 806 | 807 | ||
| @@ -1002,23 +1003,6 @@ mdp5_crtc_atomic_print_state(struct drm_printer *p, · 195 unmodified lines | |||
| 1002 | drm_printf(p, "\tcmd_mode=%d\n", mdp5_cstate->cmd_mode); | 1003 | drm_printf(p, "\tcmd_mode=%d\n", mdp5_cstate->cmd_mode); |
| 1003 | } | 1004 | } |
| 1004 | 1005 | ||
| 1005 | static void mdp5_crtc_reset(struct drm_crtc *crtc) | ||
| 1006 | { | ||
| 1007 | struct mdp5_crtc_state *mdp5_cstate; | ||
| 1008 | |||
| 1009 | if (crtc->state) { | ||
| 1010 | __drm_atomic_helper_crtc_destroy_state(crtc->state); | ||
| 1011 | kfree(to_mdp5_crtc_state(crtc->state)); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | mdp5_cstate = kzalloc(sizeof(*mdp5_cstate), GFP_KERNEL); | ||
| 1015 | |||
| 1016 | if (mdp5_cstate) { | ||
| 1017 | mdp5_cstate->base.crtc = crtc; | ||
| 1018 | crtc->state = &mdp5_cstate->base; | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | static struct drm_crtc_state * | 1006 | static struct drm_crtc_state * |
| 1023 | mdp5_crtc_duplicate_state(struct drm_crtc *crtc) | 1007 | mdp5_crtc_duplicate_state(struct drm_crtc *crtc) |
| 1024 | { | 1008 | { |
| @@ -1046,6 +1030,17 @@ static void mdp5_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state · 21 unmodified lines | |||
| 1046 | kfree(mdp5_cstate); | 1030 | kfree(mdp5_cstate); |
| 1047 | } | 1031 | } |
| 1048 | 1032 | ||
| 1033 | static void mdp5_crtc_reset(struct drm_crtc *crtc) | ||
| 1034 | { | ||
| 1035 | struct mdp5_crtc_state *mdp5_cstate = | ||
| 1036 | kzalloc(sizeof(*mdp5_cstate), GFP_KERNEL); | ||
| 1037 | |||
| 1038 | if (crtc->state) | ||
| 1039 | mdp5_crtc_destroy_state(crtc, crtc->state); | ||
| 1040 | |||
| 1041 | __drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base); | ||
| 1042 | } | ||
| 1043 | |||
| 1049 | static const struct drm_crtc_funcs mdp5_crtc_funcs = { | 1044 | static const struct drm_crtc_funcs mdp5_crtc_funcs = { |
| 1050 | .set_config = drm_atomic_helper_set_config, | 1045 | .set_config = drm_atomic_helper_set_config, |
| 1051 | .destroy = mdp5_crtc_destroy, | 1046 | .destroy = mdp5_crtc_destroy, |
| @@ -650,10 +650,10 @@ static int calc_scalex_steps(struct drm_plane *plane, · 649 unmodified lines | |||
| 650 | uint32_t pixel_format, uint32_t src, uint32_t dest, | 650 | uint32_t pixel_format, uint32_t src, uint32_t dest, |
| 651 | uint32_t phasex_steps[COMP_MAX]) | 651 | uint32_t phasex_steps[COMP_MAX]) |
| 652 | { | 652 | { |
| 653 | const struct drm_format_info *info = drm_format_info(pixel_format); | ||
| 653 | struct mdp5_kms *mdp5_kms = get_kms(plane); | 654 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
| 654 | struct device *dev = mdp5_kms->dev->dev; | 655 | struct device *dev = mdp5_kms->dev->dev; |
| 655 | uint32_t phasex_step; | 656 | uint32_t phasex_step; |
| 656 | unsigned int hsub; | ||
| 657 | int ret; | 657 | int ret; |
| 658 | 658 | ||
| 659 | ret = calc_phase_step(src, dest, &phasex_step); | 659 | ret = calc_phase_step(src, dest, &phasex_step); |
| @@ -662,11 +662,9 @@ static int calc_scalex_steps(struct drm_plane *plane, · 2 unmodified lines | |||
| 662 | return ret; | 662 | return ret; |
| 663 | } | 663 | } |
| 664 | 664 | ||
| 665 | hsub = drm_format_horz_chroma_subsampling(pixel_format); | ||
| 666 | |||
| 667 | phasex_steps[COMP_0] = phasex_step; | 665 | phasex_steps[COMP_0] = phasex_step; |
| 668 | phasex_steps[COMP_3] = phasex_step; | 666 | phasex_steps[COMP_3] = phasex_step; |
| 669 | phasex_steps[COMP_1_2] = phasex_step / hsub; | 667 | phasex_steps[COMP_1_2] = phasex_step / info->hsub; |
| 670 | 668 | ||
| 671 | return 0; | 669 | return 0; |
| 672 | } | 670 | } |
| @@ -675,10 +673,10 @@ static int calc_scaley_steps(struct drm_plane *plane, · 2 unmodified lines | |||
| 675 | uint32_t pixel_format, uint32_t src, uint32_t dest, | 673 | uint32_t pixel_format, uint32_t src, uint32_t dest, |
| 676 | uint32_t phasey_steps[COMP_MAX]) | 674 | uint32_t phasey_steps[COMP_MAX]) |
| 677 | { | 675 | { |
| 676 | const struct drm_format_info *info = drm_format_info(pixel_format); | ||
| 678 | struct mdp5_kms *mdp5_kms = get_kms(plane); | 677 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
| 679 | struct device *dev = mdp5_kms->dev->dev; | 678 | struct device *dev = mdp5_kms->dev->dev; |
| 680 | uint32_t phasey_step; | 679 | uint32_t phasey_step; |
| 681 | unsigned int vsub; | ||
| 682 | int ret; | 680 | int ret; |
| 683 | 681 | ||
| 684 | ret = calc_phase_step(src, dest, &phasey_step); | 682 | ret = calc_phase_step(src, dest, &phasey_step); |
| @@ -687,11 +685,9 @@ static int calc_scaley_steps(struct drm_plane *plane, · 2 unmodified lines | |||
| 687 | return ret; | 685 | return ret; |
| 688 | } | 686 | } |
| 689 | 687 | ||
| 690 | vsub = drm_format_vert_chroma_subsampling(pixel_format); | ||
| 691 | |||
| 692 | phasey_steps[COMP_0] = phasey_step; | 688 | phasey_steps[COMP_0] = phasey_step; |
| 693 | phasey_steps[COMP_3] = phasey_step; | 689 | phasey_steps[COMP_3] = phasey_step; |
| 694 | phasey_steps[COMP_1_2] = phasey_step / vsub; | 690 | phasey_steps[COMP_1_2] = phasey_step / info->vsub; |
| 695 | 691 | ||
| 696 | return 0; | 692 | return 0; |
| 697 | } | 693 | } |
| @@ -699,8 +695,9 @@ static int calc_scaley_steps(struct drm_plane *plane, · 1 unmodified line | |||
| 699 | static uint32_t get_scale_config(const struct mdp_format *format, | 695 | static uint32_t get_scale_config(const struct mdp_format *format, |
| 700 | uint32_t src, uint32_t dst, bool horz) | 696 | uint32_t src, uint32_t dst, bool horz) |
| 701 | { | 697 | { |
| 698 | const struct drm_format_info *info = drm_format_info(format->base.pixel_format); | ||
| 702 | bool scaling = format->is_yuv ? true : (src != dst); | 699 | bool scaling = format->is_yuv ? true : (src != dst); |
| 703 | uint32_t sub, pix_fmt = format->base.pixel_format; | 700 | uint32_t sub; |
| 704 | uint32_t ya_filter, uv_filter; | 701 | uint32_t ya_filter, uv_filter; |
| 705 | bool yuv = format->is_yuv; | 702 | bool yuv = format->is_yuv; |
| 706 | 703 | ||
| @@ -708,8 +705,7 @@ static uint32_t get_scale_config(const struct mdp_format *format, · 1 unmodified line | |||
| 708 | return 0; | 705 | return 0; |
| 709 | 706 | ||
| 710 | if (yuv) { | 707 | if (yuv) { |
| 711 | sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) : | 708 | sub = horz ? info->hsub : info->vsub; |
| 712 | drm_format_vert_chroma_subsampling(pix_fmt); | ||
| 713 | uv_filter = ((src / sub) <= dst) ? | 709 | uv_filter = ((src / sub) <= dst) ? |
| 714 | SCALE_FILTER_BIL : SCALE_FILTER_PCMN; | 710 | SCALE_FILTER_BIL : SCALE_FILTER_PCMN; |
| 715 | } | 711 | } |
| @@ -754,7 +750,7 @@ static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, · 38 unmodified lines | |||
| 754 | uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX], | 750 | uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX], |
| 755 | uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX]) | 751 | uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX]) |
| 756 | { | 752 | { |
| 757 | uint32_t pix_fmt = format->base.pixel_format; | 753 | const struct drm_format_info *info = drm_format_info(format->base.pixel_format); |
| 758 | uint32_t lr, tb, req; | 754 | uint32_t lr, tb, req; |
| 759 | int i; | 755 | int i; |
| 760 | 756 | ||
| @@ -763,8 +759,8 @@ static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, · 2 unmodified lines | |||
| 763 | uint32_t roi_h = src_h; | 759 | uint32_t roi_h = src_h; |
| 764 | 760 | ||
| 765 | if (format->is_yuv && i == COMP_1_2) { | 761 | if (format->is_yuv && i == COMP_1_2) { |
| 766 | roi_w /= drm_format_horz_chroma_subsampling(pix_fmt); | 762 | roi_w /= info->hsub; |
| 767 | roi_h /= drm_format_vert_chroma_subsampling(pix_fmt); | 763 | roi_h /= info->vsub; |
| 768 | } | 764 | } |
| 769 | 765 | ||
| 770 | lr = (pe_left[i] >= 0) ? | 766 | lr = (pe_left[i] >= 0) ? |
| @@ -127,14 +127,15 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, · 126 unmodified lines | |||
| 127 | const struct mdp_format *format, | 127 | const struct mdp_format *format, |
| 128 | u32 width, bool hdecim) | 128 | u32 width, bool hdecim) |
| 129 | { | 129 | { |
| 130 | const struct drm_format_info *info = drm_format_info(format->base.pixel_format); | ||
| 130 | struct mdp5_kms *mdp5_kms = get_kms(smp); | 131 | struct mdp5_kms *mdp5_kms = get_kms(smp); |
| 131 | int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); | 132 | int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); |
| 132 | int i, hsub, nplanes, nlines; | 133 | int i, hsub, nplanes, nlines; |
| 133 | u32 fmt = format->base.pixel_format; | 134 | u32 fmt = format->base.pixel_format; |
| 134 | uint32_t blkcfg = 0; | 135 | uint32_t blkcfg = 0; |
| 135 | 136 | ||
| 136 | nplanes = drm_format_num_planes(fmt); | 137 | nplanes = info->num_planes; |
| 137 | hsub = drm_format_horz_chroma_subsampling(fmt); | 138 | hsub = info->hsub; |
| 138 | 139 | ||
| 139 | /* different if BWC (compressed framebuffer?) enabled: */ | 140 | /* different if BWC (compressed framebuffer?) enabled: */ |
| 140 | nlines = 2; | 141 | nlines = 2; |
| @@ -157,7 +158,7 @@ uint32_t mdp5_smp_calculate(struct mdp5_smp *smp, · 16 unmodified lines | |||
| 157 | for (i = 0; i < nplanes; i++) { | 158 | for (i = 0; i < nplanes; i++) { |
| 158 | int n, fetch_stride, cpp; | 159 | int n, fetch_stride, cpp; |
| 159 | 160 | ||
| 160 | cpp = drm_format_plane_cpp(fmt, i); | 161 | cpp = info->cpp[i]; |
| 161 | fetch_stride = width * cpp / (i ? hsub : 1); | 162 | fetch_stride = width * cpp / (i ? hsub : 1); |
| 162 | 163 | ||
| 163 | n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size); | 164 | n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size); |
| @@ -106,9 +106,11 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) · 105 unmodified lines | |||
| 106 | struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, | 106 | struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, |
| 107 | struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) | 107 | struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) |
| 108 | { | 108 | { |
| 109 | const struct drm_format_info *info = drm_get_format_info(dev, | ||
| 110 | mode_cmd); | ||
| 109 | struct drm_gem_object *bos[4] = {0}; | 111 | struct drm_gem_object *bos[4] = {0}; |
| 110 | struct drm_framebuffer *fb; | 112 | struct drm_framebuffer *fb; |
| 111 | int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); | 113 | int ret, i, n = info->num_planes; |
| 112 | 114 | ||
| 113 | for (i = 0; i < n; i++) { | 115 | for (i = 0; i < n; i++) { |
| 114 | bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); | 116 | bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); |
| @@ -135,22 +137,20 @@ out_unref: · 20 unmodified lines | |||
| 135 | static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, | 137 | static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, |
| 136 | const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) | 138 | const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) |
| 137 | { | 139 | { |
| 140 | const struct drm_format_info *info = drm_get_format_info(dev, | ||
| 141 | mode_cmd); | ||
| 138 | struct msm_drm_private *priv = dev->dev_private; | 142 | struct msm_drm_private *priv = dev->dev_private; |
| 139 | struct msm_kms *kms = priv->kms; | 143 | struct msm_kms *kms = priv->kms; |
| 140 | struct msm_framebuffer *msm_fb = NULL; | 144 | struct msm_framebuffer *msm_fb = NULL; |
| 141 | struct drm_framebuffer *fb; | 145 | struct drm_framebuffer *fb; |
| 142 | const struct msm_format *format; | 146 | const struct msm_format *format; |
| 143 | int ret, i, n; | 147 | int ret, i, n; |
| 144 | unsigned int hsub, vsub; | ||
| 145 | 148 | ||
| 146 | DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", | 149 | DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", |
| 147 | dev, mode_cmd, mode_cmd->width, mode_cmd->height, | 150 | dev, mode_cmd, mode_cmd->width, mode_cmd->height, |
| 148 | (char *)&mode_cmd->pixel_format); | 151 | (char *)&mode_cmd->pixel_format); |
| 149 | 152 | ||
| 150 | n = drm_format_num_planes(mode_cmd->pixel_format); | 153 | n = info->num_planes; |
| 151 | hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); | ||
| 152 | vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); | ||
| 153 | |||
| 154 | format = kms->funcs->get_format(kms, mode_cmd->pixel_format, | 154 | format = kms->funcs->get_format(kms, mode_cmd->pixel_format, |
| 155 | mode_cmd->modifier[0]); | 155 | mode_cmd->modifier[0]); |
| 156 | if (!format) { | 156 | if (!format) { |
| @@ -176,12 +176,12 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, · 19 unmodified lines | |||
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | for (i = 0; i < n; i++) { | 178 | for (i = 0; i < n; i++) { |
| 179 | unsigned int width = mode_cmd->width / (i ? hsub : 1); | 179 | unsigned int width = mode_cmd->width / (i ? info->hsub : 1); |
| 180 | unsigned int height = mode_cmd->height / (i ? vsub : 1); | 180 | unsigned int height = mode_cmd->height / (i ? info->vsub : 1); |
| 181 | unsigned int min_size; | 181 | unsigned int min_size; |
| 182 | 182 | ||
| 183 | min_size = (height - 1) * mode_cmd->pitches[i] | 183 | min_size = (height - 1) * mode_cmd->pitches[i] |
| 184 | + width * drm_format_plane_cpp(mode_cmd->pixel_format, i) | 184 | + width * info->cpp[i] |
| 185 | + mode_cmd->offsets[i]; | 185 | + mode_cmd->offsets[i]; |
| 186 | 186 | ||
| 187 | if (bos[i]->size < min_size) { | 187 | if (bos[i]->size < min_size) { |
| @@ -420,16 +420,6 @@ nv50_head_atomic_duplicate_state(struct drm_crtc *crtc) · 419 unmodified lines | |||
| 420 | return &asyh->state; | 420 | return &asyh->state; |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | static void | ||
| 424 | __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, | ||
| 425 | struct drm_crtc_state *state) | ||
| 426 | { | ||
| 427 | if (crtc->state) | ||
| 428 | crtc->funcs->atomic_destroy_state(crtc, crtc->state); | ||
| 429 | crtc->state = state; | ||
| 430 | crtc->state->crtc = crtc; | ||
| 431 | } | ||
| 432 | |||
| 433 | static void | 423 | static void |
| 434 | nv50_head_reset(struct drm_crtc *crtc) | 424 | nv50_head_reset(struct drm_crtc *crtc) |
| 435 | { | 425 | { |
| @@ -438,6 +428,9 @@ nv50_head_reset(struct drm_crtc *crtc) · 2 unmodified lines | |||
| 438 | if (WARN_ON(!(asyh = kzalloc(sizeof(*asyh), GFP_KERNEL)))) | 428 | if (WARN_ON(!(asyh = kzalloc(sizeof(*asyh), GFP_KERNEL)))) |
| 439 | return; | 429 | return; |
| 440 | 430 | ||
| 431 | if (crtc->state) | ||
| 432 | nv50_head_atomic_destroy_state(crtc, crtc->state); | ||
| 433 | |||
| 441 | __drm_atomic_helper_crtc_reset(crtc, &asyh->state); | 434 | __drm_atomic_helper_crtc_reset(crtc, &asyh->state); |
| 442 | } | 435 | } |
| 443 | 436 | ||
| @@ -26,8 +26,6 @@ · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | #include <subdev/gpio.h> | 27 | #include <subdev/gpio.h> |
| 28 | 28 | ||
| 29 | #include <subdev/gpio.h> | ||
| 30 | |||
| 31 | static void | 29 | static void |
| 32 | nv04_bus_intr(struct nvkm_bus *bus) | 30 | nv04_bus_intr(struct nvkm_bus *bus) |
| 33 | { | 31 | { |
| @@ -298,7 +298,9 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) · 297 unmodified lines | |||
| 298 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, | 298 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, |
| 299 | struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) | 299 | struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) |
| 300 | { | 300 | { |
| 301 | unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format); | 301 | const struct drm_format_info *info = drm_get_format_info(dev, |
| 302 | mode_cmd); | ||
| 303 | unsigned int num_planes = info->num_planes; | ||
| 302 | struct drm_gem_object *bos[4]; | 304 | struct drm_gem_object *bos[4]; |
| 303 | struct drm_framebuffer *fb; | 305 | struct drm_framebuffer *fb; |
| 304 | int i; | 306 | int i; |
| @@ -337,7 +339,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, · 32 unmodified lines | |||
| 337 | dev, mode_cmd, mode_cmd->width, mode_cmd->height, | 339 | dev, mode_cmd, mode_cmd->width, mode_cmd->height, |
| 338 | (char *)&mode_cmd->pixel_format); | 340 | (char *)&mode_cmd->pixel_format); |
| 339 | 341 | ||
| 340 | format = drm_format_info(mode_cmd->pixel_format); | 342 | format = drm_get_format_info(dev, mode_cmd); |
| 341 | 343 | ||
| 342 | for (i = 0; i < ARRAY_SIZE(formats); i++) { | 344 | for (i = 0; i < ARRAY_SIZE(formats); i++) { |
| 343 | if (formats[i] == mode_cmd->pixel_format) | 345 | if (formats[i] == mode_cmd->pixel_format) |
| @@ -132,6 +132,15 @@ config DRM_PANEL_ORISETECH_OTM8009A · 131 unmodified lines | |||
| 132 | Say Y here if you want to enable support for Orise Technology | 132 | Say Y here if you want to enable support for Orise Technology |
| 133 | otm8009a 480x800 dsi 2dl panel. | 133 | otm8009a 480x800 dsi 2dl panel. |
| 134 | 134 | ||
| 135 | config DRM_PANEL_OSD_OSD101T2587_53TS | ||
| 136 | tristate "OSD OSD101T2587-53TS DSI 1920x1200 video mode panel" | ||
| 137 | depends on OF | ||
| 138 | depends on DRM_MIPI_DSI | ||
| 139 | depends on BACKLIGHT_CLASS_DEVICE | ||
| 140 | help | ||
| 141 | Say Y here if you want to enable support for One Stop Displays | ||
| 142 | OSD101T2587-53TS 10.1" 1920x1200 dsi panel. | ||
| 143 | |||
| 135 | config DRM_PANEL_PANASONIC_VVX10F034N00 | 144 | config DRM_PANEL_PANASONIC_VVX10F034N00 |
| 136 | tristate "Panasonic VVX10F034N00 1920x1200 video mode panel" | 145 | tristate "Panasonic VVX10F034N00 1920x1200 video mode panel" |
| 137 | depends on OF | 146 | depends on OF |
| @@ -201,6 +210,15 @@ config DRM_PANEL_SAMSUNG_S6E63J0X03 · 63 unmodified lines | |||
| 201 | depends on BACKLIGHT_CLASS_DEVICE | 210 | depends on BACKLIGHT_CLASS_DEVICE |
| 202 | select VIDEOMODE_HELPERS | 211 | select VIDEOMODE_HELPERS |
| 203 | 212 | ||
| 213 | config DRM_PANEL_SAMSUNG_S6E63M0 | ||
| 214 | tristate "Samsung S6E63M0 RGB/SPI panel" | ||
| 215 | depends on OF | ||
| 216 | depends on SPI | ||
| 217 | depends on BACKLIGHT_CLASS_DEVICE | ||
| 218 | help | ||
| 219 | Say Y here if you want to enable support for Samsung S6E63M0 | ||
| 220 | AMOLED LCD panel. | ||
| 221 | |||
| 204 | config DRM_PANEL_SAMSUNG_S6E8AA0 | 222 | config DRM_PANEL_SAMSUNG_S6E8AA0 |
| 205 | tristate "Samsung S6E8AA0 DSI video mode panel" | 223 | tristate "Samsung S6E8AA0 DSI video mode panel" |
| 206 | depends on OF | 224 | depends on OF |
| @@ -11,6 +11,7 @@ obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o · 10 unmodified lines | |||
| 11 | obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o | 11 | obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o |
| 12 | obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o | 12 | obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o |
| 13 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o | 13 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o |
| 14 | obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o | ||
| 14 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o | 15 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o |
| 15 | obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o | 16 | obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o |
| 16 | obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o | 17 | obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o |
| @@ -20,6 +21,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o · 3 unmodified lines | |||
| 20 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o | 21 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o |
| 21 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o | 22 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o |
| 22 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o | 23 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o |
| 24 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o | ||
| 23 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o | 25 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o |
| 24 | obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o | 26 | obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o |
| 25 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o | 27 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o |
| @@ -0,0 +1,254 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com | ||
| 4 | * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/backlight.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/of.h> | ||
| 10 | #include <linux/regulator/consumer.h> | ||
| 11 | |||
| 12 | #include <drm/drm_crtc.h> | ||
| 13 | #include <drm/drm_device.h> | ||
| 14 | #include <drm/drm_mipi_dsi.h> | ||
| 15 | #include <drm/drm_panel.h> | ||
| 16 | |||
| 17 | #include <video/mipi_display.h> | ||
| 18 | |||
| 19 | struct osd101t2587_panel { | ||
| 20 | struct drm_panel base; | ||
| 21 | struct mipi_dsi_device *dsi; | ||
| 22 | |||
| 23 | struct backlight_device *backlight; | ||
| 24 | struct regulator *supply; | ||
| 25 | |||
| 26 | bool prepared; | ||
| 27 | bool enabled; | ||
| 28 | |||
| 29 | const struct drm_display_mode *default_mode; | ||
| 30 | }; | ||
| 31 | |||
| 32 | static inline struct osd101t2587_panel *ti_osd_panel(struct drm_panel *panel) | ||
| 33 | { | ||
| 34 | return container_of(panel, struct osd101t2587_panel, base); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int osd101t2587_panel_disable(struct drm_panel *panel) | ||
| 38 | { | ||
| 39 | struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel); | ||
| 40 | int ret; | ||
| 41 | |||
| 42 | if (!osd101t2587->enabled) | ||
| 43 | return 0; | ||
| 44 | |||
| 45 | backlight_disable(osd101t2587->backlight); | ||
| 46 | |||
| 47 | ret = mipi_dsi_shutdown_peripheral(osd101t2587->dsi); | ||
| 48 | |||
| 49 | osd101t2587->enabled = false; | ||
| 50 | |||
| 51 | return ret; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int osd101t2587_panel_unprepare(struct drm_panel *panel) | ||
| 55 | { | ||
| 56 | struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel); | ||
| 57 | |||
| 58 | if (!osd101t2587->prepared) | ||
| 59 | return 0; | ||
| 60 | |||
| 61 | regulator_disable(osd101t2587->supply); | ||
| 62 | osd101t2587->prepared = false; | ||
| 63 | |||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | static int osd101t2587_panel_prepare(struct drm_panel *panel) | ||
| 68 | { | ||
| 69 | struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel); | ||
| 70 | int ret; | ||
| 71 | |||
| 72 | if (osd101t2587->prepared) | ||
| 73 | return 0; | ||
| 74 | |||
| 75 | ret = regulator_enable(osd101t2587->supply); | ||
| 76 | if (!ret) | ||
| 77 | osd101t2587->prepared = true; | ||
| 78 | |||
| 79 | return ret; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int osd101t2587_panel_enable(struct drm_panel *panel) | ||
| 83 | { | ||
| 84 | struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel); | ||
| 85 | int ret; | ||
| 86 | |||
| 87 | if (osd101t2587->enabled) | ||
| 88 | return 0; | ||
| 89 | |||
| 90 | ret = mipi_dsi_turn_on_peripheral(osd101t2587->dsi); | ||
| 91 | if (ret) | ||
| 92 | return ret; | ||
| 93 | |||
| 94 | backlight_enable(osd101t2587->backlight); | ||
| 95 | |||
| 96 | osd101t2587->enabled = true; | ||
| 97 | |||
| 98 | return ret; | ||
| 99 | } | ||
| 100 | |||
| 101 | static const struct drm_display_mode default_mode_osd101t2587 = { | ||
| 102 | .clock = 164400, | ||
| 103 | .hdisplay = 1920, | ||
| 104 | .hsync_start = 1920 + 152, | ||
| 105 | .hsync_end = 1920 + 152 + 52, | ||
| 106 | .htotal = 1920 + 152 + 52 + 20, | ||
| 107 | .vdisplay = 1200, | ||
| 108 | .vsync_start = 1200 + 24, | ||
| 109 | .vsync_end = 1200 + 24 + 6, | ||
| 110 | .vtotal = 1200 + 24 + 6 + 48, | ||
| 111 | .vrefresh = 60, | ||
| 112 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static int osd101t2587_panel_get_modes(struct drm_panel *panel) | ||
| 116 | { | ||
| 117 | struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel); | ||
| 118 | struct drm_display_mode *mode; | ||
| 119 | |||
| 120 | mode = drm_mode_duplicate(panel->drm, osd101t2587->default_mode); | ||
| 121 | if (!mode) { | ||
| 122 | dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", | ||
| 123 | osd101t2587->default_mode->hdisplay, | ||
| 124 | osd101t2587->default_mode->vdisplay, | ||
| 125 | osd101t2587->default_mode->vrefresh); | ||
| 126 | return -ENOMEM; | ||
| 127 | } | ||
| 128 | |||
| 129 | drm_mode_set_name(mode); | ||
| 130 | |||
| 131 | drm_mode_probed_add(panel->connector, mode); | ||
| 132 | |||
| 133 | panel->connector->display_info.width_mm = 217; | ||
| 134 | panel->connector->display_info.height_mm = 136; | ||
| 135 | |||
| 136 | return 1; | ||
| 137 | } | ||
| 138 | |||
| 139 | static const struct drm_panel_funcs osd101t2587_panel_funcs = { | ||
| 140 | .disable = osd101t2587_panel_disable, | ||
| 141 | .unprepare = osd101t2587_panel_unprepare, | ||
| 142 | .prepare = osd101t2587_panel_prepare, | ||
| 143 | .enable = osd101t2587_panel_enable, | ||
| 144 | .get_modes = osd101t2587_panel_get_modes, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static const struct of_device_id osd101t2587_of_match[] = { | ||
| 148 | { | ||
| 149 | .compatible = "osddisplays,osd101t2587-53ts", | ||
| 150 | .data = &default_mode_osd101t2587, | ||
| 151 | }, { | ||
| 152 | /* sentinel */ | ||
| 153 | } | ||
| 154 | }; | ||
| 155 | MODULE_DEVICE_TABLE(of, osd101t2587_of_match); | ||
| 156 | |||
| 157 | static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587) | ||
| 158 | { | ||
| 159 | struct device *dev = &osd101t2587->dsi->dev; | ||
| 160 | |||
| 161 | osd101t2587->supply = devm_regulator_get(dev, "power"); | ||
| 162 | if (IS_ERR(osd101t2587->supply)) | ||
| 163 | return PTR_ERR(osd101t2587->supply); | ||
| 164 | |||
| 165 | osd101t2587->backlight = devm_of_find_backlight(dev); | ||
| 166 | if (IS_ERR(osd101t2587->backlight)) | ||
| 167 | return PTR_ERR(osd101t2587->backlight); | ||
| 168 | |||
| 169 | drm_panel_init(&osd101t2587->base); | ||
| 170 | osd101t2587->base.funcs = &osd101t2587_panel_funcs; | ||
| 171 | osd101t2587->base.dev = &osd101t2587->dsi->dev; | ||
| 172 | |||
| 173 | return drm_panel_add(&osd101t2587->base); | ||
| 174 | } | ||
| 175 | |||
| 176 | static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) | ||
| 177 | { | ||
| 178 | struct osd101t2587_panel *osd101t2587; | ||
| 179 | const struct of_device_id *id; | ||
| 180 | int ret; | ||
| 181 | |||
| 182 | id = of_match_node(osd101t2587_of_match, dsi->dev.of_node); | ||
| 183 | if (!id) | ||
| 184 | return -ENODEV; | ||
| 185 | |||
| 186 | dsi->lanes = 4; | ||
| 187 | dsi->format = MIPI_DSI_FMT_RGB888; | ||
| 188 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | | ||
| 189 | MIPI_DSI_MODE_VIDEO_BURST | | ||
| 190 | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | | ||
| 191 | MIPI_DSI_MODE_EOT_PACKET; | ||
| 192 | |||
| 193 | osd101t2587 = devm_kzalloc(&dsi->dev, sizeof(*osd101t2587), GFP_KERNEL); | ||
| 194 | if (!osd101t2587) | ||
| 195 | return -ENOMEM; | ||
| 196 | |||
| 197 | mipi_dsi_set_drvdata(dsi, osd101t2587); | ||
| 198 | |||
| 199 | osd101t2587->dsi = dsi; | ||
| 200 | osd101t2587->default_mode = id->data; | ||
| 201 | |||
| 202 | ret = osd101t2587_panel_add(osd101t2587); | ||
| 203 | if (ret < 0) | ||
| 204 | return ret; | ||
| 205 | |||
| 206 | ret = mipi_dsi_attach(dsi); | ||
| 207 | if (ret) | ||
| 208 | drm_panel_remove(&osd101t2587->base); | ||
| 209 | |||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int osd101t2587_panel_remove(struct mipi_dsi_device *dsi) | ||
| 214 | { | ||
| 215 | struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi); | ||
| 216 | int ret; | ||
| 217 | |||
| 218 | ret = osd101t2587_panel_disable(&osd101t2587->base); | ||
| 219 | if (ret < 0) | ||
| 220 | dev_warn(&dsi->dev, "failed to disable panel: %d\n", ret); | ||
| 221 | |||
| 222 | osd101t2587_panel_unprepare(&osd101t2587->base); | ||
| 223 | |||
| 224 | drm_panel_remove(&osd101t2587->base); | ||
| 225 | |||
| 226 | ret = mipi_dsi_detach(dsi); | ||
| 227 | if (ret < 0) | ||
| 228 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); | ||
| 229 | |||
| 230 | return ret; | ||
| 231 | } | ||
| 232 | |||
| 233 | static void osd101t2587_panel_shutdown(struct mipi_dsi_device *dsi) | ||
| 234 | { | ||
| 235 | struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi); | ||
| 236 | |||
| 237 | osd101t2587_panel_disable(&osd101t2587->base); | ||
| 238 | osd101t2587_panel_unprepare(&osd101t2587->base); | ||
| 239 | } | ||
| 240 | |||
| 241 | static struct mipi_dsi_driver osd101t2587_panel_driver = { | ||
| 242 | .driver = { | ||
| 243 | .name = "panel-osd-osd101t2587-53ts", | ||
| 244 | .of_match_table = osd101t2587_of_match, | ||
| 245 | }, | ||
| 246 | .probe = osd101t2587_panel_probe, | ||
| 247 | .remove = osd101t2587_panel_remove, | ||
| 248 | .shutdown = osd101t2587_panel_shutdown, | ||
| 249 | }; | ||
| 250 | module_mipi_dsi_driver(osd101t2587_panel_driver); | ||
| 251 | |||
| 252 | MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); | ||
| 253 | MODULE_DESCRIPTION("OSD101T2587-53TS DSI panel"); | ||
| 254 | MODULE_LICENSE("GPL v2"); | ||
| @@ -57,7 +57,6 @@ · 56 unmodified lines | |||
| 57 | #include <drm/drmP.h> | 57 | #include <drm/drmP.h> |
| 58 | #include <drm/drm_crtc.h> | 58 | #include <drm/drm_crtc.h> |
| 59 | #include <drm/drm_mipi_dsi.h> | 59 | #include <drm/drm_mipi_dsi.h> |
| 60 | #include <drm/drm_panel.h> | ||
| 61 | 60 | ||
| 62 | #define RPI_DSI_DRIVER_NAME "rpi-ts-dsi" | 61 | #define RPI_DSI_DRIVER_NAME "rpi-ts-dsi" |
| 63 | 62 | ||
| @@ -0,0 +1,514 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * S6E63M0 AMOLED LCD drm_panel driver. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com> | ||
| 6 | * Derived from drivers/gpu/drm/panel-samsung-ld9040.c | ||
| 7 | * | ||
| 8 | * Andrzej Hajda <a.hajda@samsung.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <drm/drm_modes.h> | ||
| 12 | #include <drm/drm_panel.h> | ||
| 13 | #include <drm/drm_print.h> | ||
| 14 | |||
| 15 | #include <linux/backlight.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/gpio/consumer.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/regulator/consumer.h> | ||
| 20 | #include <linux/spi/spi.h> | ||
| 21 | |||
| 22 | #include <video/mipi_display.h> | ||
| 23 | |||
| 24 | /* Manufacturer Command Set */ | ||
| 25 | #define MCS_ELVSS_ON 0xb1 | ||
| 26 | #define MCS_MIECTL1 0xc0 | ||
| 27 | #define MCS_BCMODE 0xc1 | ||
| 28 | #define MCS_DISCTL 0xf2 | ||
| 29 | #define MCS_SRCCTL 0xf6 | ||
| 30 | #define MCS_IFCTL 0xf7 | ||
| 31 | #define MCS_PANELCTL 0xF8 | ||
| 32 | #define MCS_PGAMMACTL 0xfa | ||
| 33 | |||
| 34 | #define NUM_GAMMA_LEVELS 11 | ||
| 35 | #define GAMMA_TABLE_COUNT 23 | ||
| 36 | |||
| 37 | #define DATA_MASK 0x100 | ||
| 38 | |||
| 39 | #define MAX_BRIGHTNESS (NUM_GAMMA_LEVELS - 1) | ||
| 40 | |||
| 41 | /* array of gamma tables for gamma value 2.2 */ | ||
| 42 | static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = { | ||
| 43 | { MCS_PGAMMACTL, 0x00, | ||
| 44 | 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8, | ||
| 45 | 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7, | ||
| 46 | 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 }, | ||
| 47 | { MCS_PGAMMACTL, 0x00, | ||
| 48 | 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0, | ||
| 49 | 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF, | ||
| 50 | 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 }, | ||
| 51 | { MCS_PGAMMACTL, 0x00, | ||
| 52 | 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF, | ||
| 53 | 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC, | ||
| 54 | 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D }, | ||
| 55 | { MCS_PGAMMACTL, 0x00, | ||
| 56 | 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC, | ||
| 57 | 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9, | ||
| 58 | 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E }, | ||
| 59 | { MCS_PGAMMACTL, 0x00, | ||
| 60 | 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB, | ||
| 61 | 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8, | ||
| 62 | 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB }, | ||
| 63 | { MCS_PGAMMACTL, 0x00, | ||
| 64 | 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA, | ||
| 65 | 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6, | ||
| 66 | 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA }, | ||
| 67 | { MCS_PGAMMACTL, 0x00, | ||
| 68 | 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8, | ||
| 69 | 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4, | ||
| 70 | 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 }, | ||
| 71 | { MCS_PGAMMACTL, 0x00, | ||
| 72 | 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9, | ||
| 73 | 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3, | ||
| 74 | 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA }, | ||
| 75 | { MCS_PGAMMACTL, 0x00, | ||
| 76 | 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6, | ||
| 77 | 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2, | ||
| 78 | 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 }, | ||
| 79 | { MCS_PGAMMACTL, 0x00, | ||
| 80 | 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6, | ||
| 81 | 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1, | ||
| 82 | 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 }, | ||
| 83 | { MCS_PGAMMACTL, 0x00, | ||
| 84 | 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6, | ||
| 85 | 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0, | ||
| 86 | 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb }, | ||
| 87 | }; | ||
| 88 | |||
| 89 | struct s6e63m0 { | ||
| 90 | struct device *dev; | ||
| 91 | struct drm_panel panel; | ||
| 92 | struct backlight_device *bl_dev; | ||
| 93 | |||
| 94 | struct regulator_bulk_data supplies[2]; | ||
| 95 | struct gpio_desc *reset_gpio; | ||
| 96 | |||
| 97 | bool prepared; | ||
| 98 | bool enabled; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * This field is tested by functions directly accessing bus before | ||
| 102 | * transfer, transfer is skipped if it is set. In case of transfer | ||
| 103 | * failure or unexpected response the field is set to error value. | ||
| 104 | * Such construct allows to eliminate many checks in higher level | ||
| 105 | * functions. | ||
| 106 | */ | ||
| 107 | int error; | ||
| 108 | }; | ||
| 109 | |||
| 110 | static const struct drm_display_mode default_mode = { | ||
| 111 | .clock = 25628, | ||
| 112 | .hdisplay = 480, | ||
| 113 | .hsync_start = 480 + 16, | ||
| 114 | .hsync_end = 480 + 16 + 2, | ||
| 115 | .htotal = 480 + 16 + 2 + 16, | ||
| 116 | .vdisplay = 800, | ||
| 117 | .vsync_start = 800 + 28, | ||
| 118 | .vsync_end = 800 + 28 + 2, | ||
| 119 | .vtotal = 800 + 28 + 2 + 1, | ||
| 120 | .vrefresh = 60, | ||
| 121 | .width_mm = 53, | ||
| 122 | .height_mm = 89, | ||
| 123 | .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, | ||
| 124 | }; | ||
| 125 | |||
| 126 | static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel) | ||
| 127 | { | ||
| 128 | return container_of(panel, struct s6e63m0, panel); | ||
| 129 | } | ||
| 130 | |||
| 131 | static int s6e63m0_clear_error(struct s6e63m0 *ctx) | ||
| 132 | { | ||
| 133 | int ret = ctx->error; | ||
| 134 | |||
| 135 | ctx->error = 0; | ||
| 136 | return ret; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int s6e63m0_spi_write_word(struct s6e63m0 *ctx, u16 data) | ||
| 140 | { | ||
| 141 | struct spi_device *spi = to_spi_device(ctx->dev); | ||
| 142 | struct spi_transfer xfer = { | ||
| 143 | .len = 2, | ||
| 144 | .tx_buf = &data, | ||
| 145 | }; | ||
| 146 | struct spi_message msg; | ||
| 147 | |||
| 148 | spi_message_init(&msg); | ||
| 149 | spi_message_add_tail(&xfer, &msg); | ||
| 150 | |||
| 151 | return spi_sync(spi, &msg); | ||
| 152 | } | ||
| 153 | |||
| 154 | static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) | ||
| 155 | { | ||
| 156 | int ret = 0; | ||
| 157 | |||
| 158 | if (ctx->error < 0 || len == 0) | ||
| 159 | return; | ||
| 160 | |||
| 161 | DRM_DEV_DEBUG(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); | ||
| 162 | ret = s6e63m0_spi_write_word(ctx, *data); | ||
| 163 | |||
| 164 | while (!ret && --len) { | ||
| 165 | ++data; | ||
| 166 | ret = s6e63m0_spi_write_word(ctx, *data | DATA_MASK); | ||
| 167 | } | ||
| 168 | |||
| 169 | if (ret) { | ||
| 170 | DRM_DEV_ERROR(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, | ||
| 171 | (int)len, data); | ||
| 172 | ctx->error = ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | usleep_range(300, 310); | ||
| 176 | } | ||
| 177 | |||
| 178 | #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \ | ||
| 179 | ({ \ | ||
| 180 | static const u8 d[] = { seq }; \ | ||
| 181 | s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \ | ||
| 182 | }) | ||
| 183 | |||
| 184 | static void s6e63m0_init(struct s6e63m0 *ctx) | ||
| 185 | { | ||
| 186 | s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL, | ||
| 187 | 0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f, | ||
| 188 | 0x63, 0x86, 0x1a, 0x33, 0x0d, 0x00, 0x00); | ||
| 189 | |||
| 190 | s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL, | ||
| 191 | 0x02, 0x03, 0x1c, 0x10, 0x10); | ||
| 192 | s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL, | ||
| 193 | 0x03, 0x00, 0x00); | ||
| 194 | |||
| 195 | s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, | ||
| 196 | 0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, | ||
| 197 | 0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1, | ||
| 198 | 0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00, | ||
| 199 | 0xd6); | ||
| 200 | s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, | ||
| 201 | 0x01); | ||
| 202 | |||
| 203 | s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL, | ||
| 204 | 0x00, 0x8c, 0x07); | ||
| 205 | s6e63m0_dcs_write_seq_static(ctx, 0xb3, | ||
| 206 | 0xc); | ||
| 207 | |||
| 208 | s6e63m0_dcs_write_seq_static(ctx, 0xb5, | ||
| 209 | 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, | ||
| 210 | 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, | ||
| 211 | 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a, | ||
| 212 | 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23, | ||
| 213 | 0x21, 0x20, 0x1e, 0x1e); | ||
| 214 | |||
| 215 | s6e63m0_dcs_write_seq_static(ctx, 0xb6, | ||
| 216 | 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44, | ||
| 217 | 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, | ||
| 218 | 0x66, 0x66); | ||
| 219 | |||
| 220 | s6e63m0_dcs_write_seq_static(ctx, 0xb7, | ||
| 221 | 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, | ||
| 222 | 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, | ||
| 223 | 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a, | ||
| 224 | 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23, | ||
| 225 | 0x21, 0x20, 0x1e, 0x1e, 0x00, 0x00, 0x11, | ||
| 226 | 0x22, 0x33, 0x44, 0x44, 0x44, 0x55, 0x55, | ||
| 227 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66); | ||
| 228 | |||
| 229 | s6e63m0_dcs_write_seq_static(ctx, 0xb9, | ||
| 230 | 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, | ||
| 231 | 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, | ||
| 232 | 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a, | ||
| 233 | 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23, | ||
| 234 | 0x21, 0x20, 0x1e, 0x1e); | ||
| 235 | |||
| 236 | s6e63m0_dcs_write_seq_static(ctx, 0xba, | ||
| 237 | 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44, | ||
| 238 | 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, | ||
| 239 | 0x66, 0x66); | ||
| 240 | |||
| 241 | s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE, | ||
| 242 | 0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf, | ||
| 243 | 0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00, | ||
| 244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, | ||
| 245 | 0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18); | ||
| 246 | |||
| 247 | s6e63m0_dcs_write_seq_static(ctx, 0xb2, | ||
| 248 | 0x10, 0x10, 0x0b, 0x05); | ||
| 249 | |||
| 250 | s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1, | ||
| 251 | 0x01); | ||
| 252 | |||
| 253 | s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON, | ||
| 254 | 0x0b); | ||
| 255 | |||
| 256 | s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE); | ||
| 257 | } | ||
| 258 | |||
| 259 | static int s6e63m0_power_on(struct s6e63m0 *ctx) | ||
| 260 | { | ||
| 261 | int ret; | ||
| 262 | |||
| 263 | ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | ||
| 264 | if (ret < 0) | ||
| 265 | return ret; | ||
| 266 | |||
| 267 | msleep(25); | ||
| 268 | |||
| 269 | gpiod_set_value(ctx->reset_gpio, 0); | ||
| 270 | msleep(120); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int s6e63m0_power_off(struct s6e63m0 *ctx) | ||
| 276 | { | ||
| 277 | int ret; | ||
| 278 | |||
| 279 | gpiod_set_value(ctx->reset_gpio, 1); | ||
| 280 | msleep(120); | ||
| 281 | |||
| 282 | ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | ||
| 283 | if (ret < 0) | ||
| 284 | return ret; | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int s6e63m0_disable(struct drm_panel *panel) | ||
| 290 | { | ||
| 291 | struct s6e63m0 *ctx = panel_to_s6e63m0(panel); | ||
| 292 | |||
| 293 | if (!ctx->enabled) | ||
| 294 | return 0; | ||
| 295 | |||
| 296 | backlight_disable(ctx->bl_dev); | ||
| 297 | |||
| 298 | s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); | ||
| 299 | msleep(200); | ||
| 300 | |||
| 301 | ctx->enabled = false; | ||
| 302 | |||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | static int s6e63m0_unprepare(struct drm_panel *panel) | ||
| 307 | { | ||
| 308 | struct s6e63m0 *ctx = panel_to_s6e63m0(panel); | ||
| 309 | int ret; | ||
| 310 | |||
| 311 | if (!ctx->prepared) | ||
| 312 | return 0; | ||
| 313 | |||
| 314 | s6e63m0_clear_error(ctx); | ||
| 315 | |||
| 316 | ret = s6e63m0_power_off(ctx); | ||
| 317 | if (ret < 0) | ||
| 318 | return ret; | ||
| 319 | |||
| 320 | ctx->prepared = false; | ||
| 321 | |||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | |||
| 325 | static int s6e63m0_prepare(struct drm_panel *panel) | ||
| 326 | { | ||
| 327 | struct s6e63m0 *ctx = panel_to_s6e63m0(panel); | ||
| 328 | int ret; | ||
| 329 | |||
| 330 | if (ctx->prepared) | ||
| 331 | return 0; | ||
| 332 | |||
| 333 | ret = s6e63m0_power_on(ctx); | ||
| 334 | if (ret < 0) | ||
| 335 | return ret; | ||
| 336 | |||
| 337 | s6e63m0_init(ctx); | ||
| 338 | |||
| 339 | ret = s6e63m0_clear_error(ctx); | ||
| 340 | |||
| 341 | if (ret < 0) | ||
| 342 | s6e63m0_unprepare(panel); | ||
| 343 | |||
| 344 | ctx->prepared = true; | ||
| 345 | |||
| 346 | return ret; | ||
| 347 | } | ||
| 348 | |||
| 349 | static int s6e63m0_enable(struct drm_panel *panel) | ||
| 350 | { | ||
| 351 | struct s6e63m0 *ctx = panel_to_s6e63m0(panel); | ||
| 352 | |||
| 353 | if (ctx->enabled) | ||
| 354 | return 0; | ||
| 355 | |||
| 356 | s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON); | ||
| 357 | |||
| 358 | backlight_enable(ctx->bl_dev); | ||
| 359 | |||
| 360 | ctx->enabled = true; | ||
| 361 | |||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 365 | static int s6e63m0_get_modes(struct drm_panel *panel) | ||
| 366 | { | ||
| 367 | struct drm_connector *connector = panel->connector; | ||
| 368 | struct drm_display_mode *mode; | ||
| 369 | |||
| 370 | mode = drm_mode_duplicate(panel->drm, &default_mode); | ||
| 371 | if (!mode) { | ||
| 372 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | ||
| 373 | default_mode.hdisplay, default_mode.vdisplay, | ||
| 374 | default_mode.vrefresh); | ||
| 375 | return -ENOMEM; | ||
| 376 | } | ||
| 377 | |||
| 378 | drm_mode_set_name(mode); | ||
| 379 | |||
| 380 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
| 381 | drm_mode_probed_add(connector, mode); | ||
| 382 | |||
| 383 | return 1; | ||
| 384 | } | ||
| 385 | |||
| 386 | static const struct drm_panel_funcs s6e63m0_drm_funcs = { | ||
| 387 | .disable = s6e63m0_disable, | ||
| 388 | .unprepare = s6e63m0_unprepare, | ||
| 389 | .prepare = s6e63m0_prepare, | ||
| 390 | .enable = s6e63m0_enable, | ||
| 391 | .get_modes = s6e63m0_get_modes, | ||
| 392 | }; | ||
| 393 | |||
| 394 | static int s6e63m0_set_brightness(struct backlight_device *bd) | ||
| 395 | { | ||
| 396 | struct s6e63m0 *ctx = bl_get_data(bd); | ||
| 397 | |||
| 398 | int brightness = bd->props.brightness; | ||
| 399 | |||
| 400 | /* disable and set new gamma */ | ||
| 401 | s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness], | ||
| 402 | ARRAY_SIZE(s6e63m0_gamma_22[brightness])); | ||
| 403 | |||
| 404 | /* update gamma table. */ | ||
| 405 | s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x01); | ||
| 406 | |||
| 407 | return s6e63m0_clear_error(ctx); | ||
| 408 | } | ||
| 409 | |||
| 410 | static const struct backlight_ops s6e63m0_backlight_ops = { | ||
| 411 | .update_status = s6e63m0_set_brightness, | ||
| 412 | }; | ||
| 413 | |||
| 414 | static int s6e63m0_backlight_register(struct s6e63m0 *ctx) | ||
| 415 | { | ||
| 416 | struct backlight_properties props = { | ||
| 417 | .type = BACKLIGHT_RAW, | ||
| 418 | .brightness = MAX_BRIGHTNESS, | ||
| 419 | .max_brightness = MAX_BRIGHTNESS | ||
| 420 | }; | ||
| 421 | struct device *dev = ctx->dev; | ||
| 422 | int ret = 0; | ||
| 423 | |||
| 424 | ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx, | ||
| 425 | &s6e63m0_backlight_ops, | ||
| 426 | &props); | ||
| 427 | if (IS_ERR(ctx->bl_dev)) { | ||
| 428 | ret = PTR_ERR(ctx->bl_dev); | ||
| 429 | DRM_DEV_ERROR(dev, "error registering backlight device (%d)\n", | ||
| 430 | ret); | ||
| 431 | } | ||
| 432 | |||
| 433 | return ret; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int s6e63m0_probe(struct spi_device *spi) | ||
| 437 | { | ||
| 438 | struct device *dev = &spi->dev; | ||
| 439 | struct s6e63m0 *ctx; | ||
| 440 | int ret; | ||
| 441 | |||
| 442 | ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL); | ||
| 443 | if (!ctx) | ||
| 444 | return -ENOMEM; | ||
| 445 | |||
| 446 | spi_set_drvdata(spi, ctx); | ||
| 447 | |||
| 448 | ctx->dev = dev; | ||
| 449 | ctx->enabled = false; | ||
| 450 | ctx->prepared = false; | ||
| 451 | |||
| 452 | ctx->supplies[0].supply = "vdd3"; | ||
| 453 | ctx->supplies[1].supply = "vci"; | ||
| 454 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), | ||
| 455 | ctx->supplies); | ||
| 456 | if (ret < 0) { | ||
| 457 | DRM_DEV_ERROR(dev, "failed to get regulators: %d\n", ret); | ||
| 458 | return ret; | ||
| 459 | } | ||
| 460 | |||
| 461 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | ||
| 462 | if (IS_ERR(ctx->reset_gpio)) { | ||
| 463 | DRM_DEV_ERROR(dev, "cannot get reset-gpios %ld\n", | ||
| 464 | PTR_ERR(ctx->reset_gpio)); | ||
| 465 | return PTR_ERR(ctx->reset_gpio); | ||
| 466 | } | ||
| 467 | |||
| 468 | spi->bits_per_word = 9; | ||
| 469 | spi->mode = SPI_MODE_3; | ||
| 470 | ret = spi_setup(spi); | ||
| 471 | if (ret < 0) { | ||
| 472 | DRM_DEV_ERROR(dev, "spi setup failed.\n"); | ||
| 473 | return ret; | ||
| 474 | } | ||
| 475 | |||
| 476 | drm_panel_init(&ctx->panel); | ||
| 477 | ctx->panel.dev = dev; | ||
| 478 | ctx->panel.funcs = &s6e63m0_drm_funcs; | ||
| 479 | |||
| 480 | ret = s6e63m0_backlight_register(ctx); | ||
| 481 | if (ret < 0) | ||
| 482 | return ret; | ||
| 483 | |||
| 484 | return drm_panel_add(&ctx->panel); | ||
| 485 | } | ||
| 486 | |||
| 487 | static int s6e63m0_remove(struct spi_device *spi) | ||
| 488 | { | ||
| 489 | struct s6e63m0 *ctx = spi_get_drvdata(spi); | ||
| 490 | |||
| 491 | drm_panel_remove(&ctx->panel); | ||
| 492 | |||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | static const struct of_device_id s6e63m0_of_match[] = { | ||
| 497 | { .compatible = "samsung,s6e63m0" }, | ||
| 498 | { /* sentinel */ } | ||
| 499 | }; | ||
| 500 | MODULE_DEVICE_TABLE(of, s6e63m0_of_match); | ||
| 501 | |||
| 502 | static struct spi_driver s6e63m0_driver = { | ||
| 503 | .probe = s6e63m0_probe, | ||
| 504 | .remove = s6e63m0_remove, | ||
| 505 | .driver = { | ||
| 506 | .name = "panel-samsung-s6e63m0", | ||
| 507 | .of_match_table = s6e63m0_of_match, | ||
| 508 | }, | ||
| 509 | }; | ||
| 510 | module_spi_driver(s6e63m0_driver); | ||
| 511 | |||
| 512 | MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>"); | ||
| 513 | MODULE_DESCRIPTION("s6e63m0 LCD Driver"); | ||
| 514 | MODULE_LICENSE("GPL v2"); | ||
| @@ -1096,6 +1096,56 @@ static const struct panel_desc dlc_dlc1010gig = { · 1095 unmodified lines | |||
| 1096 | .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, | 1096 | .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, |
| 1097 | }; | 1097 | }; |
| 1098 | 1098 | ||
| 1099 | static const struct drm_display_mode edt_et035012dm6_mode = { | ||
| 1100 | .clock = 6500, | ||
| 1101 | .hdisplay = 320, | ||
| 1102 | .hsync_start = 320 + 20, | ||
| 1103 | .hsync_end = 320 + 20 + 30, | ||
| 1104 | .htotal = 320 + 20 + 68, | ||
| 1105 | .vdisplay = 240, | ||
| 1106 | .vsync_start = 240 + 4, | ||
| 1107 | .vsync_end = 240 + 4 + 4, | ||
| 1108 | .vtotal = 240 + 4 + 4 + 14, | ||
| 1109 | .vrefresh = 60, | ||
| 1110 | .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, | ||
| 1111 | }; | ||
| 1112 | |||
| 1113 | static const struct panel_desc edt_et035012dm6 = { | ||
| 1114 | .modes = &edt_et035012dm6_mode, | ||
| 1115 | .num_modes = 1, | ||
| 1116 | .bpc = 8, | ||
| 1117 | .size = { | ||
| 1118 | .width = 70, | ||
| 1119 | .height = 52, | ||
| 1120 | }, | ||
| 1121 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||
| 1122 | .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_NEGEDGE, | ||
| 1123 | }; | ||
| 1124 | |||
| 1125 | static const struct drm_display_mode edt_etm0430g0dh6_mode = { | ||
| 1126 | .clock = 9000, | ||
| 1127 | .hdisplay = 480, | ||
| 1128 | .hsync_start = 480 + 2, | ||
| 1129 | .hsync_end = 480 + 2 + 41, | ||
| 1130 | .htotal = 480 + 2 + 41 + 2, | ||
| 1131 | .vdisplay = 272, | ||
| 1132 | .vsync_start = 272 + 2, | ||
| 1133 | .vsync_end = 272 + 2 + 10, | ||
| 1134 | .vtotal = 272 + 2 + 10 + 2, | ||
| 1135 | .vrefresh = 60, | ||
| 1136 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | ||
| 1137 | }; | ||
| 1138 | |||
| 1139 | static const struct panel_desc edt_etm0430g0dh6 = { | ||
| 1140 | .modes = &edt_etm0430g0dh6_mode, | ||
| 1141 | .num_modes = 1, | ||
| 1142 | .bpc = 6, | ||
| 1143 | .size = { | ||
| 1144 | .width = 95, | ||
| 1145 | .height = 54, | ||
| 1146 | }, | ||
| 1147 | }; | ||
| 1148 | |||
| 1099 | static const struct drm_display_mode edt_et057090dhu_mode = { | 1149 | static const struct drm_display_mode edt_et057090dhu_mode = { |
| 1100 | .clock = 25175, | 1150 | .clock = 25175, |
| 1101 | .hdisplay = 640, | 1151 | .hdisplay = 640, |
| @@ -1160,6 +1210,33 @@ static const struct panel_desc edt_etm0700g0bdh6 = { · 58 unmodified lines | |||
| 1160 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, | 1210 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
| 1161 | }; | 1211 | }; |
| 1162 | 1212 | ||
| 1213 | static const struct display_timing evervision_vgg804821_timing = { | ||
| 1214 | .pixelclock = { 27600000, 33300000, 50000000 }, | ||
| 1215 | .hactive = { 800, 800, 800 }, | ||
| 1216 | .hfront_porch = { 40, 66, 70 }, | ||
| 1217 | .hback_porch = { 40, 67, 70 }, | ||
| 1218 | .hsync_len = { 40, 67, 70 }, | ||
| 1219 | .vactive = { 480, 480, 480 }, | ||
| 1220 | .vfront_porch = { 6, 10, 10 }, | ||
| 1221 | .vback_porch = { 7, 11, 11 }, | ||
| 1222 | .vsync_len = { 7, 11, 11 }, | ||
| 1223 | .flags = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH | | ||
| 1224 | DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE | | ||
| 1225 | DISPLAY_FLAGS_SYNC_NEGEDGE, | ||
| 1226 | }; | ||
| 1227 | |||
| 1228 | static const struct panel_desc evervision_vgg804821 = { | ||
| 1229 | .timings = &evervision_vgg804821_timing, | ||
| 1230 | .num_timings = 1, | ||
| 1231 | .bpc = 8, | ||
| 1232 | .size = { | ||
| 1233 | .width = 108, | ||
| 1234 | .height = 64, | ||
| 1235 | }, | ||
| 1236 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||
| 1237 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, | ||
| 1238 | }; | ||
| 1239 | |||
| 1163 | static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { | 1240 | static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { |
| 1164 | .clock = 32260, | 1241 | .clock = 32260, |
| 1165 | .hdisplay = 800, | 1242 | .hdisplay = 800, |
| @@ -1184,6 +1261,29 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = { · 18 unmodified lines | |||
| 1184 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | 1261 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
| 1185 | }; | 1262 | }; |
| 1186 | 1263 | ||
| 1264 | static const struct drm_display_mode friendlyarm_hd702e_mode = { | ||
| 1265 | .clock = 67185, | ||
| 1266 | .hdisplay = 800, | ||
| 1267 | .hsync_start = 800 + 20, | ||
| 1268 | .hsync_end = 800 + 20 + 24, | ||
| 1269 | .htotal = 800 + 20 + 24 + 20, | ||
| 1270 | .vdisplay = 1280, | ||
| 1271 | .vsync_start = 1280 + 4, | ||
| 1272 | .vsync_end = 1280 + 4 + 8, | ||
| 1273 | .vtotal = 1280 + 4 + 8 + 4, | ||
| 1274 | .vrefresh = 60, | ||
| 1275 | .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, | ||
| 1276 | }; | ||
| 1277 | |||
| 1278 | static const struct panel_desc friendlyarm_hd702e = { | ||
| 1279 | .modes = &friendlyarm_hd702e_mode, | ||
| 1280 | .num_modes = 1, | ||
| 1281 | .size = { | ||
| 1282 | .width = 94, | ||
| 1283 | .height = 151, | ||
| 1284 | }, | ||
| 1285 | }; | ||
| 1286 | |||
| 1187 | static const struct drm_display_mode giantplus_gpg482739qs5_mode = { | 1287 | static const struct drm_display_mode giantplus_gpg482739qs5_mode = { |
| 1188 | .clock = 9000, | 1288 | .clock = 9000, |
| 1189 | .hdisplay = 480, | 1289 | .hdisplay = 480, |
| @@ -2355,6 +2455,31 @@ static const struct panel_desc starry_kr122ea0sra = { · 1165 unmodified lines | |||
| 2355 | }, | 2455 | }, |
| 2356 | }; | 2456 | }; |
| 2357 | 2457 | ||
| 2458 | static const struct drm_display_mode tfc_s9700rtwv43tr_01b_mode = { | ||
| 2459 | .clock = 30000, | ||
| 2460 | .hdisplay = 800, | ||
| 2461 | .hsync_start = 800 + 39, | ||
| 2462 | .hsync_end = 800 + 39 + 47, | ||
| 2463 | .htotal = 800 + 39 + 47 + 39, | ||
| 2464 | .vdisplay = 480, | ||
| 2465 | .vsync_start = 480 + 13, | ||
| 2466 | .vsync_end = 480 + 13 + 2, | ||
| 2467 | .vtotal = 480 + 13 + 2 + 29, | ||
| 2468 | .vrefresh = 62, | ||
| 2469 | }; | ||
| 2470 | |||
| 2471 | static const struct panel_desc tfc_s9700rtwv43tr_01b = { | ||
| 2472 | .modes = &tfc_s9700rtwv43tr_01b_mode, | ||
| 2473 | .num_modes = 1, | ||
| 2474 | .bpc = 8, | ||
| 2475 | .size = { | ||
| 2476 | .width = 155, | ||
| 2477 | .height = 90, | ||
| 2478 | }, | ||
| 2479 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||
| 2480 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
| 2481 | }; | ||
| 2482 | |||
| 2358 | static const struct display_timing tianma_tm070jdhg30_timing = { | 2483 | static const struct display_timing tianma_tm070jdhg30_timing = { |
| 2359 | .pixelclock = { 62600000, 68200000, 78100000 }, | 2484 | .pixelclock = { 62600000, 68200000, 78100000 }, |
| 2360 | .hactive = { 1280, 1280, 1280 }, | 2485 | .hactive = { 1280, 1280, 1280 }, |
| @@ -2508,6 +2633,32 @@ static const struct panel_desc urt_umsh_8596md_parallel = { · 147 unmodified lines | |||
| 2508 | .bus_format = MEDIA_BUS_FMT_RGB666_1X18, | 2633 | .bus_format = MEDIA_BUS_FMT_RGB666_1X18, |
| 2509 | }; | 2634 | }; |
| 2510 | 2635 | ||
| 2636 | static const struct drm_display_mode vl050_8048nt_c01_mode = { | ||
| 2637 | .clock = 33333, | ||
| 2638 | .hdisplay = 800, | ||
| 2639 | .hsync_start = 800 + 210, | ||
| 2640 | .hsync_end = 800 + 210 + 20, | ||
| 2641 | .htotal = 800 + 210 + 20 + 46, | ||
| 2642 | .vdisplay = 480, | ||
| 2643 | .vsync_start = 480 + 22, | ||
| 2644 | .vsync_end = 480 + 22 + 10, | ||
| 2645 | .vtotal = 480 + 22 + 10 + 23, | ||
| 2646 | .vrefresh = 60, | ||
| 2647 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | ||
| 2648 | }; | ||
| 2649 | |||
| 2650 | static const struct panel_desc vl050_8048nt_c01 = { | ||
| 2651 | .modes = &vl050_8048nt_c01_mode, | ||
| 2652 | .num_modes = 1, | ||
| 2653 | .bpc = 8, | ||
| 2654 | .size = { | ||
| 2655 | .width = 120, | ||
| 2656 | .height = 76, | ||
| 2657 | }, | ||
| 2658 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||
| 2659 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, | ||
| 2660 | }; | ||
| 2661 | |||
| 2511 | static const struct drm_display_mode winstar_wf35ltiacd_mode = { | 2662 | static const struct drm_display_mode winstar_wf35ltiacd_mode = { |
| 2512 | .clock = 6410, | 2663 | .clock = 6410, |
| 2513 | .hdisplay = 320, | 2664 | .hdisplay = 320, |
| @@ -2645,6 +2796,12 @@ static const struct of_device_id platform_of_match[] = { · 131 unmodified lines | |||
| 2645 | }, { | 2796 | }, { |
| 2646 | .compatible = "dlc,dlc1010gig", | 2797 | .compatible = "dlc,dlc1010gig", |
| 2647 | .data = &dlc_dlc1010gig, | 2798 | .data = &dlc_dlc1010gig, |
| 2799 | }, { | ||
| 2800 | .compatible = "edt,et035012dm6", | ||
| 2801 | .data = &edt_et035012dm6, | ||
| 2802 | }, { | ||
| 2803 | .compatible = "edt,etm0430g0dh6", | ||
| 2804 | .data = &edt_etm0430g0dh6, | ||
| 2648 | }, { | 2805 | }, { |
| 2649 | .compatible = "edt,et057090dhu", | 2806 | .compatible = "edt,et057090dhu", |
| 2650 | .data = &edt_et057090dhu, | 2807 | .data = &edt_et057090dhu, |
| @@ -2660,9 +2817,15 @@ static const struct of_device_id platform_of_match[] = { · 9 unmodified lines | |||
| 2660 | }, { | 2817 | }, { |
| 2661 | .compatible = "edt,etm0700g0edh6", | 2818 | .compatible = "edt,etm0700g0edh6", |
| 2662 | .data = &edt_etm0700g0bdh6, | 2819 | .data = &edt_etm0700g0bdh6, |
| 2820 | }, { | ||
| 2821 | .compatible = "evervision,vgg804821", | ||
| 2822 | .data = &evervision_vgg804821, | ||
| 2663 | }, { | 2823 | }, { |
| 2664 | .compatible = "foxlink,fl500wvr00-a0t", | 2824 | .compatible = "foxlink,fl500wvr00-a0t", |
| 2665 | .data = &foxlink_fl500wvr00_a0t, | 2825 | .data = &foxlink_fl500wvr00_a0t, |
| 2826 | }, { | ||
| 2827 | .compatible = "friendlyarm,hd702e", | ||
| 2828 | .data = &friendlyarm_hd702e, | ||
| 2666 | }, { | 2829 | }, { |
| 2667 | .compatible = "giantplus,gpg482739qs5", | 2830 | .compatible = "giantplus,gpg482739qs5", |
| 2668 | .data = &giantplus_gpg482739qs5 | 2831 | .data = &giantplus_gpg482739qs5 |
| @@ -2801,6 +2964,9 @@ static const struct of_device_id platform_of_match[] = { · 132 unmodified lines | |||
| 2801 | }, { | 2964 | }, { |
| 2802 | .compatible = "starry,kr122ea0sra", | 2965 | .compatible = "starry,kr122ea0sra", |
| 2803 | .data = &starry_kr122ea0sra, | 2966 | .data = &starry_kr122ea0sra, |
| 2967 | }, { | ||
| 2968 | .compatible = "tfc,s9700rtwv43tr-01b", | ||
| 2969 | .data = &tfc_s9700rtwv43tr_01b, | ||
| 2804 | }, { | 2970 | }, { |
| 2805 | .compatible = "tianma,tm070jdhg30", | 2971 | .compatible = "tianma,tm070jdhg30", |
| 2806 | .data = &tianma_tm070jdhg30, | 2972 | .data = &tianma_tm070jdhg30, |
| @@ -2834,6 +3000,9 @@ static const struct of_device_id platform_of_match[] = { · 27 unmodified lines | |||
| 2834 | }, { | 3000 | }, { |
| 2835 | .compatible = "urt,umsh-8596md-20t", | 3001 | .compatible = "urt,umsh-8596md-20t", |
| 2836 | .data = &urt_umsh_8596md_parallel, | 3002 | .data = &urt_umsh_8596md_parallel, |
| 3003 | }, { | ||
| 3004 | .compatible = "vxt,vl050-8048nt-c01", | ||
| 3005 | .data = &vl050_8048nt_c01, | ||
| 2837 | }, { | 3006 | }, { |
| 2838 | .compatible = "winstar,wf35ltiacd", | 3007 | .compatible = "winstar,wf35ltiacd", |
| 2839 | .data = &winstar_wf35ltiacd, | 3008 | .data = &winstar_wf35ltiacd, |
| @@ -3053,6 +3222,37 @@ static const struct panel_desc_dsi lg_acx467akm_7 = { · 213 unmodified lines | |||
| 3053 | .lanes = 4, | 3222 | .lanes = 4, |
| 3054 | }; | 3223 | }; |
| 3055 | 3224 | ||
| 3225 | static const struct drm_display_mode osd101t2045_53ts_mode = { | ||
| 3226 | .clock = 154500, | ||
| 3227 | .hdisplay = 1920, | ||
| 3228 | .hsync_start = 1920 + 112, | ||
| 3229 | .hsync_end = 1920 + 112 + 16, | ||
| 3230 | .htotal = 1920 + 112 + 16 + 32, | ||
| 3231 | .vdisplay = 1200, | ||
| 3232 | .vsync_start = 1200 + 16, | ||
| 3233 | .vsync_end = 1200 + 16 + 2, | ||
| 3234 | .vtotal = 1200 + 16 + 2 + 16, | ||
| 3235 | .vrefresh = 60, | ||
| 3236 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | ||
| 3237 | }; | ||
| 3238 | |||
| 3239 | static const struct panel_desc_dsi osd101t2045_53ts = { | ||
| 3240 | .desc = { | ||
| 3241 | .modes = &osd101t2045_53ts_mode, | ||
| 3242 | .num_modes = 1, | ||
| 3243 | .bpc = 8, | ||
| 3244 | .size = { | ||
| 3245 | .width = 217, | ||
| 3246 | .height = 136, | ||
| 3247 | }, | ||
| 3248 | }, | ||
| 3249 | .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | | ||
| 3250 | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | | ||
| 3251 | MIPI_DSI_MODE_EOT_PACKET, | ||
| 3252 | .format = MIPI_DSI_FMT_RGB888, | ||
| 3253 | .lanes = 4, | ||
| 3254 | }; | ||
| 3255 | |||
| 3056 | static const struct of_device_id dsi_of_match[] = { | 3256 | static const struct of_device_id dsi_of_match[] = { |
| 3057 | { | 3257 | { |
| 3058 | .compatible = "auo,b080uan01", | 3258 | .compatible = "auo,b080uan01", |
| @@ -3072,6 +3272,9 @@ static const struct of_device_id dsi_of_match[] = { · 13 unmodified lines | |||
| 3072 | }, { | 3272 | }, { |
| 3073 | .compatible = "lg,acx467akm-7", | 3273 | .compatible = "lg,acx467akm-7", |
| 3074 | .data = &lg_acx467akm_7 | 3274 | .data = &lg_acx467akm_7 |
| 3275 | }, { | ||
| 3276 | .compatible = "osddisplays,osd101t2045-53ts", | ||
| 3277 | .data = &osd101t2045_53ts | ||
| 3075 | }, { | 3278 | }, { |
| 3076 | /* sentinel */ | 3279 | /* sentinel */ |
| 3077 | } | 3280 | } |
| @@ -3098,7 +3301,14 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) · 20 unmodified lines | |||
| 3098 | dsi->format = desc->format; | 3301 | dsi->format = desc->format; |
| 3099 | dsi->lanes = desc->lanes; | 3302 | dsi->lanes = desc->lanes; |
| 3100 | 3303 | ||
| 3101 | return mipi_dsi_attach(dsi); | 3304 | err = mipi_dsi_attach(dsi); |
| 3305 | if (err) { | ||
| 3306 | struct panel_simple *panel = dev_get_drvdata(&dsi->dev); | ||
| 3307 | |||
| 3308 | drm_panel_remove(&panel->base); | ||
| 3309 | } | ||
| 3310 | |||
| 3311 | return err; | ||
| 3102 | } | 3312 | } |
| 3103 | 3313 | ||
| 3104 | static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi) | 3314 | static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi) |
| @@ -55,11 +55,33 @@ static int panfrost_clk_init(struct panfrost_device *pfdev) · 54 unmodified lines | |||
| 55 | if (err) | 55 | if (err) |
| 56 | return err; | 56 | return err; |
| 57 | 57 | ||
| 58 | pfdev->bus_clock = devm_clk_get_optional(pfdev->dev, "bus"); | ||
| 59 | if (IS_ERR(pfdev->bus_clock)) { | ||
| 60 | dev_err(pfdev->dev, "get bus_clock failed %ld\n", | ||
| 61 | PTR_ERR(pfdev->bus_clock)); | ||
| 62 | return PTR_ERR(pfdev->bus_clock); | ||
| 63 | } | ||
| 64 | |||
| 65 | if (pfdev->bus_clock) { | ||
| 66 | rate = clk_get_rate(pfdev->bus_clock); | ||
| 67 | dev_info(pfdev->dev, "bus_clock rate = %lu\n", rate); | ||
| 68 | |||
| 69 | err = clk_prepare_enable(pfdev->bus_clock); | ||
| 70 | if (err) | ||
| 71 | goto disable_clock; | ||
| 72 | } | ||
| 73 | |||
| 58 | return 0; | 74 | return 0; |
| 75 | |||
| 76 | disable_clock: | ||
| 77 | clk_disable_unprepare(pfdev->clock); | ||
| 78 | |||
| 79 | return err; | ||
| 59 | } | 80 | } |
| 60 | 81 | ||
| 61 | static void panfrost_clk_fini(struct panfrost_device *pfdev) | 82 | static void panfrost_clk_fini(struct panfrost_device *pfdev) |
| 62 | { | 83 | { |
| 84 | clk_disable_unprepare(pfdev->bus_clock); | ||
| 63 | clk_disable_unprepare(pfdev->clock); | 85 | clk_disable_unprepare(pfdev->clock); |
| 64 | } | 86 | } |
| 65 | 87 | ||
| @@ -66,6 +66,7 @@ struct panfrost_device { · 65 unmodified lines | |||
| 66 | 66 | ||
| 67 | void __iomem *iomem; | 67 | void __iomem *iomem; |
| 68 | struct clk *clock; | 68 | struct clk *clock; |
| 69 | struct clk *bus_clock; | ||
| 69 | struct regulator *regulator; | 70 | struct regulator *regulator; |
| 70 | struct reset_control *rstc; | 71 | struct reset_control *rstc; |
| 71 | 72 | ||
| @@ -387,7 +387,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) · 386 unmodified lines | |||
| 387 | mutex_lock(&pfdev->reset_lock); | 387 | mutex_lock(&pfdev->reset_lock); |
| 388 | 388 | ||
| 389 | for (i = 0; i < NUM_JOB_SLOTS; i++) | 389 | for (i = 0; i < NUM_JOB_SLOTS; i++) |
| 390 | drm_sched_stop(&pfdev->js->queue[i].sched); | 390 | drm_sched_stop(&pfdev->js->queue[i].sched, sched_job); |
| 391 | 391 | ||
| 392 | if (sched_job) | 392 | if (sched_job) |
| 393 | drm_sched_increase_karma(sched_job); | 393 | drm_sched_increase_karma(sched_job); |
| @@ -125,6 +125,7 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, · 124 unmodified lines | |||
| 125 | struct drm_mode_fb_cmd2 *mode_cmd, | 125 | struct drm_mode_fb_cmd2 *mode_cmd, |
| 126 | struct drm_gem_object **gobj_p) | 126 | struct drm_gem_object **gobj_p) |
| 127 | { | 127 | { |
| 128 | const struct drm_format_info *info; | ||
| 128 | struct radeon_device *rdev = rfbdev->rdev; | 129 | struct radeon_device *rdev = rfbdev->rdev; |
| 129 | struct drm_gem_object *gobj = NULL; | 130 | struct drm_gem_object *gobj = NULL; |
| 130 | struct radeon_bo *rbo = NULL; | 131 | struct radeon_bo *rbo = NULL; |
| @@ -135,7 +136,8 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, · 4 unmodified lines | |||
| 135 | int height = mode_cmd->height; | 136 | int height = mode_cmd->height; |
| 136 | u32 cpp; | 137 | u32 cpp; |
| 137 | 138 | ||
| 138 | cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); | 139 | info = drm_get_format_info(rdev->ddev, mode_cmd); |
| 140 | cpp = info->cpp[0]; | ||
| 139 | 141 | ||
| 140 | /* need to align pitch with crtc limits */ | 142 | /* need to align pitch with crtc limits */ |
| 141 | mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, cpp, | 143 | mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, cpp, |
| @@ -74,23 +74,18 @@ static struct drm_framebuffer * · 73 unmodified lines | |||
| 74 | rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, | 74 | rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, |
| 75 | const struct drm_mode_fb_cmd2 *mode_cmd) | 75 | const struct drm_mode_fb_cmd2 *mode_cmd) |
| 76 | { | 76 | { |
| 77 | const struct drm_format_info *info = drm_get_format_info(dev, | ||
| 78 | mode_cmd); | ||
| 77 | struct drm_framebuffer *fb; | 79 | struct drm_framebuffer *fb; |
| 78 | struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; | 80 | struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; |
| 79 | struct drm_gem_object *obj; | 81 | struct drm_gem_object *obj; |
| 80 | unsigned int hsub; | 82 | int num_planes = min_t(int, info->num_planes, ROCKCHIP_MAX_FB_BUFFER); |
| 81 | unsigned int vsub; | ||
| 82 | int num_planes; | ||
| 83 | int ret; | 83 | int ret; |
| 84 | int i; | 84 | int i; |
| 85 | 85 | ||
| 86 | hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); | ||
| 87 | vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); | ||
| 88 | num_planes = min(drm_format_num_planes(mode_cmd->pixel_format), | ||
| 89 | ROCKCHIP_MAX_FB_BUFFER); | ||
| 90 | |||
| 91 | for (i = 0; i < num_planes; i++) { | 86 | for (i = 0; i < num_planes; i++) { |
| 92 | unsigned int width = mode_cmd->width / (i ? hsub : 1); | 87 | unsigned int width = mode_cmd->width / (i ? info->hsub : 1); |
| 93 | unsigned int height = mode_cmd->height / (i ? vsub : 1); | 88 | unsigned int height = mode_cmd->height / (i ? info->vsub : 1); |
| 94 | unsigned int min_size; | 89 | unsigned int min_size; |
| 95 | 90 | ||
| 96 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); | 91 | obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); |
| @@ -103,7 +98,7 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, · 6 unmodified lines | |||
| 103 | 98 | ||
| 104 | min_size = (height - 1) * mode_cmd->pitches[i] + | 99 | min_size = (height - 1) * mode_cmd->pitches[i] + |
| 105 | mode_cmd->offsets[i] + | 100 | mode_cmd->offsets[i] + |
| 106 | width * drm_format_plane_cpp(mode_cmd->pixel_format, i); | 101 | width * info->cpp[i]; |
| 107 | 102 | ||
| 108 | if (obj->size < min_size) { | 103 | if (obj->size < min_size) { |
| 109 | drm_gem_object_put_unlocked(obj); | 104 | drm_gem_object_put_unlocked(obj); |
| @@ -315,24 +315,19 @@ static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, · 314 unmodified lines | |||
| 315 | 315 | ||
| 316 | static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, | 316 | static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, |
| 317 | uint32_t src_w, uint32_t src_h, uint32_t dst_w, | 317 | uint32_t src_w, uint32_t src_h, uint32_t dst_w, |
| 318 | uint32_t dst_h, uint32_t pixel_format) | 318 | uint32_t dst_h, const struct drm_format_info *info) |
| 319 | { | 319 | { |
| 320 | uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode; | 320 | uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode; |
| 321 | uint16_t cbcr_hor_scl_mode = SCALE_NONE; | 321 | uint16_t cbcr_hor_scl_mode = SCALE_NONE; |
| 322 | uint16_t cbcr_ver_scl_mode = SCALE_NONE; | 322 | uint16_t cbcr_ver_scl_mode = SCALE_NONE; |
| 323 | int hsub = drm_format_horz_chroma_subsampling(pixel_format); | ||
| 324 | int vsub = drm_format_vert_chroma_subsampling(pixel_format); | ||
| 325 | const struct drm_format_info *info; | ||
| 326 | bool is_yuv = false; | 323 | bool is_yuv = false; |
| 327 | uint16_t cbcr_src_w = src_w / hsub; | 324 | uint16_t cbcr_src_w = src_w / info->hsub; |
| 328 | uint16_t cbcr_src_h = src_h / vsub; | 325 | uint16_t cbcr_src_h = src_h / info->vsub; |
| 329 | uint16_t vsu_mode; | 326 | uint16_t vsu_mode; |
| 330 | uint16_t lb_mode; | 327 | uint16_t lb_mode; |
| 331 | uint32_t val; | 328 | uint32_t val; |
| 332 | int vskiplines; | 329 | int vskiplines; |
| 333 | 330 | ||
| 334 | info = drm_format_info(pixel_format); | ||
| 335 | |||
| 336 | if (info->is_yuv) | 331 | if (info->is_yuv) |
| 337 | is_yuv = true; | 332 | is_yuv = true; |
| 338 | 333 | ||
| @@ -831,8 +826,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane, · 492 unmodified lines | |||
| 831 | (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0); | 826 | (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0); |
| 832 | 827 | ||
| 833 | if (is_yuv) { | 828 | if (is_yuv) { |
| 834 | int hsub = drm_format_horz_chroma_subsampling(fb->format->format); | 829 | int hsub = fb->format->hsub; |
| 835 | int vsub = drm_format_vert_chroma_subsampling(fb->format->format); | 830 | int vsub = fb->format->vsub; |
| 836 | int bpp = fb->format->cpp[1]; | 831 | int bpp = fb->format->cpp[1]; |
| 837 | 832 | ||
| 838 | uv_obj = fb->obj[1]; | 833 | uv_obj = fb->obj[1]; |
| @@ -856,7 +851,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, · 17 unmodified lines | |||
| 856 | if (win->phy->scl) | 851 | if (win->phy->scl) |
| 857 | scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, | 852 | scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, |
| 858 | drm_rect_width(dest), drm_rect_height(dest), | 853 | drm_rect_width(dest), drm_rect_height(dest), |
| 859 | fb->format->format); | 854 | fb->format); |
| 860 | 855 | ||
| 861 | VOP_WIN_SET(vop, win, act_info, act_info); | 856 | VOP_WIN_SET(vop, win, act_info, act_info); |
| 862 | VOP_WIN_SET(vop, win, dsp_info, dsp_info); | 857 | VOP_WIN_SET(vop, win, dsp_info, dsp_info); |
| @@ -1222,17 +1217,6 @@ static void vop_crtc_destroy(struct drm_crtc *crtc) · 359 unmodified lines | |||
| 1222 | drm_crtc_cleanup(crtc); | 1217 | drm_crtc_cleanup(crtc); |
| 1223 | } | 1218 | } |
| 1224 | 1219 | ||
| 1225 | static void vop_crtc_reset(struct drm_crtc *crtc) | ||
| 1226 | { | ||
| 1227 | if (crtc->state) | ||
| 1228 | __drm_atomic_helper_crtc_destroy_state(crtc->state); | ||
| 1229 | kfree(crtc->state); | ||
| 1230 | |||
| 1231 | crtc->state = kzalloc(sizeof(struct rockchip_crtc_state), GFP_KERNEL); | ||
| 1232 | if (crtc->state) | ||
| 1233 | crtc->state->crtc = crtc; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) | 1220 | static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) |
| 1237 | { | 1221 | { |
| 1238 | struct rockchip_crtc_state *rockchip_state; | 1222 | struct rockchip_crtc_state *rockchip_state; |
| @@ -1254,6 +1238,17 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc, · 15 unmodified lines | |||
| 1254 | kfree(s); | 1238 | kfree(s); |
| 1255 | } | 1239 | } |
| 1256 | 1240 | ||
| 1241 | static void vop_crtc_reset(struct drm_crtc *crtc) | ||
| 1242 | { | ||
| 1243 | struct rockchip_crtc_state *crtc_state = | ||
| 1244 | kzalloc(sizeof(*crtc_state), GFP_KERNEL); | ||
| 1245 | |||
| 1246 | if (crtc->state) | ||
| 1247 | vop_crtc_destroy_state(crtc, crtc->state); | ||
| 1248 | |||
| 1249 | __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); | ||
| 1250 | } | ||
| 1251 | |||
| 1257 | #ifdef CONFIG_DRM_ANALOGIX_DP | 1252 | #ifdef CONFIG_DRM_ANALOGIX_DP |
| 1258 | static struct drm_connector *vop_get_edp_connector(struct vop *vop) | 1253 | static struct drm_connector *vop_get_edp_connector(struct vop *vop) |
| 1259 | { | 1254 | { |
| @@ -265,32 +265,6 @@ void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched, · 264 unmodified lines | |||
| 265 | } | 265 | } |
| 266 | EXPORT_SYMBOL(drm_sched_resume_timeout); | 266 | EXPORT_SYMBOL(drm_sched_resume_timeout); |
| 267 | 267 | ||
| 268 | /* job_finish is called after hw fence signaled | ||
| 269 | */ | ||
| 270 | static void drm_sched_job_finish(struct work_struct *work) | ||
| 271 | { | ||
| 272 | struct drm_sched_job *s_job = container_of(work, struct drm_sched_job, | ||
| 273 | finish_work); | ||
| 274 | struct drm_gpu_scheduler *sched = s_job->sched; | ||
| 275 | unsigned long flags; | ||
| 276 | |||
| 277 | /* | ||
| 278 | * Canceling the timeout without removing our job from the ring mirror | ||
| 279 | * list is safe, as we will only end up in this worker if our jobs | ||
| 280 | * finished fence has been signaled. So even if some another worker | ||
| 281 | * manages to find this job as the next job in the list, the fence | ||
| 282 | * signaled check below will prevent the timeout to be restarted. | ||
| 283 | */ | ||
| 284 | cancel_delayed_work_sync(&sched->work_tdr); | ||
| 285 | |||
| 286 | spin_lock_irqsave(&sched->job_list_lock, flags); | ||
| 287 | /* queue TDR for next job */ | ||
| 288 | drm_sched_start_timeout(sched); | ||
| 289 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 290 | |||
| 291 | sched->ops->free_job(s_job); | ||
| 292 | } | ||
| 293 | |||
| 294 | static void drm_sched_job_begin(struct drm_sched_job *s_job) | 268 | static void drm_sched_job_begin(struct drm_sched_job *s_job) |
| 295 | { | 269 | { |
| 296 | struct drm_gpu_scheduler *sched = s_job->sched; | 270 | struct drm_gpu_scheduler *sched = s_job->sched; |
| @@ -315,6 +289,15 @@ static void drm_sched_job_timedout(struct work_struct *work) · 18 unmodified lines | |||
| 315 | if (job) | 289 | if (job) |
| 316 | job->sched->ops->timedout_job(job); | 290 | job->sched->ops->timedout_job(job); |
| 317 | 291 | ||
| 292 | /* | ||
| 293 | * Guilty job did complete and hence needs to be manually removed | ||
| 294 | * See drm_sched_stop doc. | ||
| 295 | */ | ||
| 296 | if (sched->free_guilty) { | ||
| 297 | job->sched->ops->free_job(job); | ||
| 298 | sched->free_guilty = false; | ||
| 299 | } | ||
| 300 | |||
| 318 | spin_lock_irqsave(&sched->job_list_lock, flags); | 301 | spin_lock_irqsave(&sched->job_list_lock, flags); |
| 319 | drm_sched_start_timeout(sched); | 302 | drm_sched_start_timeout(sched); |
| 320 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | 303 | spin_unlock_irqrestore(&sched->job_list_lock, flags); |
| @@ -370,40 +353,66 @@ EXPORT_SYMBOL(drm_sched_increase_karma); · 49 unmodified lines | |||
| 370 | * | 353 | * |
| 371 | * @sched: scheduler instance | 354 | * @sched: scheduler instance |
| 372 | * | 355 | * |
| 356 | * Stop the scheduler and also removes and frees all completed jobs. | ||
| 357 | * Note: bad job will not be freed as it might be used later and so it's | ||
| 358 | * callers responsibility to release it manually if it's not part of the | ||
| 359 | * mirror list any more. | ||
| 360 | * | ||
| 373 | */ | 361 | */ |
| 374 | void drm_sched_stop(struct drm_gpu_scheduler *sched) | 362 | void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad) |
| 375 | { | 363 | { |
| 376 | struct drm_sched_job *s_job; | 364 | struct drm_sched_job *s_job, *tmp; |
| 377 | unsigned long flags; | 365 | unsigned long flags; |
| 378 | struct dma_fence *last_fence = NULL; | ||
| 379 | 366 | ||
| 380 | kthread_park(sched->thread); | 367 | kthread_park(sched->thread); |
| 381 | 368 | ||
| 382 | /* | 369 | /* |
| 383 | * Verify all the signaled jobs in mirror list are removed from the ring | 370 | * Iterate the job list from later to earlier one and either deactive |
| 384 | * by waiting for the latest job to enter the list. This should insure that | 371 | * their HW callbacks or remove them from mirror list if they already |
| 385 | * also all the previous jobs that were in flight also already singaled | 372 | * signaled. |
| 386 | * and removed from the list. | 373 | * This iteration is thread safe as sched thread is stopped. |
| 387 | */ | 374 | */ |
| 388 | spin_lock_irqsave(&sched->job_list_lock, flags); | 375 | list_for_each_entry_safe_reverse(s_job, tmp, &sched->ring_mirror_list, node) { |
| 389 | list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) { | ||
| 390 | if (s_job->s_fence->parent && | 376 | if (s_job->s_fence->parent && |
| 391 | dma_fence_remove_callback(s_job->s_fence->parent, | 377 | dma_fence_remove_callback(s_job->s_fence->parent, |
| 392 | &s_job->cb)) { | 378 | &s_job->cb)) { |
| 393 | dma_fence_put(s_job->s_fence->parent); | ||
| 394 | s_job->s_fence->parent = NULL; | ||
| 395 | atomic_dec(&sched->hw_rq_count); | 379 | atomic_dec(&sched->hw_rq_count); |
| 396 | } else { | 380 | } else { |
| 397 | last_fence = dma_fence_get(&s_job->s_fence->finished); | 381 | /* |
| 398 | break; | 382 | * remove job from ring_mirror_list. |
| 383 | * Locking here is for concurrent resume timeout | ||
| 384 | */ | ||
| 385 | spin_lock_irqsave(&sched->job_list_lock, flags); | ||
| 386 | list_del_init(&s_job->node); | ||
| 387 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 388 | |||
| 389 | /* | ||
| 390 | * Wait for job's HW fence callback to finish using s_job | ||
| 391 | * before releasing it. | ||
| 392 | * | ||
| 393 | * Job is still alive so fence refcount at least 1 | ||
| 394 | */ | ||
| 395 | dma_fence_wait(&s_job->s_fence->finished, false); | ||
| 396 | |||
| 397 | /* | ||
| 398 | * We must keep bad job alive for later use during | ||
| 399 | * recovery by some of the drivers but leave a hint | ||
| 400 | * that the guilty job must be released. | ||
| 401 | */ | ||
| 402 | if (bad != s_job) | ||
| 403 | sched->ops->free_job(s_job); | ||
| 404 | else | ||
| 405 | sched->free_guilty = true; | ||
| 399 | } | 406 | } |
| 400 | } | 407 | } |
| 401 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 402 | 408 | ||
| 403 | if (last_fence) { | 409 | /* |
| 404 | dma_fence_wait(last_fence, false); | 410 | * Stop pending timer in flight as we rearm it in drm_sched_start. This |
| 405 | dma_fence_put(last_fence); | 411 | * avoids the pending timeout work in progress to fire right away after |
| 406 | } | 412 | * this TDR finished and before the newly restarted jobs had a |
| 413 | * chance to complete. | ||
| 414 | */ | ||
| 415 | cancel_delayed_work(&sched->work_tdr); | ||
| 407 | } | 416 | } |
| 408 | 417 | ||
| 409 | EXPORT_SYMBOL(drm_sched_stop); | 418 | EXPORT_SYMBOL(drm_sched_stop); |
| @@ -417,21 +426,22 @@ EXPORT_SYMBOL(drm_sched_stop); · 7 unmodified lines | |||
| 417 | void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) | 426 | void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) |
| 418 | { | 427 | { |
| 419 | struct drm_sched_job *s_job, *tmp; | 428 | struct drm_sched_job *s_job, *tmp; |
| 429 | unsigned long flags; | ||
| 420 | int r; | 430 | int r; |
| 421 | 431 | ||
| 422 | if (!full_recovery) | ||
| 423 | goto unpark; | ||
| 424 | |||
| 425 | /* | 432 | /* |
| 426 | * Locking the list is not required here as the sched thread is parked | 433 | * Locking the list is not required here as the sched thread is parked |
| 427 | * so no new jobs are being pushed in to HW and in drm_sched_stop we | 434 | * so no new jobs are being inserted or removed. Also concurrent |
| 428 | * flushed all the jobs who were still in mirror list but who already | ||
| 429 | * signaled and removed them self from the list. Also concurrent | ||
| 430 | * GPU recovers can't run in parallel. | 435 | * GPU recovers can't run in parallel. |
| 431 | */ | 436 | */ |
| 432 | list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) { | 437 | list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) { |
| 433 | struct dma_fence *fence = s_job->s_fence->parent; | 438 | struct dma_fence *fence = s_job->s_fence->parent; |
| 434 | 439 | ||
| 440 | atomic_inc(&sched->hw_rq_count); | ||
| 441 | |||
| 442 | if (!full_recovery) | ||
| 443 | continue; | ||
| 444 | |||
| 435 | if (fence) { | 445 | if (fence) { |
| 436 | r = dma_fence_add_callback(fence, &s_job->cb, | 446 | r = dma_fence_add_callback(fence, &s_job->cb, |
| 437 | drm_sched_process_job); | 447 | drm_sched_process_job); |
| @@ -444,9 +454,12 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery) · 6 unmodified lines | |||
| 444 | drm_sched_process_job(NULL, &s_job->cb); | 454 | drm_sched_process_job(NULL, &s_job->cb); |
| 445 | } | 455 | } |
| 446 | 456 | ||
| 447 | drm_sched_start_timeout(sched); | 457 | if (full_recovery) { |
| 458 | spin_lock_irqsave(&sched->job_list_lock, flags); | ||
| 459 | drm_sched_start_timeout(sched); | ||
| 460 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 461 | } | ||
| 448 | 462 | ||
| 449 | unpark: | ||
| 450 | kthread_unpark(sched->thread); | 463 | kthread_unpark(sched->thread); |
| 451 | } | 464 | } |
| 452 | EXPORT_SYMBOL(drm_sched_start); | 465 | EXPORT_SYMBOL(drm_sched_start); |
| @@ -463,7 +476,6 @@ void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched) · 10 unmodified lines | |||
| 463 | uint64_t guilty_context; | 476 | uint64_t guilty_context; |
| 464 | bool found_guilty = false; | 477 | bool found_guilty = false; |
| 465 | 478 | ||
| 466 | /*TODO DO we need spinlock here ? */ | ||
| 467 | list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) { | 479 | list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) { |
| 468 | struct drm_sched_fence *s_fence = s_job->s_fence; | 480 | struct drm_sched_fence *s_fence = s_job->s_fence; |
| 469 | 481 | ||
| @@ -475,8 +487,8 @@ void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched) · 5 unmodified lines | |||
| 475 | if (found_guilty && s_job->s_fence->scheduled.context == guilty_context) | 487 | if (found_guilty && s_job->s_fence->scheduled.context == guilty_context) |
| 476 | dma_fence_set_error(&s_fence->finished, -ECANCELED); | 488 | dma_fence_set_error(&s_fence->finished, -ECANCELED); |
| 477 | 489 | ||
| 490 | dma_fence_put(s_job->s_fence->parent); | ||
| 478 | s_job->s_fence->parent = sched->ops->run_job(s_job); | 491 | s_job->s_fence->parent = sched->ops->run_job(s_job); |
| 479 | atomic_inc(&sched->hw_rq_count); | ||
| 480 | } | 492 | } |
| 481 | } | 493 | } |
| 482 | EXPORT_SYMBOL(drm_sched_resubmit_jobs); | 494 | EXPORT_SYMBOL(drm_sched_resubmit_jobs); |
| @@ -513,7 +525,6 @@ int drm_sched_job_init(struct drm_sched_job *job, · 30 unmodified lines | |||
| 513 | return -ENOMEM; | 525 | return -ENOMEM; |
| 514 | job->id = atomic64_inc_return(&sched->job_id_count); | 526 | job->id = atomic64_inc_return(&sched->job_id_count); |
| 515 | 527 | ||
| 516 | INIT_WORK(&job->finish_work, drm_sched_job_finish); | ||
| 517 | INIT_LIST_HEAD(&job->node); | 528 | INIT_LIST_HEAD(&job->node); |
| 518 | 529 | ||
| 519 | return 0; | 530 | return 0; |
| @@ -596,24 +607,54 @@ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb) · 76 unmodified lines | |||
| 596 | struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb); | 607 | struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb); |
| 597 | struct drm_sched_fence *s_fence = s_job->s_fence; | 608 | struct drm_sched_fence *s_fence = s_job->s_fence; |
| 598 | struct drm_gpu_scheduler *sched = s_fence->sched; | 609 | struct drm_gpu_scheduler *sched = s_fence->sched; |
| 599 | unsigned long flags; | ||
| 600 | |||
| 601 | cancel_delayed_work(&sched->work_tdr); | ||
| 602 | 610 | ||
| 603 | atomic_dec(&sched->hw_rq_count); | 611 | atomic_dec(&sched->hw_rq_count); |
| 604 | atomic_dec(&sched->num_jobs); | 612 | atomic_dec(&sched->num_jobs); |
| 605 | 613 | ||
| 606 | spin_lock_irqsave(&sched->job_list_lock, flags); | 614 | trace_drm_sched_process_job(s_fence); |
| 607 | /* remove job from ring_mirror_list */ | ||
| 608 | list_del_init(&s_job->node); | ||
| 609 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 610 | 615 | ||
| 611 | drm_sched_fence_finished(s_fence); | 616 | drm_sched_fence_finished(s_fence); |
| 612 | |||
| 613 | trace_drm_sched_process_job(s_fence); | ||
| 614 | wake_up_interruptible(&sched->wake_up_worker); | 617 | wake_up_interruptible(&sched->wake_up_worker); |
| 618 | } | ||
| 619 | |||
| 620 | /** | ||
| 621 | * drm_sched_cleanup_jobs - destroy finished jobs | ||
| 622 | * | ||
| 623 | * @sched: scheduler instance | ||
| 624 | * | ||
| 625 | * Remove all finished jobs from the mirror list and destroy them. | ||
| 626 | */ | ||
| 627 | static void drm_sched_cleanup_jobs(struct drm_gpu_scheduler *sched) | ||
| 628 | { | ||
| 629 | unsigned long flags; | ||
| 630 | |||
| 631 | /* Don't destroy jobs while the timeout worker is running */ | ||
| 632 | if (sched->timeout != MAX_SCHEDULE_TIMEOUT && | ||
| 633 | !cancel_delayed_work(&sched->work_tdr)) | ||
| 634 | return; | ||
| 635 | |||
| 636 | |||
| 637 | while (!list_empty(&sched->ring_mirror_list)) { | ||
| 638 | struct drm_sched_job *job; | ||
| 639 | |||
| 640 | job = list_first_entry(&sched->ring_mirror_list, | ||
| 641 | struct drm_sched_job, node); | ||
| 642 | if (!dma_fence_is_signaled(&job->s_fence->finished)) | ||
| 643 | break; | ||
| 644 | |||
| 645 | spin_lock_irqsave(&sched->job_list_lock, flags); | ||
| 646 | /* remove job from ring_mirror_list */ | ||
| 647 | list_del_init(&job->node); | ||
| 648 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 649 | |||
| 650 | sched->ops->free_job(job); | ||
| 651 | } | ||
| 652 | |||
| 653 | /* queue timeout for next job */ | ||
| 654 | spin_lock_irqsave(&sched->job_list_lock, flags); | ||
| 655 | drm_sched_start_timeout(sched); | ||
| 656 | spin_unlock_irqrestore(&sched->job_list_lock, flags); | ||
| 615 | 657 | ||
| 616 | schedule_work(&s_job->finish_work); | ||
| 617 | } | 658 | } |
| 618 | 659 | ||
| 619 | /** | 660 | /** |
| @@ -655,9 +696,10 @@ static int drm_sched_main(void *param) · 35 unmodified lines | |||
| 655 | struct dma_fence *fence; | 696 | struct dma_fence *fence; |
| 656 | 697 | ||
| 657 | wait_event_interruptible(sched->wake_up_worker, | 698 | wait_event_interruptible(sched->wake_up_worker, |
| 699 | (drm_sched_cleanup_jobs(sched), | ||
| 658 | (!drm_sched_blocked(sched) && | 700 | (!drm_sched_blocked(sched) && |
| 659 | (entity = drm_sched_select_entity(sched))) || | 701 | (entity = drm_sched_select_entity(sched))) || |
| 660 | kthread_should_stop()); | 702 | kthread_should_stop())); |
| 661 | 703 | ||
| 662 | if (!entity) | 704 | if (!entity) |
| 663 | continue; | 705 | continue; |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
| 10 | #include <linux/iopoll.h> | 10 | #include <linux/iopoll.h> |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/regulator/consumer.h> | ||
| 12 | #include <drm/drmP.h> | 13 | #include <drm/drmP.h> |
| 13 | #include <drm/drm_mipi_dsi.h> | 14 | #include <drm/drm_mipi_dsi.h> |
| 14 | #include <drm/bridge/dw_mipi_dsi.h> | 15 | #include <drm/bridge/dw_mipi_dsi.h> |
| @@ -76,6 +77,7 @@ struct dw_mipi_dsi_stm { · 61 unmodified lines | |||
| 76 | u32 hw_version; | 77 | u32 hw_version; |
| 77 | int lane_min_kbps; | 78 | int lane_min_kbps; |
| 78 | int lane_max_kbps; | 79 | int lane_max_kbps; |
| 80 | struct regulator *vdd_supply; | ||
| 79 | }; | 81 | }; |
| 80 | 82 | ||
| 81 | static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val) | 83 | static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val) |
| @@ -314,21 +316,36 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) · 232 unmodified lines | |||
| 314 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 316 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 315 | dsi->base = devm_ioremap_resource(dev, res); | 317 | dsi->base = devm_ioremap_resource(dev, res); |
| 316 | if (IS_ERR(dsi->base)) { | 318 | if (IS_ERR(dsi->base)) { |
| 317 | DRM_ERROR("Unable to get dsi registers\n"); | 319 | ret = PTR_ERR(dsi->base); |
| 318 | return PTR_ERR(dsi->base); | 320 | DRM_ERROR("Unable to get dsi registers %d\n", ret); |
| 321 | return ret; | ||
| 322 | } | ||
| 323 | |||
| 324 | dsi->vdd_supply = devm_regulator_get(dev, "phy-dsi"); | ||
| 325 | if (IS_ERR(dsi->vdd_supply)) { | ||
| 326 | ret = PTR_ERR(dsi->vdd_supply); | ||
| 327 | if (ret != -EPROBE_DEFER) | ||
| 328 | DRM_ERROR("Failed to request regulator: %d\n", ret); | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 332 | ret = regulator_enable(dsi->vdd_supply); | ||
| 333 | if (ret) { | ||
| 334 | DRM_ERROR("Failed to enable regulator: %d\n", ret); | ||
| 335 | return ret; | ||
| 319 | } | 336 | } |
| 320 | 337 | ||
| 321 | dsi->pllref_clk = devm_clk_get(dev, "ref"); | 338 | dsi->pllref_clk = devm_clk_get(dev, "ref"); |
| 322 | if (IS_ERR(dsi->pllref_clk)) { | 339 | if (IS_ERR(dsi->pllref_clk)) { |
| 323 | ret = PTR_ERR(dsi->pllref_clk); | 340 | ret = PTR_ERR(dsi->pllref_clk); |
| 324 | dev_err(dev, "Unable to get pll reference clock: %d\n", ret); | 341 | DRM_ERROR("Unable to get pll reference clock: %d\n", ret); |
| 325 | return ret; | 342 | goto err_clk_get; |
| 326 | } | 343 | } |
| 327 | 344 | ||
| 328 | ret = clk_prepare_enable(dsi->pllref_clk); | 345 | ret = clk_prepare_enable(dsi->pllref_clk); |
| 329 | if (ret) { | 346 | if (ret) { |
| 330 | dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); | 347 | DRM_ERROR("Failed to enable pllref_clk: %d\n", ret); |
| 331 | return ret; | 348 | goto err_clk_get; |
| 332 | } | 349 | } |
| 333 | 350 | ||
| 334 | dw_mipi_dsi_stm_plat_data.base = dsi->base; | 351 | dw_mipi_dsi_stm_plat_data.base = dsi->base; |
| @@ -338,20 +355,28 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) · 3 unmodified lines | |||
| 338 | 355 | ||
| 339 | dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); | 356 | dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); |
| 340 | if (IS_ERR(dsi->dsi)) { | 357 | if (IS_ERR(dsi->dsi)) { |
| 341 | DRM_ERROR("Failed to initialize mipi dsi host\n"); | 358 | ret = PTR_ERR(dsi->dsi); |
| 342 | clk_disable_unprepare(dsi->pllref_clk); | 359 | DRM_ERROR("Failed to initialize mipi dsi host: %d\n", ret); |
| 343 | return PTR_ERR(dsi->dsi); | 360 | goto err_dsi_probe; |
| 344 | } | 361 | } |
| 345 | 362 | ||
| 346 | return 0; | 363 | return 0; |
| 364 | |||
| 365 | err_dsi_probe: | ||
| 366 | clk_disable_unprepare(dsi->pllref_clk); | ||
| 367 | err_clk_get: | ||
| 368 | regulator_disable(dsi->vdd_supply); | ||
| 369 | |||
| 370 | return ret; | ||
| 347 | } | 371 | } |
| 348 | 372 | ||
| 349 | static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) | 373 | static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) |
| 350 | { | 374 | { |
| 351 | struct dw_mipi_dsi_stm *dsi = platform_get_drvdata(pdev); | 375 | struct dw_mipi_dsi_stm *dsi = platform_get_drvdata(pdev); |
| 352 | 376 | ||
| 353 | clk_disable_unprepare(dsi->pllref_clk); | ||
| 354 | dw_mipi_dsi_remove(dsi->dsi); | 377 | dw_mipi_dsi_remove(dsi->dsi); |
| 378 | clk_disable_unprepare(dsi->pllref_clk); | ||
| 379 | regulator_disable(dsi->vdd_supply); | ||
| 355 | 380 | ||
| 356 | return 0; | 381 | return 0; |
| 357 | } | 382 | } |
| @@ -363,6 +388,7 @@ static int __maybe_unused dw_mipi_dsi_stm_suspend(struct device *dev) · 5 unmodified lines | |||
| 363 | DRM_DEBUG_DRIVER("\n"); | 388 | DRM_DEBUG_DRIVER("\n"); |
| 364 | 389 | ||
| 365 | clk_disable_unprepare(dsi->pllref_clk); | 390 | clk_disable_unprepare(dsi->pllref_clk); |
| 391 | regulator_disable(dsi->vdd_supply); | ||
| 366 | 392 | ||
| 367 | return 0; | 393 | return 0; |
| 368 | } | 394 | } |
| @@ -370,10 +396,22 @@ static int __maybe_unused dw_mipi_dsi_stm_suspend(struct device *dev) · 1 unmodified line | |||
| 370 | static int __maybe_unused dw_mipi_dsi_stm_resume(struct device *dev) | 396 | static int __maybe_unused dw_mipi_dsi_stm_resume(struct device *dev) |
| 371 | { | 397 | { |
| 372 | struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data; | 398 | struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data; |
| 399 | int ret; | ||
| 373 | 400 | ||
| 374 | DRM_DEBUG_DRIVER("\n"); | 401 | DRM_DEBUG_DRIVER("\n"); |
| 375 | 402 | ||
| 376 | clk_prepare_enable(dsi->pllref_clk); | 403 | ret = regulator_enable(dsi->vdd_supply); |
| 404 | if (ret) { | ||
| 405 | DRM_ERROR("Failed to enable regulator: %d\n", ret); | ||
| 406 | return ret; | ||
| 407 | } | ||
| 408 | |||
| 409 | ret = clk_prepare_enable(dsi->pllref_clk); | ||
| 410 | if (ret) { | ||
| 411 | regulator_disable(dsi->vdd_supply); | ||
| 412 | DRM_ERROR("Failed to enable pllref_clk: %d\n", ret); | ||
| 413 | return ret; | ||
| 414 | } | ||
| 377 | 415 | ||
| 378 | return 0; | 416 | return 0; |
| 379 | } | 417 | } |
| @@ -232,6 +232,11 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { · 231 unmodified lines | |||
| 232 | PF_ARGB4444 /* 0x07 */ | 232 | PF_ARGB4444 /* 0x07 */ |
| 233 | }; | 233 | }; |
| 234 | 234 | ||
| 235 | static const u64 ltdc_format_modifiers[] = { | ||
| 236 | DRM_FORMAT_MOD_LINEAR, | ||
| 237 | DRM_FORMAT_MOD_INVALID | ||
| 238 | }; | ||
| 239 | |||
| 235 | static inline u32 reg_read(void __iomem *base, u32 reg) | 240 | static inline u32 reg_read(void __iomem *base, u32 reg) |
| 236 | { | 241 | { |
| 237 | return readl_relaxed(base + reg); | 242 | return readl_relaxed(base + reg); |
| @@ -426,8 +431,8 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, · 188 unmodified lines | |||
| 426 | /* Enable IRQ */ | 431 | /* Enable IRQ */ |
| 427 | reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | 432 | reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); |
| 428 | 433 | ||
| 429 | /* Immediately commit the planes */ | 434 | /* Commit shadow registers = update planes at next vblank */ |
| 430 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | 435 | reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); |
| 431 | 436 | ||
| 432 | /* Enable LTDC */ | 437 | /* Enable LTDC */ |
| 433 | reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); | 438 | reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); |
| @@ -555,7 +560,7 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 121 unmodified lines | |||
| 555 | if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) | 560 | if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) |
| 556 | val |= GCR_VSPOL; | 561 | val |= GCR_VSPOL; |
| 557 | 562 | ||
| 558 | if (vm.flags & DISPLAY_FLAGS_DE_HIGH) | 563 | if (vm.flags & DISPLAY_FLAGS_DE_LOW) |
| 559 | val |= GCR_DEPOL; | 564 | val |= GCR_DEPOL; |
| 560 | 565 | ||
| 561 | if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) | 566 | if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) |
| @@ -779,7 +784,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 217 unmodified lines | |||
| 779 | 784 | ||
| 780 | /* Configures the color frame buffer pitch in bytes & line length */ | 785 | /* Configures the color frame buffer pitch in bytes & line length */ |
| 781 | pitch_in_bytes = fb->pitches[0]; | 786 | pitch_in_bytes = fb->pitches[0]; |
| 782 | line_length = drm_format_plane_cpp(fb->format->format, 0) * | 787 | line_length = fb->format->cpp[0] * |
| 783 | (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; | 788 | (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; |
| 784 | val = ((pitch_in_bytes << 16) | line_length); | 789 | val = ((pitch_in_bytes << 16) | line_length); |
| 785 | reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, | 790 | reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, |
| @@ -822,11 +827,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 36 unmodified lines | |||
| 822 | 827 | ||
| 823 | mutex_lock(&ldev->err_lock); | 828 | mutex_lock(&ldev->err_lock); |
| 824 | if (ldev->error_status & ISR_FUIF) { | 829 | if (ldev->error_status & ISR_FUIF) { |
| 825 | DRM_DEBUG_DRIVER("Fifo underrun\n"); | 830 | DRM_WARN("ltdc fifo underrun: please verify display mode\n"); |
| 826 | ldev->error_status &= ~ISR_FUIF; | 831 | ldev->error_status &= ~ISR_FUIF; |
| 827 | } | 832 | } |
| 828 | if (ldev->error_status & ISR_TERRIF) { | 833 | if (ldev->error_status & ISR_TERRIF) { |
| 829 | DRM_DEBUG_DRIVER("Transfer error\n"); | 834 | DRM_WARN("ltdc transfer error\n"); |
| 830 | ldev->error_status &= ~ISR_TERRIF; | 835 | ldev->error_status &= ~ISR_TERRIF; |
| 831 | } | 836 | } |
| 832 | mutex_unlock(&ldev->err_lock); | 837 | mutex_unlock(&ldev->err_lock); |
| @@ -864,6 +869,16 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, · 31 unmodified lines | |||
| 864 | fpsi->counter = 0; | 869 | fpsi->counter = 0; |
| 865 | } | 870 | } |
| 866 | 871 | ||
| 872 | static bool ltdc_plane_format_mod_supported(struct drm_plane *plane, | ||
| 873 | u32 format, | ||
| 874 | u64 modifier) | ||
| 875 | { | ||
| 876 | if (modifier == DRM_FORMAT_MOD_LINEAR) | ||
| 877 | return true; | ||
| 878 | |||
| 879 | return false; | ||
| 880 | } | ||
| 881 | |||
| 867 | static const struct drm_plane_funcs ltdc_plane_funcs = { | 882 | static const struct drm_plane_funcs ltdc_plane_funcs = { |
| 868 | .update_plane = drm_atomic_helper_update_plane, | 883 | .update_plane = drm_atomic_helper_update_plane, |
| 869 | .disable_plane = drm_atomic_helper_disable_plane, | 884 | .disable_plane = drm_atomic_helper_disable_plane, |
| @@ -872,6 +887,7 @@ static const struct drm_plane_funcs ltdc_plane_funcs = { · 2 unmodified lines | |||
| 872 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | 887 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
| 873 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | 888 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, |
| 874 | .atomic_print_state = ltdc_plane_atomic_print_state, | 889 | .atomic_print_state = ltdc_plane_atomic_print_state, |
| 890 | .format_mod_supported = ltdc_plane_format_mod_supported, | ||
| 875 | }; | 891 | }; |
| 876 | 892 | ||
| 877 | static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { | 893 | static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { |
| @@ -890,6 +906,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, · 12 unmodified lines | |||
| 890 | unsigned int i, nb_fmt = 0; | 906 | unsigned int i, nb_fmt = 0; |
| 891 | u32 formats[NB_PF * 2]; | 907 | u32 formats[NB_PF * 2]; |
| 892 | u32 drm_fmt, drm_fmt_no_alpha; | 908 | u32 drm_fmt, drm_fmt_no_alpha; |
| 909 | const u64 *modifiers = ltdc_format_modifiers; | ||
| 893 | int ret; | 910 | int ret; |
| 894 | 911 | ||
| 895 | /* Get supported pixel formats */ | 912 | /* Get supported pixel formats */ |
| @@ -918,7 +935,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, · 22 unmodified lines | |||
| 918 | 935 | ||
| 919 | ret = drm_universal_plane_init(ddev, plane, possible_crtcs, | 936 | ret = drm_universal_plane_init(ddev, plane, possible_crtcs, |
| 920 | <dc_plane_funcs, formats, nb_fmt, | 937 | <dc_plane_funcs, formats, nb_fmt, |
| 921 | NULL, type, NULL); | 938 | modifiers, type, NULL); |
| 922 | if (ret < 0) | 939 | if (ret < 0) |
| 923 | return NULL; | 940 | return NULL; |
| 924 | 941 | ||
| @@ -1021,10 +1038,13 @@ static int ltdc_get_caps(struct drm_device *ddev) · 96 unmodified lines | |||
| 1021 | struct ltdc_device *ldev = ddev->dev_private; | 1038 | struct ltdc_device *ldev = ddev->dev_private; |
| 1022 | u32 bus_width_log2, lcr, gc2r; | 1039 | u32 bus_width_log2, lcr, gc2r; |
| 1023 | 1040 | ||
| 1024 | /* at least 1 layer must be managed */ | 1041 | /* |
| 1042 | * at least 1 layer must be managed & the number of layers | ||
| 1043 | * must not exceed LTDC_MAX_LAYER | ||
| 1044 | */ | ||
| 1025 | lcr = reg_read(ldev->regs, LTDC_LCR); | 1045 | lcr = reg_read(ldev->regs, LTDC_LCR); |
| 1026 | 1046 | ||
| 1027 | ldev->caps.nb_layers = max_t(int, lcr, 1); | 1047 | ldev->caps.nb_layers = clamp((int)lcr, 1, LTDC_MAX_LAYER); |
| 1028 | 1048 | ||
| 1029 | /* set data bus width */ | 1049 | /* set data bus width */ |
| 1030 | gc2r = reg_read(ldev->regs, LTDC_GC2R); | 1050 | gc2r = reg_read(ldev->regs, LTDC_GC2R); |
| @@ -1125,8 +1145,9 @@ int ltdc_load(struct drm_device *ddev) · 94 unmodified lines | |||
| 1125 | 1145 | ||
| 1126 | ldev->pixel_clk = devm_clk_get(dev, "lcd"); | 1146 | ldev->pixel_clk = devm_clk_get(dev, "lcd"); |
| 1127 | if (IS_ERR(ldev->pixel_clk)) { | 1147 | if (IS_ERR(ldev->pixel_clk)) { |
| 1128 | DRM_ERROR("Unable to get lcd clock\n"); | 1148 | if (PTR_ERR(ldev->pixel_clk) != -EPROBE_DEFER) |
| 1129 | return -ENODEV; | 1149 | DRM_ERROR("Unable to get lcd clock\n"); |
| 1150 | return PTR_ERR(ldev->pixel_clk); | ||
| 1130 | } | 1151 | } |
| 1131 | 1152 | ||
| 1132 | if (clk_prepare_enable(ldev->pixel_clk)) { | 1153 | if (clk_prepare_enable(ldev->pixel_clk)) { |
| @@ -1134,6 +1155,12 @@ int ltdc_load(struct drm_device *ddev) · 1 unmodified line | |||
| 1134 | return -ENODEV; | 1155 | return -ENODEV; |
| 1135 | } | 1156 | } |
| 1136 | 1157 | ||
| 1158 | if (!IS_ERR(rstc)) { | ||
| 1159 | reset_control_assert(rstc); | ||
| 1160 | usleep_range(10, 20); | ||
| 1161 | reset_control_deassert(rstc); | ||
| 1162 | } | ||
| 1163 | |||
| 1137 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1164 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1138 | ldev->regs = devm_ioremap_resource(dev, res); | 1165 | ldev->regs = devm_ioremap_resource(dev, res); |
| 1139 | if (IS_ERR(ldev->regs)) { | 1166 | if (IS_ERR(ldev->regs)) { |
| @@ -1142,8 +1169,15 @@ int ltdc_load(struct drm_device *ddev) · 2 unmodified lines | |||
| 1142 | goto err; | 1169 | goto err; |
| 1143 | } | 1170 | } |
| 1144 | 1171 | ||
| 1172 | /* Disable interrupts */ | ||
| 1173 | reg_clear(ldev->regs, LTDC_IER, | ||
| 1174 | IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); | ||
| 1175 | |||
| 1145 | for (i = 0; i < MAX_IRQ; i++) { | 1176 | for (i = 0; i < MAX_IRQ; i++) { |
| 1146 | irq = platform_get_irq(pdev, i); | 1177 | irq = platform_get_irq(pdev, i); |
| 1178 | if (irq == -EPROBE_DEFER) | ||
| 1179 | goto err; | ||
| 1180 | |||
| 1147 | if (irq < 0) | 1181 | if (irq < 0) |
| 1148 | continue; | 1182 | continue; |
| 1149 | 1183 | ||
| @@ -1156,15 +1190,6 @@ int ltdc_load(struct drm_device *ddev) · 6 unmodified lines | |||
| 1156 | } | 1190 | } |
| 1157 | } | 1191 | } |
| 1158 | 1192 | ||
| 1159 | if (!IS_ERR(rstc)) { | ||
| 1160 | reset_control_assert(rstc); | ||
| 1161 | usleep_range(10, 20); | ||
| 1162 | reset_control_deassert(rstc); | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | /* Disable interrupts */ | ||
| 1166 | reg_clear(ldev->regs, LTDC_IER, | ||
| 1167 | IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); | ||
| 1168 | 1193 | ||
| 1169 | ret = ltdc_get_caps(ddev); | 1194 | ret = ltdc_get_caps(ddev); |
| 1170 | if (ret) { | 1195 | if (ret) { |
| @@ -1203,6 +1228,8 @@ int ltdc_load(struct drm_device *ddev) · 32 unmodified lines | |||
| 1203 | goto err; | 1228 | goto err; |
| 1204 | } | 1229 | } |
| 1205 | 1230 | ||
| 1231 | ddev->mode_config.allow_fb_modifiers = true; | ||
| 1232 | |||
| 1206 | ret = ltdc_crtc_init(ddev, crtc); | 1233 | ret = ltdc_crtc_init(ddev, crtc); |
| 1207 | if (ret) { | 1234 | if (ret) { |
| 1208 | DRM_ERROR("Failed to init crtc\n"); | 1235 | DRM_ERROR("Failed to init crtc\n"); |
| @@ -53,22 +53,8 @@ static struct drm_driver sun4i_drv_driver = { · 52 unmodified lines | |||
| 53 | .minor = 0, | 53 | .minor = 0, |
| 54 | 54 | ||
| 55 | /* GEM Operations */ | 55 | /* GEM Operations */ |
| 56 | DRM_GEM_CMA_VMAP_DRIVER_OPS, | ||
| 56 | .dumb_create = drm_sun4i_gem_dumb_create, | 57 | .dumb_create = drm_sun4i_gem_dumb_create, |
| 57 | .gem_free_object_unlocked = drm_gem_cma_free_object, | ||
| 58 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
| 59 | |||
| 60 | /* PRIME Operations */ | ||
| 61 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
| 62 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
| 63 | .gem_prime_import = drm_gem_prime_import, | ||
| 64 | .gem_prime_export = drm_gem_prime_export, | ||
| 65 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
| 66 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
| 67 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
| 68 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
| 69 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
| 70 | |||
| 71 | /* Frame Buffer Operations */ | ||
| 72 | }; | 58 | }; |
| 73 | 59 | ||
| 74 | static int sun4i_drv_bind(struct device *dev) | 60 | static int sun4i_drv_bind(struct device *dev) |
| @@ -980,6 +980,7 @@ static ssize_t sun6i_dsi_transfer(struct mipi_dsi_host *host, · 979 unmodified lines | |||
| 980 | switch (msg->type) { | 980 | switch (msg->type) { |
| 981 | case MIPI_DSI_DCS_SHORT_WRITE: | 981 | case MIPI_DSI_DCS_SHORT_WRITE: |
| 982 | case MIPI_DSI_DCS_SHORT_WRITE_PARAM: | 982 | case MIPI_DSI_DCS_SHORT_WRITE_PARAM: |
| 983 | case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: | ||
| 983 | ret = sun6i_dsi_dcs_write_short(dsi, msg); | 984 | ret = sun6i_dsi_dcs_write_short(dsi, msg); |
| 984 | break; | 985 | break; |
| 985 | 986 | ||
| @@ -26,6 +26,9 @@ · 25 unmodified lines | |||
| 26 | #include <drm/drm_atomic_helper.h> | 26 | #include <drm/drm_atomic_helper.h> |
| 27 | #include <drm/drm_plane_helper.h> | 27 | #include <drm/drm_plane_helper.h> |
| 28 | 28 | ||
| 29 | static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, | ||
| 30 | struct drm_crtc_state *state); | ||
| 31 | |||
| 29 | static void tegra_dc_stats_reset(struct tegra_dc_stats *stats) | 32 | static void tegra_dc_stats_reset(struct tegra_dc_stats *stats) |
| 30 | { | 33 | { |
| 31 | stats->frames = 0; | 34 | stats->frames = 0; |
| @@ -1155,20 +1158,12 @@ static void tegra_dc_destroy(struct drm_crtc *crtc) · 1123 unmodified lines | |||
| 1155 | 1158 | ||
| 1156 | static void tegra_crtc_reset(struct drm_crtc *crtc) | 1159 | static void tegra_crtc_reset(struct drm_crtc *crtc) |
| 1157 | { | 1160 | { |
| 1158 | struct tegra_dc_state *state; | 1161 | struct tegra_dc_state *state = kzalloc(sizeof(*state), GFP_KERNEL); |
| 1159 | 1162 | ||
| 1160 | if (crtc->state) | 1163 | if (crtc->state) |
| 1161 | __drm_atomic_helper_crtc_destroy_state(crtc->state); | 1164 | tegra_crtc_atomic_destroy_state(crtc, crtc->state); |
| 1162 | |||
| 1163 | kfree(crtc->state); | ||
| 1164 | crtc->state = NULL; | ||
| 1165 | |||
| 1166 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
| 1167 | if (state) { | ||
| 1168 | crtc->state = &state->base; | ||
| 1169 | crtc->state->crtc = crtc; | ||
| 1170 | } | ||
| 1171 | 1165 | ||
| 1166 | __drm_atomic_helper_crtc_reset(crtc, &state->base); | ||
| 1172 | drm_crtc_vblank_reset(crtc); | 1167 | drm_crtc_vblank_reset(crtc); |
| 1173 | } | 1168 | } |
| 1174 | 1169 | ||
| @@ -131,18 +131,16 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, · 130 unmodified lines | |||
| 131 | struct drm_file *file, | 131 | struct drm_file *file, |
| 132 | const struct drm_mode_fb_cmd2 *cmd) | 132 | const struct drm_mode_fb_cmd2 *cmd) |
| 133 | { | 133 | { |
| 134 | unsigned int hsub, vsub, i; | 134 | const struct drm_format_info *info = drm_get_format_info(drm, cmd); |
| 135 | struct tegra_bo *planes[4]; | 135 | struct tegra_bo *planes[4]; |
| 136 | struct drm_gem_object *gem; | 136 | struct drm_gem_object *gem; |
| 137 | struct drm_framebuffer *fb; | 137 | struct drm_framebuffer *fb; |
| 138 | unsigned int i; | ||
| 138 | int err; | 139 | int err; |
| 139 | 140 | ||
| 140 | hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); | 141 | for (i = 0; i < info->num_planes; i++) { |
| 141 | vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format); | 142 | unsigned int width = cmd->width / (i ? info->hsub : 1); |
| 142 | 143 | unsigned int height = cmd->height / (i ? info->vsub : 1); | |
| 143 | for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) { | ||
| 144 | unsigned int width = cmd->width / (i ? hsub : 1); | ||
| 145 | unsigned int height = cmd->height / (i ? vsub : 1); | ||
| 146 | unsigned int size, bpp; | 144 | unsigned int size, bpp; |
| 147 | 145 | ||
| 148 | gem = drm_gem_object_lookup(file, cmd->handles[i]); | 146 | gem = drm_gem_object_lookup(file, cmd->handles[i]); |
| @@ -151,7 +149,7 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, · 2 unmodified lines | |||
| 151 | goto unreference; | 149 | goto unreference; |
| 152 | } | 150 | } |
| 153 | 151 | ||
| 154 | bpp = drm_format_plane_cpp(cmd->pixel_format, i); | 152 | bpp = info->cpp[i]; |
| 155 | 153 | ||
| 156 | size = (height - 1) * cmd->pitches[i] + | 154 | size = (height - 1) * cmd->pitches[i] + |
| 157 | width * bpp + cmd->offsets[i]; | 155 | width * bpp + cmd->offsets[i]; |
| @@ -26,6 +26,11 @@ static const struct v3d_reg_def v3d_hub_reg_defs[] = { · 25 unmodified lines | |||
| 26 | REGDEF(V3D_HUB_IDENT3), | 26 | REGDEF(V3D_HUB_IDENT3), |
| 27 | REGDEF(V3D_HUB_INT_STS), | 27 | REGDEF(V3D_HUB_INT_STS), |
| 28 | REGDEF(V3D_HUB_INT_MSK_STS), | 28 | REGDEF(V3D_HUB_INT_MSK_STS), |
| 29 | |||
| 30 | REGDEF(V3D_MMU_CTL), | ||
| 31 | REGDEF(V3D_MMU_VIO_ADDR), | ||
| 32 | REGDEF(V3D_MMU_VIO_ID), | ||
| 33 | REGDEF(V3D_MMU_DEBUG_INFO), | ||
| 29 | }; | 34 | }; |
| 30 | 35 | ||
| 31 | static const struct v3d_reg_def v3d_gca_reg_defs[] = { | 36 | static const struct v3d_reg_def v3d_gca_reg_defs[] = { |
| @@ -50,12 +55,25 @@ static const struct v3d_reg_def v3d_core_reg_defs[] = { · 18 unmodified lines | |||
| 50 | REGDEF(V3D_PTB_BPCA), | 55 | REGDEF(V3D_PTB_BPCA), |
| 51 | REGDEF(V3D_PTB_BPCS), | 56 | REGDEF(V3D_PTB_BPCS), |
| 52 | 57 | ||
| 53 | REGDEF(V3D_MMU_CTL), | ||
| 54 | REGDEF(V3D_MMU_VIO_ADDR), | ||
| 55 | |||
| 56 | REGDEF(V3D_GMP_STATUS), | 58 | REGDEF(V3D_GMP_STATUS), |
| 57 | REGDEF(V3D_GMP_CFG), | 59 | REGDEF(V3D_GMP_CFG), |
| 58 | REGDEF(V3D_GMP_VIO_ADDR), | 60 | REGDEF(V3D_GMP_VIO_ADDR), |
| 61 | |||
| 62 | REGDEF(V3D_ERR_FDBGO), | ||
| 63 | REGDEF(V3D_ERR_FDBGB), | ||
| 64 | REGDEF(V3D_ERR_FDBGS), | ||
| 65 | REGDEF(V3D_ERR_STAT), | ||
| 66 | }; | ||
| 67 | |||
| 68 | static const struct v3d_reg_def v3d_csd_reg_defs[] = { | ||
| 69 | REGDEF(V3D_CSD_STATUS), | ||
| 70 | REGDEF(V3D_CSD_CURRENT_CFG0), | ||
| 71 | REGDEF(V3D_CSD_CURRENT_CFG1), | ||
| 72 | REGDEF(V3D_CSD_CURRENT_CFG2), | ||
| 73 | REGDEF(V3D_CSD_CURRENT_CFG3), | ||
| 74 | REGDEF(V3D_CSD_CURRENT_CFG4), | ||
| 75 | REGDEF(V3D_CSD_CURRENT_CFG5), | ||
| 76 | REGDEF(V3D_CSD_CURRENT_CFG6), | ||
| 59 | }; | 77 | }; |
| 60 | 78 | ||
| 61 | static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) | 79 | static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) |
| @@ -89,6 +107,17 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused) · 27 unmodified lines | |||
| 89 | V3D_CORE_READ(core, | 107 | V3D_CORE_READ(core, |
| 90 | v3d_core_reg_defs[i].reg)); | 108 | v3d_core_reg_defs[i].reg)); |
| 91 | } | 109 | } |
| 110 | |||
| 111 | if (v3d_has_csd(v3d)) { | ||
| 112 | for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) { | ||
| 113 | seq_printf(m, "core %d %s (0x%04x): 0x%08x\n", | ||
| 114 | core, | ||
| 115 | v3d_csd_reg_defs[i].name, | ||
| 116 | v3d_csd_reg_defs[i].reg, | ||
| 117 | V3D_CORE_READ(core, | ||
| 118 | v3d_csd_reg_defs[i].reg)); | ||
| 119 | } | ||
| 120 | } | ||
| 92 | } | 121 | } |
| 93 | 122 | ||
| 94 | return 0; | 123 | return 0; |
| @@ -7,9 +7,9 @@ · 6 unmodified lines | |||
| 7 | * This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs. | 7 | * This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs. |
| 8 | * For V3D 2.x support, see the VC4 driver. | 8 | * For V3D 2.x support, see the VC4 driver. |
| 9 | * | 9 | * |
| 10 | * Currently only single-core rendering using the binner and renderer, | 10 | * The V3D GPU includes a tiled render (composed of a bin and render |
| 11 | * along with TFU (texture formatting unit) rendering is supported. | 11 | * pipelines), the TFU (texture formatting unit), and the CSD (compute |
| 12 | * V3D 4.x's CSD (compute shader dispatch) is not yet supported. | 12 | * shader dispatch). |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
| @@ -120,6 +120,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, · 104 unmodified lines | |||
| 120 | case DRM_V3D_PARAM_SUPPORTS_TFU: | 120 | case DRM_V3D_PARAM_SUPPORTS_TFU: |
| 121 | args->value = 1; | 121 | args->value = 1; |
| 122 | return 0; | 122 | return 0; |
| 123 | case DRM_V3D_PARAM_SUPPORTS_CSD: | ||
| 124 | args->value = v3d_has_csd(v3d); | ||
| 125 | return 0; | ||
| 123 | default: | 126 | default: |
| 124 | DRM_DEBUG("Unknown parameter %d\n", args->param); | 127 | DRM_DEBUG("Unknown parameter %d\n", args->param); |
| 125 | return -EINVAL; | 128 | return -EINVAL; |
| @@ -179,6 +182,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = { · 53 unmodified lines | |||
| 179 | DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW), | 182 | DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW), |
| 180 | DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW), | 183 | DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW), |
| 181 | DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), | 184 | DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), |
| 185 | DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CSD, v3d_submit_csd_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), | ||
| 182 | }; | 186 | }; |
| 183 | 187 | ||
| 184 | static struct drm_driver v3d_drm_driver = { | 188 | static struct drm_driver v3d_drm_driver = { |
| @@ -235,9 +239,9 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) · 50 unmodified lines | |||
| 235 | struct drm_device *drm; | 239 | struct drm_device *drm; |
| 236 | struct v3d_dev *v3d; | 240 | struct v3d_dev *v3d; |
| 237 | int ret; | 241 | int ret; |
| 242 | u32 mmu_debug; | ||
| 238 | u32 ident1; | 243 | u32 ident1; |
| 239 | 244 | ||
| 240 | dev->coherent_dma_mask = DMA_BIT_MASK(36); | ||
| 241 | 245 | ||
| 242 | v3d = kzalloc(sizeof(*v3d), GFP_KERNEL); | 246 | v3d = kzalloc(sizeof(*v3d), GFP_KERNEL); |
| 243 | if (!v3d) | 247 | if (!v3d) |
| @@ -254,6 +258,11 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) · 10 unmodified lines | |||
| 254 | if (ret) | 258 | if (ret) |
| 255 | goto dev_free; | 259 | goto dev_free; |
| 256 | 260 | ||
| 261 | mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); | ||
| 262 | dev->coherent_dma_mask = | ||
| 263 | DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); | ||
| 264 | v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); | ||
| 265 | |||
| 257 | ident1 = V3D_READ(V3D_HUB_IDENT1); | 266 | ident1 = V3D_READ(V3D_HUB_IDENT1); |
| 258 | v3d->ver = (V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER) * 10 + | 267 | v3d->ver = (V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER) * 10 + |
| 259 | V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV)); | 268 | V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV)); |
| @@ -16,9 +16,11 @@ enum v3d_queue { · 15 unmodified lines | |||
| 16 | V3D_BIN, | 16 | V3D_BIN, |
| 17 | V3D_RENDER, | 17 | V3D_RENDER, |
| 18 | V3D_TFU, | 18 | V3D_TFU, |
| 19 | V3D_CSD, | ||
| 20 | V3D_CACHE_CLEAN, | ||
| 19 | }; | 21 | }; |
| 20 | 22 | ||
| 21 | #define V3D_MAX_QUEUES (V3D_TFU + 1) | 23 | #define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) |
| 22 | 24 | ||
| 23 | struct v3d_queue_state { | 25 | struct v3d_queue_state { |
| 24 | struct drm_gpu_scheduler sched; | 26 | struct drm_gpu_scheduler sched; |
| @@ -55,6 +57,8 @@ struct v3d_dev { · 30 unmodified lines | |||
| 55 | */ | 57 | */ |
| 56 | void *mmu_scratch; | 58 | void *mmu_scratch; |
| 57 | dma_addr_t mmu_scratch_paddr; | 59 | dma_addr_t mmu_scratch_paddr; |
| 60 | /* virtual address bits from V3D to the MMU. */ | ||
| 61 | int va_width; | ||
| 58 | 62 | ||
| 59 | /* Number of V3D cores. */ | 63 | /* Number of V3D cores. */ |
| 60 | u32 cores; | 64 | u32 cores; |
| @@ -67,9 +71,10 @@ struct v3d_dev { · 6 unmodified lines | |||
| 67 | 71 | ||
| 68 | struct work_struct overflow_mem_work; | 72 | struct work_struct overflow_mem_work; |
| 69 | 73 | ||
| 70 | struct v3d_exec_info *bin_job; | 74 | struct v3d_bin_job *bin_job; |
| 71 | struct v3d_exec_info *render_job; | 75 | struct v3d_render_job *render_job; |
| 72 | struct v3d_tfu_job *tfu_job; | 76 | struct v3d_tfu_job *tfu_job; |
| 77 | struct v3d_csd_job *csd_job; | ||
| 73 | 78 | ||
| 74 | struct v3d_queue_state queue[V3D_MAX_QUEUES]; | 79 | struct v3d_queue_state queue[V3D_MAX_QUEUES]; |
| 75 | 80 | ||
| @@ -92,6 +97,12 @@ struct v3d_dev { · 16 unmodified lines | |||
| 92 | */ | 97 | */ |
| 93 | struct mutex sched_lock; | 98 | struct mutex sched_lock; |
| 94 | 99 | ||
| 100 | /* Lock taken during a cache clean and when initiating an L2 | ||
| 101 | * flush, to keep L2 flushes from interfering with the | ||
| 102 | * synchronous L2 cleans. | ||
| 103 | */ | ||
| 104 | struct mutex cache_clean_lock; | ||
| 105 | |||
| 95 | struct { | 106 | struct { |
| 96 | u32 num_allocated; | 107 | u32 num_allocated; |
| 97 | u32 pages_allocated; | 108 | u32 pages_allocated; |
| @@ -104,6 +115,12 @@ to_v3d_dev(struct drm_device *dev) · 6 unmodified lines | |||
| 104 | return (struct v3d_dev *)dev->dev_private; | 115 | return (struct v3d_dev *)dev->dev_private; |
| 105 | } | 116 | } |
| 106 | 117 | ||
| 118 | static inline bool | ||
| 119 | v3d_has_csd(struct v3d_dev *v3d) | ||
| 120 | { | ||
| 121 | return v3d->ver >= 41; | ||
| 122 | } | ||
| 123 | |||
| 107 | /* The per-fd struct, which tracks the MMU mappings. */ | 124 | /* The per-fd struct, which tracks the MMU mappings. */ |
| 108 | struct v3d_file_priv { | 125 | struct v3d_file_priv { |
| 109 | struct v3d_dev *v3d; | 126 | struct v3d_dev *v3d; |
| @@ -117,7 +134,7 @@ struct v3d_bo { · 7 unmodified lines | |||
| 117 | struct drm_mm_node node; | 134 | struct drm_mm_node node; |
| 118 | 135 | ||
| 119 | /* List entry for the BO's position in | 136 | /* List entry for the BO's position in |
| 120 | * v3d_exec_info->unref_list | 137 | * v3d_render_job->unref_list |
| 121 | */ | 138 | */ |
| 122 | struct list_head unref_head; | 139 | struct list_head unref_head; |
| 123 | }; | 140 | }; |
| @@ -157,67 +174,74 @@ to_v3d_fence(struct dma_fence *fence) · 33 unmodified lines | |||
| 157 | struct v3d_job { | 174 | struct v3d_job { |
| 158 | struct drm_sched_job base; | 175 | struct drm_sched_job base; |
| 159 | 176 | ||
| 160 | struct v3d_exec_info *exec; | 177 | struct kref refcount; |
| 161 | 178 | ||
| 162 | /* An optional fence userspace can pass in for the job to depend on. */ | 179 | struct v3d_dev *v3d; |
| 163 | struct dma_fence *in_fence; | 180 | |
| 181 | /* This is the array of BOs that were looked up at the start | ||
| 182 | * of submission. | ||
| 183 | */ | ||
| 184 | struct drm_gem_object **bo; | ||
| 185 | u32 bo_count; | ||
| 186 | |||
| 187 | /* Array of struct dma_fence * to block on before submitting this job. | ||
| 188 | */ | ||
| 189 | struct xarray deps; | ||
| 190 | unsigned long last_dep; | ||
| 164 | 191 | ||
| 165 | /* v3d fence to be signaled by IRQ handler when the job is complete. */ | 192 | /* v3d fence to be signaled by IRQ handler when the job is complete. */ |
| 166 | struct dma_fence *irq_fence; | 193 | struct dma_fence *irq_fence; |
| 167 | 194 | ||
| 195 | /* scheduler fence for when the job is considered complete and | ||
| 196 | * the BO reservations can be released. | ||
| 197 | */ | ||
| 198 | struct dma_fence *done_fence; | ||
| 199 | |||
| 200 | /* Callback for the freeing of the job on refcount going to 0. */ | ||
| 201 | void (*free)(struct kref *ref); | ||
| 202 | }; | ||
| 203 | |||
| 204 | struct v3d_bin_job { | ||
| 205 | struct v3d_job base; | ||
| 206 | |||
| 168 | /* GPU virtual addresses of the start/end of the CL job. */ | 207 | /* GPU virtual addresses of the start/end of the CL job. */ |
| 169 | u32 start, end; | 208 | u32 start, end; |
| 170 | 209 | ||
| 171 | u32 timedout_ctca, timedout_ctra; | 210 | u32 timedout_ctca, timedout_ctra; |
| 172 | }; | ||
| 173 | 211 | ||
| 174 | struct v3d_exec_info { | 212 | /* Corresponding render job, for attaching our overflow memory. */ |
| 175 | struct v3d_dev *v3d; | 213 | struct v3d_render_job *render; |
| 176 | 214 | ||
| 177 | struct v3d_job bin, render; | 215 | /* Submitted tile memory allocation start/size, tile state. */ |
| 178 | 216 | u32 qma, qms, qts; | |
| 179 | /* Fence for when the scheduler considers the binner to be | 217 | }; |
| 180 | * done, for render to depend on. | ||
| 181 | */ | ||
| 182 | struct dma_fence *bin_done_fence; | ||
| 183 | 218 | ||
| 184 | /* Fence for when the scheduler considers the render to be | 219 | struct v3d_render_job { |
| 185 | * done, for when the BOs reservations should be complete. | 220 | struct v3d_job base; |
| 186 | */ | ||
| 187 | struct dma_fence *render_done_fence; | ||
| 188 | 221 | ||
| 189 | struct kref refcount; | 222 | /* GPU virtual addresses of the start/end of the CL job. */ |
| 223 | u32 start, end; | ||
| 190 | 224 | ||
| 191 | /* This is the array of BOs that were looked up at the start of exec. */ | 225 | u32 timedout_ctca, timedout_ctra; |
| 192 | struct v3d_bo **bo; | ||
| 193 | u32 bo_count; | ||
| 194 | 226 | ||
| 195 | /* List of overflow BOs used in the job that need to be | 227 | /* List of overflow BOs used in the job that need to be |
| 196 | * released once the job is complete. | 228 | * released once the job is complete. |
| 197 | */ | 229 | */ |
| 198 | struct list_head unref_list; | 230 | struct list_head unref_list; |
| 199 | |||
| 200 | /* Submitted tile memory allocation start/size, tile state. */ | ||
| 201 | u32 qma, qms, qts; | ||
| 202 | }; | 231 | }; |
| 203 | 232 | ||
| 204 | struct v3d_tfu_job { | 233 | struct v3d_tfu_job { |
| 205 | struct drm_sched_job base; | 234 | struct v3d_job base; |
| 206 | 235 | ||
| 207 | struct drm_v3d_submit_tfu args; | 236 | struct drm_v3d_submit_tfu args; |
| 237 | }; | ||
| 208 | 238 | ||
| 209 | /* An optional fence userspace can pass in for the job to depend on. */ | 239 | struct v3d_csd_job { |
| 210 | struct dma_fence *in_fence; | 240 | struct v3d_job base; |
| 211 | |||
| 212 | /* v3d fence to be signaled by IRQ handler when the job is complete. */ | ||
| 213 | struct dma_fence *irq_fence; | ||
| 214 | |||
| 215 | struct v3d_dev *v3d; | ||
| 216 | 241 | ||
| 217 | struct kref refcount; | 242 | u32 timedout_batches; |
| 218 | 243 | ||
| 219 | /* This is the array of BOs that were looked up at the start of exec. */ | 244 | struct drm_v3d_submit_csd args; |
| 220 | struct v3d_bo *bo[4]; | ||
| 221 | }; | 245 | }; |
| 222 | 246 | ||
| 223 | /** | 247 | /** |
| @@ -281,12 +305,14 @@ int v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 57 unmodified lines | |||
| 281 | struct drm_file *file_priv); | 305 | struct drm_file *file_priv); |
| 282 | int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, | 306 | int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, |
| 283 | struct drm_file *file_priv); | 307 | struct drm_file *file_priv); |
| 308 | int v3d_submit_csd_ioctl(struct drm_device *dev, void *data, | ||
| 309 | struct drm_file *file_priv); | ||
| 284 | int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, | 310 | int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, |
| 285 | struct drm_file *file_priv); | 311 | struct drm_file *file_priv); |
| 286 | void v3d_exec_put(struct v3d_exec_info *exec); | 312 | void v3d_job_put(struct v3d_job *job); |
| 287 | void v3d_tfu_job_put(struct v3d_tfu_job *exec); | ||
| 288 | void v3d_reset(struct v3d_dev *v3d); | 313 | void v3d_reset(struct v3d_dev *v3d); |
| 289 | void v3d_invalidate_caches(struct v3d_dev *v3d); | 314 | void v3d_invalidate_caches(struct v3d_dev *v3d); |
| 315 | void v3d_clean_caches(struct v3d_dev *v3d); | ||
| 290 | 316 | ||
| 291 | /* v3d_irq.c */ | 317 | /* v3d_irq.c */ |
| 292 | int v3d_irq_init(struct v3d_dev *v3d); | 318 | int v3d_irq_init(struct v3d_dev *v3d); |
| @@ -36,6 +36,8 @@ static const char *v3d_fence_get_timeline_name(struct dma_fence *fence) · 35 unmodified lines | |||
| 36 | return "v3d-render"; | 36 | return "v3d-render"; |
| 37 | case V3D_TFU: | 37 | case V3D_TFU: |
| 38 | return "v3d-tfu"; | 38 | return "v3d-tfu"; |
| 39 | case V3D_CSD: | ||
| 40 | return "v3d-csd"; | ||
| 39 | default: | 41 | default: |
| 40 | return NULL; | 42 | return NULL; |
| 41 | } | 43 | } |
| @@ -109,7 +109,9 @@ v3d_reset(struct v3d_dev *v3d) · 108 unmodified lines | |||
| 109 | { | 109 | { |
| 110 | struct drm_device *dev = &v3d->drm; | 110 | struct drm_device *dev = &v3d->drm; |
| 111 | 111 | ||
| 112 | DRM_ERROR("Resetting GPU.\n"); | 112 | DRM_DEV_ERROR(dev->dev, "Resetting GPU for hang.\n"); |
| 113 | DRM_DEV_ERROR(dev->dev, "V3D_ERR_STAT: 0x%08x\n", | ||
| 114 | V3D_CORE_READ(0, V3D_ERR_STAT)); | ||
| 113 | trace_v3d_reset_begin(dev); | 115 | trace_v3d_reset_begin(dev); |
| 114 | 116 | ||
| 115 | /* XXX: only needed for safe powerdown, not reset. */ | 117 | /* XXX: only needed for safe powerdown, not reset. */ |
| @@ -162,10 +164,52 @@ v3d_flush_l2t(struct v3d_dev *v3d, int core) · 46 unmodified lines | |||
| 162 | /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't | 164 | /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't |
| 163 | * need to wait for completion before dispatching the job -- | 165 | * need to wait for completion before dispatching the job -- |
| 164 | * L2T accesses will be stalled until the flush has completed. | 166 | * L2T accesses will be stalled until the flush has completed. |
| 167 | * However, we do need to make sure we don't try to trigger a | ||
| 168 | * new flush while the L2_CLEAN queue is trying to | ||
| 169 | * synchronously clean after a job. | ||
| 165 | */ | 170 | */ |
| 171 | mutex_lock(&v3d->cache_clean_lock); | ||
| 166 | V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, | 172 | V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, |
| 167 | V3D_L2TCACTL_L2TFLS | | 173 | V3D_L2TCACTL_L2TFLS | |
| 168 | V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM)); | 174 | V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM)); |
| 175 | mutex_unlock(&v3d->cache_clean_lock); | ||
| 176 | } | ||
| 177 | |||
| 178 | /* Cleans texture L1 and L2 cachelines (writing back dirty data). | ||
| 179 | * | ||
| 180 | * For cleaning, which happens from the CACHE_CLEAN queue after CSD has | ||
| 181 | * executed, we need to make sure that the clean is done before | ||
| 182 | * signaling job completion. So, we synchronously wait before | ||
| 183 | * returning, and we make sure that L2 invalidates don't happen in the | ||
| 184 | * meantime to confuse our are-we-done checks. | ||
| 185 | */ | ||
| 186 | void | ||
| 187 | v3d_clean_caches(struct v3d_dev *v3d) | ||
| 188 | { | ||
| 189 | struct drm_device *dev = &v3d->drm; | ||
| 190 | int core = 0; | ||
| 191 | |||
| 192 | trace_v3d_cache_clean_begin(dev); | ||
| 193 | |||
| 194 | V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF); | ||
| 195 | if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) & | ||
| 196 | V3D_L2TCACTL_L2TFLS), 100)) { | ||
| 197 | DRM_ERROR("Timeout waiting for L1T write combiner flush\n"); | ||
| 198 | } | ||
| 199 | |||
| 200 | mutex_lock(&v3d->cache_clean_lock); | ||
| 201 | V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, | ||
| 202 | V3D_L2TCACTL_L2TFLS | | ||
| 203 | V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAN, V3D_L2TCACTL_FLM)); | ||
| 204 | |||
| 205 | if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) & | ||
| 206 | V3D_L2TCACTL_L2TFLS), 100)) { | ||
| 207 | DRM_ERROR("Timeout waiting for L2T clean\n"); | ||
| 208 | } | ||
| 209 | |||
| 210 | mutex_unlock(&v3d->cache_clean_lock); | ||
| 211 | |||
| 212 | trace_v3d_cache_clean_end(dev); | ||
| 169 | } | 213 | } |
| 170 | 214 | ||
| 171 | /* Invalidates the slice caches. These are read-only caches. */ | 215 | /* Invalidates the slice caches. These are read-only caches. */ |
| @@ -193,28 +237,6 @@ v3d_invalidate_caches(struct v3d_dev *v3d) · 21 unmodified lines | |||
| 193 | v3d_invalidate_slices(v3d, 0); | 237 | v3d_invalidate_slices(v3d, 0); |
| 194 | } | 238 | } |
| 195 | 239 | ||
| 196 | static void | ||
| 197 | v3d_attach_object_fences(struct v3d_bo **bos, int bo_count, | ||
| 198 | struct dma_fence *fence) | ||
| 199 | { | ||
| 200 | int i; | ||
| 201 | |||
| 202 | for (i = 0; i < bo_count; i++) { | ||
| 203 | /* XXX: Use shared fences for read-only objects. */ | ||
| 204 | reservation_object_add_excl_fence(bos[i]->base.base.resv, | ||
| 205 | fence); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | static void | ||
| 210 | v3d_unlock_bo_reservations(struct v3d_bo **bos, | ||
| 211 | int bo_count, | ||
| 212 | struct ww_acquire_ctx *acquire_ctx) | ||
| 213 | { | ||
| 214 | drm_gem_unlock_reservations((struct drm_gem_object **)bos, bo_count, | ||
| 215 | acquire_ctx); | ||
| 216 | } | ||
| 217 | |||
| 218 | /* Takes the reservation lock on all the BOs being referenced, so that | 240 | /* Takes the reservation lock on all the BOs being referenced, so that |
| 219 | * at queue submit time we can update the reservations. | 241 | * at queue submit time we can update the reservations. |
| 220 | * | 242 | * |
| @@ -223,26 +245,21 @@ v3d_unlock_bo_reservations(struct v3d_bo **bos, · 2 unmodified lines | |||
| 223 | * to v3d, so we don't attach dma-buf fences to them. | 245 | * to v3d, so we don't attach dma-buf fences to them. |
| 224 | */ | 246 | */ |
| 225 | static int | 247 | static int |
| 226 | v3d_lock_bo_reservations(struct v3d_bo **bos, | 248 | v3d_lock_bo_reservations(struct v3d_job *job, |
| 227 | int bo_count, | ||
| 228 | struct ww_acquire_ctx *acquire_ctx) | 249 | struct ww_acquire_ctx *acquire_ctx) |
| 229 | { | 250 | { |
| 230 | int i, ret; | 251 | int i, ret; |
| 231 | 252 | ||
| 232 | ret = drm_gem_lock_reservations((struct drm_gem_object **)bos, | 253 | ret = drm_gem_lock_reservations(job->bo, job->bo_count, acquire_ctx); |
| 233 | bo_count, acquire_ctx); | ||
| 234 | if (ret) | 254 | if (ret) |
| 235 | return ret; | 255 | return ret; |
| 236 | 256 | ||
| 237 | /* Reserve space for our shared (read-only) fence references, | 257 | for (i = 0; i < job->bo_count; i++) { |
| 238 | * before we commit the CL to the hardware. | 258 | ret = drm_gem_fence_array_add_implicit(&job->deps, |
| 239 | */ | 259 | job->bo[i], true); |
| 240 | for (i = 0; i < bo_count; i++) { | ||
| 241 | ret = reservation_object_reserve_shared(bos[i]->base.base.resv, | ||
| 242 | 1); | ||
| 243 | if (ret) { | 260 | if (ret) { |
| 244 | v3d_unlock_bo_reservations(bos, bo_count, | 261 | drm_gem_unlock_reservations(job->bo, job->bo_count, |
| 245 | acquire_ctx); | 262 | acquire_ctx); |
| 246 | return ret; | 263 | return ret; |
| 247 | } | 264 | } |
| 248 | } | 265 | } |
| @@ -251,11 +268,11 @@ v3d_lock_bo_reservations(struct v3d_bo **bos, · 2 unmodified lines | |||
| 251 | } | 268 | } |
| 252 | 269 | ||
| 253 | /** | 270 | /** |
| 254 | * v3d_cl_lookup_bos() - Sets up exec->bo[] with the GEM objects | 271 | * v3d_lookup_bos() - Sets up job->bo[] with the GEM objects |
| 255 | * referenced by the job. | 272 | * referenced by the job. |
| 256 | * @dev: DRM device | 273 | * @dev: DRM device |
| 257 | * @file_priv: DRM file for this fd | 274 | * @file_priv: DRM file for this fd |
| 258 | * @exec: V3D job being set up | 275 | * @job: V3D job being set up |
| 259 | * | 276 | * |
| 260 | * The command validator needs to reference BOs by their index within | 277 | * The command validator needs to reference BOs by their index within |
| 261 | * the submitted job's BO list. This does the validation of the job's | 278 | * the submitted job's BO list. This does the validation of the job's |
| @@ -265,18 +282,19 @@ v3d_lock_bo_reservations(struct v3d_bo **bos, · 3 unmodified lines | |||
| 265 | * failure, because that will happen at v3d_exec_cleanup() time. | 282 | * failure, because that will happen at v3d_exec_cleanup() time. |
| 266 | */ | 283 | */ |
| 267 | static int | 284 | static int |
| 268 | v3d_cl_lookup_bos(struct drm_device *dev, | 285 | v3d_lookup_bos(struct drm_device *dev, |
| 269 | struct drm_file *file_priv, | 286 | struct drm_file *file_priv, |
| 270 | struct drm_v3d_submit_cl *args, | 287 | struct v3d_job *job, |
| 271 | struct v3d_exec_info *exec) | 288 | u64 bo_handles, |
| 289 | u32 bo_count) | ||
| 272 | { | 290 | { |
| 273 | u32 *handles; | 291 | u32 *handles; |
| 274 | int ret = 0; | 292 | int ret = 0; |
| 275 | int i; | 293 | int i; |
| 276 | 294 | ||
| 277 | exec->bo_count = args->bo_handle_count; | 295 | job->bo_count = bo_count; |
| 278 | 296 | ||
| 279 | if (!exec->bo_count) { | 297 | if (!job->bo_count) { |
| 280 | /* See comment on bo_index for why we have to check | 298 | /* See comment on bo_index for why we have to check |
| 281 | * this. | 299 | * this. |
| 282 | */ | 300 | */ |
| @@ -284,15 +302,15 @@ v3d_cl_lookup_bos(struct drm_device *dev, · 1 unmodified line | |||
| 284 | return -EINVAL; | 302 | return -EINVAL; |
| 285 | } | 303 | } |
| 286 | 304 | ||
| 287 | exec->bo = kvmalloc_array(exec->bo_count, | 305 | job->bo = kvmalloc_array(job->bo_count, |
| 288 | sizeof(struct drm_gem_cma_object *), | 306 | sizeof(struct drm_gem_cma_object *), |
| 289 | GFP_KERNEL | __GFP_ZERO); | 307 | GFP_KERNEL | __GFP_ZERO); |
| 290 | if (!exec->bo) { | 308 | if (!job->bo) { |
| 291 | DRM_DEBUG("Failed to allocate validated BO pointers\n"); | 309 | DRM_DEBUG("Failed to allocate validated BO pointers\n"); |
| 292 | return -ENOMEM; | 310 | return -ENOMEM; |
| 293 | } | 311 | } |
| 294 | 312 | ||
| 295 | handles = kvmalloc_array(exec->bo_count, sizeof(u32), GFP_KERNEL); | 313 | handles = kvmalloc_array(job->bo_count, sizeof(u32), GFP_KERNEL); |
| 296 | if (!handles) { | 314 | if (!handles) { |
| 297 | ret = -ENOMEM; | 315 | ret = -ENOMEM; |
| 298 | DRM_DEBUG("Failed to allocate incoming GEM handles\n"); | 316 | DRM_DEBUG("Failed to allocate incoming GEM handles\n"); |
| @@ -300,15 +318,15 @@ v3d_cl_lookup_bos(struct drm_device *dev, · 1 unmodified line | |||
| 300 | } | 318 | } |
| 301 | 319 | ||
| 302 | if (copy_from_user(handles, | 320 | if (copy_from_user(handles, |
| 303 | (void __user *)(uintptr_t)args->bo_handles, | 321 | (void __user *)(uintptr_t)bo_handles, |
| 304 | exec->bo_count * sizeof(u32))) { | 322 | job->bo_count * sizeof(u32))) { |
| 305 | ret = -EFAULT; | 323 | ret = -EFAULT; |
| 306 | DRM_DEBUG("Failed to copy in GEM handles\n"); | 324 | DRM_DEBUG("Failed to copy in GEM handles\n"); |
| 307 | goto fail; | 325 | goto fail; |
| 308 | } | 326 | } |
| 309 | 327 | ||
| 310 | spin_lock(&file_priv->table_lock); | 328 | spin_lock(&file_priv->table_lock); |
| 311 | for (i = 0; i < exec->bo_count; i++) { | 329 | for (i = 0; i < job->bo_count; i++) { |
| 312 | struct drm_gem_object *bo = idr_find(&file_priv->object_idr, | 330 | struct drm_gem_object *bo = idr_find(&file_priv->object_idr, |
| 313 | handles[i]); | 331 | handles[i]); |
| 314 | if (!bo) { | 332 | if (!bo) { |
| @@ -319,7 +337,7 @@ v3d_cl_lookup_bos(struct drm_device *dev, · 4 unmodified lines | |||
| 319 | goto fail; | 337 | goto fail; |
| 320 | } | 338 | } |
| 321 | drm_gem_object_get(bo); | 339 | drm_gem_object_get(bo); |
| 322 | exec->bo[i] = to_v3d_bo(bo); | 340 | job->bo[i] = bo; |
| 323 | } | 341 | } |
| 324 | spin_unlock(&file_priv->table_lock); | 342 | spin_unlock(&file_priv->table_lock); |
| 325 | 343 | ||
| @@ -329,67 +347,50 @@ fail: · 3 unmodified lines | |||
| 329 | } | 347 | } |
| 330 | 348 | ||
| 331 | static void | 349 | static void |
| 332 | v3d_exec_cleanup(struct kref *ref) | 350 | v3d_job_free(struct kref *ref) |
| 333 | { | 351 | { |
| 334 | struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info, | 352 | struct v3d_job *job = container_of(ref, struct v3d_job, refcount); |
| 335 | refcount); | 353 | unsigned long index; |
| 336 | struct v3d_dev *v3d = exec->v3d; | 354 | struct dma_fence *fence; |
| 337 | unsigned int i; | 355 | int i; |
| 338 | struct v3d_bo *bo, *save; | ||
| 339 | |||
| 340 | dma_fence_put(exec->bin.in_fence); | ||
| 341 | dma_fence_put(exec->render.in_fence); | ||
| 342 | |||
| 343 | dma_fence_put(exec->bin.irq_fence); | ||
| 344 | dma_fence_put(exec->render.irq_fence); | ||
| 345 | |||
| 346 | dma_fence_put(exec->bin_done_fence); | ||
| 347 | dma_fence_put(exec->render_done_fence); | ||
| 348 | 356 | ||
| 349 | for (i = 0; i < exec->bo_count; i++) | 357 | for (i = 0; i < job->bo_count; i++) { |
| 350 | drm_gem_object_put_unlocked(&exec->bo[i]->base.base); | 358 | if (job->bo[i]) |
| 351 | kvfree(exec->bo); | 359 | drm_gem_object_put_unlocked(job->bo[i]); |
| 360 | } | ||
| 361 | kvfree(job->bo); | ||
| 352 | 362 | ||
| 353 | list_for_each_entry_safe(bo, save, &exec->unref_list, unref_head) { | 363 | xa_for_each(&job->deps, index, fence) { |
| 354 | drm_gem_object_put_unlocked(&bo->base.base); | 364 | dma_fence_put(fence); |
| 355 | } | 365 | } |
| 366 | xa_destroy(&job->deps); | ||
| 356 | 367 | ||
| 357 | pm_runtime_mark_last_busy(v3d->dev); | 368 | dma_fence_put(job->irq_fence); |
| 358 | pm_runtime_put_autosuspend(v3d->dev); | 369 | dma_fence_put(job->done_fence); |
| 359 | 370 | ||
| 360 | kfree(exec); | 371 | pm_runtime_mark_last_busy(job->v3d->dev); |
| 361 | } | 372 | pm_runtime_put_autosuspend(job->v3d->dev); |
| 362 | 373 | ||
| 363 | void v3d_exec_put(struct v3d_exec_info *exec) | 374 | kfree(job); |
| 364 | { | ||
| 365 | kref_put(&exec->refcount, v3d_exec_cleanup); | ||
| 366 | } | 375 | } |
| 367 | 376 | ||
| 368 | static void | 377 | static void |
| 369 | v3d_tfu_job_cleanup(struct kref *ref) | 378 | v3d_render_job_free(struct kref *ref) |
| 370 | { | 379 | { |
| 371 | struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job, | 380 | struct v3d_render_job *job = container_of(ref, struct v3d_render_job, |
| 372 | refcount); | 381 | base.refcount); |
| 373 | struct v3d_dev *v3d = job->v3d; | 382 | struct v3d_bo *bo, *save; |
| 374 | unsigned int i; | ||
| 375 | |||
| 376 | dma_fence_put(job->in_fence); | ||
| 377 | dma_fence_put(job->irq_fence); | ||
| 378 | 383 | ||
| 379 | for (i = 0; i < ARRAY_SIZE(job->bo); i++) { | 384 | list_for_each_entry_safe(bo, save, &job->unref_list, unref_head) { |
| 380 | if (job->bo[i]) | 385 | drm_gem_object_put_unlocked(&bo->base.base); |
| 381 | drm_gem_object_put_unlocked(&job->bo[i]->base.base); | ||
| 382 | } | 386 | } |
| 383 | 387 | ||
| 384 | pm_runtime_mark_last_busy(v3d->dev); | 388 | v3d_job_free(ref); |
| 385 | pm_runtime_put_autosuspend(v3d->dev); | ||
| 386 | |||
| 387 | kfree(job); | ||
| 388 | } | 389 | } |
| 389 | 390 | ||
| 390 | void v3d_tfu_job_put(struct v3d_tfu_job *job) | 391 | void v3d_job_put(struct v3d_job *job) |
| 391 | { | 392 | { |
| 392 | kref_put(&job->refcount, v3d_tfu_job_cleanup); | 393 | kref_put(&job->refcount, job->free); |
| 393 | } | 394 | } |
| 394 | 395 | ||
| 395 | int | 396 | int |
| @@ -425,6 +426,87 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data, · 29 unmodified lines | |||
| 425 | return ret; | 426 | return ret; |
| 426 | } | 427 | } |
| 427 | 428 | ||
| 429 | static int | ||
| 430 | v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv, | ||
| 431 | struct v3d_job *job, void (*free)(struct kref *ref), | ||
| 432 | u32 in_sync) | ||
| 433 | { | ||
| 434 | struct dma_fence *in_fence = NULL; | ||
| 435 | int ret; | ||
| 436 | |||
| 437 | job->v3d = v3d; | ||
| 438 | job->free = free; | ||
| 439 | |||
| 440 | ret = pm_runtime_get_sync(v3d->dev); | ||
| 441 | if (ret < 0) | ||
| 442 | return ret; | ||
| 443 | |||
| 444 | xa_init_flags(&job->deps, XA_FLAGS_ALLOC); | ||
| 445 | |||
| 446 | ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence); | ||
| 447 | if (ret == -EINVAL) | ||
| 448 | goto fail; | ||
| 449 | |||
| 450 | ret = drm_gem_fence_array_add(&job->deps, in_fence); | ||
| 451 | if (ret) | ||
| 452 | goto fail; | ||
| 453 | |||
| 454 | kref_init(&job->refcount); | ||
| 455 | |||
| 456 | return 0; | ||
| 457 | fail: | ||
| 458 | xa_destroy(&job->deps); | ||
| 459 | pm_runtime_put_autosuspend(v3d->dev); | ||
| 460 | return ret; | ||
| 461 | } | ||
| 462 | |||
| 463 | static int | ||
| 464 | v3d_push_job(struct v3d_file_priv *v3d_priv, | ||
| 465 | struct v3d_job *job, enum v3d_queue queue) | ||
| 466 | { | ||
| 467 | int ret; | ||
| 468 | |||
| 469 | ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue], | ||
| 470 | v3d_priv); | ||
| 471 | if (ret) | ||
| 472 | return ret; | ||
| 473 | |||
| 474 | job->done_fence = dma_fence_get(&job->base.s_fence->finished); | ||
| 475 | |||
| 476 | /* put by scheduler job completion */ | ||
| 477 | kref_get(&job->refcount); | ||
| 478 | |||
| 479 | drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[queue]); | ||
| 480 | |||
| 481 | return 0; | ||
| 482 | } | ||
| 483 | |||
| 484 | static void | ||
| 485 | v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, | ||
| 486 | struct v3d_job *job, | ||
| 487 | struct ww_acquire_ctx *acquire_ctx, | ||
| 488 | u32 out_sync, | ||
| 489 | struct dma_fence *done_fence) | ||
| 490 | { | ||
| 491 | struct drm_syncobj *sync_out; | ||
| 492 | int i; | ||
| 493 | |||
| 494 | for (i = 0; i < job->bo_count; i++) { | ||
| 495 | /* XXX: Use shared fences for read-only objects. */ | ||
| 496 | reservation_object_add_excl_fence(job->bo[i]->resv, | ||
| 497 | job->done_fence); | ||
| 498 | } | ||
| 499 | |||
| 500 | drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx); | ||
| 501 | |||
| 502 | /* Update the return sync object for the job */ | ||
| 503 | sync_out = drm_syncobj_find(file_priv, out_sync); | ||
| 504 | if (sync_out) { | ||
| 505 | drm_syncobj_replace_fence(sync_out, done_fence); | ||
| 506 | drm_syncobj_put(sync_out); | ||
| 507 | } | ||
| 508 | } | ||
| 509 | |||
| 428 | /** | 510 | /** |
| 429 | * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D. | 511 | * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D. |
| 430 | * @dev: DRM device | 512 | * @dev: DRM device |
| @@ -444,9 +526,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 13 unmodified lines | |||
| 444 | struct v3d_dev *v3d = to_v3d_dev(dev); | 526 | struct v3d_dev *v3d = to_v3d_dev(dev); |
| 445 | struct v3d_file_priv *v3d_priv = file_priv->driver_priv; | 527 | struct v3d_file_priv *v3d_priv = file_priv->driver_priv; |
| 446 | struct drm_v3d_submit_cl *args = data; | 528 | struct drm_v3d_submit_cl *args = data; |
| 447 | struct v3d_exec_info *exec; | 529 | struct v3d_bin_job *bin = NULL; |
| 530 | struct v3d_render_job *render; | ||
| 448 | struct ww_acquire_ctx acquire_ctx; | 531 | struct ww_acquire_ctx acquire_ctx; |
| 449 | struct drm_syncobj *sync_out; | ||
| 450 | int ret = 0; | 532 | int ret = 0; |
| 451 | 533 | ||
| 452 | trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); | 534 | trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); |
| @@ -456,100 +538,87 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 3 unmodified lines | |||
| 456 | return -EINVAL; | 538 | return -EINVAL; |
| 457 | } | 539 | } |
| 458 | 540 | ||
| 459 | exec = kcalloc(1, sizeof(*exec), GFP_KERNEL); | 541 | render = kcalloc(1, sizeof(*render), GFP_KERNEL); |
| 460 | if (!exec) | 542 | if (!render) |
| 461 | return -ENOMEM; | 543 | return -ENOMEM; |
| 462 | 544 | ||
| 463 | ret = pm_runtime_get_sync(v3d->dev); | 545 | render->start = args->rcl_start; |
| 464 | if (ret < 0) { | 546 | render->end = args->rcl_end; |
| 465 | kfree(exec); | 547 | INIT_LIST_HEAD(&render->unref_list); |
| 548 | |||
| 549 | ret = v3d_job_init(v3d, file_priv, &render->base, | ||
| 550 | v3d_render_job_free, args->in_sync_rcl); | ||
| 551 | if (ret) { | ||
| 552 | kfree(render); | ||
| 466 | return ret; | 553 | return ret; |
| 467 | } | 554 | } |
| 468 | 555 | ||
| 469 | kref_init(&exec->refcount); | 556 | if (args->bcl_start != args->bcl_end) { |
| 557 | bin = kcalloc(1, sizeof(*bin), GFP_KERNEL); | ||
| 558 | if (!bin) | ||
| 559 | return -ENOMEM; | ||
| 470 | 560 | ||
| 471 | ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl, | 561 | ret = v3d_job_init(v3d, file_priv, &bin->base, |
| 472 | 0, 0, &exec->bin.in_fence); | 562 | v3d_job_free, args->in_sync_bcl); |
| 473 | if (ret == -EINVAL) | 563 | if (ret) { |
| 474 | goto fail; | 564 | v3d_job_put(&render->base); |
| 565 | return ret; | ||
| 566 | } | ||
| 475 | 567 | ||
| 476 | ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl, | 568 | bin->start = args->bcl_start; |
| 477 | 0, 0, &exec->render.in_fence); | 569 | bin->end = args->bcl_end; |
| 478 | if (ret == -EINVAL) | 570 | bin->qma = args->qma; |
| 479 | goto fail; | 571 | bin->qms = args->qms; |
| 572 | bin->qts = args->qts; | ||
| 573 | bin->render = render; | ||
| 574 | } | ||
| 480 | 575 | ||
| 481 | exec->qma = args->qma; | 576 | ret = v3d_lookup_bos(dev, file_priv, &render->base, |
| 482 | exec->qms = args->qms; | 577 | args->bo_handles, args->bo_handle_count); |
| 483 | exec->qts = args->qts; | ||
| 484 | exec->bin.exec = exec; | ||
| 485 | exec->bin.start = args->bcl_start; | ||
| 486 | exec->bin.end = args->bcl_end; | ||
| 487 | exec->render.exec = exec; | ||
| 488 | exec->render.start = args->rcl_start; | ||
| 489 | exec->render.end = args->rcl_end; | ||
| 490 | exec->v3d = v3d; | ||
| 491 | INIT_LIST_HEAD(&exec->unref_list); | ||
| 492 | |||
| 493 | ret = v3d_cl_lookup_bos(dev, file_priv, args, exec); | ||
| 494 | if (ret) | 578 | if (ret) |
| 495 | goto fail; | 579 | goto fail; |
| 496 | 580 | ||
| 497 | ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count, | 581 | ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx); |
| 498 | &acquire_ctx); | ||
| 499 | if (ret) | 582 | if (ret) |
| 500 | goto fail; | 583 | goto fail; |
| 501 | 584 | ||
| 502 | mutex_lock(&v3d->sched_lock); | 585 | mutex_lock(&v3d->sched_lock); |
| 503 | if (exec->bin.start != exec->bin.end) { | 586 | if (bin) { |
| 504 | ret = drm_sched_job_init(&exec->bin.base, | 587 | ret = v3d_push_job(v3d_priv, &bin->base, V3D_BIN); |
| 505 | &v3d_priv->sched_entity[V3D_BIN], | ||
| 506 | v3d_priv); | ||
| 507 | if (ret) | 588 | if (ret) |
| 508 | goto fail_unreserve; | 589 | goto fail_unreserve; |
| 509 | 590 | ||
| 510 | exec->bin_done_fence = | 591 | ret = drm_gem_fence_array_add(&render->base.deps, |
| 511 | dma_fence_get(&exec->bin.base.s_fence->finished); | 592 | dma_fence_get(bin->base.done_fence)); |
| 512 | 593 | if (ret) | |
| 513 | kref_get(&exec->refcount); /* put by scheduler job completion */ | 594 | goto fail_unreserve; |
| 514 | drm_sched_entity_push_job(&exec->bin.base, | ||
| 515 | &v3d_priv->sched_entity[V3D_BIN]); | ||
| 516 | } | 595 | } |
| 517 | 596 | ||
| 518 | ret = drm_sched_job_init(&exec->render.base, | 597 | ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER); |
| 519 | &v3d_priv->sched_entity[V3D_RENDER], | ||
| 520 | v3d_priv); | ||
| 521 | if (ret) | 598 | if (ret) |
| 522 | goto fail_unreserve; | 599 | goto fail_unreserve; |
| 523 | |||
| 524 | exec->render_done_fence = | ||
| 525 | dma_fence_get(&exec->render.base.s_fence->finished); | ||
| 526 | |||
| 527 | kref_get(&exec->refcount); /* put by scheduler job completion */ | ||
| 528 | drm_sched_entity_push_job(&exec->render.base, | ||
| 529 | &v3d_priv->sched_entity[V3D_RENDER]); | ||
| 530 | mutex_unlock(&v3d->sched_lock); | 600 | mutex_unlock(&v3d->sched_lock); |
| 531 | 601 | ||
| 532 | v3d_attach_object_fences(exec->bo, exec->bo_count, | 602 | v3d_attach_fences_and_unlock_reservation(file_priv, |
| 533 | exec->render_done_fence); | 603 | &render->base, |
| 534 | 604 | &acquire_ctx, | |
| 535 | v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); | 605 | args->out_sync, |
| 536 | 606 | render->base.done_fence); | |
| 537 | /* Update the return sync object for the */ | ||
| 538 | sync_out = drm_syncobj_find(file_priv, args->out_sync); | ||
| 539 | if (sync_out) { | ||
| 540 | drm_syncobj_replace_fence(sync_out, exec->render_done_fence); | ||
| 541 | drm_syncobj_put(sync_out); | ||
| 542 | } | ||
| 543 | 607 | ||
| 544 | v3d_exec_put(exec); | 608 | if (bin) |
| 609 | v3d_job_put(&bin->base); | ||
| 610 | v3d_job_put(&render->base); | ||
| 545 | 611 | ||
| 546 | return 0; | 612 | return 0; |
| 547 | 613 | ||
| 548 | fail_unreserve: | 614 | fail_unreserve: |
| 549 | mutex_unlock(&v3d->sched_lock); | 615 | mutex_unlock(&v3d->sched_lock); |
| 550 | v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); | 616 | drm_gem_unlock_reservations(render->base.bo, |
| 617 | render->base.bo_count, &acquire_ctx); | ||
| 551 | fail: | 618 | fail: |
| 552 | v3d_exec_put(exec); | 619 | if (bin) |
| 620 | v3d_job_put(&bin->base); | ||
| 621 | v3d_job_put(&render->base); | ||
| 553 | 622 | ||
| 554 | return ret; | 623 | return ret; |
| 555 | } | 624 | } |
| @@ -572,10 +641,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, · 16 unmodified lines | |||
| 572 | struct drm_v3d_submit_tfu *args = data; | 641 | struct drm_v3d_submit_tfu *args = data; |
| 573 | struct v3d_tfu_job *job; | 642 | struct v3d_tfu_job *job; |
| 574 | struct ww_acquire_ctx acquire_ctx; | 643 | struct ww_acquire_ctx acquire_ctx; |
| 575 | struct drm_syncobj *sync_out; | ||
| 576 | struct dma_fence *sched_done_fence; | ||
| 577 | int ret = 0; | 644 | int ret = 0; |
| 578 | int bo_count; | ||
| 579 | 645 | ||
| 580 | trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); | 646 | trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); |
| 581 | 647 | ||
| @@ -583,81 +649,172 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, · 1 unmodified line | |||
| 583 | if (!job) | 649 | if (!job) |
| 584 | return -ENOMEM; | 650 | return -ENOMEM; |
| 585 | 651 | ||
| 586 | ret = pm_runtime_get_sync(v3d->dev); | 652 | ret = v3d_job_init(v3d, file_priv, &job->base, |
| 587 | if (ret < 0) { | 653 | v3d_job_free, args->in_sync); |
| 654 | if (ret) { | ||
| 588 | kfree(job); | 655 | kfree(job); |
| 589 | return ret; | 656 | return ret; |
| 590 | } | 657 | } |
| 591 | 658 | ||
| 592 | kref_init(&job->refcount); | 659 | job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles), |
| 593 | 660 | sizeof(*job->base.bo), GFP_KERNEL); | |
| 594 | ret = drm_syncobj_find_fence(file_priv, args->in_sync, | 661 | if (!job->base.bo) { |
| 595 | 0, 0, &job->in_fence); | 662 | v3d_job_put(&job->base); |
| 596 | if (ret == -EINVAL) | 663 | return -ENOMEM; |
| 597 | goto fail; | 664 | } |
| 598 | 665 | ||
| 599 | job->args = *args; | 666 | job->args = *args; |
| 600 | job->v3d = v3d; | ||
| 601 | 667 | ||
| 602 | spin_lock(&file_priv->table_lock); | 668 | spin_lock(&file_priv->table_lock); |
| 603 | for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) { | 669 | for (job->base.bo_count = 0; |
| 670 | job->base.bo_count < ARRAY_SIZE(args->bo_handles); | ||
| 671 | job->base.bo_count++) { | ||
| 604 | struct drm_gem_object *bo; | 672 | struct drm_gem_object *bo; |
| 605 | 673 | ||
| 606 | if (!args->bo_handles[bo_count]) | 674 | if (!args->bo_handles[job->base.bo_count]) |
| 607 | break; | 675 | break; |
| 608 | 676 | ||
| 609 | bo = idr_find(&file_priv->object_idr, | 677 | bo = idr_find(&file_priv->object_idr, |
| 610 | args->bo_handles[bo_count]); | 678 | args->bo_handles[job->base.bo_count]); |
| 611 | if (!bo) { | 679 | if (!bo) { |
| 612 | DRM_DEBUG("Failed to look up GEM BO %d: %d\n", | 680 | DRM_DEBUG("Failed to look up GEM BO %d: %d\n", |
| 613 | bo_count, args->bo_handles[bo_count]); | 681 | job->base.bo_count, |
| 682 | args->bo_handles[job->base.bo_count]); | ||
| 614 | ret = -ENOENT; | 683 | ret = -ENOENT; |
| 615 | spin_unlock(&file_priv->table_lock); | 684 | spin_unlock(&file_priv->table_lock); |
| 616 | goto fail; | 685 | goto fail; |
| 617 | } | 686 | } |
| 618 | drm_gem_object_get(bo); | 687 | drm_gem_object_get(bo); |
| 619 | job->bo[bo_count] = to_v3d_bo(bo); | 688 | job->base.bo[job->base.bo_count] = bo; |
| 620 | } | 689 | } |
| 621 | spin_unlock(&file_priv->table_lock); | 690 | spin_unlock(&file_priv->table_lock); |
| 622 | 691 | ||
| 623 | ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx); | 692 | ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx); |
| 624 | if (ret) | 693 | if (ret) |
| 625 | goto fail; | 694 | goto fail; |
| 626 | 695 | ||
| 627 | mutex_lock(&v3d->sched_lock); | 696 | mutex_lock(&v3d->sched_lock); |
| 628 | ret = drm_sched_job_init(&job->base, | 697 | ret = v3d_push_job(v3d_priv, &job->base, V3D_TFU); |
| 629 | &v3d_priv->sched_entity[V3D_TFU], | ||
| 630 | v3d_priv); | ||
| 631 | if (ret) | 698 | if (ret) |
| 632 | goto fail_unreserve; | 699 | goto fail_unreserve; |
| 700 | mutex_unlock(&v3d->sched_lock); | ||
| 633 | 701 | ||
| 634 | sched_done_fence = dma_fence_get(&job->base.s_fence->finished); | 702 | v3d_attach_fences_and_unlock_reservation(file_priv, |
| 703 | &job->base, &acquire_ctx, | ||
| 704 | args->out_sync, | ||
| 705 | job->base.done_fence); | ||
| 635 | 706 | ||
| 636 | kref_get(&job->refcount); /* put by scheduler job completion */ | 707 | v3d_job_put(&job->base); |
| 637 | drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]); | 708 | |
| 709 | return 0; | ||
| 710 | |||
| 711 | fail_unreserve: | ||
| 638 | mutex_unlock(&v3d->sched_lock); | 712 | mutex_unlock(&v3d->sched_lock); |
| 713 | drm_gem_unlock_reservations(job->base.bo, job->base.bo_count, | ||
| 714 | &acquire_ctx); | ||
| 715 | fail: | ||
| 716 | v3d_job_put(&job->base); | ||
| 639 | 717 | ||
| 640 | v3d_attach_object_fences(job->bo, bo_count, sched_done_fence); | 718 | return ret; |
| 719 | } | ||
| 641 | 720 | ||
| 642 | v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx); | 721 | /** |
| 722 | * v3d_submit_csd_ioctl() - Submits a CSD (texture formatting) job to the V3D. | ||
| 723 | * @dev: DRM device | ||
| 724 | * @data: ioctl argument | ||
| 725 | * @file_priv: DRM file for this fd | ||
| 726 | * | ||
| 727 | * Userspace provides the register setup for the CSD, which we don't | ||
| 728 | * need to validate since the CSD is behind the MMU. | ||
| 729 | */ | ||
| 730 | int | ||
| 731 | v3d_submit_csd_ioctl(struct drm_device *dev, void *data, | ||
| 732 | struct drm_file *file_priv) | ||
| 733 | { | ||
| 734 | struct v3d_dev *v3d = to_v3d_dev(dev); | ||
| 735 | struct v3d_file_priv *v3d_priv = file_priv->driver_priv; | ||
| 736 | struct drm_v3d_submit_csd *args = data; | ||
| 737 | struct v3d_csd_job *job; | ||
| 738 | struct v3d_job *clean_job; | ||
| 739 | struct ww_acquire_ctx acquire_ctx; | ||
| 740 | int ret; | ||
| 643 | 741 | ||
| 644 | /* Update the return sync object */ | 742 | trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]); |
| 645 | sync_out = drm_syncobj_find(file_priv, args->out_sync); | 743 | |
| 646 | if (sync_out) { | 744 | if (!v3d_has_csd(v3d)) { |
| 647 | drm_syncobj_replace_fence(sync_out, sched_done_fence); | 745 | DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n"); |
| 648 | drm_syncobj_put(sync_out); | 746 | return -EINVAL; |
| 747 | } | ||
| 748 | |||
| 749 | job = kcalloc(1, sizeof(*job), GFP_KERNEL); | ||
| 750 | if (!job) | ||
| 751 | return -ENOMEM; | ||
| 752 | |||
| 753 | ret = v3d_job_init(v3d, file_priv, &job->base, | ||
| 754 | v3d_job_free, args->in_sync); | ||
| 755 | if (ret) { | ||
| 756 | kfree(job); | ||
| 757 | return ret; | ||
| 758 | } | ||
| 759 | |||
| 760 | clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL); | ||
| 761 | if (!clean_job) { | ||
| 762 | v3d_job_put(&job->base); | ||
| 763 | kfree(job); | ||
| 764 | return -ENOMEM; | ||
| 649 | } | 765 | } |
| 650 | dma_fence_put(sched_done_fence); | ||
| 651 | 766 | ||
| 652 | v3d_tfu_job_put(job); | 767 | ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0); |
| 768 | if (ret) { | ||
| 769 | v3d_job_put(&job->base); | ||
| 770 | kfree(clean_job); | ||
| 771 | return ret; | ||
| 772 | } | ||
| 773 | |||
| 774 | job->args = *args; | ||
| 775 | |||
| 776 | ret = v3d_lookup_bos(dev, file_priv, clean_job, | ||
| 777 | args->bo_handles, args->bo_handle_count); | ||
| 778 | if (ret) | ||
| 779 | goto fail; | ||
| 780 | |||
| 781 | ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx); | ||
| 782 | if (ret) | ||
| 783 | goto fail; | ||
| 784 | |||
| 785 | mutex_lock(&v3d->sched_lock); | ||
| 786 | ret = v3d_push_job(v3d_priv, &job->base, V3D_CSD); | ||
| 787 | if (ret) | ||
| 788 | goto fail_unreserve; | ||
| 789 | |||
| 790 | ret = drm_gem_fence_array_add(&clean_job->deps, | ||
| 791 | dma_fence_get(job->base.done_fence)); | ||
| 792 | if (ret) | ||
| 793 | goto fail_unreserve; | ||
| 794 | |||
| 795 | ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN); | ||
| 796 | if (ret) | ||
| 797 | goto fail_unreserve; | ||
| 798 | mutex_unlock(&v3d->sched_lock); | ||
| 799 | |||
| 800 | v3d_attach_fences_and_unlock_reservation(file_priv, | ||
| 801 | clean_job, | ||
| 802 | &acquire_ctx, | ||
| 803 | args->out_sync, | ||
| 804 | clean_job->done_fence); | ||
| 805 | |||
| 806 | v3d_job_put(&job->base); | ||
| 807 | v3d_job_put(clean_job); | ||
| 653 | 808 | ||
| 654 | return 0; | 809 | return 0; |
| 655 | 810 | ||
| 656 | fail_unreserve: | 811 | fail_unreserve: |
| 657 | mutex_unlock(&v3d->sched_lock); | 812 | mutex_unlock(&v3d->sched_lock); |
| 658 | v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx); | 813 | drm_gem_unlock_reservations(clean_job->bo, clean_job->bo_count, |
| 814 | &acquire_ctx); | ||
| 659 | fail: | 815 | fail: |
| 660 | v3d_tfu_job_put(job); | 816 | v3d_job_put(&job->base); |
| 817 | v3d_job_put(clean_job); | ||
| 661 | 818 | ||
| 662 | return ret; | 819 | return ret; |
| 663 | } | 820 | } |
| @@ -677,6 +834,7 @@ v3d_gem_init(struct drm_device *dev) · 13 unmodified lines | |||
| 677 | mutex_init(&v3d->bo_lock); | 834 | mutex_init(&v3d->bo_lock); |
| 678 | mutex_init(&v3d->reset_lock); | 835 | mutex_init(&v3d->reset_lock); |
| 679 | mutex_init(&v3d->sched_lock); | 836 | mutex_init(&v3d->sched_lock); |
| 837 | mutex_init(&v3d->cache_clean_lock); | ||
| 680 | 838 | ||
| 681 | /* Note: We don't allocate address 0. Various bits of HW | 839 | /* Note: We don't allocate address 0. Various bits of HW |
| 682 | * treat 0 as special, such as the occlusion query counters | 840 | * treat 0 as special, such as the occlusion query counters |
| @@ -715,7 +873,7 @@ v3d_gem_destroy(struct drm_device *dev) · 32 unmodified lines | |||
| 715 | 873 | ||
| 716 | v3d_sched_fini(v3d); | 874 | v3d_sched_fini(v3d); |
| 717 | 875 | ||
| 718 | /* Waiting for exec to finish would need to be done before | 876 | /* Waiting for jobs to finish would need to be done before |
| 719 | * unregistering V3D. | 877 | * unregistering V3D. |
| 720 | */ | 878 | */ |
| 721 | WARN_ON(v3d->bin_job); | 879 | WARN_ON(v3d->bin_job); |
| @@ -4,9 +4,9 @@ · 3 unmodified lines | |||
| 4 | /** | 4 | /** |
| 5 | * DOC: Interrupt management for the V3D engine | 5 | * DOC: Interrupt management for the V3D engine |
| 6 | * | 6 | * |
| 7 | * When we take a bin, render, or TFU done interrupt, we need to | 7 | * When we take a bin, render, TFU done, or CSD done interrupt, we |
| 8 | * signal the fence for that job so that the scheduler can queue up | 8 | * need to signal the fence for that job so that the scheduler can |
| 9 | * the next one and unblock any waiters. | 9 | * queue up the next one and unblock any waiters. |
| 10 | * | 10 | * |
| 11 | * When we take the binner out of memory interrupt, we need to | 11 | * When we take the binner out of memory interrupt, we need to |
| 12 | * allocate some new memory and pass it to the binner so that the | 12 | * allocate some new memory and pass it to the binner so that the |
| @@ -20,6 +20,7 @@ · 7 unmodified lines | |||
| 20 | #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ | 20 | #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ |
| 21 | V3D_INT_FLDONE | \ | 21 | V3D_INT_FLDONE | \ |
| 22 | V3D_INT_FRDONE | \ | 22 | V3D_INT_FRDONE | \ |
| 23 | V3D_INT_CSDDONE | \ | ||
| 23 | V3D_INT_GMPV)) | 24 | V3D_INT_GMPV)) |
| 24 | 25 | ||
| 25 | #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ | 26 | #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ |
| @@ -62,7 +63,7 @@ v3d_overflow_mem_work(struct work_struct *work) · 36 unmodified lines | |||
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | drm_gem_object_get(obj); | 65 | drm_gem_object_get(obj); |
| 65 | list_add_tail(&bo->unref_head, &v3d->bin_job->unref_list); | 66 | list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list); |
| 66 | spin_unlock_irqrestore(&v3d->job_lock, irqflags); | 67 | spin_unlock_irqrestore(&v3d->job_lock, irqflags); |
| 67 | 68 | ||
| 68 | V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT); | 69 | V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT); |
| @@ -96,7 +97,7 @@ v3d_irq(int irq, void *arg) · 27 unmodified lines | |||
| 96 | 97 | ||
| 97 | if (intsts & V3D_INT_FLDONE) { | 98 | if (intsts & V3D_INT_FLDONE) { |
| 98 | struct v3d_fence *fence = | 99 | struct v3d_fence *fence = |
| 99 | to_v3d_fence(v3d->bin_job->bin.irq_fence); | 100 | to_v3d_fence(v3d->bin_job->base.irq_fence); |
| 100 | 101 | ||
| 101 | trace_v3d_bcl_irq(&v3d->drm, fence->seqno); | 102 | trace_v3d_bcl_irq(&v3d->drm, fence->seqno); |
| 102 | dma_fence_signal(&fence->base); | 103 | dma_fence_signal(&fence->base); |
| @@ -105,13 +106,22 @@ v3d_irq(int irq, void *arg) · 2 unmodified lines | |||
| 105 | 106 | ||
| 106 | if (intsts & V3D_INT_FRDONE) { | 107 | if (intsts & V3D_INT_FRDONE) { |
| 107 | struct v3d_fence *fence = | 108 | struct v3d_fence *fence = |
| 108 | to_v3d_fence(v3d->render_job->render.irq_fence); | 109 | to_v3d_fence(v3d->render_job->base.irq_fence); |
| 109 | 110 | ||
| 110 | trace_v3d_rcl_irq(&v3d->drm, fence->seqno); | 111 | trace_v3d_rcl_irq(&v3d->drm, fence->seqno); |
| 111 | dma_fence_signal(&fence->base); | 112 | dma_fence_signal(&fence->base); |
| 112 | status = IRQ_HANDLED; | 113 | status = IRQ_HANDLED; |
| 113 | } | 114 | } |
| 114 | 115 | ||
| 116 | if (intsts & V3D_INT_CSDDONE) { | ||
| 117 | struct v3d_fence *fence = | ||
| 118 | to_v3d_fence(v3d->csd_job->base.irq_fence); | ||
| 119 | |||
| 120 | trace_v3d_csd_irq(&v3d->drm, fence->seqno); | ||
| 121 | dma_fence_signal(&fence->base); | ||
| 122 | status = IRQ_HANDLED; | ||
| 123 | } | ||
| 124 | |||
| 115 | /* We shouldn't be triggering these if we have GMP in | 125 | /* We shouldn't be triggering these if we have GMP in |
| 116 | * always-allowed mode. | 126 | * always-allowed mode. |
| 117 | */ | 127 | */ |
| @@ -141,7 +151,7 @@ v3d_hub_irq(int irq, void *arg) · 23 unmodified lines | |||
| 141 | 151 | ||
| 142 | if (intsts & V3D_HUB_INT_TFUC) { | 152 | if (intsts & V3D_HUB_INT_TFUC) { |
| 143 | struct v3d_fence *fence = | 153 | struct v3d_fence *fence = |
| 144 | to_v3d_fence(v3d->tfu_job->irq_fence); | 154 | to_v3d_fence(v3d->tfu_job->base.irq_fence); |
| 145 | 155 | ||
| 146 | trace_v3d_tfu_irq(&v3d->drm, fence->seqno); | 156 | trace_v3d_tfu_irq(&v3d->drm, fence->seqno); |
| 147 | dma_fence_signal(&fence->base); | 157 | dma_fence_signal(&fence->base); |
| @@ -152,10 +162,33 @@ v3d_hub_irq(int irq, void *arg) · 4 unmodified lines | |||
| 152 | V3D_HUB_INT_MMU_PTI | | 162 | V3D_HUB_INT_MMU_PTI | |
| 153 | V3D_HUB_INT_MMU_CAP)) { | 163 | V3D_HUB_INT_MMU_CAP)) { |
| 154 | u32 axi_id = V3D_READ(V3D_MMU_VIO_ID); | 164 | u32 axi_id = V3D_READ(V3D_MMU_VIO_ID); |
| 155 | u64 vio_addr = (u64)V3D_READ(V3D_MMU_VIO_ADDR) << 8; | 165 | u64 vio_addr = ((u64)V3D_READ(V3D_MMU_VIO_ADDR) << |
| 156 | 166 | (v3d->va_width - 32)); | |
| 157 | dev_err(v3d->dev, "MMU error from client %d at 0x%08llx%s%s%s\n", | 167 | static const char *const v3d41_axi_ids[] = { |
| 158 | axi_id, (long long)vio_addr, | 168 | "L2T", |
| 169 | "PTB", | ||
| 170 | "PSE", | ||
| 171 | "TLB", | ||
| 172 | "CLE", | ||
| 173 | "TFU", | ||
| 174 | "MMU", | ||
| 175 | "GMP", | ||
| 176 | }; | ||
| 177 | const char *client = "?"; | ||
| 178 | |||
| 179 | V3D_WRITE(V3D_MMU_CTL, | ||
| 180 | V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED | | ||
| 181 | V3D_MMU_CTL_PT_INVALID | | ||
| 182 | V3D_MMU_CTL_WRITE_VIOLATION)); | ||
| 183 | |||
| 184 | if (v3d->ver >= 41) { | ||
| 185 | axi_id = axi_id >> 5; | ||
| 186 | if (axi_id < ARRAY_SIZE(v3d41_axi_ids)) | ||
| 187 | client = v3d41_axi_ids[axi_id]; | ||
| 188 | } | ||
| 189 | |||
| 190 | dev_err(v3d->dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n", | ||
| 191 | client, axi_id, (long long)vio_addr, | ||
| 159 | ((intsts & V3D_HUB_INT_MMU_WRV) ? | 192 | ((intsts & V3D_HUB_INT_MMU_WRV) ? |
| 160 | ", write violation" : ""), | 193 | ", write violation" : ""), |
| 161 | ((intsts & V3D_HUB_INT_MMU_PTI) ? | 194 | ((intsts & V3D_HUB_INT_MMU_PTI) ? |
| @@ -69,10 +69,13 @@ int v3d_mmu_set_page_table(struct v3d_dev *v3d) · 68 unmodified lines | |||
| 69 | V3D_WRITE(V3D_MMU_PT_PA_BASE, v3d->pt_paddr >> V3D_MMU_PAGE_SHIFT); | 69 | V3D_WRITE(V3D_MMU_PT_PA_BASE, v3d->pt_paddr >> V3D_MMU_PAGE_SHIFT); |
| 70 | V3D_WRITE(V3D_MMU_CTL, | 70 | V3D_WRITE(V3D_MMU_CTL, |
| 71 | V3D_MMU_CTL_ENABLE | | 71 | V3D_MMU_CTL_ENABLE | |
| 72 | V3D_MMU_CTL_PT_INVALID | | 72 | V3D_MMU_CTL_PT_INVALID_ENABLE | |
| 73 | V3D_MMU_CTL_PT_INVALID_ABORT | | 73 | V3D_MMU_CTL_PT_INVALID_ABORT | |
| 74 | V3D_MMU_CTL_PT_INVALID_INT | | ||
| 74 | V3D_MMU_CTL_WRITE_VIOLATION_ABORT | | 75 | V3D_MMU_CTL_WRITE_VIOLATION_ABORT | |
| 75 | V3D_MMU_CTL_CAP_EXCEEDED_ABORT); | 76 | V3D_MMU_CTL_WRITE_VIOLATION_INT | |
| 77 | V3D_MMU_CTL_CAP_EXCEEDED_ABORT | | ||
| 78 | V3D_MMU_CTL_CAP_EXCEEDED_INT); | ||
| 76 | V3D_WRITE(V3D_MMU_ILLEGAL_ADDR, | 79 | V3D_WRITE(V3D_MMU_ILLEGAL_ADDR, |
| 77 | (v3d->mmu_scratch_paddr >> V3D_MMU_PAGE_SHIFT) | | 80 | (v3d->mmu_scratch_paddr >> V3D_MMU_PAGE_SHIFT) | |
| 78 | V3D_MMU_ILLEGAL_ADDR_ENABLE); | 81 | V3D_MMU_ILLEGAL_ADDR_ENABLE); |
| @@ -152,7 +152,8 @@ · 151 unmodified lines | |||
| 152 | # define V3D_MMU_CTL_PT_INVALID_ABORT BIT(19) | 152 | # define V3D_MMU_CTL_PT_INVALID_ABORT BIT(19) |
| 153 | # define V3D_MMU_CTL_PT_INVALID_INT BIT(18) | 153 | # define V3D_MMU_CTL_PT_INVALID_INT BIT(18) |
| 154 | # define V3D_MMU_CTL_PT_INVALID_EXCEPTION BIT(17) | 154 | # define V3D_MMU_CTL_PT_INVALID_EXCEPTION BIT(17) |
| 155 | # define V3D_MMU_CTL_WRITE_VIOLATION BIT(16) | 155 | # define V3D_MMU_CTL_PT_INVALID_ENABLE BIT(16) |
| 156 | # define V3D_MMU_CTL_WRITE_VIOLATION BIT(12) | ||
| 156 | # define V3D_MMU_CTL_WRITE_VIOLATION_ABORT BIT(11) | 157 | # define V3D_MMU_CTL_WRITE_VIOLATION_ABORT BIT(11) |
| 157 | # define V3D_MMU_CTL_WRITE_VIOLATION_INT BIT(10) | 158 | # define V3D_MMU_CTL_WRITE_VIOLATION_INT BIT(10) |
| 158 | # define V3D_MMU_CTL_WRITE_VIOLATION_EXCEPTION BIT(9) | 159 | # define V3D_MMU_CTL_WRITE_VIOLATION_EXCEPTION BIT(9) |
| @@ -191,6 +192,14 @@ · 32 unmodified lines | |||
| 191 | /* Address that faulted */ | 192 | /* Address that faulted */ |
| 192 | #define V3D_MMU_VIO_ADDR 0x01234 | 193 | #define V3D_MMU_VIO_ADDR 0x01234 |
| 193 | 194 | ||
| 195 | #define V3D_MMU_DEBUG_INFO 0x01238 | ||
| 196 | # define V3D_MMU_PA_WIDTH_MASK V3D_MASK(11, 8) | ||
| 197 | # define V3D_MMU_PA_WIDTH_SHIFT 8 | ||
| 198 | # define V3D_MMU_VA_WIDTH_MASK V3D_MASK(7, 4) | ||
| 199 | # define V3D_MMU_VA_WIDTH_SHIFT 4 | ||
| 200 | # define V3D_MMU_VERSION_MASK V3D_MASK(3, 0) | ||
| 201 | # define V3D_MMU_VERSION_SHIFT 0 | ||
| 202 | |||
| 194 | /* Per-V3D-core registers */ | 203 | /* Per-V3D-core registers */ |
| 195 | 204 | ||
| 196 | #define V3D_CTL_IDENT0 0x00000 | 205 | #define V3D_CTL_IDENT0 0x00000 |
| @@ -238,8 +247,11 @@ · 41 unmodified lines | |||
| 238 | #define V3D_CTL_L2TCACTL 0x00030 | 247 | #define V3D_CTL_L2TCACTL 0x00030 |
| 239 | # define V3D_L2TCACTL_TMUWCF BIT(8) | 248 | # define V3D_L2TCACTL_TMUWCF BIT(8) |
| 240 | # define V3D_L2TCACTL_L2T_NO_WM BIT(4) | 249 | # define V3D_L2TCACTL_L2T_NO_WM BIT(4) |
| 250 | /* Invalidates cache lines. */ | ||
| 241 | # define V3D_L2TCACTL_FLM_FLUSH 0 | 251 | # define V3D_L2TCACTL_FLM_FLUSH 0 |
| 252 | /* Removes cachelines without writing dirty lines back. */ | ||
| 242 | # define V3D_L2TCACTL_FLM_CLEAR 1 | 253 | # define V3D_L2TCACTL_FLM_CLEAR 1 |
| 254 | /* Writes out dirty cachelines and marks them clean, but doesn't invalidate. */ | ||
| 243 | # define V3D_L2TCACTL_FLM_CLEAN 2 | 255 | # define V3D_L2TCACTL_FLM_CLEAN 2 |
| 244 | # define V3D_L2TCACTL_FLM_MASK V3D_MASK(2, 1) | 256 | # define V3D_L2TCACTL_FLM_MASK V3D_MASK(2, 1) |
| 245 | # define V3D_L2TCACTL_FLM_SHIFT 1 | 257 | # define V3D_L2TCACTL_FLM_SHIFT 1 |
| @@ -255,6 +267,8 @@ · 9 unmodified lines | |||
| 255 | #define V3D_CTL_INT_MSK_CLR 0x00064 | 267 | #define V3D_CTL_INT_MSK_CLR 0x00064 |
| 256 | # define V3D_INT_QPU_MASK V3D_MASK(27, 16) | 268 | # define V3D_INT_QPU_MASK V3D_MASK(27, 16) |
| 257 | # define V3D_INT_QPU_SHIFT 16 | 269 | # define V3D_INT_QPU_SHIFT 16 |
| 270 | # define V3D_INT_CSDDONE BIT(7) | ||
| 271 | # define V3D_INT_PCTR BIT(6) | ||
| 258 | # define V3D_INT_GMPV BIT(5) | 272 | # define V3D_INT_GMPV BIT(5) |
| 259 | # define V3D_INT_TRFB BIT(4) | 273 | # define V3D_INT_TRFB BIT(4) |
| 260 | # define V3D_INT_SPILLUSE BIT(3) | 274 | # define V3D_INT_SPILLUSE BIT(3) |
| @@ -374,4 +388,110 @@ · 113 unmodified lines | |||
| 374 | #define V3D_GMP_PRESERVE_LOAD 0x00818 | 388 | #define V3D_GMP_PRESERVE_LOAD 0x00818 |
| 375 | #define V3D_GMP_VALID_LINES 0x00820 | 389 | #define V3D_GMP_VALID_LINES 0x00820 |
| 376 | 390 | ||
| 391 | #define V3D_CSD_STATUS 0x00900 | ||
| 392 | # define V3D_CSD_STATUS_NUM_COMPLETED_MASK V3D_MASK(11, 4) | ||
| 393 | # define V3D_CSD_STATUS_NUM_COMPLETED_SHIFT 4 | ||
| 394 | # define V3D_CSD_STATUS_NUM_ACTIVE_MASK V3D_MASK(3, 2) | ||
| 395 | # define V3D_CSD_STATUS_NUM_ACTIVE_SHIFT 2 | ||
| 396 | # define V3D_CSD_STATUS_HAVE_CURRENT_DISPATCH BIT(1) | ||
| 397 | # define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0) | ||
| 398 | |||
| 399 | #define V3D_CSD_QUEUED_CFG0 0x00904 | ||
| 400 | # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16) | ||
| 401 | # define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16 | ||
| 402 | # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0) | ||
| 403 | # define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0 | ||
| 404 | |||
| 405 | #define V3D_CSD_QUEUED_CFG1 0x00908 | ||
| 406 | # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16) | ||
| 407 | # define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16 | ||
| 408 | # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0) | ||
| 409 | # define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0 | ||
| 410 | |||
| 411 | #define V3D_CSD_QUEUED_CFG2 0x0090c | ||
| 412 | # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16) | ||
| 413 | # define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16 | ||
| 414 | # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0) | ||
| 415 | # define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0 | ||
| 416 | |||
| 417 | #define V3D_CSD_QUEUED_CFG3 0x00910 | ||
| 418 | # define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26) | ||
| 419 | # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20) | ||
| 420 | # define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20 | ||
| 421 | # define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_MASK V3D_MASK(19, 12) | ||
| 422 | # define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_SHIFT 12 | ||
| 423 | # define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_MASK V3D_MASK(11, 8) | ||
| 424 | # define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_SHIFT 8 | ||
| 425 | # define V3D_CSD_QUEUED_CFG3_WG_SIZE_MASK V3D_MASK(7, 0) | ||
| 426 | # define V3D_CSD_QUEUED_CFG3_WG_SIZE_SHIFT 0 | ||
| 427 | |||
| 428 | /* Number of batches, minus 1 */ | ||
| 429 | #define V3D_CSD_QUEUED_CFG4 0x00914 | ||
| 430 | |||
| 431 | /* Shader address, pnan, singleseg, threading, like a shader record. */ | ||
| 432 | #define V3D_CSD_QUEUED_CFG5 0x00918 | ||
| 433 | |||
| 434 | /* Uniforms address (4 byte aligned) */ | ||
| 435 | #define V3D_CSD_QUEUED_CFG6 0x0091c | ||
| 436 | |||
| 437 | #define V3D_CSD_CURRENT_CFG0 0x00920 | ||
| 438 | #define V3D_CSD_CURRENT_CFG1 0x00924 | ||
| 439 | #define V3D_CSD_CURRENT_CFG2 0x00928 | ||
| 440 | #define V3D_CSD_CURRENT_CFG3 0x0092c | ||
| 441 | #define V3D_CSD_CURRENT_CFG4 0x00930 | ||
| 442 | #define V3D_CSD_CURRENT_CFG5 0x00934 | ||
| 443 | #define V3D_CSD_CURRENT_CFG6 0x00938 | ||
| 444 | |||
| 445 | #define V3D_CSD_CURRENT_ID0 0x0093c | ||
| 446 | # define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16) | ||
| 447 | # define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16 | ||
| 448 | # define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8) | ||
| 449 | # define V3D_CSD_CURRENT_ID0_WG_IN_SG_SHIFT 8 | ||
| 450 | # define V3D_CSD_CURRENT_ID0_L_IDX_MASK V3D_MASK(7, 0) | ||
| 451 | # define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0 | ||
| 452 | |||
| 453 | #define V3D_CSD_CURRENT_ID1 0x00940 | ||
| 454 | # define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16) | ||
| 455 | # define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16 | ||
| 456 | # define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0) | ||
| 457 | # define V3D_CSD_CURRENT_ID0_WG_Y_SHIFT 0 | ||
| 458 | |||
| 459 | #define V3D_ERR_FDBGO 0x00f04 | ||
| 460 | #define V3D_ERR_FDBGB 0x00f08 | ||
| 461 | #define V3D_ERR_FDBGR 0x00f0c | ||
| 462 | |||
| 463 | #define V3D_ERR_FDBGS 0x00f10 | ||
| 464 | # define V3D_ERR_FDBGS_INTERPZ_IP_STALL BIT(17) | ||
| 465 | # define V3D_ERR_FDBGS_DEPTHO_FIFO_IP_STALL BIT(16) | ||
| 466 | # define V3D_ERR_FDBGS_XYNRM_IP_STALL BIT(14) | ||
| 467 | # define V3D_ERR_FDBGS_EZREQ_FIFO_OP_VALID BIT(13) | ||
| 468 | # define V3D_ERR_FDBGS_QXYF_FIFO_OP_VALID BIT(12) | ||
| 469 | # define V3D_ERR_FDBGS_QXYF_FIFO_OP_LAST BIT(11) | ||
| 470 | # define V3D_ERR_FDBGS_EZTEST_ANYQVALID BIT(7) | ||
| 471 | # define V3D_ERR_FDBGS_EZTEST_PASS BIT(6) | ||
| 472 | # define V3D_ERR_FDBGS_EZTEST_QREADY BIT(5) | ||
| 473 | # define V3D_ERR_FDBGS_EZTEST_VLF_OKNOVALID BIT(4) | ||
| 474 | # define V3D_ERR_FDBGS_EZTEST_QSTALL BIT(3) | ||
| 475 | # define V3D_ERR_FDBGS_EZTEST_IP_VLFSTALL BIT(2) | ||
| 476 | # define V3D_ERR_FDBGS_EZTEST_IP_PRSTALL BIT(1) | ||
| 477 | # define V3D_ERR_FDBGS_EZTEST_IP_QSTALL BIT(0) | ||
| 478 | |||
| 479 | #define V3D_ERR_STAT 0x00f20 | ||
| 480 | # define V3D_ERR_L2CARE BIT(15) | ||
| 481 | # define V3D_ERR_VCMBE BIT(14) | ||
| 482 | # define V3D_ERR_VCMRE BIT(13) | ||
| 483 | # define V3D_ERR_VCDI BIT(12) | ||
| 484 | # define V3D_ERR_VCDE BIT(11) | ||
| 485 | # define V3D_ERR_VDWE BIT(10) | ||
| 486 | # define V3D_ERR_VPMEAS BIT(9) | ||
| 487 | # define V3D_ERR_VPMEFNA BIT(8) | ||
| 488 | # define V3D_ERR_VPMEWNA BIT(7) | ||
| 489 | # define V3D_ERR_VPMERNA BIT(6) | ||
| 490 | # define V3D_ERR_VPMERR BIT(5) | ||
| 491 | # define V3D_ERR_VPMEWR BIT(4) | ||
| 492 | # define V3D_ERR_VPAERRGL BIT(3) | ||
| 493 | # define V3D_ERR_VPAEBRGL BIT(2) | ||
| 494 | # define V3D_ERR_VPAERGS BIT(1) | ||
| 495 | # define V3D_ERR_VPAEABB BIT(0) | ||
| 496 | |||
| 377 | #endif /* V3D_REGS_H */ | 497 | #endif /* V3D_REGS_H */ |
| @@ -30,158 +30,152 @@ to_v3d_job(struct drm_sched_job *sched_job) · 29 unmodified lines | |||
| 30 | return container_of(sched_job, struct v3d_job, base); | 30 | return container_of(sched_job, struct v3d_job, base); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static struct v3d_tfu_job * | 33 | static struct v3d_bin_job * |
| 34 | to_tfu_job(struct drm_sched_job *sched_job) | 34 | to_bin_job(struct drm_sched_job *sched_job) |
| 35 | { | 35 | { |
| 36 | return container_of(sched_job, struct v3d_tfu_job, base); | 36 | return container_of(sched_job, struct v3d_bin_job, base.base); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | static void | 39 | static struct v3d_render_job * |
| 40 | v3d_job_free(struct drm_sched_job *sched_job) | 40 | to_render_job(struct drm_sched_job *sched_job) |
| 41 | { | 41 | { |
| 42 | struct v3d_job *job = to_v3d_job(sched_job); | 42 | return container_of(sched_job, struct v3d_render_job, base.base); |
| 43 | } | ||
| 43 | 44 | ||
| 44 | drm_sched_job_cleanup(sched_job); | 45 | static struct v3d_tfu_job * |
| 46 | to_tfu_job(struct drm_sched_job *sched_job) | ||
| 47 | { | ||
| 48 | return container_of(sched_job, struct v3d_tfu_job, base.base); | ||
| 49 | } | ||
| 45 | 50 | ||
| 46 | v3d_exec_put(job->exec); | 51 | static struct v3d_csd_job * |
| 52 | to_csd_job(struct drm_sched_job *sched_job) | ||
| 53 | { | ||
| 54 | return container_of(sched_job, struct v3d_csd_job, base.base); | ||
| 47 | } | 55 | } |
| 48 | 56 | ||
| 49 | static void | 57 | static void |
| 50 | v3d_tfu_job_free(struct drm_sched_job *sched_job) | 58 | v3d_job_free(struct drm_sched_job *sched_job) |
| 51 | { | 59 | { |
| 52 | struct v3d_tfu_job *job = to_tfu_job(sched_job); | 60 | struct v3d_job *job = to_v3d_job(sched_job); |
| 53 | 61 | ||
| 54 | drm_sched_job_cleanup(sched_job); | 62 | drm_sched_job_cleanup(sched_job); |
| 55 | 63 | v3d_job_put(job); | |
| 56 | v3d_tfu_job_put(job); | ||
| 57 | } | 64 | } |
| 58 | 65 | ||
| 59 | /** | 66 | /** |
| 60 | * Returns the fences that the bin or render job depends on, one by one. | 67 | * Returns the fences that the job depends on, one by one. |
| 61 | * v3d_job_run() won't be called until all of them have been signaled. | 68 | * |
| 69 | * If placed in the scheduler's .dependency method, the corresponding | ||
| 70 | * .run_job won't be called until all of them have been signaled. | ||
| 62 | */ | 71 | */ |
| 63 | static struct dma_fence * | 72 | static struct dma_fence * |
| 64 | v3d_job_dependency(struct drm_sched_job *sched_job, | 73 | v3d_job_dependency(struct drm_sched_job *sched_job, |
| 65 | struct drm_sched_entity *s_entity) | 74 | struct drm_sched_entity *s_entity) |
| 66 | { | 75 | { |
| 67 | struct v3d_job *job = to_v3d_job(sched_job); | 76 | struct v3d_job *job = to_v3d_job(sched_job); |
| 68 | struct v3d_exec_info *exec = job->exec; | ||
| 69 | enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER; | ||
| 70 | struct dma_fence *fence; | ||
| 71 | |||
| 72 | fence = job->in_fence; | ||
| 73 | if (fence) { | ||
| 74 | job->in_fence = NULL; | ||
| 75 | return fence; | ||
| 76 | } | ||
| 77 | |||
| 78 | if (q == V3D_RENDER) { | ||
| 79 | /* If we had a bin job, the render job definitely depends on | ||
| 80 | * it. We first have to wait for bin to be scheduled, so that | ||
| 81 | * its done_fence is created. | ||
| 82 | */ | ||
| 83 | fence = exec->bin_done_fence; | ||
| 84 | if (fence) { | ||
| 85 | exec->bin_done_fence = NULL; | ||
| 86 | return fence; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | 77 | ||
| 90 | /* XXX: Wait on a fence for switching the GMP if necessary, | 78 | /* XXX: Wait on a fence for switching the GMP if necessary, |
| 91 | * and then do so. | 79 | * and then do so. |
| 92 | */ | 80 | */ |
| 93 | 81 | ||
| 94 | return fence; | 82 | if (!xa_empty(&job->deps)) |
| 95 | } | 83 | return xa_erase(&job->deps, job->last_dep++); |
| 96 | |||
| 97 | /** | ||
| 98 | * Returns the fences that the TFU job depends on, one by one. | ||
| 99 | * v3d_tfu_job_run() won't be called until all of them have been | ||
| 100 | * signaled. | ||
| 101 | */ | ||
| 102 | static struct dma_fence * | ||
| 103 | v3d_tfu_job_dependency(struct drm_sched_job *sched_job, | ||
| 104 | struct drm_sched_entity *s_entity) | ||
| 105 | { | ||
| 106 | struct v3d_tfu_job *job = to_tfu_job(sched_job); | ||
| 107 | struct dma_fence *fence; | ||
| 108 | |||
| 109 | fence = job->in_fence; | ||
| 110 | if (fence) { | ||
| 111 | job->in_fence = NULL; | ||
| 112 | return fence; | ||
| 113 | } | ||
| 114 | 84 | ||
| 115 | return NULL; | 85 | return NULL; |
| 116 | } | 86 | } |
| 117 | 87 | ||
| 118 | static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job) | 88 | static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) |
| 119 | { | 89 | { |
| 120 | struct v3d_job *job = to_v3d_job(sched_job); | 90 | struct v3d_bin_job *job = to_bin_job(sched_job); |
| 121 | struct v3d_exec_info *exec = job->exec; | 91 | struct v3d_dev *v3d = job->base.v3d; |
| 122 | enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER; | ||
| 123 | struct v3d_dev *v3d = exec->v3d; | ||
| 124 | struct drm_device *dev = &v3d->drm; | 92 | struct drm_device *dev = &v3d->drm; |
| 125 | struct dma_fence *fence; | 93 | struct dma_fence *fence; |
| 126 | unsigned long irqflags; | 94 | unsigned long irqflags; |
| 127 | 95 | ||
| 128 | if (unlikely(job->base.s_fence->finished.error)) | 96 | if (unlikely(job->base.base.s_fence->finished.error)) |
| 129 | return NULL; | 97 | return NULL; |
| 130 | 98 | ||
| 131 | /* Lock required around bin_job update vs | 99 | /* Lock required around bin_job update vs |
| 132 | * v3d_overflow_mem_work(). | 100 | * v3d_overflow_mem_work(). |
| 133 | */ | 101 | */ |
| 134 | spin_lock_irqsave(&v3d->job_lock, irqflags); | 102 | spin_lock_irqsave(&v3d->job_lock, irqflags); |
| 135 | if (q == V3D_BIN) { | 103 | v3d->bin_job = job; |
| 136 | v3d->bin_job = job->exec; | 104 | /* Clear out the overflow allocation, so we don't |
| 137 | 105 | * reuse the overflow attached to a previous job. | |
| 138 | /* Clear out the overflow allocation, so we don't | 106 | */ |
| 139 | * reuse the overflow attached to a previous job. | 107 | V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0); |
| 140 | */ | ||
| 141 | V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0); | ||
| 142 | } else { | ||
| 143 | v3d->render_job = job->exec; | ||
| 144 | } | ||
| 145 | spin_unlock_irqrestore(&v3d->job_lock, irqflags); | 108 | spin_unlock_irqrestore(&v3d->job_lock, irqflags); |
| 146 | 109 | ||
| 147 | /* Can we avoid this flush when q==RENDER? We need to be | 110 | v3d_invalidate_caches(v3d); |
| 148 | * careful of scheduling, though -- imagine job0 rendering to | 111 | |
| 149 | * texture and job1 reading, and them being executed as bin0, | 112 | fence = v3d_fence_create(v3d, V3D_BIN); |
| 150 | * bin1, render0, render1, so that render1's flush at bin time | 113 | if (IS_ERR(fence)) |
| 114 | return NULL; | ||
| 115 | |||
| 116 | if (job->base.irq_fence) | ||
| 117 | dma_fence_put(job->base.irq_fence); | ||
| 118 | job->base.irq_fence = dma_fence_get(fence); | ||
| 119 | |||
| 120 | trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno, | ||
| 121 | job->start, job->end); | ||
| 122 | |||
| 123 | /* Set the current and end address of the control list. | ||
| 124 | * Writing the end register is what starts the job. | ||
| 125 | */ | ||
| 126 | if (job->qma) { | ||
| 127 | V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, job->qma); | ||
| 128 | V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, job->qms); | ||
| 129 | } | ||
| 130 | if (job->qts) { | ||
| 131 | V3D_CORE_WRITE(0, V3D_CLE_CT0QTS, | ||
| 132 | V3D_CLE_CT0QTS_ENABLE | | ||
| 133 | job->qts); | ||
| 134 | } | ||
| 135 | V3D_CORE_WRITE(0, V3D_CLE_CT0QBA, job->start); | ||
| 136 | V3D_CORE_WRITE(0, V3D_CLE_CT0QEA, job->end); | ||
| 137 | |||
| 138 | return fence; | ||
| 139 | } | ||
| 140 | |||
| 141 | static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) | ||
| 142 | { | ||
| 143 | struct v3d_render_job *job = to_render_job(sched_job); | ||
| 144 | struct v3d_dev *v3d = job->base.v3d; | ||
| 145 | struct drm_device *dev = &v3d->drm; | ||
| 146 | struct dma_fence *fence; | ||
| 147 | |||
| 148 | if (unlikely(job->base.base.s_fence->finished.error)) | ||
| 149 | return NULL; | ||
| 150 | |||
| 151 | v3d->render_job = job; | ||
| 152 | |||
| 153 | /* Can we avoid this flush? We need to be careful of | ||
| 154 | * scheduling, though -- imagine job0 rendering to texture and | ||
| 155 | * job1 reading, and them being executed as bin0, bin1, | ||
| 156 | * render0, render1, so that render1's flush at bin time | ||
| 151 | * wasn't enough. | 157 | * wasn't enough. |
| 152 | */ | 158 | */ |
| 153 | v3d_invalidate_caches(v3d); | 159 | v3d_invalidate_caches(v3d); |
| 154 | 160 | ||
| 155 | fence = v3d_fence_create(v3d, q); | 161 | fence = v3d_fence_create(v3d, V3D_RENDER); |
| 156 | if (IS_ERR(fence)) | 162 | if (IS_ERR(fence)) |
| 157 | return NULL; | 163 | return NULL; |
| 158 | 164 | ||
| 159 | if (job->irq_fence) | 165 | if (job->base.irq_fence) |
| 160 | dma_fence_put(job->irq_fence); | 166 | dma_fence_put(job->base.irq_fence); |
| 161 | job->irq_fence = dma_fence_get(fence); | 167 | job->base.irq_fence = dma_fence_get(fence); |
| 162 | 168 | ||
| 163 | trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno, | 169 | trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno, |
| 164 | job->start, job->end); | 170 | job->start, job->end); |
| 165 | 171 | ||
| 166 | if (q == V3D_BIN) { | 172 | /* XXX: Set the QCFG */ |
| 167 | if (exec->qma) { | ||
| 168 | V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, exec->qma); | ||
| 169 | V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, exec->qms); | ||
| 170 | } | ||
| 171 | if (exec->qts) { | ||
| 172 | V3D_CORE_WRITE(0, V3D_CLE_CT0QTS, | ||
| 173 | V3D_CLE_CT0QTS_ENABLE | | ||
| 174 | exec->qts); | ||
| 175 | } | ||
| 176 | } else { | ||
| 177 | /* XXX: Set the QCFG */ | ||
| 178 | } | ||
| 179 | 173 | ||
| 180 | /* Set the current and end address of the control list. | 174 | /* Set the current and end address of the control list. |
| 181 | * Writing the end register is what starts the job. | 175 | * Writing the end register is what starts the job. |
| 182 | */ | 176 | */ |
| 183 | V3D_CORE_WRITE(0, V3D_CLE_CTNQBA(q), job->start); | 177 | V3D_CORE_WRITE(0, V3D_CLE_CT1QBA, job->start); |
| 184 | V3D_CORE_WRITE(0, V3D_CLE_CTNQEA(q), job->end); | 178 | V3D_CORE_WRITE(0, V3D_CLE_CT1QEA, job->end); |
| 185 | 179 | ||
| 186 | return fence; | 180 | return fence; |
| 187 | } | 181 | } |
| @@ -190,7 +184,7 @@ static struct dma_fence * · 2 unmodified lines | |||
| 190 | v3d_tfu_job_run(struct drm_sched_job *sched_job) | 184 | v3d_tfu_job_run(struct drm_sched_job *sched_job) |
| 191 | { | 185 | { |
| 192 | struct v3d_tfu_job *job = to_tfu_job(sched_job); | 186 | struct v3d_tfu_job *job = to_tfu_job(sched_job); |
| 193 | struct v3d_dev *v3d = job->v3d; | 187 | struct v3d_dev *v3d = job->base.v3d; |
| 194 | struct drm_device *dev = &v3d->drm; | 188 | struct drm_device *dev = &v3d->drm; |
| 195 | struct dma_fence *fence; | 189 | struct dma_fence *fence; |
| 196 | 190 | ||
| @@ -199,9 +193,9 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) · 2 unmodified lines | |||
| 199 | return NULL; | 193 | return NULL; |
| 200 | 194 | ||
| 201 | v3d->tfu_job = job; | 195 | v3d->tfu_job = job; |
| 202 | if (job->irq_fence) | 196 | if (job->base.irq_fence) |
| 203 | dma_fence_put(job->irq_fence); | 197 | dma_fence_put(job->base.irq_fence); |
| 204 | job->irq_fence = dma_fence_get(fence); | 198 | job->base.irq_fence = dma_fence_get(fence); |
| 205 | 199 | ||
| 206 | trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); | 200 | trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); |
| 207 | 201 | ||
| @@ -223,6 +217,48 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) · 15 unmodified lines | |||
| 223 | return fence; | 217 | return fence; |
| 224 | } | 218 | } |
| 225 | 219 | ||
| 220 | static struct dma_fence * | ||
| 221 | v3d_csd_job_run(struct drm_sched_job *sched_job) | ||
| 222 | { | ||
| 223 | struct v3d_csd_job *job = to_csd_job(sched_job); | ||
| 224 | struct v3d_dev *v3d = job->base.v3d; | ||
| 225 | struct drm_device *dev = &v3d->drm; | ||
| 226 | struct dma_fence *fence; | ||
| 227 | int i; | ||
| 228 | |||
| 229 | v3d->csd_job = job; | ||
| 230 | |||
| 231 | v3d_invalidate_caches(v3d); | ||
| 232 | |||
| 233 | fence = v3d_fence_create(v3d, V3D_CSD); | ||
| 234 | if (IS_ERR(fence)) | ||
| 235 | return NULL; | ||
| 236 | |||
| 237 | if (job->base.irq_fence) | ||
| 238 | dma_fence_put(job->base.irq_fence); | ||
| 239 | job->base.irq_fence = dma_fence_get(fence); | ||
| 240 | |||
| 241 | trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno); | ||
| 242 | |||
| 243 | for (i = 1; i <= 6; i++) | ||
| 244 | V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]); | ||
| 245 | /* CFG0 write kicks off the job. */ | ||
| 246 | V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]); | ||
| 247 | |||
| 248 | return fence; | ||
| 249 | } | ||
| 250 | |||
| 251 | static struct dma_fence * | ||
| 252 | v3d_cache_clean_job_run(struct drm_sched_job *sched_job) | ||
| 253 | { | ||
| 254 | struct v3d_job *job = to_v3d_job(sched_job); | ||
| 255 | struct v3d_dev *v3d = job->v3d; | ||
| 256 | |||
| 257 | v3d_clean_caches(v3d); | ||
| 258 | |||
| 259 | return NULL; | ||
| 260 | } | ||
| 261 | |||
| 226 | static void | 262 | static void |
| 227 | v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) | 263 | v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) |
| 228 | { | 264 | { |
| @@ -232,7 +268,7 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) · 3 unmodified lines | |||
| 232 | 268 | ||
| 233 | /* block scheduler */ | 269 | /* block scheduler */ |
| 234 | for (q = 0; q < V3D_MAX_QUEUES; q++) | 270 | for (q = 0; q < V3D_MAX_QUEUES; q++) |
| 235 | drm_sched_stop(&v3d->queue[q].sched); | 271 | drm_sched_stop(&v3d->queue[q].sched, sched_job); |
| 236 | 272 | ||
| 237 | if (sched_job) | 273 | if (sched_job) |
| 238 | drm_sched_increase_karma(sched_job); | 274 | drm_sched_increase_karma(sched_job); |
| @@ -251,25 +287,23 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) · 12 unmodified lines | |||
| 251 | mutex_unlock(&v3d->reset_lock); | 287 | mutex_unlock(&v3d->reset_lock); |
| 252 | } | 288 | } |
| 253 | 289 | ||
| 290 | /* If the current address or return address have changed, then the GPU | ||
| 291 | * has probably made progress and we should delay the reset. This | ||
| 292 | * could fail if the GPU got in an infinite loop in the CL, but that | ||
| 293 | * is pretty unlikely outside of an i-g-t testcase. | ||
| 294 | */ | ||
| 254 | static void | 295 | static void |
| 255 | v3d_job_timedout(struct drm_sched_job *sched_job) | 296 | v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q, |
| 297 | u32 *timedout_ctca, u32 *timedout_ctra) | ||
| 256 | { | 298 | { |
| 257 | struct v3d_job *job = to_v3d_job(sched_job); | 299 | struct v3d_job *job = to_v3d_job(sched_job); |
| 258 | struct v3d_exec_info *exec = job->exec; | 300 | struct v3d_dev *v3d = job->v3d; |
| 259 | struct v3d_dev *v3d = exec->v3d; | 301 | u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(q)); |
| 260 | enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER; | 302 | u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(q)); |
| 261 | u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q)); | 303 | |
| 262 | u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q)); | 304 | if (*timedout_ctca != ctca || *timedout_ctra != ctra) { |
| 263 | 305 | *timedout_ctca = ctca; | |
| 264 | /* If the current address or return address have changed, then | 306 | *timedout_ctra = ctra; |
| 265 | * the GPU has probably made progress and we should delay the | ||
| 266 | * reset. This could fail if the GPU got in an infinite loop | ||
| 267 | * in the CL, but that is pretty unlikely outside of an i-g-t | ||
| 268 | * testcase. | ||
| 269 | */ | ||
| 270 | if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) { | ||
| 271 | job->timedout_ctca = ctca; | ||
| 272 | job->timedout_ctra = ctra; | ||
| 273 | return; | 307 | return; |
| 274 | } | 308 | } |
| 275 | 309 | ||
| @@ -277,25 +311,82 @@ v3d_job_timedout(struct drm_sched_job *sched_job) · 1 unmodified line | |||
| 277 | } | 311 | } |
| 278 | 312 | ||
| 279 | static void | 313 | static void |
| 280 | v3d_tfu_job_timedout(struct drm_sched_job *sched_job) | 314 | v3d_bin_job_timedout(struct drm_sched_job *sched_job) |
| 281 | { | 315 | { |
| 282 | struct v3d_tfu_job *job = to_tfu_job(sched_job); | 316 | struct v3d_bin_job *job = to_bin_job(sched_job); |
| 317 | |||
| 318 | v3d_cl_job_timedout(sched_job, V3D_BIN, | ||
| 319 | &job->timedout_ctca, &job->timedout_ctra); | ||
| 320 | } | ||
| 321 | |||
| 322 | static void | ||
| 323 | v3d_render_job_timedout(struct drm_sched_job *sched_job) | ||
| 324 | { | ||
| 325 | struct v3d_render_job *job = to_render_job(sched_job); | ||
| 326 | |||
| 327 | v3d_cl_job_timedout(sched_job, V3D_RENDER, | ||
| 328 | &job->timedout_ctca, &job->timedout_ctra); | ||
| 329 | } | ||
| 330 | |||
| 331 | static void | ||
| 332 | v3d_generic_job_timedout(struct drm_sched_job *sched_job) | ||
| 333 | { | ||
| 334 | struct v3d_job *job = to_v3d_job(sched_job); | ||
| 283 | 335 | ||
| 284 | v3d_gpu_reset_for_timeout(job->v3d, sched_job); | 336 | v3d_gpu_reset_for_timeout(job->v3d, sched_job); |
| 285 | } | 337 | } |
| 286 | 338 | ||
| 287 | static const struct drm_sched_backend_ops v3d_sched_ops = { | 339 | static void |
| 340 | v3d_csd_job_timedout(struct drm_sched_job *sched_job) | ||
| 341 | { | ||
| 342 | struct v3d_csd_job *job = to_csd_job(sched_job); | ||
| 343 | struct v3d_dev *v3d = job->base.v3d; | ||
| 344 | u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4); | ||
| 345 | |||
| 346 | /* If we've made progress, skip reset and let the timer get | ||
| 347 | * rearmed. | ||
| 348 | */ | ||
| 349 | if (job->timedout_batches != batches) { | ||
| 350 | job->timedout_batches = batches; | ||
| 351 | return; | ||
| 352 | } | ||
| 353 | |||
| 354 | v3d_gpu_reset_for_timeout(v3d, sched_job); | ||
| 355 | } | ||
| 356 | |||
| 357 | static const struct drm_sched_backend_ops v3d_bin_sched_ops = { | ||
| 288 | .dependency = v3d_job_dependency, | 358 | .dependency = v3d_job_dependency, |
| 289 | .run_job = v3d_job_run, | 359 | .run_job = v3d_bin_job_run, |
| 290 | .timedout_job = v3d_job_timedout, | 360 | .timedout_job = v3d_bin_job_timedout, |
| 291 | .free_job = v3d_job_free | 361 | .free_job = v3d_job_free, |
| 362 | }; | ||
| 363 | |||
| 364 | static const struct drm_sched_backend_ops v3d_render_sched_ops = { | ||
| 365 | .dependency = v3d_job_dependency, | ||
| 366 | .run_job = v3d_render_job_run, | ||
| 367 | .timedout_job = v3d_render_job_timedout, | ||
| 368 | .free_job = v3d_job_free, | ||
| 292 | }; | 369 | }; |
| 293 | 370 | ||
| 294 | static const struct drm_sched_backend_ops v3d_tfu_sched_ops = { | 371 | static const struct drm_sched_backend_ops v3d_tfu_sched_ops = { |
| 295 | .dependency = v3d_tfu_job_dependency, | 372 | .dependency = v3d_job_dependency, |
| 296 | .run_job = v3d_tfu_job_run, | 373 | .run_job = v3d_tfu_job_run, |
| 297 | .timedout_job = v3d_tfu_job_timedout, | 374 | .timedout_job = v3d_generic_job_timedout, |
| 298 | .free_job = v3d_tfu_job_free | 375 | .free_job = v3d_job_free, |
| 376 | }; | ||
| 377 | |||
| 378 | static const struct drm_sched_backend_ops v3d_csd_sched_ops = { | ||
| 379 | .dependency = v3d_job_dependency, | ||
| 380 | .run_job = v3d_csd_job_run, | ||
| 381 | .timedout_job = v3d_csd_job_timedout, | ||
| 382 | .free_job = v3d_job_free | ||
| 383 | }; | ||
| 384 | |||
| 385 | static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = { | ||
| 386 | .dependency = v3d_job_dependency, | ||
| 387 | .run_job = v3d_cache_clean_job_run, | ||
| 388 | .timedout_job = v3d_generic_job_timedout, | ||
| 389 | .free_job = v3d_job_free | ||
| 299 | }; | 390 | }; |
| 300 | 391 | ||
| 301 | int | 392 | int |
| @@ -307,7 +398,7 @@ v3d_sched_init(struct v3d_dev *v3d) · 5 unmodified lines | |||
| 307 | int ret; | 398 | int ret; |
| 308 | 399 | ||
| 309 | ret = drm_sched_init(&v3d->queue[V3D_BIN].sched, | 400 | ret = drm_sched_init(&v3d->queue[V3D_BIN].sched, |
| 310 | &v3d_sched_ops, | 401 | &v3d_bin_sched_ops, |
| 311 | hw_jobs_limit, job_hang_limit, | 402 | hw_jobs_limit, job_hang_limit, |
| 312 | msecs_to_jiffies(hang_limit_ms), | 403 | msecs_to_jiffies(hang_limit_ms), |
| 313 | "v3d_bin"); | 404 | "v3d_bin"); |
| @@ -317,14 +408,14 @@ v3d_sched_init(struct v3d_dev *v3d) · 3 unmodified lines | |||
| 317 | } | 408 | } |
| 318 | 409 | ||
| 319 | ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched, | 410 | ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched, |
| 320 | &v3d_sched_ops, | 411 | &v3d_render_sched_ops, |
| 321 | hw_jobs_limit, job_hang_limit, | 412 | hw_jobs_limit, job_hang_limit, |
| 322 | msecs_to_jiffies(hang_limit_ms), | 413 | msecs_to_jiffies(hang_limit_ms), |
| 323 | "v3d_render"); | 414 | "v3d_render"); |
| 324 | if (ret) { | 415 | if (ret) { |
| 325 | dev_err(v3d->dev, "Failed to create render scheduler: %d.", | 416 | dev_err(v3d->dev, "Failed to create render scheduler: %d.", |
| 326 | ret); | 417 | ret); |
| 327 | drm_sched_fini(&v3d->queue[V3D_BIN].sched); | 418 | v3d_sched_fini(v3d); |
| 328 | return ret; | 419 | return ret; |
| 329 | } | 420 | } |
| 330 | 421 | ||
| @@ -336,11 +427,36 @@ v3d_sched_init(struct v3d_dev *v3d) · 5 unmodified lines | |||
| 336 | if (ret) { | 427 | if (ret) { |
| 337 | dev_err(v3d->dev, "Failed to create TFU scheduler: %d.", | 428 | dev_err(v3d->dev, "Failed to create TFU scheduler: %d.", |
| 338 | ret); | 429 | ret); |
| 339 | drm_sched_fini(&v3d->queue[V3D_RENDER].sched); | 430 | v3d_sched_fini(v3d); |
| 340 | drm_sched_fini(&v3d->queue[V3D_BIN].sched); | ||
| 341 | return ret; | 431 | return ret; |
| 342 | } | 432 | } |
| 343 | 433 | ||
| 434 | if (v3d_has_csd(v3d)) { | ||
| 435 | ret = drm_sched_init(&v3d->queue[V3D_CSD].sched, | ||
| 436 | &v3d_csd_sched_ops, | ||
| 437 | hw_jobs_limit, job_hang_limit, | ||
| 438 | msecs_to_jiffies(hang_limit_ms), | ||
| 439 | "v3d_csd"); | ||
| 440 | if (ret) { | ||
| 441 | dev_err(v3d->dev, "Failed to create CSD scheduler: %d.", | ||
| 442 | ret); | ||
| 443 | v3d_sched_fini(v3d); | ||
| 444 | return ret; | ||
| 445 | } | ||
| 446 | |||
| 447 | ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched, | ||
| 448 | &v3d_cache_clean_sched_ops, | ||
| 449 | hw_jobs_limit, job_hang_limit, | ||
| 450 | msecs_to_jiffies(hang_limit_ms), | ||
| 451 | "v3d_cache_clean"); | ||
| 452 | if (ret) { | ||
| 453 | dev_err(v3d->dev, "Failed to create CACHE_CLEAN scheduler: %d.", | ||
| 454 | ret); | ||
| 455 | v3d_sched_fini(v3d); | ||
| 456 | return ret; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 344 | return 0; | 460 | return 0; |
| 345 | } | 461 | } |
| 346 | 462 | ||
| @@ -349,6 +465,8 @@ v3d_sched_fini(struct v3d_dev *v3d) · 2 unmodified lines | |||
| 349 | { | 465 | { |
| 350 | enum v3d_queue q; | 466 | enum v3d_queue q; |
| 351 | 467 | ||
| 352 | for (q = 0; q < V3D_MAX_QUEUES; q++) | 468 | for (q = 0; q < V3D_MAX_QUEUES; q++) { |
| 353 | drm_sched_fini(&v3d->queue[q].sched); | 469 | if (v3d->queue[q].sched.ready) |
| 470 | drm_sched_fini(&v3d->queue[q].sched); | ||
| 471 | } | ||
| 354 | } | 472 | } |
| @@ -124,6 +124,26 @@ TRACE_EVENT(v3d_tfu_irq, · 123 unmodified lines | |||
| 124 | __entry->seqno) | 124 | __entry->seqno) |
| 125 | ); | 125 | ); |
| 126 | 126 | ||
| 127 | TRACE_EVENT(v3d_csd_irq, | ||
| 128 | TP_PROTO(struct drm_device *dev, | ||
| 129 | uint64_t seqno), | ||
| 130 | TP_ARGS(dev, seqno), | ||
| 131 | |||
| 132 | TP_STRUCT__entry( | ||
| 133 | __field(u32, dev) | ||
| 134 | __field(u64, seqno) | ||
| 135 | ), | ||
| 136 | |||
| 137 | TP_fast_assign( | ||
| 138 | __entry->dev = dev->primary->index; | ||
| 139 | __entry->seqno = seqno; | ||
| 140 | ), | ||
| 141 | |||
| 142 | TP_printk("dev=%u, seqno=%llu", | ||
| 143 | __entry->dev, | ||
| 144 | __entry->seqno) | ||
| 145 | ); | ||
| 146 | |||
| 127 | TRACE_EVENT(v3d_submit_tfu_ioctl, | 147 | TRACE_EVENT(v3d_submit_tfu_ioctl, |
| 128 | TP_PROTO(struct drm_device *dev, u32 iia), | 148 | TP_PROTO(struct drm_device *dev, u32 iia), |
| 129 | TP_ARGS(dev, iia), | 149 | TP_ARGS(dev, iia), |
| @@ -163,6 +183,80 @@ TRACE_EVENT(v3d_submit_tfu, · 33 unmodified lines | |||
| 163 | __entry->seqno) | 183 | __entry->seqno) |
| 164 | ); | 184 | ); |
| 165 | 185 | ||
| 186 | TRACE_EVENT(v3d_submit_csd_ioctl, | ||
| 187 | TP_PROTO(struct drm_device *dev, u32 cfg5, u32 cfg6), | ||
| 188 | TP_ARGS(dev, cfg5, cfg6), | ||
| 189 | |||
| 190 | TP_STRUCT__entry( | ||
| 191 | __field(u32, dev) | ||
| 192 | __field(u32, cfg5) | ||
| 193 | __field(u32, cfg6) | ||
| 194 | ), | ||
| 195 | |||
| 196 | TP_fast_assign( | ||
| 197 | __entry->dev = dev->primary->index; | ||
| 198 | __entry->cfg5 = cfg5; | ||
| 199 | __entry->cfg6 = cfg6; | ||
| 200 | ), | ||
| 201 | |||
| 202 | TP_printk("dev=%u, CFG5 0x%08x, CFG6 0x%08x", | ||
| 203 | __entry->dev, | ||
| 204 | __entry->cfg5, | ||
| 205 | __entry->cfg6) | ||
| 206 | ); | ||
| 207 | |||
| 208 | TRACE_EVENT(v3d_submit_csd, | ||
| 209 | TP_PROTO(struct drm_device *dev, | ||
| 210 | uint64_t seqno), | ||
| 211 | TP_ARGS(dev, seqno), | ||
| 212 | |||
| 213 | TP_STRUCT__entry( | ||
| 214 | __field(u32, dev) | ||
| 215 | __field(u64, seqno) | ||
| 216 | ), | ||
| 217 | |||
| 218 | TP_fast_assign( | ||
| 219 | __entry->dev = dev->primary->index; | ||
| 220 | __entry->seqno = seqno; | ||
| 221 | ), | ||
| 222 | |||
| 223 | TP_printk("dev=%u, seqno=%llu", | ||
| 224 | __entry->dev, | ||
| 225 | __entry->seqno) | ||
| 226 | ); | ||
| 227 | |||
| 228 | TRACE_EVENT(v3d_cache_clean_begin, | ||
| 229 | TP_PROTO(struct drm_device *dev), | ||
| 230 | TP_ARGS(dev), | ||
| 231 | |||
| 232 | TP_STRUCT__entry( | ||
| 233 | __field(u32, dev) | ||
| 234 | ), | ||
| 235 | |||
| 236 | TP_fast_assign( | ||
| 237 | __entry->dev = dev->primary->index; | ||
| 238 | ), | ||
| 239 | |||
| 240 | TP_printk("dev=%u", | ||
| 241 | __entry->dev) | ||
| 242 | ); | ||
| 243 | |||
| 244 | TRACE_EVENT(v3d_cache_clean_end, | ||
| 245 | TP_PROTO(struct drm_device *dev), | ||
| 246 | TP_ARGS(dev), | ||
| 247 | |||
| 248 | TP_STRUCT__entry( | ||
| 249 | __field(u32, dev) | ||
| 250 | ), | ||
| 251 | |||
| 252 | TP_fast_assign( | ||
| 253 | __entry->dev = dev->primary->index; | ||
| 254 | ), | ||
| 255 | |||
| 256 | TP_printk("dev=%u", | ||
| 257 | __entry->dev) | ||
| 258 | ); | ||
| 259 | |||
| 166 | TRACE_EVENT(v3d_reset_begin, | 260 | TRACE_EVENT(v3d_reset_begin, |
| 167 | TP_PROTO(struct drm_device *dev), | 261 | TP_PROTO(struct drm_device *dev), |
| 168 | TP_ARGS(dev), | 262 | TP_ARGS(dev), |
| @@ -3,7 +3,7 @@ config DRM_VBOXVIDEO · 2 unmodified lines | |||
| 3 | tristate "Virtual Box Graphics Card" | 3 | tristate "Virtual Box Graphics Card" |
| 4 | depends on DRM && X86 && PCI | 4 | depends on DRM && X86 && PCI |
| 5 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 6 | select DRM_TTM | 6 | select DRM_VRAM_HELPER |
| 7 | select GENERIC_ALLOCATOR | 7 | select GENERIC_ALLOCATOR |
| 8 | help | 8 | help |
| 9 | This is a KMS driver for the virtual Graphics Card used in | 9 | This is a KMS driver for the virtual Graphics Card used in |
| @@ -191,13 +191,7 @@ static struct pci_driver vbox_pci_driver = { · 190 unmodified lines | |||
| 191 | 191 | ||
| 192 | static const struct file_operations vbox_fops = { | 192 | static const struct file_operations vbox_fops = { |
| 193 | .owner = THIS_MODULE, | 193 | .owner = THIS_MODULE, |
| 194 | .open = drm_open, | 194 | DRM_VRAM_MM_FILE_OPERATIONS |
| 195 | .release = drm_release, | ||
| 196 | .unlocked_ioctl = drm_ioctl, | ||
| 197 | .compat_ioctl = drm_compat_ioctl, | ||
| 198 | .mmap = vbox_mmap, | ||
| 199 | .poll = drm_poll, | ||
| 200 | .read = drm_read, | ||
| 201 | }; | 195 | }; |
| 202 | 196 | ||
| 203 | static struct drm_driver driver = { | 197 | static struct drm_driver driver = { |
| @@ -215,9 +209,7 @@ static struct drm_driver driver = { · 11 unmodified lines | |||
| 215 | .minor = DRIVER_MINOR, | 209 | .minor = DRIVER_MINOR, |
| 216 | .patchlevel = DRIVER_PATCHLEVEL, | 210 | .patchlevel = DRIVER_PATCHLEVEL, |
| 217 | 211 | ||
| 218 | .gem_free_object_unlocked = vbox_gem_free_object, | 212 | DRM_GEM_VRAM_DRIVER, |
| 219 | .dumb_create = vbox_dumb_create, | ||
| 220 | .dumb_map_offset = vbox_dumb_mmap_offset, | ||
| 221 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 213 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
| 222 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 214 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
| 223 | .gem_prime_export = drm_gem_prime_export, | 215 | .gem_prime_export = drm_gem_prime_export, |
| @@ -18,12 +18,9 @@ · 17 unmodified lines | |||
| 18 | #include <drm/drm_encoder.h> | 18 | #include <drm/drm_encoder.h> |
| 19 | #include <drm/drm_fb_helper.h> | 19 | #include <drm/drm_fb_helper.h> |
| 20 | #include <drm/drm_gem.h> | 20 | #include <drm/drm_gem.h> |
| 21 | #include <drm/drm_gem_vram_helper.h> | ||
| 21 | 22 | ||
| 22 | #include <drm/ttm/ttm_bo_api.h> | 23 | #include <drm/drm_vram_mm_helper.h> |
| 23 | #include <drm/ttm/ttm_bo_driver.h> | ||
| 24 | #include <drm/ttm/ttm_placement.h> | ||
| 25 | #include <drm/ttm/ttm_memory.h> | ||
| 26 | #include <drm/ttm/ttm_module.h> | ||
| 27 | 24 | ||
| 28 | #include "vboxvideo_guest.h" | 25 | #include "vboxvideo_guest.h" |
| 29 | #include "vboxvideo_vbe.h" | 26 | #include "vboxvideo_vbe.h" |
| @@ -77,10 +74,6 @@ struct vbox_private { · 47 unmodified lines | |||
| 77 | 74 | ||
| 78 | int fb_mtrr; | 75 | int fb_mtrr; |
| 79 | 76 | ||
| 80 | struct { | ||
| 81 | struct ttm_bo_device bdev; | ||
| 82 | } ttm; | ||
| 83 | |||
| 84 | struct mutex hw_mutex; /* protects modeset and accel/vbva accesses */ | 77 | struct mutex hw_mutex; /* protects modeset and accel/vbva accesses */ |
| 85 | struct work_struct hotplug_work; | 78 | struct work_struct hotplug_work; |
| 86 | u32 input_mapping_width; | 79 | u32 input_mapping_width; |
| @@ -96,8 +89,6 @@ struct vbox_private { · 9 unmodified lines | |||
| 96 | #undef CURSOR_PIXEL_COUNT | 89 | #undef CURSOR_PIXEL_COUNT |
| 97 | #undef CURSOR_DATA_SIZE | 90 | #undef CURSOR_DATA_SIZE |
| 98 | 91 | ||
| 99 | struct vbox_gem_object; | ||
| 100 | |||
| 101 | struct vbox_connector { | 92 | struct vbox_connector { |
| 102 | struct drm_connector base; | 93 | struct drm_connector base; |
| 103 | char name[32]; | 94 | char name[32]; |
| @@ -170,74 +161,12 @@ int vboxfb_create(struct drm_fb_helper *helper, · 66 unmodified lines | |||
| 170 | struct drm_fb_helper_surface_size *sizes); | 161 | struct drm_fb_helper_surface_size *sizes); |
| 171 | void vbox_fbdev_fini(struct vbox_private *vbox); | 162 | void vbox_fbdev_fini(struct vbox_private *vbox); |
| 172 | 163 | ||
| 173 | struct vbox_bo { | ||
| 174 | struct ttm_buffer_object bo; | ||
| 175 | struct ttm_placement placement; | ||
| 176 | struct ttm_bo_kmap_obj kmap; | ||
| 177 | struct drm_gem_object gem; | ||
| 178 | struct ttm_place placements[3]; | ||
| 179 | int pin_count; | ||
| 180 | }; | ||
| 181 | |||
| 182 | #define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem) | ||
| 183 | |||
| 184 | static inline struct vbox_bo *vbox_bo(struct ttm_buffer_object *bo) | ||
| 185 | { | ||
| 186 | return container_of(bo, struct vbox_bo, bo); | ||
| 187 | } | ||
| 188 | |||
| 189 | #define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base) | ||
| 190 | |||
| 191 | static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo) | ||
| 192 | { | ||
| 193 | return bo->bo.offset; | ||
| 194 | } | ||
| 195 | |||
| 196 | int vbox_dumb_create(struct drm_file *file, | ||
| 197 | struct drm_device *dev, | ||
| 198 | struct drm_mode_create_dumb *args); | ||
| 199 | |||
| 200 | void vbox_gem_free_object(struct drm_gem_object *obj); | ||
| 201 | int vbox_dumb_mmap_offset(struct drm_file *file, | ||
| 202 | struct drm_device *dev, | ||
| 203 | u32 handle, u64 *offset); | ||
| 204 | |||
| 205 | int vbox_mm_init(struct vbox_private *vbox); | 164 | int vbox_mm_init(struct vbox_private *vbox); |
| 206 | void vbox_mm_fini(struct vbox_private *vbox); | 165 | void vbox_mm_fini(struct vbox_private *vbox); |
| 207 | 166 | ||
| 208 | int vbox_bo_create(struct vbox_private *vbox, int size, int align, | ||
| 209 | u32 flags, struct vbox_bo **pvboxbo); | ||
| 210 | |||
| 211 | int vbox_gem_create(struct vbox_private *vbox, | 167 | int vbox_gem_create(struct vbox_private *vbox, |
| 212 | u32 size, bool iskernel, struct drm_gem_object **obj); | 168 | u32 size, bool iskernel, struct drm_gem_object **obj); |
| 213 | 169 | ||
| 214 | int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag); | ||
| 215 | int vbox_bo_unpin(struct vbox_bo *bo); | ||
| 216 | |||
| 217 | static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait) | ||
| 218 | { | ||
| 219 | int ret; | ||
| 220 | |||
| 221 | ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL); | ||
| 222 | if (ret) { | ||
| 223 | if (ret != -ERESTARTSYS && ret != -EBUSY) | ||
| 224 | DRM_ERROR("reserve failed %p\n", bo); | ||
| 225 | return ret; | ||
| 226 | } | ||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | static inline void vbox_bo_unreserve(struct vbox_bo *bo) | ||
| 231 | { | ||
| 232 | ttm_bo_unreserve(&bo->bo); | ||
| 233 | } | ||
| 234 | |||
| 235 | void vbox_ttm_placement(struct vbox_bo *bo, int domain); | ||
| 236 | int vbox_bo_push_sysram(struct vbox_bo *bo); | ||
| 237 | int vbox_mmap(struct file *filp, struct vm_area_struct *vma); | ||
| 238 | void *vbox_bo_kmap(struct vbox_bo *bo); | ||
| 239 | void vbox_bo_kunmap(struct vbox_bo *bo); | ||
| 240 | |||
| 241 | /* vbox_prime.c */ | 170 | /* vbox_prime.c */ |
| 242 | int vbox_gem_prime_pin(struct drm_gem_object *obj); | 171 | int vbox_gem_prime_pin(struct drm_gem_object *obj); |
| 243 | void vbox_gem_prime_unpin(struct drm_gem_object *obj); | 172 | void vbox_gem_prime_unpin(struct drm_gem_object *obj); |
| @@ -51,9 +51,9 @@ int vboxfb_create(struct drm_fb_helper *helper, · 50 unmodified lines | |||
| 51 | struct drm_framebuffer *fb; | 51 | struct drm_framebuffer *fb; |
| 52 | struct fb_info *info; | 52 | struct fb_info *info; |
| 53 | struct drm_gem_object *gobj; | 53 | struct drm_gem_object *gobj; |
| 54 | struct vbox_bo *bo; | 54 | struct drm_gem_vram_object *gbo; |
| 55 | int size, ret; | 55 | int size, ret; |
| 56 | u64 gpu_addr; | 56 | s64 gpu_addr; |
| 57 | u32 pitch; | 57 | u32 pitch; |
| 58 | 58 | ||
| 59 | mode_cmd.width = sizes->surface_width; | 59 | mode_cmd.width = sizes->surface_width; |
| @@ -75,9 +75,9 @@ int vboxfb_create(struct drm_fb_helper *helper, · 15 unmodified lines | |||
| 75 | if (ret) | 75 | if (ret) |
| 76 | return ret; | 76 | return ret; |
| 77 | 77 | ||
| 78 | bo = gem_to_vbox_bo(gobj); | 78 | gbo = drm_gem_vram_of_gem(gobj); |
| 79 | 79 | ||
| 80 | ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM); | 80 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 81 | if (ret) | 81 | if (ret) |
| 82 | return ret; | 82 | return ret; |
| 83 | 83 | ||
| @@ -86,7 +86,7 @@ int vboxfb_create(struct drm_fb_helper *helper, · 2 unmodified lines | |||
| 86 | return PTR_ERR(info); | 86 | return PTR_ERR(info); |
| 87 | 87 | ||
| 88 | info->screen_size = size; | 88 | info->screen_size = size; |
| 89 | info->screen_base = (char __iomem *)vbox_bo_kmap(bo); | 89 | info->screen_base = (char __iomem *)drm_gem_vram_kmap(gbo, true, NULL); |
| 90 | if (IS_ERR(info->screen_base)) | 90 | if (IS_ERR(info->screen_base)) |
| 91 | return PTR_ERR(info->screen_base); | 91 | return PTR_ERR(info->screen_base); |
| 92 | 92 | ||
| @@ -104,7 +104,9 @@ int vboxfb_create(struct drm_fb_helper *helper, · 11 unmodified lines | |||
| 104 | 104 | ||
| 105 | drm_fb_helper_fill_info(info, helper, sizes); | 105 | drm_fb_helper_fill_info(info, helper, sizes); |
| 106 | 106 | ||
| 107 | gpu_addr = vbox_bo_gpu_offset(bo); | 107 | gpu_addr = drm_gem_vram_offset(gbo); |
| 108 | if (gpu_addr < 0) | ||
| 109 | return (int)gpu_addr; | ||
| 108 | info->fix.smem_start = info->apertures->ranges[0].base + gpu_addr; | 110 | info->fix.smem_start = info->apertures->ranges[0].base + gpu_addr; |
| 109 | info->fix.smem_len = vbox->available_vram_size - gpu_addr; | 111 | info->fix.smem_len = vbox->available_vram_size - gpu_addr; |
| 110 | 112 | ||
| @@ -132,12 +134,10 @@ void vbox_fbdev_fini(struct vbox_private *vbox) · 21 unmodified lines | |||
| 132 | drm_fb_helper_unregister_fbi(&vbox->fb_helper); | 134 | drm_fb_helper_unregister_fbi(&vbox->fb_helper); |
| 133 | 135 | ||
| 134 | if (afb->obj) { | 136 | if (afb->obj) { |
| 135 | struct vbox_bo *bo = gem_to_vbox_bo(afb->obj); | 137 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(afb->obj); |
| 136 | 138 | ||
| 137 | vbox_bo_kunmap(bo); | 139 | drm_gem_vram_kunmap(gbo); |
| 138 | 140 | drm_gem_vram_unpin(gbo); | |
| 139 | if (bo->pin_count) | ||
| 140 | vbox_bo_unpin(bo); | ||
| 141 | 141 | ||
| 142 | drm_gem_object_put_unlocked(afb->obj); | 142 | drm_gem_object_put_unlocked(afb->obj); |
| 143 | afb->obj = NULL; | 143 | afb->obj = NULL; |
| @@ -274,7 +274,7 @@ void vbox_hw_fini(struct vbox_private *vbox) · 273 unmodified lines | |||
| 274 | int vbox_gem_create(struct vbox_private *vbox, | 274 | int vbox_gem_create(struct vbox_private *vbox, |
| 275 | u32 size, bool iskernel, struct drm_gem_object **obj) | 275 | u32 size, bool iskernel, struct drm_gem_object **obj) |
| 276 | { | 276 | { |
| 277 | struct vbox_bo *vboxbo; | 277 | struct drm_gem_vram_object *gbo; |
| 278 | int ret; | 278 | int ret; |
| 279 | 279 | ||
| 280 | *obj = NULL; | 280 | *obj = NULL; |
| @@ -283,79 +283,16 @@ int vbox_gem_create(struct vbox_private *vbox, · 2 unmodified lines | |||
| 283 | if (size == 0) | 283 | if (size == 0) |
| 284 | return -EINVAL; | 284 | return -EINVAL; |
| 285 | 285 | ||
| 286 | ret = vbox_bo_create(vbox, size, 0, 0, &vboxbo); | 286 | gbo = drm_gem_vram_create(&vbox->ddev, &vbox->ddev.vram_mm->bdev, |
| 287 | if (ret) { | 287 | size, 0, false); |
| 288 | if (IS_ERR(gbo)) { | ||
| 289 | ret = PTR_ERR(gbo); | ||
| 288 | if (ret != -ERESTARTSYS) | 290 | if (ret != -ERESTARTSYS) |
| 289 | DRM_ERROR("failed to allocate GEM object\n"); | 291 | DRM_ERROR("failed to allocate GEM object\n"); |
| 290 | return ret; | 292 | return ret; |
| 291 | } | 293 | } |
| 292 | 294 | ||
| 293 | *obj = &vboxbo->gem; | 295 | *obj = &gbo->gem; |
| 294 | |||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | int vbox_dumb_create(struct drm_file *file, | ||
| 299 | struct drm_device *dev, struct drm_mode_create_dumb *args) | ||
| 300 | { | ||
| 301 | struct vbox_private *vbox = | ||
| 302 | container_of(dev, struct vbox_private, ddev); | ||
| 303 | struct drm_gem_object *gobj; | ||
| 304 | u32 handle; | ||
| 305 | int ret; | ||
| 306 | |||
| 307 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
| 308 | args->size = args->pitch * args->height; | ||
| 309 | |||
| 310 | ret = vbox_gem_create(vbox, args->size, false, &gobj); | ||
| 311 | if (ret) | ||
| 312 | return ret; | ||
| 313 | |||
| 314 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
| 315 | drm_gem_object_put_unlocked(gobj); | ||
| 316 | if (ret) | ||
| 317 | return ret; | ||
| 318 | |||
| 319 | args->handle = handle; | ||
| 320 | 296 | ||
| 321 | return 0; | 297 | return 0; |
| 322 | } | 298 | } |
| 323 | |||
| 324 | void vbox_gem_free_object(struct drm_gem_object *obj) | ||
| 325 | { | ||
| 326 | struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj); | ||
| 327 | |||
| 328 | ttm_bo_put(&vbox_bo->bo); | ||
| 329 | } | ||
| 330 | |||
| 331 | static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo) | ||
| 332 | { | ||
| 333 | return drm_vma_node_offset_addr(&bo->bo.vma_node); | ||
| 334 | } | ||
| 335 | |||
| 336 | int | ||
| 337 | vbox_dumb_mmap_offset(struct drm_file *file, | ||
| 338 | struct drm_device *dev, | ||
| 339 | u32 handle, u64 *offset) | ||
| 340 | { | ||
| 341 | struct drm_gem_object *obj; | ||
| 342 | int ret; | ||
| 343 | struct vbox_bo *bo; | ||
| 344 | |||
| 345 | mutex_lock(&dev->struct_mutex); | ||
| 346 | obj = drm_gem_object_lookup(file, handle); | ||
| 347 | if (!obj) { | ||
| 348 | ret = -ENOENT; | ||
| 349 | goto out_unlock; | ||
| 350 | } | ||
| 351 | |||
| 352 | bo = gem_to_vbox_bo(obj); | ||
| 353 | *offset = vbox_bo_mmap_offset(bo); | ||
| 354 | |||
| 355 | drm_gem_object_put(obj); | ||
| 356 | ret = 0; | ||
| 357 | |||
| 358 | out_unlock: | ||
| 359 | mutex_unlock(&dev->struct_mutex); | ||
| 360 | return ret; | ||
| 361 | } | ||
| @@ -172,7 +172,8 @@ static void vbox_crtc_set_base_and_mode(struct drm_crtc *crtc, · 171 unmodified lines | |||
| 172 | struct drm_framebuffer *fb, | 172 | struct drm_framebuffer *fb, |
| 173 | int x, int y) | 173 | int x, int y) |
| 174 | { | 174 | { |
| 175 | struct vbox_bo *bo = gem_to_vbox_bo(to_vbox_framebuffer(fb)->obj); | 175 | struct drm_gem_vram_object *gbo = |
| 176 | drm_gem_vram_of_gem(to_vbox_framebuffer(fb)->obj); | ||
| 176 | struct vbox_private *vbox = crtc->dev->dev_private; | 177 | struct vbox_private *vbox = crtc->dev->dev_private; |
| 177 | struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc); | 178 | struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc); |
| 178 | bool needs_modeset = drm_atomic_crtc_needs_modeset(crtc->state); | 179 | bool needs_modeset = drm_atomic_crtc_needs_modeset(crtc->state); |
| @@ -186,7 +187,7 @@ static void vbox_crtc_set_base_and_mode(struct drm_crtc *crtc, · 7 unmodified lines | |||
| 186 | 187 | ||
| 187 | vbox_crtc->x = x; | 188 | vbox_crtc->x = x; |
| 188 | vbox_crtc->y = y; | 189 | vbox_crtc->y = y; |
| 189 | vbox_crtc->fb_offset = vbox_bo_gpu_offset(bo); | 190 | vbox_crtc->fb_offset = drm_gem_vram_offset(gbo); |
| 190 | 191 | ||
| 191 | /* vbox_do_modeset() checks vbox->single_framebuffer so update it now */ | 192 | /* vbox_do_modeset() checks vbox->single_framebuffer so update it now */ |
| 192 | if (needs_modeset && vbox_set_up_input_mapping(vbox)) { | 193 | if (needs_modeset && vbox_set_up_input_mapping(vbox)) { |
| @@ -302,14 +303,14 @@ static void vbox_primary_atomic_disable(struct drm_plane *plane, · 109 unmodified lines | |||
| 302 | static int vbox_primary_prepare_fb(struct drm_plane *plane, | 303 | static int vbox_primary_prepare_fb(struct drm_plane *plane, |
| 303 | struct drm_plane_state *new_state) | 304 | struct drm_plane_state *new_state) |
| 304 | { | 305 | { |
| 305 | struct vbox_bo *bo; | 306 | struct drm_gem_vram_object *gbo; |
| 306 | int ret; | 307 | int ret; |
| 307 | 308 | ||
| 308 | if (!new_state->fb) | 309 | if (!new_state->fb) |
| 309 | return 0; | 310 | return 0; |
| 310 | 311 | ||
| 311 | bo = gem_to_vbox_bo(to_vbox_framebuffer(new_state->fb)->obj); | 312 | gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(new_state->fb)->obj); |
| 312 | ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM); | 313 | ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); |
| 313 | if (ret) | 314 | if (ret) |
| 314 | DRM_WARN("Error %d pinning new fb, out of video mem?\n", ret); | 315 | DRM_WARN("Error %d pinning new fb, out of video mem?\n", ret); |
| 315 | 316 | ||
| @@ -319,13 +320,13 @@ static int vbox_primary_prepare_fb(struct drm_plane *plane, · 3 unmodified lines | |||
| 319 | static void vbox_primary_cleanup_fb(struct drm_plane *plane, | 320 | static void vbox_primary_cleanup_fb(struct drm_plane *plane, |
| 320 | struct drm_plane_state *old_state) | 321 | struct drm_plane_state *old_state) |
| 321 | { | 322 | { |
| 322 | struct vbox_bo *bo; | 323 | struct drm_gem_vram_object *gbo; |
| 323 | 324 | ||
| 324 | if (!old_state->fb) | 325 | if (!old_state->fb) |
| 325 | return; | 326 | return; |
| 326 | 327 | ||
| 327 | bo = gem_to_vbox_bo(to_vbox_framebuffer(old_state->fb)->obj); | 328 | gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(old_state->fb)->obj); |
| 328 | vbox_bo_unpin(bo); | 329 | drm_gem_vram_unpin(gbo); |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | static int vbox_cursor_atomic_check(struct drm_plane *plane, | 332 | static int vbox_cursor_atomic_check(struct drm_plane *plane, |
| @@ -385,7 +386,8 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, · 53 unmodified lines | |||
| 385 | container_of(plane->dev, struct vbox_private, ddev); | 386 | container_of(plane->dev, struct vbox_private, ddev); |
| 386 | struct vbox_crtc *vbox_crtc = to_vbox_crtc(plane->state->crtc); | 387 | struct vbox_crtc *vbox_crtc = to_vbox_crtc(plane->state->crtc); |
| 387 | struct drm_framebuffer *fb = plane->state->fb; | 388 | struct drm_framebuffer *fb = plane->state->fb; |
| 388 | struct vbox_bo *bo = gem_to_vbox_bo(to_vbox_framebuffer(fb)->obj); | 389 | struct drm_gem_vram_object *gbo = |
| 390 | drm_gem_vram_of_gem(to_vbox_framebuffer(fb)->obj); | ||
| 389 | u32 width = plane->state->crtc_w; | 391 | u32 width = plane->state->crtc_w; |
| 390 | u32 height = plane->state->crtc_h; | 392 | u32 height = plane->state->crtc_h; |
| 391 | size_t data_size, mask_size; | 393 | size_t data_size, mask_size; |
| @@ -404,7 +406,7 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, · 12 unmodified lines | |||
| 404 | vbox_crtc->cursor_enabled = true; | 406 | vbox_crtc->cursor_enabled = true; |
| 405 | 407 | ||
| 406 | /* pinning is done in prepare/cleanup framebuffer */ | 408 | /* pinning is done in prepare/cleanup framebuffer */ |
| 407 | src = vbox_bo_kmap(bo); | 409 | src = drm_gem_vram_kmap(gbo, true, NULL); |
| 408 | if (IS_ERR(src)) { | 410 | if (IS_ERR(src)) { |
| 409 | mutex_unlock(&vbox->hw_mutex); | 411 | mutex_unlock(&vbox->hw_mutex); |
| 410 | DRM_WARN("Could not kmap cursor bo, skipping update\n"); | 412 | DRM_WARN("Could not kmap cursor bo, skipping update\n"); |
| @@ -420,7 +422,7 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, · 9 unmodified lines | |||
| 420 | data_size = width * height * 4 + mask_size; | 422 | data_size = width * height * 4 + mask_size; |
| 421 | 423 | ||
| 422 | copy_cursor_image(src, vbox->cursor_data, width, height, mask_size); | 424 | copy_cursor_image(src, vbox->cursor_data, width, height, mask_size); |
| 423 | vbox_bo_kunmap(bo); | 425 | drm_gem_vram_kunmap(gbo); |
| 424 | 426 | ||
| 425 | flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE | | 427 | flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE | |
| 426 | VBOX_MOUSE_POINTER_ALPHA; | 428 | VBOX_MOUSE_POINTER_ALPHA; |
| @@ -460,25 +462,25 @@ static void vbox_cursor_atomic_disable(struct drm_plane *plane, · 33 unmodified lines | |||
| 460 | static int vbox_cursor_prepare_fb(struct drm_plane *plane, | 462 | static int vbox_cursor_prepare_fb(struct drm_plane *plane, |
| 461 | struct drm_plane_state *new_state) | 463 | struct drm_plane_state *new_state) |
| 462 | { | 464 | { |
| 463 | struct vbox_bo *bo; | 465 | struct drm_gem_vram_object *gbo; |
| 464 | 466 | ||
| 465 | if (!new_state->fb) | 467 | if (!new_state->fb) |
| 466 | return 0; | 468 | return 0; |
| 467 | 469 | ||
| 468 | bo = gem_to_vbox_bo(to_vbox_framebuffer(new_state->fb)->obj); | 470 | gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(new_state->fb)->obj); |
| 469 | return vbox_bo_pin(bo, TTM_PL_FLAG_SYSTEM); | 471 | return drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_SYSTEM); |
| 470 | } | 472 | } |
| 471 | 473 | ||
| 472 | static void vbox_cursor_cleanup_fb(struct drm_plane *plane, | 474 | static void vbox_cursor_cleanup_fb(struct drm_plane *plane, |
| 473 | struct drm_plane_state *old_state) | 475 | struct drm_plane_state *old_state) |
| 474 | { | 476 | { |
| 475 | struct vbox_bo *bo; | 477 | struct drm_gem_vram_object *gbo; |
| 476 | 478 | ||
| 477 | if (!plane->state->fb) | 479 | if (!plane->state->fb) |
| 478 | return; | 480 | return; |
| 479 | 481 | ||
| 480 | bo = gem_to_vbox_bo(to_vbox_framebuffer(plane->state->fb)->obj); | 482 | gbo = drm_gem_vram_of_gem(to_vbox_framebuffer(plane->state->fb)->obj); |
| 481 | vbox_bo_unpin(bo); | 483 | drm_gem_vram_unpin(gbo); |
| 482 | } | 484 | } |
| 483 | 485 | ||
| 484 | static const u32 vbox_cursor_plane_formats[] = { | 486 | static const u32 vbox_cursor_plane_formats[] = { |
| @@ -8,167 +8,23 @@ · 7 unmodified lines | |||
| 8 | */ | 8 | */ |
| 9 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
| 10 | #include <drm/drm_file.h> | 10 | #include <drm/drm_file.h> |
| 11 | #include <drm/ttm/ttm_page_alloc.h> | ||
| 12 | #include "vbox_drv.h" | 11 | #include "vbox_drv.h" |
| 13 | 12 | ||
| 14 | static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd) | ||
| 15 | { | ||
| 16 | return container_of(bd, struct vbox_private, ttm.bdev); | ||
| 17 | } | ||
| 18 | |||
| 19 | static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo) | ||
| 20 | { | ||
| 21 | struct vbox_bo *bo; | ||
| 22 | |||
| 23 | bo = container_of(tbo, struct vbox_bo, bo); | ||
| 24 | |||
| 25 | drm_gem_object_release(&bo->gem); | ||
| 26 | kfree(bo); | ||
| 27 | } | ||
| 28 | |||
| 29 | static bool vbox_ttm_bo_is_vbox_bo(struct ttm_buffer_object *bo) | ||
| 30 | { | ||
| 31 | if (bo->destroy == &vbox_bo_ttm_destroy) | ||
| 32 | return true; | ||
| 33 | |||
| 34 | return false; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int | ||
| 38 | vbox_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type, | ||
| 39 | struct ttm_mem_type_manager *man) | ||
| 40 | { | ||
| 41 | switch (type) { | ||
| 42 | case TTM_PL_SYSTEM: | ||
| 43 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 44 | man->available_caching = TTM_PL_MASK_CACHING; | ||
| 45 | man->default_caching = TTM_PL_FLAG_CACHED; | ||
| 46 | break; | ||
| 47 | case TTM_PL_VRAM: | ||
| 48 | man->func = &ttm_bo_manager_func; | ||
| 49 | man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; | ||
| 50 | man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; | ||
| 51 | man->default_caching = TTM_PL_FLAG_WC; | ||
| 52 | break; | ||
| 53 | default: | ||
| 54 | DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); | ||
| 55 | return -EINVAL; | ||
| 56 | } | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | static void | ||
| 62 | vbox_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | ||
| 63 | { | ||
| 64 | struct vbox_bo *vboxbo = vbox_bo(bo); | ||
| 65 | |||
| 66 | if (!vbox_ttm_bo_is_vbox_bo(bo)) | ||
| 67 | return; | ||
| 68 | |||
| 69 | vbox_ttm_placement(vboxbo, TTM_PL_FLAG_SYSTEM); | ||
| 70 | *pl = vboxbo->placement; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int vbox_bo_verify_access(struct ttm_buffer_object *bo, | ||
| 74 | struct file *filp) | ||
| 75 | { | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | ||
| 80 | struct ttm_mem_reg *mem) | ||
| 81 | { | ||
| 82 | struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | ||
| 83 | struct vbox_private *vbox = vbox_bdev(bdev); | ||
| 84 | |||
| 85 | mem->bus.addr = NULL; | ||
| 86 | mem->bus.offset = 0; | ||
| 87 | mem->bus.size = mem->num_pages << PAGE_SHIFT; | ||
| 88 | mem->bus.base = 0; | ||
| 89 | mem->bus.is_iomem = false; | ||
| 90 | if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | ||
| 91 | return -EINVAL; | ||
| 92 | switch (mem->mem_type) { | ||
| 93 | case TTM_PL_SYSTEM: | ||
| 94 | /* system memory */ | ||
| 95 | return 0; | ||
| 96 | case TTM_PL_VRAM: | ||
| 97 | mem->bus.offset = mem->start << PAGE_SHIFT; | ||
| 98 | mem->bus.base = pci_resource_start(vbox->ddev.pdev, 0); | ||
| 99 | mem->bus.is_iomem = true; | ||
| 100 | break; | ||
| 101 | default: | ||
| 102 | return -EINVAL; | ||
| 103 | } | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev, | ||
| 108 | struct ttm_mem_reg *mem) | ||
| 109 | { | ||
| 110 | } | ||
| 111 | |||
| 112 | static void vbox_ttm_backend_destroy(struct ttm_tt *tt) | ||
| 113 | { | ||
| 114 | ttm_tt_fini(tt); | ||
| 115 | kfree(tt); | ||
| 116 | } | ||
| 117 | |||
| 118 | static struct ttm_backend_func vbox_tt_backend_func = { | ||
| 119 | .destroy = &vbox_ttm_backend_destroy, | ||
| 120 | }; | ||
| 121 | |||
| 122 | static struct ttm_tt *vbox_ttm_tt_create(struct ttm_buffer_object *bo, | ||
| 123 | u32 page_flags) | ||
| 124 | { | ||
| 125 | struct ttm_tt *tt; | ||
| 126 | |||
| 127 | tt = kzalloc(sizeof(*tt), GFP_KERNEL); | ||
| 128 | if (!tt) | ||
| 129 | return NULL; | ||
| 130 | |||
| 131 | tt->func = &vbox_tt_backend_func; | ||
| 132 | if (ttm_tt_init(tt, bo, page_flags)) { | ||
| 133 | kfree(tt); | ||
| 134 | return NULL; | ||
| 135 | } | ||
| 136 | |||
| 137 | return tt; | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct ttm_bo_driver vbox_bo_driver = { | ||
| 141 | .ttm_tt_create = vbox_ttm_tt_create, | ||
| 142 | .init_mem_type = vbox_bo_init_mem_type, | ||
| 143 | .eviction_valuable = ttm_bo_eviction_valuable, | ||
| 144 | .evict_flags = vbox_bo_evict_flags, | ||
| 145 | .verify_access = vbox_bo_verify_access, | ||
| 146 | .io_mem_reserve = &vbox_ttm_io_mem_reserve, | ||
| 147 | .io_mem_free = &vbox_ttm_io_mem_free, | ||
| 148 | }; | ||
| 149 | |||
| 150 | int vbox_mm_init(struct vbox_private *vbox) | 13 | int vbox_mm_init(struct vbox_private *vbox) |
| 151 | { | 14 | { |
| 15 | struct drm_vram_mm *vmm; | ||
| 152 | int ret; | 16 | int ret; |
| 153 | struct drm_device *dev = &vbox->ddev; | 17 | struct drm_device *dev = &vbox->ddev; |
| 154 | struct ttm_bo_device *bdev = &vbox->ttm.bdev; | ||
| 155 | 18 | ||
| 156 | ret = ttm_bo_device_init(&vbox->ttm.bdev, | 19 | vmm = drm_vram_helper_alloc_mm(dev, pci_resource_start(dev->pdev, 0), |
| 157 | &vbox_bo_driver, | 20 | vbox->available_vram_size, |
| 158 | dev->anon_inode->i_mapping, | 21 | &drm_gem_vram_mm_funcs); |
| 159 | true); | 22 | if (IS_ERR(vmm)) { |
| 160 | if (ret) { | 23 | ret = PTR_ERR(vmm); |
| 161 | DRM_ERROR("Error initialising bo driver; %d\n", ret); | 24 | DRM_ERROR("Error initializing VRAM MM; %d\n", ret); |
| 162 | return ret; | 25 | return ret; |
| 163 | } | 26 | } |
| 164 | 27 | ||
| 165 | ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, | ||
| 166 | vbox->available_vram_size >> PAGE_SHIFT); | ||
| 167 | if (ret) { | ||
| 168 | DRM_ERROR("Failed ttm VRAM init: %d\n", ret); | ||
| 169 | goto err_device_release; | ||
| 170 | } | ||
| 171 | |||
| 172 | #ifdef DRM_MTRR_WC | 28 | #ifdef DRM_MTRR_WC |
| 173 | vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), | 29 | vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), |
| 174 | pci_resource_len(dev->pdev, 0), | 30 | pci_resource_len(dev->pdev, 0), |
| @@ -178,10 +34,6 @@ int vbox_mm_init(struct vbox_private *vbox) · 3 unmodified lines | |||
| 178 | pci_resource_len(dev->pdev, 0)); | 34 | pci_resource_len(dev->pdev, 0)); |
| 179 | #endif | 35 | #endif |
| 180 | return 0; | 36 | return 0; |
| 181 | |||
| 182 | err_device_release: | ||
| 183 | ttm_bo_device_release(&vbox->ttm.bdev); | ||
| 184 | return ret; | ||
| 185 | } | 37 | } |
| 186 | 38 | ||
| 187 | void vbox_mm_fini(struct vbox_private *vbox) | 39 | void vbox_mm_fini(struct vbox_private *vbox) |
| @@ -193,196 +45,5 @@ void vbox_mm_fini(struct vbox_private *vbox) · 5 unmodified lines | |||
| 193 | #else | 45 | #else |
| 194 | arch_phys_wc_del(vbox->fb_mtrr); | 46 | arch_phys_wc_del(vbox->fb_mtrr); |
| 195 | #endif | 47 | #endif |
| 196 | ttm_bo_device_release(&vbox->ttm.bdev); | 48 | drm_vram_helper_release_mm(&vbox->ddev); |
| 197 | } | ||
| 198 | |||
| 199 | void vbox_ttm_placement(struct vbox_bo *bo, int domain) | ||
| 200 | { | ||
| 201 | unsigned int i; | ||
| 202 | u32 c = 0; | ||
| 203 | |||
| 204 | bo->placement.placement = bo->placements; | ||
| 205 | bo->placement.busy_placement = bo->placements; | ||
| 206 | |||
| 207 | if (domain & TTM_PL_FLAG_VRAM) | ||
| 208 | bo->placements[c++].flags = | ||
| 209 | TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; | ||
| 210 | if (domain & TTM_PL_FLAG_SYSTEM) | ||
| 211 | bo->placements[c++].flags = | ||
| 212 | TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
| 213 | if (!c) | ||
| 214 | bo->placements[c++].flags = | ||
| 215 | TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | ||
| 216 | |||
| 217 | bo->placement.num_placement = c; | ||
| 218 | bo->placement.num_busy_placement = c; | ||
| 219 | |||
| 220 | for (i = 0; i < c; ++i) { | ||
| 221 | bo->placements[i].fpfn = 0; | ||
| 222 | bo->placements[i].lpfn = 0; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | int vbox_bo_create(struct vbox_private *vbox, int size, int align, | ||
| 227 | u32 flags, struct vbox_bo **pvboxbo) | ||
| 228 | { | ||
| 229 | struct vbox_bo *vboxbo; | ||
| 230 | size_t acc_size; | ||
| 231 | int ret; | ||
| 232 | |||
| 233 | vboxbo = kzalloc(sizeof(*vboxbo), GFP_KERNEL); | ||
| 234 | if (!vboxbo) | ||
| 235 | return -ENOMEM; | ||
| 236 | |||
| 237 | ret = drm_gem_object_init(&vbox->ddev, &vboxbo->gem, size); | ||
| 238 | if (ret) | ||
| 239 | goto err_free_vboxbo; | ||
| 240 | |||
| 241 | vboxbo->bo.bdev = &vbox->ttm.bdev; | ||
| 242 | |||
| 243 | vbox_ttm_placement(vboxbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | ||
| 244 | |||
| 245 | acc_size = ttm_bo_dma_acc_size(&vbox->ttm.bdev, size, | ||
| 246 | sizeof(struct vbox_bo)); | ||
| 247 | |||
| 248 | ret = ttm_bo_init(&vbox->ttm.bdev, &vboxbo->bo, size, | ||
| 249 | ttm_bo_type_device, &vboxbo->placement, | ||
| 250 | align >> PAGE_SHIFT, false, acc_size, | ||
| 251 | NULL, NULL, vbox_bo_ttm_destroy); | ||
| 252 | if (ret) | ||
| 253 | goto err_free_vboxbo; | ||
| 254 | |||
| 255 | *pvboxbo = vboxbo; | ||
| 256 | |||
| 257 | return 0; | ||
| 258 | |||
| 259 | err_free_vboxbo: | ||
| 260 | kfree(vboxbo); | ||
| 261 | return ret; | ||
| 262 | } | ||
| 263 | |||
| 264 | int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag) | ||
| 265 | { | ||
| 266 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 267 | int i, ret; | ||
| 268 | |||
| 269 | if (bo->pin_count) { | ||
| 270 | bo->pin_count++; | ||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | ret = vbox_bo_reserve(bo, false); | ||
| 275 | if (ret) | ||
| 276 | return ret; | ||
| 277 | |||
| 278 | vbox_ttm_placement(bo, pl_flag); | ||
| 279 | |||
| 280 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 281 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 282 | |||
| 283 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 284 | if (ret == 0) | ||
| 285 | bo->pin_count = 1; | ||
| 286 | |||
| 287 | vbox_bo_unreserve(bo); | ||
| 288 | |||
| 289 | return ret; | ||
| 290 | } | ||
| 291 | |||
| 292 | int vbox_bo_unpin(struct vbox_bo *bo) | ||
| 293 | { | ||
| 294 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 295 | int i, ret; | ||
| 296 | |||
| 297 | if (!bo->pin_count) { | ||
| 298 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | bo->pin_count--; | ||
| 302 | if (bo->pin_count) | ||
| 303 | return 0; | ||
| 304 | |||
| 305 | ret = vbox_bo_reserve(bo, false); | ||
| 306 | if (ret) { | ||
| 307 | DRM_ERROR("Error %d reserving bo, leaving it pinned\n", ret); | ||
| 308 | return ret; | ||
| 309 | } | ||
| 310 | |||
| 311 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 312 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | ||
| 313 | |||
| 314 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 315 | |||
| 316 | vbox_bo_unreserve(bo); | ||
| 317 | |||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | /* | ||
| 322 | * Move a vbox-owned buffer object to system memory if no one else has it | ||
| 323 | * pinned. The caller must have pinned it previously, and this call will | ||
| 324 | * release the caller's pin. | ||
| 325 | */ | ||
| 326 | int vbox_bo_push_sysram(struct vbox_bo *bo) | ||
| 327 | { | ||
| 328 | struct ttm_operation_ctx ctx = { false, false }; | ||
| 329 | int i, ret; | ||
| 330 | |||
| 331 | if (!bo->pin_count) { | ||
| 332 | DRM_ERROR("unpin bad %p\n", bo); | ||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | bo->pin_count--; | ||
| 336 | if (bo->pin_count) | ||
| 337 | return 0; | ||
| 338 | |||
| 339 | if (bo->kmap.virtual) { | ||
| 340 | ttm_bo_kunmap(&bo->kmap); | ||
| 341 | bo->kmap.virtual = NULL; | ||
| 342 | } | ||
| 343 | |||
| 344 | vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); | ||
| 345 | |||
| 346 | for (i = 0; i < bo->placement.num_placement; i++) | ||
| 347 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | ||
| 348 | |||
| 349 | ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx); | ||
| 350 | if (ret) { | ||
| 351 | DRM_ERROR("pushing to VRAM failed\n"); | ||
| 352 | return ret; | ||
| 353 | } | ||
| 354 | |||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | int vbox_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 359 | { | ||
| 360 | struct drm_file *file_priv = filp->private_data; | ||
| 361 | struct vbox_private *vbox = file_priv->minor->dev->dev_private; | ||
| 362 | |||
| 363 | return ttm_bo_mmap(filp, vma, &vbox->ttm.bdev); | ||
| 364 | } | ||
| 365 | |||
| 366 | void *vbox_bo_kmap(struct vbox_bo *bo) | ||
| 367 | { | ||
| 368 | int ret; | ||
| 369 | |||
| 370 | if (bo->kmap.virtual) | ||
| 371 | return bo->kmap.virtual; | ||
| 372 | |||
| 373 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
| 374 | if (ret) { | ||
| 375 | DRM_ERROR("Error kmapping bo: %d\n", ret); | ||
| 376 | return NULL; | ||
| 377 | } | ||
| 378 | |||
| 379 | return bo->kmap.virtual; | ||
| 380 | } | ||
| 381 | |||
| 382 | void vbox_bo_kunmap(struct vbox_bo *bo) | ||
| 383 | { | ||
| 384 | if (bo->kmap.virtual) { | ||
| 385 | ttm_bo_kunmap(&bo->kmap); | ||
| 386 | bo->kmap.virtual = NULL; | ||
| 387 | } | ||
| 388 | } | 49 | } |
| @@ -799,13 +799,36 @@ vc4_prime_import_sg_table(struct drm_device *dev, · 798 unmodified lines | |||
| 799 | return obj; | 799 | return obj; |
| 800 | } | 800 | } |
| 801 | 801 | ||
| 802 | static int vc4_grab_bin_bo(struct vc4_dev *vc4, struct vc4_file *vc4file) | ||
| 803 | { | ||
| 804 | int ret; | ||
| 805 | |||
| 806 | if (!vc4->v3d) | ||
| 807 | return -ENODEV; | ||
| 808 | |||
| 809 | if (vc4file->bin_bo_used) | ||
| 810 | return 0; | ||
| 811 | |||
| 812 | ret = vc4_v3d_bin_bo_get(vc4, &vc4file->bin_bo_used); | ||
| 813 | if (ret) | ||
| 814 | return ret; | ||
| 815 | |||
| 816 | return 0; | ||
| 817 | } | ||
| 818 | |||
| 802 | int vc4_create_bo_ioctl(struct drm_device *dev, void *data, | 819 | int vc4_create_bo_ioctl(struct drm_device *dev, void *data, |
| 803 | struct drm_file *file_priv) | 820 | struct drm_file *file_priv) |
| 804 | { | 821 | { |
| 805 | struct drm_vc4_create_bo *args = data; | 822 | struct drm_vc4_create_bo *args = data; |
| 823 | struct vc4_file *vc4file = file_priv->driver_priv; | ||
| 824 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
| 806 | struct vc4_bo *bo = NULL; | 825 | struct vc4_bo *bo = NULL; |
| 807 | int ret; | 826 | int ret; |
| 808 | 827 | ||
| 828 | ret = vc4_grab_bin_bo(vc4, vc4file); | ||
| 829 | if (ret) | ||
| 830 | return ret; | ||
| 831 | |||
| 809 | /* | 832 | /* |
| 810 | * We can't allocate from the BO cache, because the BOs don't | 833 | * We can't allocate from the BO cache, because the BOs don't |
| 811 | * get zeroed, and that might leak data between users. | 834 | * get zeroed, and that might leak data between users. |
| @@ -846,6 +869,8 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, · 34 unmodified lines | |||
| 846 | struct drm_file *file_priv) | 869 | struct drm_file *file_priv) |
| 847 | { | 870 | { |
| 848 | struct drm_vc4_create_shader_bo *args = data; | 871 | struct drm_vc4_create_shader_bo *args = data; |
| 872 | struct vc4_file *vc4file = file_priv->driver_priv; | ||
| 873 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
| 849 | struct vc4_bo *bo = NULL; | 874 | struct vc4_bo *bo = NULL; |
| 850 | int ret; | 875 | int ret; |
| 851 | 876 | ||
| @@ -865,6 +890,10 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, · 13 unmodified lines | |||
| 865 | return -EINVAL; | 890 | return -EINVAL; |
| 866 | } | 891 | } |
| 867 | 892 | ||
| 893 | ret = vc4_grab_bin_bo(vc4, vc4file); | ||
| 894 | if (ret) | ||
| 895 | return ret; | ||
| 896 | |||
| 868 | bo = vc4_bo_create(dev, args->size, true, VC4_BO_TYPE_V3D_SHADER); | 897 | bo = vc4_bo_create(dev, args->size, true, VC4_BO_TYPE_V3D_SHADER); |
| 869 | if (IS_ERR(bo)) | 898 | if (IS_ERR(bo)) |
| 870 | return PTR_ERR(bo); | 899 | return PTR_ERR(bo); |
| @@ -894,7 +923,7 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, · 23 unmodified lines | |||
| 894 | */ | 923 | */ |
| 895 | ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); | 924 | ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); |
| 896 | 925 | ||
| 897 | fail: | 926 | fail: |
| 898 | drm_gem_object_put_unlocked(&bo->base.base); | 927 | drm_gem_object_put_unlocked(&bo->base.base); |
| 899 | 928 | ||
| 900 | return ret; | 929 | return ret; |
| @@ -128,8 +128,12 @@ static int vc4_open(struct drm_device *dev, struct drm_file *file) · 127 unmodified lines | |||
| 128 | 128 | ||
| 129 | static void vc4_close(struct drm_device *dev, struct drm_file *file) | 129 | static void vc4_close(struct drm_device *dev, struct drm_file *file) |
| 130 | { | 130 | { |
| 131 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
| 131 | struct vc4_file *vc4file = file->driver_priv; | 132 | struct vc4_file *vc4file = file->driver_priv; |
| 132 | 133 | ||
| 134 | if (vc4file->bin_bo_used) | ||
| 135 | vc4_v3d_bin_bo_put(vc4); | ||
| 136 | |||
| 133 | vc4_perfmon_close_file(vc4file); | 137 | vc4_perfmon_close_file(vc4file); |
| 134 | kfree(vc4file); | 138 | kfree(vc4file); |
| 135 | } | 139 | } |
| @@ -274,6 +278,8 @@ static int vc4_drm_bind(struct device *dev) · 138 unmodified lines | |||
| 274 | drm->dev_private = vc4; | 278 | drm->dev_private = vc4; |
| 275 | INIT_LIST_HEAD(&vc4->debugfs_list); | 279 | INIT_LIST_HEAD(&vc4->debugfs_list); |
| 276 | 280 | ||
| 281 | mutex_init(&vc4->bin_bo_lock); | ||
| 282 | |||
| 277 | ret = vc4_bo_cache_init(drm); | 283 | ret = vc4_bo_cache_init(drm); |
| 278 | if (ret) | 284 | if (ret) |
| 279 | goto dev_put; | 285 | goto dev_put; |
| @@ -216,6 +216,11 @@ struct vc4_dev { · 215 unmodified lines | |||
| 216 | * the minor is available (after drm_dev_register()). | 216 | * the minor is available (after drm_dev_register()). |
| 217 | */ | 217 | */ |
| 218 | struct list_head debugfs_list; | 218 | struct list_head debugfs_list; |
| 219 | |||
| 220 | /* Mutex for binner bo allocation. */ | ||
| 221 | struct mutex bin_bo_lock; | ||
| 222 | /* Reference count for our binner bo. */ | ||
| 223 | struct kref bin_bo_kref; | ||
| 219 | }; | 224 | }; |
| 220 | 225 | ||
| 221 | static inline struct vc4_dev * | 226 | static inline struct vc4_dev * |
| @@ -584,6 +589,11 @@ struct vc4_exec_info { · 362 unmodified lines | |||
| 584 | * NULL otherwise. | 589 | * NULL otherwise. |
| 585 | */ | 590 | */ |
| 586 | struct vc4_perfmon *perfmon; | 591 | struct vc4_perfmon *perfmon; |
| 592 | |||
| 593 | /* Whether the exec has taken a reference to the binner BO, which should | ||
| 594 | * happen with a VC4_PACKET_TILE_BINNING_MODE_CONFIG packet. | ||
| 595 | */ | ||
| 596 | bool bin_bo_used; | ||
| 587 | }; | 597 | }; |
| 588 | 598 | ||
| 589 | /* Per-open file private data. Any driver-specific resource that has to be | 599 | /* Per-open file private data. Any driver-specific resource that has to be |
| @@ -594,6 +604,8 @@ struct vc4_file { · 4 unmodified lines | |||
| 594 | struct idr idr; | 604 | struct idr idr; |
| 595 | struct mutex lock; | 605 | struct mutex lock; |
| 596 | } perfmon; | 606 | } perfmon; |
| 607 | |||
| 608 | bool bin_bo_used; | ||
| 597 | }; | 609 | }; |
| 598 | 610 | ||
| 599 | static inline struct vc4_exec_info * | 611 | static inline struct vc4_exec_info * |
| @@ -833,6 +845,8 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, · 233 unmodified lines | |||
| 833 | extern struct platform_driver vc4_v3d_driver; | 845 | extern struct platform_driver vc4_v3d_driver; |
| 834 | extern const struct of_device_id vc4_v3d_dt_match[]; | 846 | extern const struct of_device_id vc4_v3d_dt_match[]; |
| 835 | int vc4_v3d_get_bin_slot(struct vc4_dev *vc4); | 847 | int vc4_v3d_get_bin_slot(struct vc4_dev *vc4); |
| 848 | int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used); | ||
| 849 | void vc4_v3d_bin_bo_put(struct vc4_dev *vc4); | ||
| 836 | int vc4_v3d_pm_get(struct vc4_dev *vc4); | 850 | int vc4_v3d_pm_get(struct vc4_dev *vc4); |
| 837 | void vc4_v3d_pm_put(struct vc4_dev *vc4); | 851 | void vc4_v3d_pm_put(struct vc4_dev *vc4); |
| 838 | 852 | ||
| @@ -820,6 +820,7 @@ static int · 819 unmodified lines | |||
| 820 | vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) | 820 | vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) |
| 821 | { | 821 | { |
| 822 | struct drm_vc4_submit_cl *args = exec->args; | 822 | struct drm_vc4_submit_cl *args = exec->args; |
| 823 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
| 823 | void *temp = NULL; | 824 | void *temp = NULL; |
| 824 | void *bin; | 825 | void *bin; |
| 825 | int ret = 0; | 826 | int ret = 0; |
| @@ -918,6 +919,12 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) · 92 unmodified lines | |||
| 918 | if (ret) | 919 | if (ret) |
| 919 | goto fail; | 920 | goto fail; |
| 920 | 921 | ||
| 922 | if (exec->found_tile_binning_mode_config_packet) { | ||
| 923 | ret = vc4_v3d_bin_bo_get(vc4, &exec->bin_bo_used); | ||
| 924 | if (ret) | ||
| 925 | goto fail; | ||
| 926 | } | ||
| 927 | |||
| 921 | /* Block waiting on any previous rendering into the CS's VBO, | 928 | /* Block waiting on any previous rendering into the CS's VBO, |
| 922 | * IB, or textures, so that pixels are actually written by the | 929 | * IB, or textures, so that pixels are actually written by the |
| 923 | * time we try to read them. | 930 | * time we try to read them. |
| @@ -966,6 +973,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) · 42 unmodified lines | |||
| 966 | vc4->bin_alloc_used &= ~exec->bin_slots; | 973 | vc4->bin_alloc_used &= ~exec->bin_slots; |
| 967 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | 974 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); |
| 968 | 975 | ||
| 976 | /* Release the reference on the binner BO if needed. */ | ||
| 977 | if (exec->bin_bo_used) | ||
| 978 | vc4_v3d_bin_bo_put(vc4); | ||
| 979 | |||
| 969 | /* Release the reference we had on the perf monitor. */ | 980 | /* Release the reference we had on the perf monitor. */ |
| 970 | vc4_perfmon_put(exec->perfmon); | 981 | vc4_perfmon_put(exec->perfmon); |
| 971 | 982 | ||
| @@ -59,15 +59,22 @@ vc4_overflow_mem_work(struct work_struct *work) · 58 unmodified lines | |||
| 59 | { | 59 | { |
| 60 | struct vc4_dev *vc4 = | 60 | struct vc4_dev *vc4 = |
| 61 | container_of(work, struct vc4_dev, overflow_mem_work); | 61 | container_of(work, struct vc4_dev, overflow_mem_work); |
| 62 | struct vc4_bo *bo = vc4->bin_bo; | 62 | struct vc4_bo *bo; |
| 63 | int bin_bo_slot; | 63 | int bin_bo_slot; |
| 64 | struct vc4_exec_info *exec; | 64 | struct vc4_exec_info *exec; |
| 65 | unsigned long irqflags; | 65 | unsigned long irqflags; |
| 66 | 66 | ||
| 67 | mutex_lock(&vc4->bin_bo_lock); | ||
| 68 | |||
| 69 | if (!vc4->bin_bo) | ||
| 70 | goto complete; | ||
| 71 | |||
| 72 | bo = vc4->bin_bo; | ||
| 73 | |||
| 67 | bin_bo_slot = vc4_v3d_get_bin_slot(vc4); | 74 | bin_bo_slot = vc4_v3d_get_bin_slot(vc4); |
| 68 | if (bin_bo_slot < 0) { | 75 | if (bin_bo_slot < 0) { |
| 69 | DRM_ERROR("Couldn't allocate binner overflow mem\n"); | 76 | DRM_ERROR("Couldn't allocate binner overflow mem\n"); |
| 70 | return; | 77 | goto complete; |
| 71 | } | 78 | } |
| 72 | 79 | ||
| 73 | spin_lock_irqsave(&vc4->job_lock, irqflags); | 80 | spin_lock_irqsave(&vc4->job_lock, irqflags); |
| @@ -98,6 +105,9 @@ vc4_overflow_mem_work(struct work_struct *work) · 24 unmodified lines | |||
| 98 | V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); | 105 | V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); |
| 99 | V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); | 106 | V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); |
| 100 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); | 107 | spin_unlock_irqrestore(&vc4->job_lock, irqflags); |
| 108 | |||
| 109 | complete: | ||
| 110 | mutex_unlock(&vc4->bin_bo_lock); | ||
| 101 | } | 111 | } |
| 102 | 112 | ||
| 103 | static void | 113 | static void |
| @@ -249,8 +259,10 @@ vc4_irq_postinstall(struct drm_device *dev) · 145 unmodified lines | |||
| 249 | if (!vc4->v3d) | 259 | if (!vc4->v3d) |
| 250 | return 0; | 260 | return 0; |
| 251 | 261 | ||
| 252 | /* Enable both the render done and out of memory interrupts. */ | 262 | /* Enable the render done interrupts. The out-of-memory interrupt is |
| 253 | V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); | 263 | * enabled as soon as we have a binner BO allocated. |
| 264 | */ | ||
| 265 | V3D_WRITE(V3D_INTENA, V3D_INT_FLDONE | V3D_INT_FRDONE); | ||
| 254 | 266 | ||
| 255 | return 0; | 267 | return 0; |
| 256 | } | 268 | } |
| @@ -310,10 +310,10 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) · 309 unmodified lines | |||
| 310 | struct drm_framebuffer *fb = state->fb; | 310 | struct drm_framebuffer *fb = state->fb; |
| 311 | struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); | 311 | struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); |
| 312 | u32 subpixel_src_mask = (1 << 16) - 1; | 312 | u32 subpixel_src_mask = (1 << 16) - 1; |
| 313 | u32 format = fb->format->format; | ||
| 314 | int num_planes = fb->format->num_planes; | 313 | int num_planes = fb->format->num_planes; |
| 315 | struct drm_crtc_state *crtc_state; | 314 | struct drm_crtc_state *crtc_state; |
| 316 | u32 h_subsample, v_subsample; | 315 | u32 h_subsample = fb->format->hsub; |
| 316 | u32 v_subsample = fb->format->vsub; | ||
| 317 | int i, ret; | 317 | int i, ret; |
| 318 | 318 | ||
| 319 | crtc_state = drm_atomic_get_existing_crtc_state(state->state, | 319 | crtc_state = drm_atomic_get_existing_crtc_state(state->state, |
| @@ -328,9 +328,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) · 8 unmodified lines | |||
| 328 | if (ret) | 328 | if (ret) |
| 329 | return ret; | 329 | return ret; |
| 330 | 330 | ||
| 331 | h_subsample = drm_format_horz_chroma_subsampling(format); | ||
| 332 | v_subsample = drm_format_vert_chroma_subsampling(format); | ||
| 333 | |||
| 334 | for (i = 0; i < num_planes; i++) | 331 | for (i = 0; i < num_planes; i++) |
| 335 | vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; | 332 | vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; |
| 336 | 333 | ||
| @@ -592,8 +589,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, · 255 unmodified lines | |||
| 592 | u32 ctl0_offset = vc4_state->dlist_count; | 589 | u32 ctl0_offset = vc4_state->dlist_count; |
| 593 | const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); | 590 | const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); |
| 594 | u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); | 591 | u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); |
| 595 | int num_planes = drm_format_num_planes(format->drm); | 592 | int num_planes = fb->format->num_planes; |
| 596 | u32 h_subsample, v_subsample; | 593 | u32 h_subsample = fb->format->hsub; |
| 594 | u32 v_subsample = fb->format->vsub; | ||
| 597 | bool mix_plane_alpha; | 595 | bool mix_plane_alpha; |
| 598 | bool covers_screen; | 596 | bool covers_screen; |
| 599 | u32 scl0, scl1, pitch0; | 597 | u32 scl0, scl1, pitch0; |
| @@ -623,9 +621,6 @@ static int vc4_plane_mode_set(struct drm_plane *plane, · 23 unmodified lines | |||
| 623 | scl1 = vc4_get_scl_field(state, 0); | 621 | scl1 = vc4_get_scl_field(state, 0); |
| 624 | } | 622 | } |
| 625 | 623 | ||
| 626 | h_subsample = drm_format_horz_chroma_subsampling(format->drm); | ||
| 627 | v_subsample = drm_format_vert_chroma_subsampling(format->drm); | ||
| 628 | |||
| 629 | rotation = drm_rotation_simplify(state->rotation, | 624 | rotation = drm_rotation_simplify(state->rotation, |
| 630 | DRM_MODE_ROTATE_0 | | 625 | DRM_MODE_ROTATE_0 | |
| 631 | DRM_MODE_REFLECT_X | | 626 | DRM_MODE_REFLECT_X | |
| @@ -213,7 +213,7 @@ try_again: · 212 unmodified lines | |||
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | /** | 215 | /** |
| 216 | * vc4_allocate_bin_bo() - allocates the memory that will be used for | 216 | * bin_bo_alloc() - allocates the memory that will be used for |
| 217 | * tile binning. | 217 | * tile binning. |
| 218 | * | 218 | * |
| 219 | * The binner has a limitation that the addresses in the tile state | 219 | * The binner has a limitation that the addresses in the tile state |
| @@ -234,14 +234,16 @@ try_again: · 14 unmodified lines | |||
| 234 | * overall CMA pool before they make scenes complicated enough to run | 234 | * overall CMA pool before they make scenes complicated enough to run |
| 235 | * out of bin space. | 235 | * out of bin space. |
| 236 | */ | 236 | */ |
| 237 | static int vc4_allocate_bin_bo(struct drm_device *drm) | 237 | static int bin_bo_alloc(struct vc4_dev *vc4) |
| 238 | { | 238 | { |
| 239 | struct vc4_dev *vc4 = to_vc4_dev(drm); | ||
| 240 | struct vc4_v3d *v3d = vc4->v3d; | 239 | struct vc4_v3d *v3d = vc4->v3d; |
| 241 | uint32_t size = 16 * 1024 * 1024; | 240 | uint32_t size = 16 * 1024 * 1024; |
| 242 | int ret = 0; | 241 | int ret = 0; |
| 243 | struct list_head list; | 242 | struct list_head list; |
| 244 | 243 | ||
| 244 | if (!v3d) | ||
| 245 | return -ENODEV; | ||
| 246 | |||
| 245 | /* We may need to try allocating more than once to get a BO | 247 | /* We may need to try allocating more than once to get a BO |
| 246 | * that doesn't cross 256MB. Track the ones we've allocated | 248 | * that doesn't cross 256MB. Track the ones we've allocated |
| 247 | * that failed so far, so that we can free them when we've got | 249 | * that failed so far, so that we can free them when we've got |
| @@ -251,7 +253,7 @@ static int vc4_allocate_bin_bo(struct drm_device *drm) · 3 unmodified lines | |||
| 251 | INIT_LIST_HEAD(&list); | 253 | INIT_LIST_HEAD(&list); |
| 252 | 254 | ||
| 253 | while (true) { | 255 | while (true) { |
| 254 | struct vc4_bo *bo = vc4_bo_create(drm, size, true, | 256 | struct vc4_bo *bo = vc4_bo_create(vc4->dev, size, true, |
| 255 | VC4_BO_TYPE_BIN); | 257 | VC4_BO_TYPE_BIN); |
| 256 | 258 | ||
| 257 | if (IS_ERR(bo)) { | 259 | if (IS_ERR(bo)) { |
| @@ -292,6 +294,14 @@ static int vc4_allocate_bin_bo(struct drm_device *drm) · 34 unmodified lines | |||
| 292 | WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 != | 294 | WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 != |
| 293 | bo->base.base.size / vc4->bin_alloc_size); | 295 | bo->base.base.size / vc4->bin_alloc_size); |
| 294 | 296 | ||
| 297 | kref_init(&vc4->bin_bo_kref); | ||
| 298 | |||
| 299 | /* Enable the out-of-memory interrupt to set our | ||
| 300 | * newly-allocated binner BO, potentially from an | ||
| 301 | * already-pending-but-masked interrupt. | ||
| 302 | */ | ||
| 303 | V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); | ||
| 304 | |||
| 295 | break; | 305 | break; |
| 296 | } | 306 | } |
| 297 | 307 | ||
| @@ -311,6 +321,47 @@ static int vc4_allocate_bin_bo(struct drm_device *drm) · 13 unmodified lines | |||
| 311 | return ret; | 321 | return ret; |
| 312 | } | 322 | } |
| 313 | 323 | ||
| 324 | int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used) | ||
| 325 | { | ||
| 326 | int ret = 0; | ||
| 327 | |||
| 328 | mutex_lock(&vc4->bin_bo_lock); | ||
| 329 | |||
| 330 | if (used && *used) | ||
| 331 | goto complete; | ||
| 332 | |||
| 333 | if (vc4->bin_bo) | ||
| 334 | kref_get(&vc4->bin_bo_kref); | ||
| 335 | else | ||
| 336 | ret = bin_bo_alloc(vc4); | ||
| 337 | |||
| 338 | if (ret == 0 && used) | ||
| 339 | *used = true; | ||
| 340 | |||
| 341 | complete: | ||
| 342 | mutex_unlock(&vc4->bin_bo_lock); | ||
| 343 | |||
| 344 | return ret; | ||
| 345 | } | ||
| 346 | |||
| 347 | static void bin_bo_release(struct kref *ref) | ||
| 348 | { | ||
| 349 | struct vc4_dev *vc4 = container_of(ref, struct vc4_dev, bin_bo_kref); | ||
| 350 | |||
| 351 | if (WARN_ON_ONCE(!vc4->bin_bo)) | ||
| 352 | return; | ||
| 353 | |||
| 354 | drm_gem_object_put_unlocked(&vc4->bin_bo->base.base); | ||
| 355 | vc4->bin_bo = NULL; | ||
| 356 | } | ||
| 357 | |||
| 358 | void vc4_v3d_bin_bo_put(struct vc4_dev *vc4) | ||
| 359 | { | ||
| 360 | mutex_lock(&vc4->bin_bo_lock); | ||
| 361 | kref_put(&vc4->bin_bo_kref, bin_bo_release); | ||
| 362 | mutex_unlock(&vc4->bin_bo_lock); | ||
| 363 | } | ||
| 364 | |||
| 314 | #ifdef CONFIG_PM | 365 | #ifdef CONFIG_PM |
| 315 | static int vc4_v3d_runtime_suspend(struct device *dev) | 366 | static int vc4_v3d_runtime_suspend(struct device *dev) |
| 316 | { | 367 | { |
| @@ -319,9 +370,6 @@ static int vc4_v3d_runtime_suspend(struct device *dev) · 2 unmodified lines | |||
| 319 | 370 | ||
| 320 | vc4_irq_uninstall(vc4->dev); | 371 | vc4_irq_uninstall(vc4->dev); |
| 321 | 372 | ||
| 322 | drm_gem_object_put_unlocked(&vc4->bin_bo->base.base); | ||
| 323 | vc4->bin_bo = NULL; | ||
| 324 | |||
| 325 | clk_disable_unprepare(v3d->clk); | 373 | clk_disable_unprepare(v3d->clk); |
| 326 | 374 | ||
| 327 | return 0; | 375 | return 0; |
| @@ -333,10 +381,6 @@ static int vc4_v3d_runtime_resume(struct device *dev) · 5 unmodified lines | |||
| 333 | struct vc4_dev *vc4 = v3d->vc4; | 381 | struct vc4_dev *vc4 = v3d->vc4; |
| 334 | int ret; | 382 | int ret; |
| 335 | 383 | ||
| 336 | ret = vc4_allocate_bin_bo(vc4->dev); | ||
| 337 | if (ret) | ||
| 338 | return ret; | ||
| 339 | |||
| 340 | ret = clk_prepare_enable(v3d->clk); | 384 | ret = clk_prepare_enable(v3d->clk); |
| 341 | if (ret != 0) | 385 | if (ret != 0) |
| 342 | return ret; | 386 | return ret; |
| @@ -403,12 +447,6 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) · 60 unmodified lines | |||
| 403 | if (ret != 0) | 447 | if (ret != 0) |
| 404 | return ret; | 448 | return ret; |
| 405 | 449 | ||
| 406 | ret = vc4_allocate_bin_bo(drm); | ||
| 407 | if (ret) { | ||
| 408 | clk_disable_unprepare(v3d->clk); | ||
| 409 | return ret; | ||
| 410 | } | ||
| 411 | |||
| 412 | /* Reset the binner overflow address/size at setup, to be sure | 450 | /* Reset the binner overflow address/size at setup, to be sure |
| 413 | * we don't reuse an old one. | 451 | * we don't reuse an old one. |
| 414 | */ | 452 | */ |
| @@ -6,6 +6,6 @@ · 5 unmodified lines | |||
| 6 | virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o \ | 6 | virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o \ |
| 7 | virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ | 7 | virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ |
| 8 | virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ | 8 | virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ |
| 9 | virtgpu_ioctl.o virtgpu_prime.o | 9 | virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o |
| 10 | 10 | ||
| 11 | obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o | 11 | obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o |
| @@ -102,7 +102,6 @@ struct virtio_gpu_fence { · 101 unmodified lines | |||
| 102 | struct dma_fence f; | 102 | struct dma_fence f; |
| 103 | struct virtio_gpu_fence_driver *drv; | 103 | struct virtio_gpu_fence_driver *drv; |
| 104 | struct list_head node; | 104 | struct list_head node; |
| 105 | uint64_t seq; | ||
| 106 | }; | 105 | }; |
| 107 | #define to_virtio_fence(x) \ | 106 | #define to_virtio_fence(x) \ |
| 108 | container_of(x, struct virtio_gpu_fence, f) | 107 | container_of(x, struct virtio_gpu_fence, f) |
| @@ -356,7 +355,7 @@ int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma); · 247 unmodified lines | |||
| 356 | bool virtio_fence_signaled(struct dma_fence *f); | 355 | bool virtio_fence_signaled(struct dma_fence *f); |
| 357 | struct virtio_gpu_fence *virtio_gpu_fence_alloc( | 356 | struct virtio_gpu_fence *virtio_gpu_fence_alloc( |
| 358 | struct virtio_gpu_device *vgdev); | 357 | struct virtio_gpu_device *vgdev); |
| 359 | int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, | 358 | void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, |
| 360 | struct virtio_gpu_ctrl_hdr *cmd_hdr, | 359 | struct virtio_gpu_ctrl_hdr *cmd_hdr, |
| 361 | struct virtio_gpu_fence *fence); | 360 | struct virtio_gpu_fence *fence); |
| 362 | void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev, | 361 | void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev, |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <drm/drmP.h> | 26 | #include <drm/drmP.h> |
| 27 | #include <trace/events/dma_fence.h> | ||
| 27 | #include "virtgpu_drv.h" | 28 | #include "virtgpu_drv.h" |
| 28 | 29 | ||
| 29 | static const char *virtio_get_driver_name(struct dma_fence *f) | 30 | static const char *virtio_get_driver_name(struct dma_fence *f) |
| @@ -40,16 +41,14 @@ bool virtio_fence_signaled(struct dma_fence *f) · 10 unmodified lines | |||
| 40 | { | 41 | { |
| 41 | struct virtio_gpu_fence *fence = to_virtio_fence(f); | 42 | struct virtio_gpu_fence *fence = to_virtio_fence(f); |
| 42 | 43 | ||
| 43 | if (atomic64_read(&fence->drv->last_seq) >= fence->seq) | 44 | if (atomic64_read(&fence->drv->last_seq) >= fence->f.seqno) |
| 44 | return true; | 45 | return true; |
| 45 | return false; | 46 | return false; |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | static void virtio_fence_value_str(struct dma_fence *f, char *str, int size) | 49 | static void virtio_fence_value_str(struct dma_fence *f, char *str, int size) |
| 49 | { | 50 | { |
| 50 | struct virtio_gpu_fence *fence = to_virtio_fence(f); | 51 | snprintf(str, size, "%llu", f->seqno); |
| 51 | |||
| 52 | snprintf(str, size, "%llu", fence->seq); | ||
| 53 | } | 52 | } |
| 54 | 53 | ||
| 55 | static void virtio_timeline_value_str(struct dma_fence *f, char *str, int size) | 54 | static void virtio_timeline_value_str(struct dma_fence *f, char *str, int size) |
| @@ -71,17 +70,22 @@ struct virtio_gpu_fence *virtio_gpu_fence_alloc(struct virtio_gpu_device *vgdev) · 15 unmodified lines | |||
| 71 | { | 70 | { |
| 72 | struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; | 71 | struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; |
| 73 | struct virtio_gpu_fence *fence = kzalloc(sizeof(struct virtio_gpu_fence), | 72 | struct virtio_gpu_fence *fence = kzalloc(sizeof(struct virtio_gpu_fence), |
| 74 | GFP_ATOMIC); | 73 | GFP_KERNEL); |
| 75 | if (!fence) | 74 | if (!fence) |
| 76 | return fence; | 75 | return fence; |
| 77 | 76 | ||
| 78 | fence->drv = drv; | 77 | fence->drv = drv; |
| 78 | |||
| 79 | /* This only partially initializes the fence because the seqno is | ||
| 80 | * unknown yet. The fence must not be used outside of the driver | ||
| 81 | * until virtio_gpu_fence_emit is called. | ||
| 82 | */ | ||
| 79 | dma_fence_init(&fence->f, &virtio_fence_ops, &drv->lock, drv->context, 0); | 83 | dma_fence_init(&fence->f, &virtio_fence_ops, &drv->lock, drv->context, 0); |
| 80 | 84 | ||
| 81 | return fence; | 85 | return fence; |
| 82 | } | 86 | } |
| 83 | 87 | ||
| 84 | int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, | 88 | void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, |
| 85 | struct virtio_gpu_ctrl_hdr *cmd_hdr, | 89 | struct virtio_gpu_ctrl_hdr *cmd_hdr, |
| 86 | struct virtio_gpu_fence *fence) | 90 | struct virtio_gpu_fence *fence) |
| 87 | { | 91 | { |
| @@ -89,14 +93,15 @@ int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, · 1 unmodified line | |||
| 89 | unsigned long irq_flags; | 93 | unsigned long irq_flags; |
| 90 | 94 | ||
| 91 | spin_lock_irqsave(&drv->lock, irq_flags); | 95 | spin_lock_irqsave(&drv->lock, irq_flags); |
| 92 | fence->seq = ++drv->sync_seq; | 96 | fence->f.seqno = ++drv->sync_seq; |
| 93 | dma_fence_get(&fence->f); | 97 | dma_fence_get(&fence->f); |
| 94 | list_add_tail(&fence->node, &drv->fences); | 98 | list_add_tail(&fence->node, &drv->fences); |
| 95 | spin_unlock_irqrestore(&drv->lock, irq_flags); | 99 | spin_unlock_irqrestore(&drv->lock, irq_flags); |
| 96 | 100 | ||
| 101 | trace_dma_fence_emit(&fence->f); | ||
| 102 | |||
| 97 | cmd_hdr->flags |= cpu_to_le32(VIRTIO_GPU_FLAG_FENCE); | 103 | cmd_hdr->flags |= cpu_to_le32(VIRTIO_GPU_FLAG_FENCE); |
| 98 | cmd_hdr->fence_id = cpu_to_le64(fence->seq); | 104 | cmd_hdr->fence_id = cpu_to_le64(fence->f.seqno); |
| 99 | return 0; | ||
| 100 | } | 105 | } |
| 101 | 106 | ||
| 102 | void virtio_gpu_fence_event_process(struct virtio_gpu_device *vgdev, | 107 | void virtio_gpu_fence_event_process(struct virtio_gpu_device *vgdev, |
| @@ -109,7 +114,7 @@ void virtio_gpu_fence_event_process(struct virtio_gpu_device *vgdev, · 6 unmodified lines | |||
| 109 | spin_lock_irqsave(&drv->lock, irq_flags); | 114 | spin_lock_irqsave(&drv->lock, irq_flags); |
| 110 | atomic64_set(&vgdev->fence_drv.last_seq, last_seq); | 115 | atomic64_set(&vgdev->fence_drv.last_seq, last_seq); |
| 111 | list_for_each_entry_safe(fence, tmp, &drv->fences, node) { | 116 | list_for_each_entry_safe(fence, tmp, &drv->fences, node) { |
| 112 | if (last_seq < fence->seq) | 117 | if (last_seq < fence->f.seqno) |
| 113 | continue; | 118 | continue; |
| 114 | dma_fence_signal_locked(&fence->f); | 119 | dma_fence_signal_locked(&fence->f); |
| 115 | list_del(&fence->node); | 120 | list_del(&fence->node); |
| @@ -553,34 +553,34 @@ copy_exit: · 552 unmodified lines | |||
| 553 | 553 | ||
| 554 | struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { | 554 | struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = { |
| 555 | DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl, | 555 | DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl, |
| 556 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 556 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 557 | 557 | ||
| 558 | DRM_IOCTL_DEF_DRV(VIRTGPU_EXECBUFFER, virtio_gpu_execbuffer_ioctl, | 558 | DRM_IOCTL_DEF_DRV(VIRTGPU_EXECBUFFER, virtio_gpu_execbuffer_ioctl, |
| 559 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 559 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 560 | 560 | ||
| 561 | DRM_IOCTL_DEF_DRV(VIRTGPU_GETPARAM, virtio_gpu_getparam_ioctl, | 561 | DRM_IOCTL_DEF_DRV(VIRTGPU_GETPARAM, virtio_gpu_getparam_ioctl, |
| 562 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 562 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 563 | 563 | ||
| 564 | DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE, | 564 | DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE, |
| 565 | virtio_gpu_resource_create_ioctl, | 565 | virtio_gpu_resource_create_ioctl, |
| 566 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 566 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 567 | 567 | ||
| 568 | DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_INFO, virtio_gpu_resource_info_ioctl, | 568 | DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_INFO, virtio_gpu_resource_info_ioctl, |
| 569 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 569 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 570 | 570 | ||
| 571 | /* make transfer async to the main ring? - no sure, can we | 571 | /* make transfer async to the main ring? - no sure, can we |
| 572 | * thread these in the underlying GL | 572 | * thread these in the underlying GL |
| 573 | */ | 573 | */ |
| 574 | DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST, | 574 | DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST, |
| 575 | virtio_gpu_transfer_from_host_ioctl, | 575 | virtio_gpu_transfer_from_host_ioctl, |
| 576 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 576 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 577 | DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_TO_HOST, | 577 | DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_TO_HOST, |
| 578 | virtio_gpu_transfer_to_host_ioctl, | 578 | virtio_gpu_transfer_to_host_ioctl, |
| 579 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 579 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 580 | 580 | ||
| 581 | DRM_IOCTL_DEF_DRV(VIRTGPU_WAIT, virtio_gpu_wait_ioctl, | 581 | DRM_IOCTL_DEF_DRV(VIRTGPU_WAIT, virtio_gpu_wait_ioctl, |
| 582 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 582 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 583 | 583 | ||
| 584 | DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl, | 584 | DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl, |
| 585 | DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), | 585 | DRM_AUTH | DRM_RENDER_ALLOW), |
| 586 | }; | 586 | }; |
| @@ -0,0 +1,52 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #if !defined(_VIRTGPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) | ||
| 3 | #define _VIRTGPU_TRACE_H_ | ||
| 4 | |||
| 5 | #include <linux/tracepoint.h> | ||
| 6 | |||
| 7 | #undef TRACE_SYSTEM | ||
| 8 | #define TRACE_SYSTEM virtio_gpu | ||
| 9 | #define TRACE_INCLUDE_FILE virtgpu_trace | ||
| 10 | |||
| 11 | DECLARE_EVENT_CLASS(virtio_gpu_cmd, | ||
| 12 | TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr), | ||
| 13 | TP_ARGS(vq, hdr), | ||
| 14 | TP_STRUCT__entry( | ||
| 15 | __field(int, dev) | ||
| 16 | __field(unsigned int, vq) | ||
| 17 | __field(const char *, name) | ||
| 18 | __field(u32, type) | ||
| 19 | __field(u32, flags) | ||
| 20 | __field(u64, fence_id) | ||
| 21 | __field(u32, ctx_id) | ||
| 22 | ), | ||
| 23 | TP_fast_assign( | ||
| 24 | __entry->dev = vq->vdev->index; | ||
| 25 | __entry->vq = vq->index; | ||
| 26 | __entry->name = vq->name; | ||
| 27 | __entry->type = le32_to_cpu(hdr->type); | ||
| 28 | __entry->flags = le32_to_cpu(hdr->flags); | ||
| 29 | __entry->fence_id = le64_to_cpu(hdr->fence_id); | ||
| 30 | __entry->ctx_id = le32_to_cpu(hdr->ctx_id); | ||
| 31 | ), | ||
| 32 | TP_printk("vdev=%d vq=%u name=%s type=0x%x flags=0x%x fence_id=%llu ctx_id=%u", | ||
| 33 | __entry->dev, __entry->vq, __entry->name, | ||
| 34 | __entry->type, __entry->flags, __entry->fence_id, | ||
| 35 | __entry->ctx_id) | ||
| 36 | ); | ||
| 37 | |||
| 38 | DEFINE_EVENT(virtio_gpu_cmd, virtio_gpu_cmd_queue, | ||
| 39 | TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr), | ||
| 40 | TP_ARGS(vq, hdr) | ||
| 41 | ); | ||
| 42 | |||
| 43 | DEFINE_EVENT(virtio_gpu_cmd, virtio_gpu_cmd_response, | ||
| 44 | TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr), | ||
| 45 | TP_ARGS(vq, hdr) | ||
| 46 | ); | ||
| 47 | |||
| 48 | #endif | ||
| 49 | |||
| 50 | #undef TRACE_INCLUDE_PATH | ||
| 51 | #define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/virtio | ||
| 52 | #include <trace/define_trace.h> | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include "virtgpu_drv.h" | ||
| 3 | |||
| 4 | #define CREATE_TRACE_POINTS | ||
| 5 | #include "virtgpu_trace.h" | ||
| @@ -28,6 +28,7 @@ · 27 unmodified lines | |||
| 28 | 28 | ||
| 29 | #include <drm/drmP.h> | 29 | #include <drm/drmP.h> |
| 30 | #include "virtgpu_drv.h" | 30 | #include "virtgpu_drv.h" |
| 31 | #include "virtgpu_trace.h" | ||
| 31 | #include <linux/virtio.h> | 32 | #include <linux/virtio.h> |
| 32 | #include <linux/virtio_config.h> | 33 | #include <linux/virtio_config.h> |
| 33 | #include <linux/virtio_ring.h> | 34 | #include <linux/virtio_ring.h> |
| @@ -192,6 +193,9 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work) · 158 unmodified lines | |||
| 192 | 193 | ||
| 193 | list_for_each_entry_safe(entry, tmp, &reclaim_list, list) { | 194 | list_for_each_entry_safe(entry, tmp, &reclaim_list, list) { |
| 194 | resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf; | 195 | resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf; |
| 196 | |||
| 197 | trace_virtio_gpu_cmd_response(vgdev->ctrlq.vq, resp); | ||
| 198 | |||
| 195 | if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) { | 199 | if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) { |
| 196 | if (resp->type >= cpu_to_le32(VIRTIO_GPU_RESP_ERR_UNSPEC)) { | 200 | if (resp->type >= cpu_to_le32(VIRTIO_GPU_RESP_ERR_UNSPEC)) { |
| 197 | struct virtio_gpu_ctrl_hdr *cmd; | 201 | struct virtio_gpu_ctrl_hdr *cmd; |
| @@ -284,6 +288,9 @@ retry: · 86 unmodified lines | |||
| 284 | spin_lock(&vgdev->ctrlq.qlock); | 288 | spin_lock(&vgdev->ctrlq.qlock); |
| 285 | goto retry; | 289 | goto retry; |
| 286 | } else { | 290 | } else { |
| 291 | trace_virtio_gpu_cmd_queue(vq, | ||
| 292 | (struct virtio_gpu_ctrl_hdr *)vbuf->buf); | ||
| 293 | |||
| 287 | virtqueue_kick(vq); | 294 | virtqueue_kick(vq); |
| 288 | } | 295 | } |
| 289 | 296 | ||
| @@ -359,6 +366,9 @@ retry: · 69 unmodified lines | |||
| 359 | spin_lock(&vgdev->cursorq.qlock); | 366 | spin_lock(&vgdev->cursorq.qlock); |
| 360 | goto retry; | 367 | goto retry; |
| 361 | } else { | 368 | } else { |
| 369 | trace_virtio_gpu_cmd_queue(vq, | ||
| 370 | (struct virtio_gpu_ctrl_hdr *)vbuf->buf); | ||
| 371 | |||
| 362 | virtqueue_kick(vq); | 372 | virtqueue_kick(vq); |
| 363 | } | 373 | } |
| 364 | 374 | ||
| @@ -83,26 +83,6 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, · 82 unmodified lines | |||
| 83 | return true; | 83 | return true; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) | ||
| 87 | { | ||
| 88 | struct vkms_crtc_state *vkms_state = NULL; | ||
| 89 | |||
| 90 | if (crtc->state) { | ||
| 91 | vkms_state = to_vkms_crtc_state(crtc->state); | ||
| 92 | __drm_atomic_helper_crtc_destroy_state(crtc->state); | ||
| 93 | kfree(vkms_state); | ||
| 94 | crtc->state = NULL; | ||
| 95 | } | ||
| 96 | |||
| 97 | vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); | ||
| 98 | if (!vkms_state) | ||
| 99 | return; | ||
| 100 | INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle); | ||
| 101 | |||
| 102 | crtc->state = &vkms_state->base; | ||
| 103 | crtc->state->crtc = crtc; | ||
| 104 | } | ||
| 105 | |||
| 106 | static struct drm_crtc_state * | 86 | static struct drm_crtc_state * |
| 107 | vkms_atomic_crtc_duplicate_state(struct drm_crtc *crtc) | 87 | vkms_atomic_crtc_duplicate_state(struct drm_crtc *crtc) |
| 108 | { | 88 | { |
| @@ -135,6 +115,19 @@ static void vkms_atomic_crtc_destroy_state(struct drm_crtc *crtc, · 26 unmodified lines | |||
| 135 | } | 115 | } |
| 136 | } | 116 | } |
| 137 | 117 | ||
| 118 | static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) | ||
| 119 | { | ||
| 120 | struct vkms_crtc_state *vkms_state = | ||
| 121 | kzalloc(sizeof(*vkms_state), GFP_KERNEL); | ||
| 122 | |||
| 123 | if (crtc->state) | ||
| 124 | vkms_atomic_crtc_destroy_state(crtc, crtc->state); | ||
| 125 | |||
| 126 | __drm_atomic_helper_crtc_reset(crtc, &vkms_state->base); | ||
| 127 | if (vkms_state) | ||
| 128 | INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle); | ||
| 129 | } | ||
| 130 | |||
| 138 | static const struct drm_crtc_funcs vkms_crtc_funcs = { | 131 | static const struct drm_crtc_funcs vkms_crtc_funcs = { |
| 139 | .set_config = drm_atomic_helper_set_config, | 132 | .set_config = drm_atomic_helper_set_config, |
| 140 | .destroy = drm_crtc_cleanup, | 133 | .destroy = drm_crtc_cleanup, |
| @@ -199,7 +199,6 @@ static void zx_vl_plane_atomic_update(struct drm_plane *plane, · 198 unmodified lines | |||
| 199 | u32 dst_x, dst_y, dst_w, dst_h; | 199 | u32 dst_x, dst_y, dst_w, dst_h; |
| 200 | uint32_t format; | 200 | uint32_t format; |
| 201 | int fmt; | 201 | int fmt; |
| 202 | int num_planes; | ||
| 203 | int i; | 202 | int i; |
| 204 | 203 | ||
| 205 | if (!fb) | 204 | if (!fb) |
| @@ -218,13 +217,12 @@ static void zx_vl_plane_atomic_update(struct drm_plane *plane, · 12 unmodified lines | |||
| 218 | dst_h = drm_rect_height(dst); | 217 | dst_h = drm_rect_height(dst); |
| 219 | 218 | ||
| 220 | /* Set up data address registers for Y, Cb and Cr planes */ | 219 | /* Set up data address registers for Y, Cb and Cr planes */ |
| 221 | num_planes = drm_format_num_planes(format); | ||
| 222 | paddr_reg = layer + VL_Y; | 220 | paddr_reg = layer + VL_Y; |
| 223 | for (i = 0; i < num_planes; i++) { | 221 | for (i = 0; i < fb->format->num_planes; i++) { |
| 224 | cma_obj = drm_fb_cma_get_gem_obj(fb, i); | 222 | cma_obj = drm_fb_cma_get_gem_obj(fb, i); |
| 225 | paddr = cma_obj->paddr + fb->offsets[i]; | 223 | paddr = cma_obj->paddr + fb->offsets[i]; |
| 226 | paddr += src_y * fb->pitches[i]; | 224 | paddr += src_y * fb->pitches[i]; |
| 227 | paddr += src_x * drm_format_plane_cpp(format, i); | 225 | paddr += src_x * fb->format->cpp[i]; |
| 228 | zx_writel(paddr_reg, paddr); | 226 | zx_writel(paddr_reg, paddr); |
| 229 | paddr_reg += 4; | 227 | paddr_reg += 4; |
| 230 | } | 228 | } |
| @@ -650,6 +650,150 @@ hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *fram · 649 unmodified lines | |||
| 650 | return 0; | 650 | return 0; |
| 651 | } | 651 | } |
| 652 | 652 | ||
| 653 | /** | ||
| 654 | * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and | ||
| 655 | * mastering infoframe | ||
| 656 | * @frame: HDMI DRM infoframe | ||
| 657 | * | ||
| 658 | * Returns 0 on success or a negative error code on failure. | ||
| 659 | */ | ||
| 660 | int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame) | ||
| 661 | { | ||
| 662 | memset(frame, 0, sizeof(*frame)); | ||
| 663 | |||
| 664 | frame->type = HDMI_INFOFRAME_TYPE_DRM; | ||
| 665 | frame->version = 1; | ||
| 666 | frame->length = HDMI_DRM_INFOFRAME_SIZE; | ||
| 667 | |||
| 668 | return 0; | ||
| 669 | } | ||
| 670 | EXPORT_SYMBOL(hdmi_drm_infoframe_init); | ||
| 671 | |||
| 672 | static int hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe *frame) | ||
| 673 | { | ||
| 674 | if (frame->type != HDMI_INFOFRAME_TYPE_DRM || | ||
| 675 | frame->version != 1) | ||
| 676 | return -EINVAL; | ||
| 677 | |||
| 678 | if (frame->length != HDMI_DRM_INFOFRAME_SIZE) | ||
| 679 | return -EINVAL; | ||
| 680 | |||
| 681 | return 0; | ||
| 682 | } | ||
| 683 | |||
| 684 | /** | ||
| 685 | * hdmi_drm_infoframe_check() - check a HDMI DRM infoframe | ||
| 686 | * @frame: HDMI DRM infoframe | ||
| 687 | * | ||
| 688 | * Validates that the infoframe is consistent. | ||
| 689 | * Returns 0 on success or a negative error code on failure. | ||
| 690 | */ | ||
| 691 | int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame) | ||
| 692 | { | ||
| 693 | return hdmi_drm_infoframe_check_only(frame); | ||
| 694 | } | ||
| 695 | EXPORT_SYMBOL(hdmi_drm_infoframe_check); | ||
| 696 | |||
| 697 | /** | ||
| 698 | * hdmi_drm_infoframe_pack_only() - write HDMI DRM infoframe to binary buffer | ||
| 699 | * @frame: HDMI DRM infoframe | ||
| 700 | * @buffer: destination buffer | ||
| 701 | * @size: size of buffer | ||
| 702 | * | ||
| 703 | * Packs the information contained in the @frame structure into a binary | ||
| 704 | * representation that can be written into the corresponding controller | ||
| 705 | * registers. Also computes the checksum as required by section 5.3.5 of | ||
| 706 | * the HDMI 1.4 specification. | ||
| 707 | * | ||
| 708 | * Returns the number of bytes packed into the binary buffer or a negative | ||
| 709 | * error code on failure. | ||
| 710 | */ | ||
| 711 | ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame, | ||
| 712 | void *buffer, size_t size) | ||
| 713 | { | ||
| 714 | u8 *ptr = buffer; | ||
| 715 | size_t length; | ||
| 716 | int i; | ||
| 717 | |||
| 718 | length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; | ||
| 719 | |||
| 720 | if (size < length) | ||
| 721 | return -ENOSPC; | ||
| 722 | |||
| 723 | memset(buffer, 0, size); | ||
| 724 | |||
| 725 | ptr[0] = frame->type; | ||
| 726 | ptr[1] = frame->version; | ||
| 727 | ptr[2] = frame->length; | ||
| 728 | ptr[3] = 0; /* checksum */ | ||
| 729 | |||
| 730 | /* start infoframe payload */ | ||
| 731 | ptr += HDMI_INFOFRAME_HEADER_SIZE; | ||
| 732 | |||
| 733 | *ptr++ = frame->eotf; | ||
| 734 | *ptr++ = frame->metadata_type; | ||
| 735 | |||
| 736 | for (i = 0; i < 3; i++) { | ||
| 737 | *ptr++ = frame->display_primaries[i].x; | ||
| 738 | *ptr++ = frame->display_primaries[i].x >> 8; | ||
| 739 | *ptr++ = frame->display_primaries[i].y; | ||
| 740 | *ptr++ = frame->display_primaries[i].y >> 8; | ||
| 741 | } | ||
| 742 | |||
| 743 | *ptr++ = frame->white_point.x; | ||
| 744 | *ptr++ = frame->white_point.x >> 8; | ||
| 745 | |||
| 746 | *ptr++ = frame->white_point.y; | ||
| 747 | *ptr++ = frame->white_point.y >> 8; | ||
| 748 | |||
| 749 | *ptr++ = frame->max_display_mastering_luminance; | ||
| 750 | *ptr++ = frame->max_display_mastering_luminance >> 8; | ||
| 751 | |||
| 752 | *ptr++ = frame->min_display_mastering_luminance; | ||
| 753 | *ptr++ = frame->min_display_mastering_luminance >> 8; | ||
| 754 | |||
| 755 | *ptr++ = frame->max_cll; | ||
| 756 | *ptr++ = frame->max_cll >> 8; | ||
| 757 | |||
| 758 | *ptr++ = frame->max_fall; | ||
| 759 | *ptr++ = frame->max_fall >> 8; | ||
| 760 | |||
| 761 | hdmi_infoframe_set_checksum(buffer, length); | ||
| 762 | |||
| 763 | return length; | ||
| 764 | } | ||
| 765 | EXPORT_SYMBOL(hdmi_drm_infoframe_pack_only); | ||
| 766 | |||
| 767 | /** | ||
| 768 | * hdmi_drm_infoframe_pack() - check a HDMI DRM infoframe, | ||
| 769 | * and write it to binary buffer | ||
| 770 | * @frame: HDMI DRM infoframe | ||
| 771 | * @buffer: destination buffer | ||
| 772 | * @size: size of buffer | ||
| 773 | * | ||
| 774 | * Validates that the infoframe is consistent and updates derived fields | ||
| 775 | * (eg. length) based on other fields, after which it packs the information | ||
| 776 | * contained in the @frame structure into a binary representation that | ||
| 777 | * can be written into the corresponding controller registers. This function | ||
| 778 | * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 | ||
| 779 | * specification. | ||
| 780 | * | ||
| 781 | * Returns the number of bytes packed into the binary buffer or a negative | ||
| 782 | * error code on failure. | ||
| 783 | */ | ||
| 784 | ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, | ||
| 785 | void *buffer, size_t size) | ||
| 786 | { | ||
| 787 | int ret; | ||
| 788 | |||
| 789 | ret = hdmi_drm_infoframe_check(frame); | ||
| 790 | if (ret) | ||
| 791 | return ret; | ||
| 792 | |||
| 793 | return hdmi_drm_infoframe_pack_only(frame, buffer, size); | ||
| 794 | } | ||
| 795 | EXPORT_SYMBOL(hdmi_drm_infoframe_pack); | ||
| 796 | |||
| 653 | /* | 797 | /* |
| 654 | * hdmi_vendor_any_infoframe_check() - check a vendor infoframe | 798 | * hdmi_vendor_any_infoframe_check() - check a vendor infoframe |
| 655 | */ | 799 | */ |
| @@ -758,6 +902,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t · 102 unmodified lines | |||
| 758 | length = hdmi_avi_infoframe_pack_only(&frame->avi, | 902 | length = hdmi_avi_infoframe_pack_only(&frame->avi, |
| 759 | buffer, size); | 903 | buffer, size); |
| 760 | break; | 904 | break; |
| 905 | case HDMI_INFOFRAME_TYPE_DRM: | ||
| 906 | length = hdmi_drm_infoframe_pack_only(&frame->drm, | ||
| 907 | buffer, size); | ||
| 908 | break; | ||
| 761 | case HDMI_INFOFRAME_TYPE_SPD: | 909 | case HDMI_INFOFRAME_TYPE_SPD: |
| 762 | length = hdmi_spd_infoframe_pack_only(&frame->spd, | 910 | length = hdmi_spd_infoframe_pack_only(&frame->spd, |
| 763 | buffer, size); | 911 | buffer, size); |
| @@ -806,6 +954,9 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, · 42 unmodified lines | |||
| 806 | case HDMI_INFOFRAME_TYPE_AVI: | 954 | case HDMI_INFOFRAME_TYPE_AVI: |
| 807 | length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size); | 955 | length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size); |
| 808 | break; | 956 | break; |
| 957 | case HDMI_INFOFRAME_TYPE_DRM: | ||
| 958 | length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size); | ||
| 959 | break; | ||
| 809 | case HDMI_INFOFRAME_TYPE_SPD: | 960 | case HDMI_INFOFRAME_TYPE_SPD: |
| 810 | length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size); | 961 | length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size); |
| 811 | break; | 962 | break; |
| @@ -838,6 +989,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type) · 26 unmodified lines | |||
| 838 | return "Source Product Description (SPD)"; | 989 | return "Source Product Description (SPD)"; |
| 839 | case HDMI_INFOFRAME_TYPE_AUDIO: | 990 | case HDMI_INFOFRAME_TYPE_AUDIO: |
| 840 | return "Audio"; | 991 | return "Audio"; |
| 992 | case HDMI_INFOFRAME_TYPE_DRM: | ||
| 993 | return "Dynamic Range and Mastering"; | ||
| 841 | } | 994 | } |
| 842 | return "Reserved"; | 995 | return "Reserved"; |
| 843 | } | 996 | } |
| @@ -1284,6 +1437,40 @@ static void hdmi_audio_infoframe_log(const char *level, · 440 unmodified lines | |||
| 1284 | frame->downmix_inhibit ? "Yes" : "No"); | 1437 | frame->downmix_inhibit ? "Yes" : "No"); |
| 1285 | } | 1438 | } |
| 1286 | 1439 | ||
| 1440 | /** | ||
| 1441 | * hdmi_drm_infoframe_log() - log info of HDMI DRM infoframe | ||
| 1442 | * @level: logging level | ||
| 1443 | * @dev: device | ||
| 1444 | * @frame: HDMI DRM infoframe | ||
| 1445 | */ | ||
| 1446 | static void hdmi_drm_infoframe_log(const char *level, | ||
| 1447 | struct device *dev, | ||
| 1448 | const struct hdmi_drm_infoframe *frame) | ||
| 1449 | { | ||
| 1450 | int i; | ||
| 1451 | |||
| 1452 | hdmi_infoframe_log_header(level, dev, | ||
| 1453 | (struct hdmi_any_infoframe *)frame); | ||
| 1454 | hdmi_log("length: %d\n", frame->length); | ||
| 1455 | hdmi_log("metadata type: %d\n", frame->metadata_type); | ||
| 1456 | hdmi_log("eotf: %d\n", frame->eotf); | ||
| 1457 | for (i = 0; i < 3; i++) { | ||
| 1458 | hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x); | ||
| 1459 | hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y); | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | hdmi_log("white point x: %d\n", frame->white_point.x); | ||
| 1463 | hdmi_log("white point y: %d\n", frame->white_point.y); | ||
| 1464 | |||
| 1465 | hdmi_log("max_display_mastering_luminance: %d\n", | ||
| 1466 | frame->max_display_mastering_luminance); | ||
| 1467 | hdmi_log("min_display_mastering_luminance: %d\n", | ||
| 1468 | frame->min_display_mastering_luminance); | ||
| 1469 | |||
| 1470 | hdmi_log("max_cll: %d\n", frame->max_cll); | ||
| 1471 | hdmi_log("max_fall: %d\n", frame->max_fall); | ||
| 1472 | } | ||
| 1473 | |||
| 1287 | static const char * | 1474 | static const char * |
| 1288 | hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) | 1475 | hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) |
| 1289 | { | 1476 | { |
| @@ -1372,6 +1559,9 @@ void hdmi_infoframe_log(const char *level, · 82 unmodified lines | |||
| 1372 | case HDMI_INFOFRAME_TYPE_VENDOR: | 1559 | case HDMI_INFOFRAME_TYPE_VENDOR: |
| 1373 | hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor); | 1560 | hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor); |
| 1374 | break; | 1561 | break; |
| 1562 | case HDMI_INFOFRAME_TYPE_DRM: | ||
| 1563 | hdmi_drm_infoframe_log(level, dev, &frame->drm); | ||
| 1564 | break; | ||
| 1375 | } | 1565 | } |
| 1376 | } | 1566 | } |
| 1377 | EXPORT_SYMBOL(hdmi_infoframe_log); | 1567 | EXPORT_SYMBOL(hdmi_infoframe_log); |
| @@ -1614,6 +1804,70 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, · 236 unmodified lines | |||
| 1614 | return 0; | 1804 | return 0; |
| 1615 | } | 1805 | } |
| 1616 | 1806 | ||
| 1807 | /** | ||
| 1808 | * hdmi_drm_infoframe_unpack() - unpack binary buffer to a HDMI DRM infoframe | ||
| 1809 | * @frame: HDMI DRM infoframe | ||
| 1810 | * @buffer: source buffer | ||
| 1811 | * @size: size of buffer | ||
| 1812 | * | ||
| 1813 | * Unpacks the information contained in binary @buffer into a structured | ||
| 1814 | * @frame of the HDMI Dynamic Range and Mastering (DRM) information frame. | ||
| 1815 | * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4 | ||
| 1816 | * specification. | ||
| 1817 | * | ||
| 1818 | * Returns 0 on success or a negative error code on failure. | ||
| 1819 | */ | ||
| 1820 | static int hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame, | ||
| 1821 | const void *buffer, size_t size) | ||
| 1822 | { | ||
| 1823 | const u8 *ptr = buffer; | ||
| 1824 | const u8 *temp; | ||
| 1825 | u8 x_lsb, x_msb; | ||
| 1826 | u8 y_lsb, y_msb; | ||
| 1827 | int ret; | ||
| 1828 | int i; | ||
| 1829 | |||
| 1830 | if (size < HDMI_INFOFRAME_SIZE(DRM)) | ||
| 1831 | return -EINVAL; | ||
| 1832 | |||
| 1833 | if (ptr[0] != HDMI_INFOFRAME_TYPE_DRM || | ||
| 1834 | ptr[1] != 1 || | ||
| 1835 | ptr[2] != HDMI_DRM_INFOFRAME_SIZE) | ||
| 1836 | return -EINVAL; | ||
| 1837 | |||
| 1838 | if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(DRM)) != 0) | ||
| 1839 | return -EINVAL; | ||
| 1840 | |||
| 1841 | ret = hdmi_drm_infoframe_init(frame); | ||
| 1842 | if (ret) | ||
| 1843 | return ret; | ||
| 1844 | |||
| 1845 | ptr += HDMI_INFOFRAME_HEADER_SIZE; | ||
| 1846 | |||
| 1847 | frame->eotf = ptr[0] & 0x7; | ||
| 1848 | frame->metadata_type = ptr[1] & 0x7; | ||
| 1849 | |||
| 1850 | temp = ptr + 2; | ||
| 1851 | for (i = 0; i < 3; i++) { | ||
| 1852 | x_lsb = *temp++; | ||
| 1853 | x_msb = *temp++; | ||
| 1854 | frame->display_primaries[i].x = (x_msb << 8) | x_lsb; | ||
| 1855 | y_lsb = *temp++; | ||
| 1856 | y_msb = *temp++; | ||
| 1857 | frame->display_primaries[i].y = (y_msb << 8) | y_lsb; | ||
| 1858 | } | ||
| 1859 | |||
| 1860 | frame->white_point.x = (ptr[15] << 8) | ptr[14]; | ||
| 1861 | frame->white_point.y = (ptr[17] << 8) | ptr[16]; | ||
| 1862 | |||
| 1863 | frame->max_display_mastering_luminance = (ptr[19] << 8) | ptr[18]; | ||
| 1864 | frame->min_display_mastering_luminance = (ptr[21] << 8) | ptr[20]; | ||
| 1865 | frame->max_cll = (ptr[23] << 8) | ptr[22]; | ||
| 1866 | frame->max_fall = (ptr[25] << 8) | ptr[24]; | ||
| 1867 | |||
| 1868 | return 0; | ||
| 1869 | } | ||
| 1870 | |||
| 1617 | /** | 1871 | /** |
| 1618 | * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe | 1872 | * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe |
| 1619 | * @frame: HDMI infoframe | 1873 | * @frame: HDMI infoframe |
| @@ -1640,6 +1894,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, · 20 unmodified lines | |||
| 1640 | case HDMI_INFOFRAME_TYPE_AVI: | 1894 | case HDMI_INFOFRAME_TYPE_AVI: |
| 1641 | ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size); | 1895 | ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size); |
| 1642 | break; | 1896 | break; |
| 1897 | case HDMI_INFOFRAME_TYPE_DRM: | ||
| 1898 | ret = hdmi_drm_infoframe_unpack(&frame->drm, buffer, size); | ||
| 1899 | break; | ||
| 1643 | case HDMI_INFOFRAME_TYPE_SPD: | 1900 | case HDMI_INFOFRAME_TYPE_SPD: |
| 1644 | ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size); | 1901 | ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size); |
| 1645 | break; | 1902 | break; |
| @@ -37,6 +37,8 @@ struct drm_private_state; · 36 unmodified lines | |||
| 37 | struct drm_modeset_acquire_ctx; | 37 | struct drm_modeset_acquire_ctx; |
| 38 | struct drm_device; | 38 | struct drm_device; |
| 39 | 39 | ||
| 40 | void __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, | ||
| 41 | struct drm_crtc_state *state); | ||
| 40 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); | 42 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); |
| 41 | void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, | 43 | void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, |
| 42 | struct drm_crtc_state *state); | 44 | struct drm_crtc_state *state); |
| @@ -517,6 +517,10 @@ struct drm_connector_state { · 516 unmodified lines | |||
| 517 | * Used by the atomic helpers to select the encoder, through the | 517 | * Used by the atomic helpers to select the encoder, through the |
| 518 | * &drm_connector_helper_funcs.atomic_best_encoder or | 518 | * &drm_connector_helper_funcs.atomic_best_encoder or |
| 519 | * &drm_connector_helper_funcs.best_encoder callbacks. | 519 | * &drm_connector_helper_funcs.best_encoder callbacks. |
| 520 | * | ||
| 521 | * NOTE: Atomic drivers must fill this out (either themselves or through | ||
| 522 | * helpers), for otherwise the GETCONNECTOR and GETENCODER IOCTLs will | ||
| 523 | * not return correct data to userspace. | ||
| 520 | */ | 524 | */ |
| 521 | struct drm_encoder *best_encoder; | 525 | struct drm_encoder *best_encoder; |
| 522 | 526 | ||
| @@ -599,6 +603,12 @@ struct drm_connector_state { · 76 unmodified lines | |||
| 599 | * and the connector bpc limitations obtained from edid. | 603 | * and the connector bpc limitations obtained from edid. |
| 600 | */ | 604 | */ |
| 601 | u8 max_bpc; | 605 | u8 max_bpc; |
| 606 | |||
| 607 | /** | ||
| 608 | * @hdr_output_metadata: | ||
| 609 | * DRM blob property for HDR output metadata | ||
| 610 | */ | ||
| 611 | struct drm_property_blob *hdr_output_metadata; | ||
| 602 | }; | 612 | }; |
| 603 | 613 | ||
| 604 | /** | 614 | /** |
| @@ -1239,6 +1249,10 @@ struct drm_connector { · 634 unmodified lines | |||
| 1239 | * &drm_mode_config.connector_free_work. | 1249 | * &drm_mode_config.connector_free_work. |
| 1240 | */ | 1250 | */ |
| 1241 | struct llist_node free_node; | 1251 | struct llist_node free_node; |
| 1252 | |||
| 1253 | /* HDR metdata */ | ||
| 1254 | struct hdr_output_metadata hdr_output_metadata; | ||
| 1255 | struct hdr_sink_metadata hdr_sink_metadata; | ||
| 1242 | }; | 1256 | }; |
| 1243 | 1257 | ||
| 1244 | #define obj_to_connector(x) container_of(x, struct drm_connector, base) | 1258 | #define obj_to_connector(x) container_of(x, struct drm_connector, base) |
| @@ -17,6 +17,7 @@ struct drm_vblank_crtc; · 16 unmodified lines | |||
| 17 | struct drm_sg_mem; | 17 | struct drm_sg_mem; |
| 18 | struct drm_local_map; | 18 | struct drm_local_map; |
| 19 | struct drm_vma_offset_manager; | 19 | struct drm_vma_offset_manager; |
| 20 | struct drm_vram_mm; | ||
| 20 | struct drm_fb_helper; | 21 | struct drm_fb_helper; |
| 21 | 22 | ||
| 22 | struct inode; | 23 | struct inode; |
| @@ -286,6 +287,9 @@ struct drm_device { · 263 unmodified lines | |||
| 286 | /** @vma_offset_manager: GEM information */ | 287 | /** @vma_offset_manager: GEM information */ |
| 287 | struct drm_vma_offset_manager *vma_offset_manager; | 288 | struct drm_vma_offset_manager *vma_offset_manager; |
| 288 | 289 | ||
| 290 | /** @vram_mm: VRAM MM memory manager */ | ||
| 291 | struct drm_vram_mm *vram_mm; | ||
| 292 | |||
| 289 | /** | 293 | /** |
| 290 | * @switch_power_state: | 294 | * @switch_power_state: |
| 291 | * | 295 | * |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
| 27 | #include <linux/hdmi.h> | 27 | #include <linux/hdmi.h> |
| 28 | #include <drm/drm_mode.h> | ||
| 28 | 29 | ||
| 29 | struct drm_device; | 30 | struct drm_device; |
| 30 | struct i2c_adapter; | 31 | struct i2c_adapter; |
| @@ -370,6 +371,10 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, · 339 unmodified lines | |||
| 370 | const struct drm_display_mode *mode, | 371 | const struct drm_display_mode *mode, |
| 371 | enum hdmi_quantization_range rgb_quant_range); | 372 | enum hdmi_quantization_range rgb_quant_range); |
| 372 | 373 | ||
| 374 | int | ||
| 375 | drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, | ||
| 376 | const struct drm_connector_state *conn_state); | ||
| 377 | |||
| 373 | /** | 378 | /** |
| 374 | * drm_eld_mnl - Get ELD monitor name length in bytes. | 379 | * drm_eld_mnl - Get ELD monitor name length in bytes. |
| 375 | * @eld: pointer to an eld memory structure with mnl set | 380 | * @eld: pointer to an eld memory structure with mnl set |
| @@ -49,9 +49,6 @@ struct drm_fb_offset { · 48 unmodified lines | |||
| 49 | 49 | ||
| 50 | struct drm_fb_helper_crtc { | 50 | struct drm_fb_helper_crtc { |
| 51 | struct drm_mode_set mode_set; | 51 | struct drm_mode_set mode_set; |
| 52 | struct drm_display_mode *desired_mode; | ||
| 53 | int x, y; | ||
| 54 | int rotation; | ||
| 55 | }; | 52 | }; |
| 56 | 53 | ||
| 57 | /** | 54 | /** |
| @@ -151,13 +148,6 @@ struct drm_fb_helper { · 93 unmodified lines | |||
| 151 | struct drm_fb_helper_crtc *crtc_info; | 148 | struct drm_fb_helper_crtc *crtc_info; |
| 152 | int connector_count; | 149 | int connector_count; |
| 153 | int connector_info_alloc_count; | 150 | int connector_info_alloc_count; |
| 154 | /** | ||
| 155 | * @sw_rotations: | ||
| 156 | * Bitmask of all rotations requested for panel-orientation which | ||
| 157 | * could not be handled in hardware. If only one bit is set | ||
| 158 | * fbdev->fbcon_rotate_hint gets set to the requested rotation. | ||
| 159 | */ | ||
| 160 | int sw_rotations; | ||
| 161 | /** | 151 | /** |
| 162 | * @connector_info: | 152 | * @connector_info: |
| 163 | * | 153 | * |
| @@ -260,6 +260,50 @@ drm_format_info_is_yuv_sampling_444(const struct drm_format_info *info) · 259 unmodified lines | |||
| 260 | return info->is_yuv && info->hsub == 1 && info->vsub == 1; | 260 | return info->is_yuv && info->hsub == 1 && info->vsub == 1; |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | /** | ||
| 264 | * drm_format_info_plane_width - width of the plane given the first plane | ||
| 265 | * @info: pixel format info | ||
| 266 | * @width: width of the first plane | ||
| 267 | * @plane: plane index | ||
| 268 | * | ||
| 269 | * Returns: | ||
| 270 | * The width of @plane, given that the width of the first plane is @width. | ||
| 271 | */ | ||
| 272 | static inline | ||
| 273 | int drm_format_info_plane_width(const struct drm_format_info *info, int width, | ||
| 274 | int plane) | ||
| 275 | { | ||
| 276 | if (!info || plane >= info->num_planes) | ||
| 277 | return 0; | ||
| 278 | |||
| 279 | if (plane == 0) | ||
| 280 | return width; | ||
| 281 | |||
| 282 | return width / info->hsub; | ||
| 283 | } | ||
| 284 | |||
| 285 | /** | ||
| 286 | * drm_format_info_plane_height - height of the plane given the first plane | ||
| 287 | * @info: pixel format info | ||
| 288 | * @height: height of the first plane | ||
| 289 | * @plane: plane index | ||
| 290 | * | ||
| 291 | * Returns: | ||
| 292 | * The height of @plane, given that the height of the first plane is @height. | ||
| 293 | */ | ||
| 294 | static inline | ||
| 295 | int drm_format_info_plane_height(const struct drm_format_info *info, int height, | ||
| 296 | int plane) | ||
| 297 | { | ||
| 298 | if (!info || plane >= info->num_planes) | ||
| 299 | return 0; | ||
| 300 | |||
| 301 | if (plane == 0) | ||
| 302 | return height; | ||
| 303 | |||
| 304 | return height / info->vsub; | ||
| 305 | } | ||
| 306 | |||
| 263 | const struct drm_format_info *__drm_format_info(u32 format); | 307 | const struct drm_format_info *__drm_format_info(u32 format); |
| 264 | const struct drm_format_info *drm_format_info(u32 format); | 308 | const struct drm_format_info *drm_format_info(u32 format); |
| 265 | const struct drm_format_info * | 309 | const struct drm_format_info * |
| @@ -268,12 +312,6 @@ drm_get_format_info(struct drm_device *dev, · 2 unmodified lines | |||
| 268 | uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); | 312 | uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); |
| 269 | uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, | 313 | uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, |
| 270 | uint32_t bpp, uint32_t depth); | 314 | uint32_t bpp, uint32_t depth); |
| 271 | int drm_format_num_planes(uint32_t format); | ||
| 272 | int drm_format_plane_cpp(uint32_t format, int plane); | ||
| 273 | int drm_format_horz_chroma_subsampling(uint32_t format); | ||
| 274 | int drm_format_vert_chroma_subsampling(uint32_t format); | ||
| 275 | int drm_format_plane_width(int width, uint32_t format, int plane); | ||
| 276 | int drm_format_plane_height(int height, uint32_t format, int plane); | ||
| 277 | unsigned int drm_format_info_block_width(const struct drm_format_info *info, | 315 | unsigned int drm_format_info_block_width(const struct drm_format_info *info, |
| 278 | int plane); | 316 | int plane); |
| 279 | unsigned int drm_format_info_block_height(const struct drm_format_info *info, | 317 | unsigned int drm_format_info_block_height(const struct drm_format_info *info, |
| @@ -0,0 +1,162 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 2 | |||
| 3 | #ifndef DRM_GEM_VRAM_HELPER_H | ||
| 4 | #define DRM_GEM_VRAM_HELPER_H | ||
| 5 | |||
| 6 | #include <drm/drm_gem.h> | ||
| 7 | #include <drm/ttm/ttm_bo_api.h> | ||
| 8 | #include <drm/ttm/ttm_placement.h> | ||
| 9 | #include <linux/kernel.h> /* for container_of() */ | ||
| 10 | |||
| 11 | struct drm_mode_create_dumb; | ||
| 12 | struct drm_vram_mm_funcs; | ||
| 13 | struct filp; | ||
| 14 | struct vm_area_struct; | ||
| 15 | |||
| 16 | #define DRM_GEM_VRAM_PL_FLAG_VRAM TTM_PL_FLAG_VRAM | ||
| 17 | #define DRM_GEM_VRAM_PL_FLAG_SYSTEM TTM_PL_FLAG_SYSTEM | ||
| 18 | |||
| 19 | /* | ||
| 20 | * Buffer-object helpers | ||
| 21 | */ | ||
| 22 | |||
| 23 | /** | ||
| 24 | * struct drm_gem_vram_object - GEM object backed by VRAM | ||
| 25 | * @gem: GEM object | ||
| 26 | * @bo: TTM buffer object | ||
| 27 | * @kmap: Mapping information for @bo | ||
| 28 | * @placement: TTM placement information. Supported placements are \ | ||
| 29 | %TTM_PL_VRAM and %TTM_PL_SYSTEM | ||
| 30 | * @placements: TTM placement information. | ||
| 31 | * @pin_count: Pin counter | ||
| 32 | * | ||
| 33 | * The type struct drm_gem_vram_object represents a GEM object that is | ||
| 34 | * backed by VRAM. It can be used for simple framebuffer devices with | ||
| 35 | * dedicated memory. The buffer object can be evicted to system memory if | ||
| 36 | * video memory becomes scarce. | ||
| 37 | */ | ||
| 38 | struct drm_gem_vram_object { | ||
| 39 | struct drm_gem_object gem; | ||
| 40 | struct ttm_buffer_object bo; | ||
| 41 | struct ttm_bo_kmap_obj kmap; | ||
| 42 | |||
| 43 | /* Supported placements are %TTM_PL_VRAM and %TTM_PL_SYSTEM */ | ||
| 44 | struct ttm_placement placement; | ||
| 45 | struct ttm_place placements[2]; | ||
| 46 | |||
| 47 | int pin_count; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Returns the container of type &struct drm_gem_vram_object | ||
| 52 | * for field bo. | ||
| 53 | * @bo: the VRAM buffer object | ||
| 54 | * Returns: The containing GEM VRAM object | ||
| 55 | */ | ||
| 56 | static inline struct drm_gem_vram_object *drm_gem_vram_of_bo( | ||
| 57 | struct ttm_buffer_object *bo) | ||
| 58 | { | ||
| 59 | return container_of(bo, struct drm_gem_vram_object, bo); | ||
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * Returns the container of type &struct drm_gem_vram_object | ||
| 64 | * for field gem. | ||
| 65 | * @gem: the GEM object | ||
| 66 | * Returns: The containing GEM VRAM object | ||
| 67 | */ | ||
| 68 | static inline struct drm_gem_vram_object *drm_gem_vram_of_gem( | ||
| 69 | struct drm_gem_object *gem) | ||
| 70 | { | ||
| 71 | return container_of(gem, struct drm_gem_vram_object, gem); | ||
| 72 | } | ||
| 73 | |||
| 74 | struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, | ||
| 75 | struct ttm_bo_device *bdev, | ||
| 76 | size_t size, | ||
| 77 | unsigned long pg_align, | ||
| 78 | bool interruptible); | ||
| 79 | void drm_gem_vram_put(struct drm_gem_vram_object *gbo); | ||
| 80 | int drm_gem_vram_lock(struct drm_gem_vram_object *gbo, bool no_wait); | ||
| 81 | void drm_gem_vram_unlock(struct drm_gem_vram_object *gbo); | ||
| 82 | u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo); | ||
| 83 | s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo); | ||
| 84 | int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag); | ||
| 85 | int drm_gem_vram_pin_locked(struct drm_gem_vram_object *gbo, | ||
| 86 | unsigned long pl_flag); | ||
| 87 | int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo); | ||
| 88 | int drm_gem_vram_unpin_locked(struct drm_gem_vram_object *gbo); | ||
| 89 | void *drm_gem_vram_kmap_at(struct drm_gem_vram_object *gbo, bool map, | ||
| 90 | bool *is_iomem, struct ttm_bo_kmap_obj *kmap); | ||
| 91 | void *drm_gem_vram_kmap(struct drm_gem_vram_object *gbo, bool map, | ||
| 92 | bool *is_iomem); | ||
| 93 | void drm_gem_vram_kunmap_at(struct drm_gem_vram_object *gbo, | ||
| 94 | struct ttm_bo_kmap_obj *kmap); | ||
| 95 | void drm_gem_vram_kunmap(struct drm_gem_vram_object *gbo); | ||
| 96 | |||
| 97 | int drm_gem_vram_fill_create_dumb(struct drm_file *file, | ||
| 98 | struct drm_device *dev, | ||
| 99 | struct ttm_bo_device *bdev, | ||
| 100 | unsigned long pg_align, | ||
| 101 | bool interruptible, | ||
| 102 | struct drm_mode_create_dumb *args); | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Helpers for struct ttm_bo_driver | ||
| 106 | */ | ||
| 107 | |||
| 108 | void drm_gem_vram_bo_driver_evict_flags(struct ttm_buffer_object *bo, | ||
| 109 | struct ttm_placement *pl); | ||
| 110 | |||
| 111 | int drm_gem_vram_bo_driver_verify_access(struct ttm_buffer_object *bo, | ||
| 112 | struct file *filp); | ||
| 113 | |||
| 114 | extern const struct drm_vram_mm_funcs drm_gem_vram_mm_funcs; | ||
| 115 | |||
| 116 | /* | ||
| 117 | * Helpers for struct drm_driver | ||
| 118 | */ | ||
| 119 | |||
| 120 | void drm_gem_vram_driver_gem_free_object_unlocked(struct drm_gem_object *gem); | ||
| 121 | int drm_gem_vram_driver_dumb_create(struct drm_file *file, | ||
| 122 | struct drm_device *dev, | ||
| 123 | struct drm_mode_create_dumb *args); | ||
| 124 | int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, | ||
| 125 | struct drm_device *dev, | ||
| 126 | uint32_t handle, uint64_t *offset); | ||
| 127 | |||
| 128 | /** | ||
| 129 | * define DRM_GEM_VRAM_DRIVER - default callback functions for \ | ||
| 130 | &struct drm_driver | ||
| 131 | * | ||
| 132 | * Drivers that use VRAM MM and GEM VRAM can use this macro to initialize | ||
| 133 | * &struct drm_driver with default functions. | ||
| 134 | */ | ||
| 135 | #define DRM_GEM_VRAM_DRIVER \ | ||
| 136 | .gem_free_object_unlocked = \ | ||
| 137 | drm_gem_vram_driver_gem_free_object_unlocked, \ | ||
| 138 | .dumb_create = drm_gem_vram_driver_dumb_create, \ | ||
| 139 | .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset | ||
| 140 | |||
| 141 | /* | ||
| 142 | * PRIME helpers for struct drm_driver | ||
| 143 | */ | ||
| 144 | |||
| 145 | int drm_gem_vram_driver_gem_prime_pin(struct drm_gem_object *obj); | ||
| 146 | void drm_gem_vram_driver_gem_prime_unpin(struct drm_gem_object *obj); | ||
| 147 | void *drm_gem_vram_driver_gem_prime_vmap(struct drm_gem_object *obj); | ||
| 148 | void drm_gem_vram_driver_gem_prime_vunmap(struct drm_gem_object *obj, | ||
| 149 | void *vaddr); | ||
| 150 | int drm_gem_vram_driver_gem_prime_mmap(struct drm_gem_object *obj, | ||
| 151 | struct vm_area_struct *vma); | ||
| 152 | |||
| 153 | #define DRM_GEM_VRAM_DRIVER_PRIME \ | ||
| 154 | .gem_prime_export = drm_gem_prime_export, \ | ||
| 155 | .gem_prime_import = drm_gem_prime_import, \ | ||
| 156 | .gem_prime_pin = drm_gem_vram_driver_gem_prime_pin, \ | ||
| 157 | .gem_prime_unpin = drm_gem_vram_driver_gem_prime_unpin, \ | ||
| 158 | .gem_prime_vmap = drm_gem_vram_driver_gem_prime_vmap, \ | ||
| 159 | .gem_prime_vunmap = drm_gem_vram_driver_gem_prime_vunmap, \ | ||
| 160 | .gem_prime_mmap = drm_gem_vram_driver_gem_prime_mmap | ||
| 161 | |||
| 162 | #endif | ||
| @@ -836,6 +836,13 @@ struct drm_mode_config { · 835 unmodified lines | |||
| 836 | */ | 836 | */ |
| 837 | struct drm_property *writeback_out_fence_ptr_property; | 837 | struct drm_property *writeback_out_fence_ptr_property; |
| 838 | 838 | ||
| 839 | /** | ||
| 840 | * hdr_output_metadata_property: Connector property containing hdr | ||
| 841 | * metatda. This will be provided by userspace compositors based | ||
| 842 | * on HDR content | ||
| 843 | */ | ||
| 844 | struct drm_property *hdr_output_metadata_property; | ||
| 845 | |||
| 839 | /* dumb ioctl parameters */ | 846 | /* dumb ioctl parameters */ |
| 840 | uint32_t preferred_depth, prefer_shadow; | 847 | uint32_t preferred_depth, prefer_shadow; |
| 841 | 848 | ||
| @@ -0,0 +1,102 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 2 | |||
| 3 | #ifndef DRM_VRAM_MM_HELPER_H | ||
| 4 | #define DRM_VRAM_MM_HELPER_H | ||
| 5 | |||
| 6 | #include <drm/ttm/ttm_bo_driver.h> | ||
| 7 | |||
| 8 | struct drm_device; | ||
| 9 | |||
| 10 | /** | ||
| 11 | * struct drm_vram_mm_funcs - Callback functions for &struct drm_vram_mm | ||
| 12 | * @evict_flags: Provides an implementation for struct \ | ||
| 13 | &ttm_bo_driver.evict_flags | ||
| 14 | * @verify_access: Provides an implementation for \ | ||
| 15 | struct &ttm_bo_driver.verify_access | ||
| 16 | * | ||
| 17 | * These callback function integrate VRAM MM with TTM buffer objects. New | ||
| 18 | * functions can be added if necessary. | ||
| 19 | */ | ||
| 20 | struct drm_vram_mm_funcs { | ||
| 21 | void (*evict_flags)(struct ttm_buffer_object *bo, | ||
| 22 | struct ttm_placement *placement); | ||
| 23 | int (*verify_access)(struct ttm_buffer_object *bo, struct file *filp); | ||
| 24 | }; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * struct drm_vram_mm - An instance of VRAM MM | ||
| 28 | * @vram_base: Base address of the managed video memory | ||
| 29 | * @vram_size: Size of the managed video memory in bytes | ||
| 30 | * @bdev: The TTM BO device. | ||
| 31 | * @funcs: TTM BO functions | ||
| 32 | * | ||
| 33 | * The fields &struct drm_vram_mm.vram_base and | ||
| 34 | * &struct drm_vram_mm.vrm_size are managed by VRAM MM, but are | ||
| 35 | * available for public read access. Use the field | ||
| 36 | * &struct drm_vram_mm.bdev to access the TTM BO device. | ||
| 37 | */ | ||
| 38 | struct drm_vram_mm { | ||
| 39 | uint64_t vram_base; | ||
| 40 | size_t vram_size; | ||
| 41 | |||
| 42 | struct ttm_bo_device bdev; | ||
| 43 | |||
| 44 | const struct drm_vram_mm_funcs *funcs; | ||
| 45 | }; | ||
| 46 | |||
| 47 | /** | ||
| 48 | * drm_vram_mm_of_bdev() - \ | ||
| 49 | Returns the container of type &struct ttm_bo_device for field bdev. | ||
| 50 | * @bdev: the TTM BO device | ||
| 51 | * | ||
| 52 | * Returns: | ||
| 53 | * The containing instance of &struct drm_vram_mm | ||
| 54 | */ | ||
| 55 | static inline struct drm_vram_mm *drm_vram_mm_of_bdev( | ||
| 56 | struct ttm_bo_device *bdev) | ||
| 57 | { | ||
| 58 | return container_of(bdev, struct drm_vram_mm, bdev); | ||
| 59 | } | ||
| 60 | |||
| 61 | int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, | ||
| 62 | uint64_t vram_base, size_t vram_size, | ||
| 63 | const struct drm_vram_mm_funcs *funcs); | ||
| 64 | void drm_vram_mm_cleanup(struct drm_vram_mm *vmm); | ||
| 65 | |||
| 66 | int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma, | ||
| 67 | struct drm_vram_mm *vmm); | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Helpers for integration with struct drm_device | ||
| 71 | */ | ||
| 72 | |||
| 73 | struct drm_vram_mm *drm_vram_helper_alloc_mm( | ||
| 74 | struct drm_device *dev, uint64_t vram_base, size_t vram_size, | ||
| 75 | const struct drm_vram_mm_funcs *funcs); | ||
| 76 | void drm_vram_helper_release_mm(struct drm_device *dev); | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Helpers for &struct file_operations | ||
| 80 | */ | ||
| 81 | |||
| 82 | int drm_vram_mm_file_operations_mmap( | ||
| 83 | struct file *filp, struct vm_area_struct *vma); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * define DRM_VRAM_MM_FILE_OPERATIONS - default callback functions for \ | ||
| 87 | &struct file_operations | ||
| 88 | * | ||
| 89 | * Drivers that use VRAM MM can use this macro to initialize | ||
| 90 | * &struct file_operations with default functions. | ||
| 91 | */ | ||
| 92 | #define DRM_VRAM_MM_FILE_OPERATIONS \ | ||
| 93 | .llseek = no_llseek, \ | ||
| 94 | .read = drm_read, \ | ||
| 95 | .poll = drm_poll, \ | ||
| 96 | .unlocked_ioctl = drm_ioctl, \ | ||
| 97 | .compat_ioctl = drm_compat_ioctl, \ | ||
| 98 | .mmap = drm_vram_mm_file_operations_mmap, \ | ||
| 99 | .open = drm_open, \ | ||
| 100 | .release = drm_release \ | ||
| 101 | |||
| 102 | #endif | ||
| @@ -1,25 +0,0 @@ | |||
| 1 | /************************************************************************** | ||
| 2 | * Copyright (c) 2007-2011, Intel Corporation. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * Copyright (c) 2008, Tungsten Graphics Inc. Cedar Park, TX., USA. | ||
| 5 | * All Rights Reserved. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along with | ||
| 17 | * this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | * | ||
| 20 | **************************************************************************/ | ||
| 21 | |||
| 22 | #ifndef _GMA_DRM_H_ | ||
| 23 | #define _GMA_DRM_H_ | ||
| 24 | |||
| 25 | #endif | ||
| @@ -167,9 +167,6 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f); · 166 unmodified lines | |||
| 167 | * @sched: the scheduler instance on which this job is scheduled. | 167 | * @sched: the scheduler instance on which this job is scheduled. |
| 168 | * @s_fence: contains the fences for the scheduling of job. | 168 | * @s_fence: contains the fences for the scheduling of job. |
| 169 | * @finish_cb: the callback for the finished fence. | 169 | * @finish_cb: the callback for the finished fence. |
| 170 | * @finish_work: schedules the function @drm_sched_job_finish once the job has | ||
| 171 | * finished to remove the job from the | ||
| 172 | * @drm_gpu_scheduler.ring_mirror_list. | ||
| 173 | * @node: used to append this struct to the @drm_gpu_scheduler.ring_mirror_list. | 170 | * @node: used to append this struct to the @drm_gpu_scheduler.ring_mirror_list. |
| 174 | * @id: a unique id assigned to each job scheduled on the scheduler. | 171 | * @id: a unique id assigned to each job scheduled on the scheduler. |
| 175 | * @karma: increment on every hang caused by this job. If this exceeds the hang | 172 | * @karma: increment on every hang caused by this job. If this exceeds the hang |
| @@ -188,7 +185,6 @@ struct drm_sched_job { · 12 unmodified lines | |||
| 188 | struct drm_gpu_scheduler *sched; | 185 | struct drm_gpu_scheduler *sched; |
| 189 | struct drm_sched_fence *s_fence; | 186 | struct drm_sched_fence *s_fence; |
| 190 | struct dma_fence_cb finish_cb; | 187 | struct dma_fence_cb finish_cb; |
| 191 | struct work_struct finish_work; | ||
| 192 | struct list_head node; | 188 | struct list_head node; |
| 193 | uint64_t id; | 189 | uint64_t id; |
| 194 | atomic_t karma; | 190 | atomic_t karma; |
| @@ -263,6 +259,7 @@ struct drm_sched_backend_ops { · 68 unmodified lines | |||
| 263 | * guilty and it will be considered for scheduling further. | 259 | * guilty and it will be considered for scheduling further. |
| 264 | * @num_jobs: the number of jobs in queue in the scheduler | 260 | * @num_jobs: the number of jobs in queue in the scheduler |
| 265 | * @ready: marks if the underlying HW is ready to work | 261 | * @ready: marks if the underlying HW is ready to work |
| 262 | * @free_guilty: A hit to time out handler to free the guilty job. | ||
| 266 | * | 263 | * |
| 267 | * One scheduler is implemented for each hardware ring. | 264 | * One scheduler is implemented for each hardware ring. |
| 268 | */ | 265 | */ |
| @@ -283,6 +280,7 @@ struct drm_gpu_scheduler { · 14 unmodified lines | |||
| 283 | int hang_limit; | 280 | int hang_limit; |
| 284 | atomic_t num_jobs; | 281 | atomic_t num_jobs; |
| 285 | bool ready; | 282 | bool ready; |
| 283 | bool free_guilty; | ||
| 286 | }; | 284 | }; |
| 287 | 285 | ||
| 288 | int drm_sched_init(struct drm_gpu_scheduler *sched, | 286 | int drm_sched_init(struct drm_gpu_scheduler *sched, |
| @@ -296,7 +294,7 @@ int drm_sched_job_init(struct drm_sched_job *job, · 7 unmodified lines | |||
| 296 | void *owner); | 294 | void *owner); |
| 297 | void drm_sched_job_cleanup(struct drm_sched_job *job); | 295 | void drm_sched_job_cleanup(struct drm_sched_job *job); |
| 298 | void drm_sched_wakeup(struct drm_gpu_scheduler *sched); | 296 | void drm_sched_wakeup(struct drm_gpu_scheduler *sched); |
| 299 | void drm_sched_stop(struct drm_gpu_scheduler *sched); | 297 | void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad); |
| 300 | void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery); | 298 | void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery); |
| 301 | void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); | 299 | void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); |
| 302 | void drm_sched_increase_karma(struct drm_sched_job *bad); | 300 | void drm_sched_increase_karma(struct drm_sched_job *bad); |
| @@ -39,18 +39,20 @@ struct dma_buf_attachment; · 38 unmodified lines | |||
| 39 | 39 | ||
| 40 | /** | 40 | /** |
| 41 | * struct dma_buf_ops - operations possible on struct dma_buf | 41 | * struct dma_buf_ops - operations possible on struct dma_buf |
| 42 | * @map_atomic: [optional] maps a page from the buffer into kernel address | ||
| 43 | * space, users may not block until the subsequent unmap call. | ||
| 44 | * This callback must not sleep. | ||
| 45 | * @unmap_atomic: [optional] unmaps a atomically mapped page from the buffer. | ||
| 46 | * This Callback must not sleep. | ||
| 47 | * @map: [optional] maps a page from the buffer into kernel address space. | ||
| 48 | * @unmap: [optional] unmaps a page from the buffer. | ||
| 49 | * @vmap: [optional] creates a virtual mapping for the buffer into kernel | 42 | * @vmap: [optional] creates a virtual mapping for the buffer into kernel |
| 50 | * address space. Same restrictions as for vmap and friends apply. | 43 | * address space. Same restrictions as for vmap and friends apply. |
| 51 | * @vunmap: [optional] unmaps a vmap from the buffer | 44 | * @vunmap: [optional] unmaps a vmap from the buffer |
| 52 | */ | 45 | */ |
| 53 | struct dma_buf_ops { | 46 | struct dma_buf_ops { |
| 47 | /** | ||
| 48 | * @cache_sgt_mapping: | ||
| 49 | * | ||
| 50 | * If true the framework will cache the first mapping made for each | ||
| 51 | * attachment. This avoids creating mappings for attachments multiple | ||
| 52 | * times. | ||
| 53 | */ | ||
| 54 | bool cache_sgt_mapping; | ||
| 55 | |||
| 54 | /** | 56 | /** |
| 55 | * @attach: | 57 | * @attach: |
| 56 | * | 58 | * |
| @@ -205,8 +207,6 @@ struct dma_buf_ops { · 148 unmodified lines | |||
| 205 | * to be restarted. | 207 | * to be restarted. |
| 206 | */ | 208 | */ |
| 207 | int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); | 209 | int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); |
| 208 | void *(*map)(struct dma_buf *, unsigned long); | ||
| 209 | void (*unmap)(struct dma_buf *, unsigned long, void *); | ||
| 210 | 210 | ||
| 211 | /** | 211 | /** |
| 212 | * @mmap: | 212 | * @mmap: |
| @@ -245,6 +245,31 @@ struct dma_buf_ops { · 32 unmodified lines | |||
| 245 | */ | 245 | */ |
| 246 | int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); | 246 | int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); |
| 247 | 247 | ||
| 248 | /** | ||
| 249 | * @map: | ||
| 250 | * | ||
| 251 | * Maps a page from the buffer into kernel address space. The page is | ||
| 252 | * specified by offset into the buffer in PAGE_SIZE units. | ||
| 253 | * | ||
| 254 | * This callback is optional. | ||
| 255 | * | ||
| 256 | * Returns: | ||
| 257 | * | ||
| 258 | * Virtual address pointer where requested page can be accessed. NULL | ||
| 259 | * on error or when this function is unimplemented by the exporter. | ||
| 260 | */ | ||
| 261 | void *(*map)(struct dma_buf *, unsigned long); | ||
| 262 | |||
| 263 | /** | ||
| 264 | * @unmap: | ||
| 265 | * | ||
| 266 | * Unmaps a page from the buffer. Page offset and address pointer should | ||
| 267 | * be the same as the one passed to and returned by matching call to map. | ||
| 268 | * | ||
| 269 | * This callback is optional. | ||
| 270 | */ | ||
| 271 | void (*unmap)(struct dma_buf *, unsigned long, void *); | ||
| 272 | |||
| 248 | void *(*vmap)(struct dma_buf *); | 273 | void *(*vmap)(struct dma_buf *); |
| 249 | void (*vunmap)(struct dma_buf *, void *vaddr); | 274 | void (*vunmap)(struct dma_buf *, void *vaddr); |
| 250 | }; | 275 | }; |
| @@ -307,6 +332,8 @@ struct dma_buf { · 56 unmodified lines | |||
| 307 | * @dmabuf: buffer for this attachment. | 332 | * @dmabuf: buffer for this attachment. |
| 308 | * @dev: device attached to the buffer. | 333 | * @dev: device attached to the buffer. |
| 309 | * @node: list of dma_buf_attachment. | 334 | * @node: list of dma_buf_attachment. |
| 335 | * @sgt: cached mapping. | ||
| 336 | * @dir: direction of cached mapping. | ||
| 310 | * @priv: exporter specific attachment data. | 337 | * @priv: exporter specific attachment data. |
| 311 | * | 338 | * |
| 312 | * This structure holds the attachment information between the dma_buf buffer | 339 | * This structure holds the attachment information between the dma_buf buffer |
| @@ -322,6 +349,8 @@ struct dma_buf_attachment { · 9 unmodified lines | |||
| 322 | struct dma_buf *dmabuf; | 349 | struct dma_buf *dmabuf; |
| 323 | struct device *dev; | 350 | struct device *dev; |
| 324 | struct list_head node; | 351 | struct list_head node; |
| 352 | struct sg_table *sgt; | ||
| 353 | enum dma_data_direction dir; | ||
| 325 | void *priv; | 354 | void *priv; |
| 326 | }; | 355 | }; |
| 327 | 356 | ||
| @@ -47,6 +47,7 @@ enum hdmi_infoframe_type { · 46 unmodified lines | |||
| 47 | HDMI_INFOFRAME_TYPE_AVI = 0x82, | 47 | HDMI_INFOFRAME_TYPE_AVI = 0x82, |
| 48 | HDMI_INFOFRAME_TYPE_SPD = 0x83, | 48 | HDMI_INFOFRAME_TYPE_SPD = 0x83, |
| 49 | HDMI_INFOFRAME_TYPE_AUDIO = 0x84, | 49 | HDMI_INFOFRAME_TYPE_AUDIO = 0x84, |
| 50 | HDMI_INFOFRAME_TYPE_DRM = 0x87, | ||
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | #define HDMI_IEEE_OUI 0x000c03 | 53 | #define HDMI_IEEE_OUI 0x000c03 |
| @@ -55,6 +56,7 @@ enum hdmi_infoframe_type { · 2 unmodified lines | |||
| 55 | #define HDMI_AVI_INFOFRAME_SIZE 13 | 56 | #define HDMI_AVI_INFOFRAME_SIZE 13 |
| 56 | #define HDMI_SPD_INFOFRAME_SIZE 25 | 57 | #define HDMI_SPD_INFOFRAME_SIZE 25 |
| 57 | #define HDMI_AUDIO_INFOFRAME_SIZE 10 | 58 | #define HDMI_AUDIO_INFOFRAME_SIZE 10 |
| 59 | #define HDMI_DRM_INFOFRAME_SIZE 26 | ||
| 58 | 60 | ||
| 59 | #define HDMI_INFOFRAME_SIZE(type) \ | 61 | #define HDMI_INFOFRAME_SIZE(type) \ |
| 60 | (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) | 62 | (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) |
| @@ -152,6 +154,17 @@ enum hdmi_content_type { · 91 unmodified lines | |||
| 152 | HDMI_CONTENT_TYPE_GAME, | 154 | HDMI_CONTENT_TYPE_GAME, |
| 153 | }; | 155 | }; |
| 154 | 156 | ||
| 157 | enum hdmi_metadata_type { | ||
| 158 | HDMI_STATIC_METADATA_TYPE1 = 1, | ||
| 159 | }; | ||
| 160 | |||
| 161 | enum hdmi_eotf { | ||
| 162 | HDMI_EOTF_TRADITIONAL_GAMMA_SDR, | ||
| 163 | HDMI_EOTF_TRADITIONAL_GAMMA_HDR, | ||
| 164 | HDMI_EOTF_SMPTE_ST2084, | ||
| 165 | HDMI_EOTF_BT_2100_HLG, | ||
| 166 | }; | ||
| 167 | |||
| 155 | struct hdmi_avi_infoframe { | 168 | struct hdmi_avi_infoframe { |
| 156 | enum hdmi_infoframe_type type; | 169 | enum hdmi_infoframe_type type; |
| 157 | unsigned char version; | 170 | unsigned char version; |
| @@ -175,12 +188,37 @@ struct hdmi_avi_infoframe { · 17 unmodified lines | |||
| 175 | unsigned short right_bar; | 188 | unsigned short right_bar; |
| 176 | }; | 189 | }; |
| 177 | 190 | ||
| 191 | /* DRM Infoframe as per CTA 861.G spec */ | ||
| 192 | struct hdmi_drm_infoframe { | ||
| 193 | enum hdmi_infoframe_type type; | ||
| 194 | unsigned char version; | ||
| 195 | unsigned char length; | ||
| 196 | enum hdmi_eotf eotf; | ||
| 197 | enum hdmi_metadata_type metadata_type; | ||
| 198 | struct { | ||
| 199 | u16 x, y; | ||
| 200 | } display_primaries[3]; | ||
| 201 | struct { | ||
| 202 | u16 x, y; | ||
| 203 | } white_point; | ||
| 204 | u16 max_display_mastering_luminance; | ||
| 205 | u16 min_display_mastering_luminance; | ||
| 206 | u16 max_cll; | ||
| 207 | u16 max_fall; | ||
| 208 | }; | ||
| 209 | |||
| 178 | int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); | 210 | int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); |
| 179 | ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, | 211 | ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, |
| 180 | size_t size); | 212 | size_t size); |
| 181 | ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, | 213 | ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, |
| 182 | void *buffer, size_t size); | 214 | void *buffer, size_t size); |
| 183 | int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame); | 215 | int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame); |
| 216 | int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame); | ||
| 217 | ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer, | ||
| 218 | size_t size); | ||
| 219 | ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame, | ||
| 220 | void *buffer, size_t size); | ||
| 221 | int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame); | ||
| 184 | 222 | ||
| 185 | enum hdmi_spd_sdi { | 223 | enum hdmi_spd_sdi { |
| 186 | HDMI_SPD_SDI_UNKNOWN, | 224 | HDMI_SPD_SDI_UNKNOWN, |
| @@ -320,6 +358,22 @@ struct hdmi_vendor_infoframe { · 133 unmodified lines | |||
| 320 | unsigned int s3d_ext_data; | 358 | unsigned int s3d_ext_data; |
| 321 | }; | 359 | }; |
| 322 | 360 | ||
| 361 | /* HDR Metadata as per 861.G spec */ | ||
| 362 | struct hdr_static_metadata { | ||
| 363 | __u8 eotf; | ||
| 364 | __u8 metadata_type; | ||
| 365 | __u16 max_cll; | ||
| 366 | __u16 max_fall; | ||
| 367 | __u16 min_cll; | ||
| 368 | }; | ||
| 369 | |||
| 370 | struct hdr_sink_metadata { | ||
| 371 | __u32 metadata_type; | ||
| 372 | union { | ||
| 373 | struct hdr_static_metadata hdmi_type1; | ||
| 374 | }; | ||
| 375 | }; | ||
| 376 | |||
| 323 | int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame); | 377 | int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame); |
| 324 | ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, | 378 | ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, |
| 325 | void *buffer, size_t size); | 379 | void *buffer, size_t size); |
| @@ -355,6 +409,7 @@ union hdmi_infoframe { · 29 unmodified lines | |||
| 355 | struct hdmi_spd_infoframe spd; | 409 | struct hdmi_spd_infoframe spd; |
| 356 | union hdmi_vendor_any_infoframe vendor; | 410 | union hdmi_vendor_any_infoframe vendor; |
| 357 | struct hdmi_audio_infoframe audio; | 411 | struct hdmi_audio_infoframe audio; |
| 412 | struct hdmi_drm_infoframe drm; | ||
| 358 | }; | 413 | }; |
| 359 | 414 | ||
| 360 | ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, | 415 | ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, |
| @@ -50,6 +50,7 @@ typedef unsigned int drm_handle_t; · 49 unmodified lines | |||
| 50 | 50 | ||
| 51 | #else /* One of the BSDs */ | 51 | #else /* One of the BSDs */ |
| 52 | 52 | ||
| 53 | #include <stdint.h> | ||
| 53 | #include <sys/ioccom.h> | 54 | #include <sys/ioccom.h> |
| 54 | #include <sys/types.h> | 55 | #include <sys/types.h> |
| 55 | typedef int8_t __s8; | 56 | typedef int8_t __s8; |
| @@ -630,6 +630,29 @@ struct drm_color_lut { · 629 unmodified lines | |||
| 630 | __u16 reserved; | 630 | __u16 reserved; |
| 631 | }; | 631 | }; |
| 632 | 632 | ||
| 633 | /* HDR Metadata Infoframe as per 861.G spec */ | ||
| 634 | struct hdr_metadata_infoframe { | ||
| 635 | __u8 eotf; | ||
| 636 | __u8 metadata_type; | ||
| 637 | struct { | ||
| 638 | __u16 x, y; | ||
| 639 | } display_primaries[3]; | ||
| 640 | struct { | ||
| 641 | __u16 x, y; | ||
| 642 | } white_point; | ||
| 643 | __u16 max_display_mastering_luminance; | ||
| 644 | __u16 min_display_mastering_luminance; | ||
| 645 | __u16 max_cll; | ||
| 646 | __u16 max_fall; | ||
| 647 | }; | ||
| 648 | |||
| 649 | struct hdr_output_metadata { | ||
| 650 | __u32 metadata_type; | ||
| 651 | union { | ||
| 652 | struct hdr_metadata_infoframe hdmi_metadata_type1; | ||
| 653 | }; | ||
| 654 | }; | ||
| 655 | |||
| 633 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 | 656 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 |
| 634 | #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 | 657 | #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 |
| 635 | #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 | 658 | #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 |
| @@ -37,6 +37,7 @@ extern "C" { · 36 unmodified lines | |||
| 37 | #define DRM_V3D_GET_PARAM 0x04 | 37 | #define DRM_V3D_GET_PARAM 0x04 |
| 38 | #define DRM_V3D_GET_BO_OFFSET 0x05 | 38 | #define DRM_V3D_GET_BO_OFFSET 0x05 |
| 39 | #define DRM_V3D_SUBMIT_TFU 0x06 | 39 | #define DRM_V3D_SUBMIT_TFU 0x06 |
| 40 | #define DRM_V3D_SUBMIT_CSD 0x07 | ||
| 40 | 41 | ||
| 41 | #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) | 42 | #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) |
| 42 | #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) | 43 | #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) |
| @@ -45,6 +46,7 @@ extern "C" { · 2 unmodified lines | |||
| 45 | #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param) | 46 | #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param) |
| 46 | #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset) | 47 | #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset) |
| 47 | #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu) | 48 | #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu) |
| 49 | #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd) | ||
| 48 | 50 | ||
| 49 | /** | 51 | /** |
| 50 | * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D | 52 | * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D |
| @@ -190,6 +192,7 @@ enum drm_v3d_param { · 139 unmodified lines | |||
| 190 | DRM_V3D_PARAM_V3D_CORE0_IDENT1, | 192 | DRM_V3D_PARAM_V3D_CORE0_IDENT1, |
| 191 | DRM_V3D_PARAM_V3D_CORE0_IDENT2, | 193 | DRM_V3D_PARAM_V3D_CORE0_IDENT2, |
| 192 | DRM_V3D_PARAM_SUPPORTS_TFU, | 194 | DRM_V3D_PARAM_SUPPORTS_TFU, |
| 195 | DRM_V3D_PARAM_SUPPORTS_CSD, | ||
| 193 | }; | 196 | }; |
| 194 | 197 | ||
| 195 | struct drm_v3d_get_param { | 198 | struct drm_v3d_get_param { |
| @@ -230,6 +233,31 @@ struct drm_v3d_submit_tfu { · 34 unmodified lines | |||
| 230 | __u32 out_sync; | 233 | __u32 out_sync; |
| 231 | }; | 234 | }; |
| 232 | 235 | ||
| 236 | /* Submits a compute shader for dispatch. This job will block on any | ||
| 237 | * previous compute shaders submitted on this fd, and any other | ||
| 238 | * synchronization must be performed with in_sync/out_sync. | ||
| 239 | */ | ||
| 240 | struct drm_v3d_submit_csd { | ||
| 241 | __u32 cfg[7]; | ||
| 242 | __u32 coef[4]; | ||
| 243 | |||
| 244 | /* Pointer to a u32 array of the BOs that are referenced by the job. | ||
| 245 | */ | ||
| 246 | __u64 bo_handles; | ||
| 247 | |||
| 248 | /* Number of BO handles passed in (size is that times 4). */ | ||
| 249 | __u32 bo_handle_count; | ||
| 250 | |||
| 251 | /* sync object to block on before running the CSD job. Each | ||
| 252 | * CSD job will execute in the order submitted to its FD. | ||
| 253 | * Synchronization against rendering/TFU jobs or CSD from | ||
| 254 | * other fds requires using sync objects. | ||
| 255 | */ | ||
| 256 | __u32 in_sync; | ||
| 257 | /* Sync object to signal when the CSD job is done. */ | ||
| 258 | __u32 out_sync; | ||
| 259 | }; | ||
| 260 | |||
| 233 | #if defined(__cplusplus) | 261 | #if defined(__cplusplus) |
| 234 | } | 262 | } |
| 235 | #endif | 263 | #endif |