Merge drm/drm-next into drm-misc-next
authorThomas Zimmermann <tzimmermann@suse.de>
Wed, 12 Aug 2020 17:17:18 +0000 (19:17 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 12 Aug 2020 18:42:08 +0000 (20:42 +0200)
Backmerging drm-next into drm-misc-next for nouveau and panel updates.
Resolves a conflict between ttm and nouveau, where struct ttm_mem_res got
renamed to struct ttm_resource.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
234 files changed:
Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/panel-simple.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/gpu/drm-uapi.rst
Documentation/gpu/pl111.rst
Documentation/gpu/todo.rst
MAINTAINERS
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/atombios_dp.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/ast/ast_cursor.c
drivers/gpu/drm/ast/ast_dp501.c
drivers/gpu/drm/ast/ast_drv.c
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/ast/ast_mm.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/ast/ast_post.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/Makefile
drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/lontium-lt9611.c [new file with mode: 0644]
drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
drivers/gpu/drm/bridge/nxp-ptn3460.c
drivers/gpu/drm/bridge/panel.c
drivers/gpu/drm/bridge/parade-ps8622.c
drivers/gpu/drm/bridge/tc358764.c
drivers/gpu/drm/bridge/tc358767.c
drivers/gpu/drm/bridge/tc358775.c [new file with mode: 0644]
drivers/gpu/drm/bridge/ti-sn65dsi86.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_gem_vram_helper.c
drivers/gpu/drm/drm_panel.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/exynos/exynos_drm_dpi.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
drivers/gpu/drm/gma500/mdfld_dsi_output.c
drivers/gpu/drm/gma500/psb_intel_sdvo.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/imx/imx-ldb.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/ingenic/ingenic-drm-drv.c
drivers/gpu/drm/ingenic/ingenic-ipu.c
drivers/gpu/drm/mgag200/Kconfig
drivers/gpu/drm/mgag200/mgag200_drv.c
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_mm.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_reg.h
drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
drivers/gpu/drm/msm/dsi/dsi_manager.c
drivers/gpu/drm/mxsfb/Kconfig
drivers/gpu/drm/mxsfb/Makefile
drivers/gpu/drm/mxsfb/mxsfb_crtc.c [deleted file]
drivers/gpu/drm/mxsfb/mxsfb_drv.c
drivers/gpu/drm/mxsfb/mxsfb_drv.h
drivers/gpu/drm/mxsfb/mxsfb_kms.c [new file with mode: 0644]
drivers/gpu/drm/mxsfb/mxsfb_out.c [deleted file]
drivers/gpu/drm/mxsfb/mxsfb_regs.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_bo0039.c
drivers/gpu/drm/nouveau/nouveau_bo5039.c
drivers/gpu/drm/nouveau/nouveau_bo74c1.c
drivers/gpu/drm/nouveau/nouveau_bo85b5.c
drivers/gpu/drm/nouveau/nouveau_bo9039.c
drivers/gpu/drm/nouveau/nouveau_bo90b5.c
drivers/gpu/drm/nouveau/nouveau_boa0b5.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_mem.h
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nouveau_ttm.h
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/panel/panel-arm-versatile.c
drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
drivers/gpu/drm/panel/panel-boe-himax8279d.c
drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
drivers/gpu/drm/panel/panel-ilitek-ili9322.c
drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
drivers/gpu/drm/panel/panel-innolux-p079zca.c
drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
drivers/gpu/drm/panel/panel-lg-lb035q02.c
drivers/gpu/drm/panel/panel-lg-lg4573.c
drivers/gpu/drm/panel/panel-lvds.c
drivers/gpu/drm/panel/panel-nec-nl8048hl11.c
drivers/gpu/drm/panel/panel-novatek-nt35510.c
drivers/gpu/drm/panel/panel-novatek-nt39016.c
drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c
drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
drivers/gpu/drm/panel/panel-raydium-rm67191.c
drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
drivers/gpu/drm/panel/panel-samsung-ld9040.c
drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c
drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/panel/panel-sitronix-st7701.c
drivers/gpu/drm/panel/panel-sitronix-st7789v.c
drivers/gpu/drm/panel/panel-sony-acx424akp.c
drivers/gpu/drm/panel/panel-sony-acx565akm.c
drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
drivers/gpu/drm/panel/panel-tpo-td043mtea1.c
drivers/gpu/drm/panel/panel-tpo-tpg110.c
drivers/gpu/drm/panfrost/panfrost_devfreq.c
drivers/gpu/drm/panfrost/panfrost_devfreq.h
drivers/gpu/drm/panfrost/panfrost_device.c
drivers/gpu/drm/panfrost/panfrost_device.h
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/panfrost/panfrost_gpu.c
drivers/gpu/drm/panfrost/panfrost_job.c
drivers/gpu/drm/panfrost/panfrost_perfcnt.c
drivers/gpu/drm/pl111/pl111_drv.c
drivers/gpu/drm/qxl/qxl_cmd.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_object.h
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/rcar-du/rcar_lvds.c
drivers/gpu/drm/rockchip/rockchip_lvds.c
drivers/gpu/drm/sti/sti_dvo.c
drivers/gpu/drm/sun4i/sun4i_lvds.c
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/ttm/Makefile
drivers/gpu/drm/ttm/ttm_agp_backend.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_manager.c [deleted file]
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_execbuf_util.c
drivers/gpu/drm/ttm/ttm_range_manager.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_resource.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/v3d/v3d_drv.c
drivers/gpu/drm/vgem/vgem_drv.c
drivers/gpu/drm/vkms/vkms_composer.c
drivers/gpu/drm/vkms/vkms_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_thp.c
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
drivers/video/fbdev/acornfb.c
drivers/video/fbdev/arcfb.c
drivers/video/fbdev/atmel_lcdfb.c
drivers/video/fbdev/aty/radeon_pm.c
drivers/video/fbdev/cirrusfb.c
drivers/video/fbdev/controlfb.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/fsl-diu-fb.c
drivers/video/fbdev/gxt4500.c
drivers/video/fbdev/i740fb.c
drivers/video/fbdev/offb.c
drivers/video/fbdev/omap/lcdc.c
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/omap2/omapfb/dss/dispc.c
drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/pm2fb.c
drivers/video/fbdev/pvr2fb.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/s3c-fb.c
drivers/video/fbdev/sa1100fb.c
drivers/video/fbdev/savage/savagefb_driver.c
drivers/video/fbdev/sh_mobile_lcdcfb.c
drivers/video/fbdev/sm501fb.c
drivers/video/fbdev/tdfxfb.c
drivers/video/fbdev/xen-fbfront.c
include/drm/drm_connector.h
include/drm/drm_dp_helper.h
include/drm/drm_mode_config.h
include/drm/drm_panel.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_resource.h [new file with mode: 0644]
include/drm/ttm/ttm_tt.h
include/linux/fb.h
include/linux/moduleparam.h
include/uapi/drm/drm_mode.h
kernel/params.c

diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
new file mode 100644 (file)
index 0000000..d602083
--- /dev/null
@@ -0,0 +1,176 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Lontium LT9611 2 Port MIPI to HDMI Bridge
+
+maintainers:
+  - Vinod Koul <vkoul@kernel.org>
+
+description: |
+  The LT9611 is a bridge device which converts DSI to HDMI
+
+properties:
+  compatible:
+    enum:
+      - lontium,lt9611
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  interrupts:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active high RESET pin.
+
+  vdd-supply:
+    description: Regulator for 1.8V MIPI phy power.
+
+  vcc-supply:
+    description: Regulator for 3.3V IO power.
+
+  ports:
+    type: object
+
+    properties:
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      port@0:
+        type: object
+        description: |
+          Primary MIPI port-1 for MIPI input
+
+        properties:
+          reg:
+            const: 0
+
+        patternProperties:
+          "^endpoint(@[0-9])$":
+            type: object
+            additionalProperties: false
+
+            properties:
+              remote-endpoint:
+                $ref: /schemas/types.yaml#/definitions/phandle
+
+        required:
+          - reg
+
+      port@1:
+        type: object
+        description: |
+          Additional MIPI port-2 for MIPI input, used in combination
+          with primary MIPI port-1 to drive higher resolution displays
+
+        properties:
+          reg:
+            const: 1
+
+        patternProperties:
+          "^endpoint(@[0-9])$":
+            type: object
+            additionalProperties: false
+
+            properties:
+              remote-endpoint:
+                $ref: /schemas/types.yaml#/definitions/phandle
+
+        required:
+          - reg
+
+      port@2:
+        type: object
+        description: |
+          HDMI port for HDMI output
+
+        properties:
+          reg:
+            const: 2
+
+        patternProperties:
+          "^endpoint(@[0-9])$":
+            type: object
+            additionalProperties: false
+
+            properties:
+              remote-endpoint:
+                $ref: /schemas/types.yaml#/definitions/phandle
+
+        required:
+          - reg
+
+    required:
+      - "#address-cells"
+      - "#size-cells"
+      - port@0
+      - port@2
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - vdd-supply
+  - vcc-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c10 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      hdmi-bridge@3b {
+        compatible = "lontium,lt9611";
+        reg = <0x3b>;
+
+        reset-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>;
+        interrupts-extended = <&tlmm 84 IRQ_TYPE_EDGE_FALLING>;
+
+        vdd-supply = <&lt9611_1v8>;
+        vcc-supply = <&lt9611_3v3>;
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          port@0 {
+            reg = <0>;
+            lt9611_a: endpoint {
+              remote-endpoint = <&dsi0_out>;
+            };
+          };
+
+          port@1 {
+            reg = <1>;
+            lt9611_b: endpoint {
+              remote-endpoint = <&dsi1_out>;
+            };
+          };
+
+          port@2 {
+            reg = <2>;
+            lt9611_out: endpoint {
+              remote-endpoint = <&hdmi_con>;
+            };
+          };
+        };
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml
new file mode 100644 (file)
index 0000000..31f085d
--- /dev/null
@@ -0,0 +1,215 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358775.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba TC358775 DSI to LVDS bridge bindings
+
+maintainers:
+ - Vinay Simha BN <simhavcs@gmail.com>
+
+description: |
+ This binding supports DSI to LVDS bridge TC358775
+
+ MIPI DSI-RX Data 4-lane, CLK 1-lane with data rates up to 800 Mbps/lane.
+ Video frame size:
+ Up to 1600x1200 24-bit/pixel resolution for single-link LVDS display panel
+ limited by 135 MHz LVDS speed
+ Up to WUXGA (1920x1200 24-bit pixels) resolution for dual-link LVDS display
+ panel, limited by 270 MHz LVDS speed.
+
+properties:
+  compatible:
+    const: toshiba,tc358775
+
+  reg:
+    maxItems: 1
+    description: i2c address of the bridge, 0x0f
+
+  vdd-supply:
+    maxItems: 1
+    description:  1.2V LVDS Power Supply
+
+  vddio-supply:
+    maxItems: 1
+    description: 1.8V IO Power Supply
+
+  stby-gpios:
+    maxItems: 1
+    description: Standby pin, Low active
+
+  reset-gpios:
+    maxItems: 1
+    description: Hardware reset, Low active
+
+  ports:
+    type: object
+    description:
+      A node containing input and output port nodes with endpoint definitions
+      as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+    properties:
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      port@0:
+        type: object
+        description: |
+          DSI Input. The remote endpoint phandle should be a
+          reference to a valid mipi_dsi_host device node.
+
+      port@1:
+        type: object
+        description: |
+          Video port for LVDS output (panel or connector).
+
+      port@2:
+        type: object
+        description: |
+          Video port for Dual link LVDS output (panel or connector).
+
+    required:
+      - port@0
+      - port@1
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vddio-supply
+ - stby-gpios
+ - reset-gpios
+ - ports
+
+examples:
+ - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    /* For single-link LVDS display panel */
+
+    i2c@78b8000 {
+        /* On High speed expansion */
+        label = "HS-I2C2";
+        reg = <0x078b8000 0x500>;
+        clock-frequency = <400000>; /* fastmode operation */
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        tc_bridge: bridge@f {
+            compatible = "toshiba,tc358775";
+            reg = <0x0f>;
+
+            vdd-supply = <&pm8916_l2>;
+            vddio-supply = <&pm8916_l6>;
+
+            stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    d2l_in_test: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    lvds_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                    };
+                };
+            };
+        };
+    };
+
+    dsi@1a98000 {
+        reg = <0x1a98000 0x25c>;
+        reg-names = "dsi_ctrl";
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            port@1 {
+                reg = <1>;
+                dsi0_out: endpoint {
+                    remote-endpoint = <&d2l_in_test>;
+                    data-lanes = <0 1 2 3>;
+                };
+             };
+         };
+     };
+
+ - |
+    /* For dual-link LVDS display panel */
+
+    i2c@78b8000 {
+        /* On High speed expansion */
+        label = "HS-I2C2";
+        reg = <0x078b8000 0x500>;
+        clock-frequency = <400000>; /* fastmode operation */
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        tc_bridge_dual: bridge@f {
+            compatible = "toshiba,tc358775";
+            reg = <0x0f>;
+
+            vdd-supply = <&pm8916_l2>;
+            vddio-supply = <&pm8916_l6>;
+
+            stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    d2l_in_dual: endpoint {
+                        remote-endpoint = <&dsi0_out_dual>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    lvds0_out: endpoint {
+                        remote-endpoint = <&panel_in0>;
+                    };
+                };
+
+                port@2 {
+                    reg = <2>;
+                    lvds1_out: endpoint {
+                        remote-endpoint = <&panel_in1>;
+                    };
+                };
+            };
+        };
+    };
+
+    dsi@1a98000 {
+        reg = <0x1a98000 0x25c>;
+        reg-names = "dsi_ctrl";
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            port@1 {
+                reg = <1>;
+                dsi0_out_dual: endpoint {
+                    remote-endpoint = <&d2l_in_dual>;
+                    data-lanes = <0 1 2 3>;
+                };
+             };
+         };
+     };
+...
index 6deeeed..47247ac 100644 (file)
@@ -87,6 +87,8 @@ properties:
       - cdtech,s070swv29hg-dc44
         # CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel
       - cdtech,s070wv95-ct16
+        # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel
+      - chefree,ch101olhlwh-002
         # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
       - chunghwa,claa070wp03xg
         # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
@@ -219,6 +221,8 @@ properties:
       - osddisplays,osd070t1718-19ts
         # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel
       - osddisplays,osd101t2045-53ts
+        # POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel
+      - powertip,ph800480t013-idf02
         # QiaoDian XianShi Corporation 4"3 TFT LCD panel
       - qiaodian,qd43003c0-40
         # Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800
index 740b116..1dd92dc 100644 (file)
@@ -193,6 +193,8 @@ patternProperties:
     description: Ceva, Inc.
   "^checkpoint,.*":
     description: Check Point Software Technologies Ltd.
+  "^chefree,.*":
+    description: Chefree Technology Corp.
   "^chipidea,.*":
     description: Chipidea, Inc
   "^chipone,.*":
@@ -595,6 +597,8 @@ patternProperties:
     description: Logic Technologies Limited
   "^longcheer,.*":
     description: Longcheer Technology (Shanghai) Co., Ltd.
+  "^lontium,.*":
+    description: Lontium Semiconductor Corporation
   "^loongson,.*":
     description: Loongson Technology Corporation Limited
   "^lsi,.*":
@@ -822,6 +826,8 @@ patternProperties:
     description: Poslab Technology Co., Ltd.
   "^pov,.*":
     description: Point of View International B.V.
+  "^powertip,.*":
+    description: Powertip Tech. Corp.
   "^powervr,.*":
     description: PowerVR (deprecated, use img)
   "^primux,.*":
index 56fec6e..9ce51e4 100644 (file)
@@ -1,3 +1,5 @@
+.. Copyright 2020 DisplayLink (UK) Ltd.
+
 ===================
 Userland interfaces
 ===================
@@ -162,6 +164,116 @@ other hand, a driver requires shared state between clients which is
 visible to user-space and accessible beyond open-file boundaries, they
 cannot support render nodes.
 
+Device Hot-Unplug
+=================
+
+.. note::
+   The following is the plan. Implementation is not there yet
+   (2020 May).
+
+Graphics devices (display and/or render) may be connected via USB (e.g.
+display adapters or docking stations) or Thunderbolt (e.g. eGPU). An end
+user is able to hot-unplug this kind of devices while they are being
+used, and expects that the very least the machine does not crash. Any
+damage from hot-unplugging a DRM device needs to be limited as much as
+possible and userspace must be given the chance to handle it if it wants
+to. Ideally, unplugging a DRM device still lets a desktop continue to
+run, but that is going to need explicit support throughout the whole
+graphics stack: from kernel and userspace drivers, through display
+servers, via window system protocols, and in applications and libraries.
+
+Other scenarios that should lead to the same are: unrecoverable GPU
+crash, PCI device disappearing off the bus, or forced unbind of a driver
+from the physical device.
+
+In other words, from userspace perspective everything needs to keep on
+working more or less, until userspace stops using the disappeared DRM
+device and closes it completely. Userspace will learn of the device
+disappearance from the device removed uevent, ioctls returning ENODEV
+(or driver-specific ioctls returning driver-specific things), or open()
+returning ENXIO.
+
+Only after userspace has closed all relevant DRM device and dmabuf file
+descriptors and removed all mmaps, the DRM driver can tear down its
+instance for the device that no longer exists. If the same physical
+device somehow comes back in the mean time, it shall be a new DRM
+device.
+
+Similar to PIDs, chardev minor numbers are not recycled immediately. A
+new DRM device always picks the next free minor number compared to the
+previous one allocated, and wraps around when minor numbers are
+exhausted.
+
+The goal raises at least the following requirements for the kernel and
+drivers.
+
+Requirements for KMS UAPI
+-------------------------
+
+- KMS connectors must change their status to disconnected.
+
+- Legacy modesets and pageflips, and atomic commits, both real and
+  TEST_ONLY, and any other ioctls either fail with ENODEV or fake
+  success.
+
+- Pending non-blocking KMS operations deliver the DRM events userspace
+  is expecting. This applies also to ioctls that faked success.
+
+- open() on a device node whose underlying device has disappeared will
+  fail with ENXIO.
+
+- Attempting to create a DRM lease on a disappeared DRM device will
+  fail with ENODEV. Existing DRM leases remain and work as listed
+  above.
+
+Requirements for Render and Cross-Device UAPI
+---------------------------------------------
+
+- All GPU jobs that can no longer run must have their fences
+  force-signalled to avoid inflicting hangs on userspace.
+  The associated error code is ENODEV.
+
+- Some userspace APIs already define what should happen when the device
+  disappears (OpenGL, GL ES: `GL_KHR_robustness`_; `Vulkan`_:
+  VK_ERROR_DEVICE_LOST; etc.). DRM drivers are free to implement this
+  behaviour the way they see best, e.g. returning failures in
+  driver-specific ioctls and handling those in userspace drivers, or
+  rely on uevents, and so on.
+
+- dmabuf which point to memory that has disappeared will either fail to
+  import with ENODEV or continue to be successfully imported if it would
+  have succeeded before the disappearance. See also about memory maps
+  below for already imported dmabufs.
+
+- Attempting to import a dmabuf to a disappeared device will either fail
+  with ENODEV or succeed if it would have succeeded without the
+  disappearance.
+
+- open() on a device node whose underlying device has disappeared will
+  fail with ENXIO.
+
+.. _GL_KHR_robustness: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_robustness.txt
+.. _Vulkan: https://www.khronos.org/vulkan/
+
+Requirements for Memory Maps
+----------------------------
+
+Memory maps have further requirements that apply to both existing maps
+and maps created after the device has disappeared. If the underlying
+memory disappears, the map is created or modified such that reads and
+writes will still complete successfully but the result is undefined.
+This applies to both userspace mmap()'d memory and memory pointed to by
+dmabuf which might be mapped to other devices (cross-device dmabuf
+imports).
+
+Raising SIGBUS is not an option, because userspace cannot realistically
+handle it. Signal handlers are global, which makes them extremely
+difficult to use correctly from libraries like those that Mesa produces.
+Signal handlers are not composable, you can't have different handlers
+for GPU1 and GPU2 from different vendors, and a third handler for
+mmapped regular files. Threads cause additional pain with signal
+handling as well.
+
 .. _drm_driver_ioctl:
 
 IOCTL Support on Device Nodes
@@ -199,7 +311,7 @@ EPERM/EACCES:
         difference between EACCES and EPERM.
 
 ENODEV:
-        The device is not (yet) present or fully initialized.
+        The device is not present anymore or is not yet fully initialized.
 
 EOPNOTSUPP:
         Feature (like PRIME, modesetting, GEM) is not supported by the driver.
index 9b03736..6d9a1b5 100644 (file)
@@ -1,6 +1,6 @@
-==========================================
- drm/pl111 ARM PrimeCell PL111 CLCD Driver
-==========================================
+====================================================
+ drm/pl111 ARM PrimeCell PL110 and PL111 CLCD Driver
+====================================================
 
 .. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c
-   :doc: ARM PrimeCell PL111 CLCD Driver
+   :doc: ARM PrimeCell PL110 and PL111 CLCD Driver
index 7969f10..b0ea17d 100644 (file)
@@ -403,6 +403,52 @@ Contact: Emil Velikov, respective driver maintainers
 
 Level: Intermediate
 
+Plumb drm_atomic_state all over
+-------------------------------
+
+Currently various atomic functions take just a single or a handful of
+object states (eg. plane state). While that single object state can
+suffice for some simple cases, we often have to dig out additional
+object states for dealing with various dependencies between the individual
+objects or the hardware they represent. The process of digging out the
+additional states is rather non-intuitive and error prone.
+
+To fix that most functions should rather take the overall
+drm_atomic_state as one of their parameters. The other parameters
+would generally be the object(s) we mainly want to interact with.
+
+For example, instead of
+
+.. code-block:: c
+
+   int (*atomic_check)(struct drm_plane *plane, struct drm_plane_state *state);
+
+we would have something like
+
+.. code-block:: c
+
+   int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state);
+
+The implementation can then trivially gain access to any required object
+state(s) via drm_atomic_get_plane_state(), drm_atomic_get_new_plane_state(),
+drm_atomic_get_old_plane_state(), and their equivalents for
+other object types.
+
+Additionally many drivers currently access the object->state pointer
+directly in their commit functions. That is not going to work if we
+eg. want to allow deeper commit pipelines as those pointers could
+then point to the states corresponding to a future commit instead of
+the current commit we're trying to process. Also non-blocking commits
+execute locklessly so there are serious concerns with dereferencing
+the object->state pointers without holding the locks that protect them.
+Use of drm_atomic_get_new_plane_state(), drm_atomic_get_old_plane_state(),
+etc. avoids these problems as well since they relate to a specific
+commit via the passed in drm_atomic_state.
+
+Contact: Ville Syrjälä, Daniel Vetter
+
+Level: Intermediate
+
 
 Core refactorings
 =================
index 153f7b3..bebc222 100644 (file)
@@ -5406,7 +5406,7 @@ S:        Orphan / Obsolete
 F:     drivers/gpu/drm/mga/
 F:     include/uapi/drm/mga_drm.h
 
-DRM DRIVER FOR MGA G200 SERVER GRAPHICS CHIPS
+DRM DRIVER FOR MGA G200 GRAPHICS CHIPS
 M:     Dave Airlie <airlied@redhat.com>
 S:     Odd Fixes
 F:     drivers/gpu/drm/mgag200/
index 1b865fe..478f674 100644 (file)
@@ -517,8 +517,9 @@ out_put:
 uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
+       struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
 
-       return amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+       return amdgpu_vram_mgr_usage(vram_man);
 }
 
 uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd)
index e5a5ba8..a7a30e3 100644 (file)
@@ -564,7 +564,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr)
 
        mutex_lock(&process_info->lock);
 
-       ret = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, user_addr, 0);
+       ret = amdgpu_ttm_tt_set_userptr(&bo->tbo, user_addr, 0);
        if (ret) {
                pr_err("%s: Failed to set userptr: %d\n", __func__, ret);
                goto out;
index a1aec20..93160a8 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <drm/drm_edid.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_dp_helper.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/amdgpu_drm.h>
 #include "amdgpu.h"
@@ -1413,6 +1414,10 @@ out:
                pm_runtime_put_autosuspend(connector->dev->dev);
        }
 
+       drm_dp_set_subconnector_property(&amdgpu_connector->base,
+                                        ret,
+                                        amdgpu_dig_connector->dpcd,
+                                        amdgpu_dig_connector->downstream_ports);
        return ret;
 }
 
@@ -1959,6 +1964,11 @@ amdgpu_connector_add(struct amdgpu_device *adev,
        if (has_aux)
                amdgpu_atombios_dp_aux_init(amdgpu_connector);
 
+       if (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+           connector_type == DRM_MODE_CONNECTOR_eDP) {
+               drm_connector_attach_dp_subconnector_property(&amdgpu_connector->base);
+       }
+
        return;
 
 failed:
index a512ccb..ecd0519 100644 (file)
@@ -299,7 +299,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
 {
        s64 time_us, increment_us;
        u64 free_vram, total_vram, used_vram;
-
+       struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
        /* Allow a maximum of 200 accumulated ms. This is basically per-IB
         * throttling.
         *
@@ -316,7 +316,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
        }
 
        total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size);
-       used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+       used_vram = amdgpu_vram_mgr_usage(vram_man);
        free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram;
 
        spin_lock(&adev->mm_stats.lock);
@@ -363,7 +363,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
        if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) {
                u64 total_vis_vram = adev->gmc.visible_vram_size;
                u64 used_vis_vram =
-                       amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+                 amdgpu_vram_mgr_vis_usage(vram_man);
 
                if (used_vis_vram < total_vis_vram) {
                        u64 free_vis_vram = total_vis_vram - used_vis_vram;
index eb7cfe8..4204cda 100644 (file)
@@ -3882,7 +3882,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
 
        amdgpu_virt_init_data_exchange(adev);
        /* we need recover gart prior to run SMC/CP/SDMA resume */
-       amdgpu_gtt_mgr_recover(&adev->mman.bdev.man[TTM_PL_TT]);
+       amdgpu_gtt_mgr_recover(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT));
 
        r = amdgpu_device_fw_loading(adev);
        if (r)
@@ -4081,8 +4081,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
                                        amdgpu_inc_vram_lost(tmp_adev);
                                }
 
-                               r = amdgpu_gtt_mgr_recover(
-                                       &tmp_adev->mman.bdev.man[TTM_PL_TT]);
+                               r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT));
                                if (r)
                                        goto out;
 
index 26127c7..81a7976 100644 (file)
@@ -393,12 +393,12 @@ MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default
 module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444);
 
 /**
- * DOC: ppfeaturemask (uint)
+ * DOC: ppfeaturemask (hexint)
  * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h.
  * The default is the current set of stable power features.
  */
 MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))");
-module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444);
+module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, hexint, 0444);
 
 /**
  * DOC: forcelongtraining (uint)
index 7f9e502..6b1eb9d 100644 (file)
@@ -332,7 +332,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
        bo = gem_to_amdgpu_bo(gobj);
        bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT;
        bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
-       r = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags);
+       r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags);
        if (r)
                goto release_object;
 
index 77fae40..697bc2c 100644 (file)
 
 #include "amdgpu.h"
 
-struct amdgpu_gtt_mgr {
-       struct drm_mm mm;
-       spinlock_t lock;
-       atomic64_t available;
-};
+static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man)
+{
+       return container_of(man, struct amdgpu_gtt_mgr, manager);
+}
 
 struct amdgpu_gtt_node {
        struct drm_mm_node node;
@@ -48,9 +47,9 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
-
+       struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
        return snprintf(buf, PAGE_SIZE, "%llu\n",
-                       (adev->mman.bdev.man[TTM_PL_TT].size) * PAGE_SIZE);
+                       man->size * PAGE_SIZE);
 }
 
 /**
@@ -66,9 +65,9 @@ static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
-
+       struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
        return snprintf(buf, PAGE_SIZE, "%llu\n",
-                       amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]));
+                       amdgpu_gtt_mgr_usage(man));
 }
 
 static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
@@ -76,6 +75,7 @@ static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
 static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
                   amdgpu_mem_info_gtt_used_show, NULL);
 
+static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func;
 /**
  * amdgpu_gtt_mgr_init - init GTT manager and DRM MM
  *
@@ -84,24 +84,25 @@ static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
  *
  * Allocate and initialize the GTT manager.
  */
-static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
-                              unsigned long p_size)
+int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
-       struct amdgpu_gtt_mgr *mgr;
+       struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
+       struct ttm_resource_manager *man = &mgr->manager;
        uint64_t start, size;
        int ret;
 
-       mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
-       if (!mgr)
-               return -ENOMEM;
+       man->use_tt = true;
+       man->func = &amdgpu_gtt_mgr_func;
+       man->available_caching = TTM_PL_MASK_CACHING;
+       man->default_caching = TTM_PL_FLAG_CACHED;
+
+       ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT);
 
        start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
        size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;
        drm_mm_init(&mgr->mm, start, size);
        spin_lock_init(&mgr->lock);
-       atomic64_set(&mgr->available, p_size);
-       man->priv = mgr;
+       atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT);
 
        ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total);
        if (ret) {
@@ -114,6 +115,8 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
                return ret;
        }
 
+       ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager);
+       ttm_resource_manager_set_used(man, true);
        return 0;
 }
 
@@ -125,20 +128,27 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
  * Destroy and free the GTT manager, returns -EBUSY if ranges are still
  * allocated inside it.
  */
-static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
+void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
-       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr;
+       struct ttm_resource_manager *man = &mgr->manager;
+       int ret;
+
+       ttm_resource_manager_set_used(man, false);
+
+       ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man);
+       if (ret)
+               return;
+
        spin_lock(&mgr->lock);
        drm_mm_takedown(&mgr->mm);
        spin_unlock(&mgr->lock);
-       kfree(mgr);
-       man->priv = NULL;
 
        device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total);
        device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used);
 
-       return 0;
+       ttm_resource_manager_cleanup(man);
+       ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL);
 }
 
 /**
@@ -148,7 +158,7 @@ static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
  *
  * Check if a mem object has already address space allocated.
  */
-bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem)
+bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem)
 {
        return mem->mm_node != NULL;
 }
@@ -163,12 +173,12 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem)
  *
  * Dummy, allocate the node but no space for it yet.
  */
-static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
+static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
                              struct ttm_buffer_object *tbo,
                              const struct ttm_place *place,
-                             struct ttm_mem_reg *mem)
+                             struct ttm_resource *mem)
 {
-       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
        struct amdgpu_gtt_node *node;
        int r;
 
@@ -226,10 +236,10 @@ err_out:
  *
  * Free the allocated GTT again.
  */
-static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
-                              struct ttm_mem_reg *mem)
+static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
+                              struct ttm_resource *mem)
 {
-       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
        struct amdgpu_gtt_node *node = mem->mm_node;
 
        if (node) {
@@ -249,17 +259,17 @@ static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man,
  *
  * Return how many bytes are used in the GTT domain
  */
-uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man)
+uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man)
 {
-       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
        s64 result = man->size - atomic64_read(&mgr->available);
 
        return (result > 0 ? result : 0) * PAGE_SIZE;
 }
 
-int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man)
+int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man)
 {
-       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
        struct amdgpu_gtt_node *node;
        struct drm_mm_node *mm_node;
        int r = 0;
@@ -284,10 +294,10 @@ int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man)
  *
  * Dump the table content using printk.
  */
-static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
+static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,
                                 struct drm_printer *printer)
 {
-       struct amdgpu_gtt_mgr *mgr = man->priv;
+       struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
 
        spin_lock(&mgr->lock);
        drm_mm_print(&mgr->mm, printer);
@@ -298,10 +308,8 @@ static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man,
                   amdgpu_gtt_mgr_usage(man) >> 20);
 }
 
-const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = {
-       .init = amdgpu_gtt_mgr_init,
-       .takedown = amdgpu_gtt_mgr_fini,
-       .get_node = amdgpu_gtt_mgr_new,
-       .put_node = amdgpu_gtt_mgr_del,
+static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
+       .alloc = amdgpu_gtt_mgr_new,
+       .free = amdgpu_gtt_mgr_del,
        .debug = amdgpu_gtt_mgr_debug
 };
index 0047da0..55ff071 100644 (file)
@@ -594,13 +594,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                ui64 = atomic64_read(&adev->num_vram_cpu_page_faults);
                return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
        case AMDGPU_INFO_VRAM_USAGE:
-               ui64 = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+               ui64 = amdgpu_vram_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM));
                return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
        case AMDGPU_INFO_VIS_VRAM_USAGE:
-               ui64 = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+               ui64 = amdgpu_vram_mgr_vis_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM));
                return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
        case AMDGPU_INFO_GTT_USAGE:
-               ui64 = amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]);
+               ui64 = amdgpu_gtt_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT));
                return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
        case AMDGPU_INFO_GDS_CONFIG: {
                struct drm_amdgpu_info_gds gds_info;
@@ -623,7 +623,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        min(adev->gmc.visible_vram_size -
                            atomic64_read(&adev->visible_pin_size),
                            vram_gtt.vram_size);
-               vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size;
+               vram_gtt.gtt_size = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)->size;
                vram_gtt.gtt_size *= PAGE_SIZE;
                vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size);
                return copy_to_user(out, &vram_gtt,
@@ -631,14 +631,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
        }
        case AMDGPU_INFO_MEMORY: {
                struct drm_amdgpu_memory_info mem;
-
+               struct ttm_resource_manager *vram_man =
+                       ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
+               struct ttm_resource_manager *gtt_man =
+                       ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
                memset(&mem, 0, sizeof(mem));
                mem.vram.total_heap_size = adev->gmc.real_vram_size;
                mem.vram.usable_heap_size = adev->gmc.real_vram_size -
                        atomic64_read(&adev->vram_pin_size) -
                        AMDGPU_VM_RESERVED_VRAM;
                mem.vram.heap_usage =
-                       amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+                       amdgpu_vram_mgr_usage(vram_man);
                mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4;
 
                mem.cpu_accessible_vram.total_heap_size =
@@ -648,16 +651,16 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                            atomic64_read(&adev->visible_pin_size),
                            mem.vram.usable_heap_size);
                mem.cpu_accessible_vram.heap_usage =
-                       amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
+                       amdgpu_vram_mgr_vis_usage(vram_man);
                mem.cpu_accessible_vram.max_allocation =
                        mem.cpu_accessible_vram.usable_heap_size * 3 / 4;
 
-               mem.gtt.total_heap_size = adev->mman.bdev.man[TTM_PL_TT].size;
+               mem.gtt.total_heap_size = gtt_man->size;
                mem.gtt.total_heap_size *= PAGE_SIZE;
                mem.gtt.usable_heap_size = mem.gtt.total_heap_size -
                        atomic64_read(&adev->gart_pin_size);
                mem.gtt.heap_usage =
-                       amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]);
+                       amdgpu_gtt_mgr_usage(gtt_man);
                mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4;
 
                return copy_to_user(out, &mem,
index 37ba07e..04a430e 100644 (file)
@@ -469,6 +469,7 @@ struct amdgpu_encoder {
 struct amdgpu_connector_atom_dig {
        /* displayport */
        u8 dpcd[DP_RECEIVER_CAP_SIZE];
+       u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
        u8 dp_sink_type;
        int dp_clock;
        int dp_lane_count;
index 5ac7b55..b36d94f 100644 (file)
@@ -381,7 +381,7 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
        if (cpu_addr)
                amdgpu_bo_kunmap(*bo_ptr);
 
-       ttm_bo_mem_put(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem);
+       ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem);
 
        for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) {
                (*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT;
@@ -442,14 +442,14 @@ void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
 static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
                                          unsigned long size, u32 domain)
 {
-       struct ttm_mem_type_manager *man = NULL;
+       struct ttm_resource_manager *man = NULL;
 
        /*
         * If GTT is part of requested domains the check must succeed to
         * allow fall back to GTT
         */
        if (domain & AMDGPU_GEM_DOMAIN_GTT) {
-               man = &adev->mman.bdev.man[TTM_PL_TT];
+               man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
 
                if (size < (man->size << PAGE_SHIFT))
                        return true;
@@ -458,7 +458,7 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
        }
 
        if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
-               man = &adev->mman.bdev.man[TTM_PL_VRAM];
+               man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
 
                if (size < (man->size << PAGE_SHIFT))
                        return true;
@@ -1268,11 +1268,11 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
  */
 void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
                           bool evict,
-                          struct ttm_mem_reg *new_mem)
+                          struct ttm_resource *new_mem)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
        struct amdgpu_bo *abo;
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
 
        if (!amdgpu_bo_is_amdgpu_bo(bo))
                return;
index afa5189..5ddb6cf 100644 (file)
@@ -160,7 +160,7 @@ static inline int amdgpu_bo_reserve(struct amdgpu_bo *bo, bool no_intr)
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
        int r;
 
-       r = __ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL);
+       r = ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL);
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS)
                        dev_err(adev->dev, "%p reserve failed\n", bo);
@@ -283,7 +283,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
                           uint64_t *flags);
 void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
                           bool evict,
-                          struct ttm_mem_reg *new_mem);
+                          struct ttm_resource *new_mem);
 void amdgpu_bo_release_notify(struct ttm_buffer_object *bo);
 int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
index e11c5d6..95f1447 100644 (file)
 
 #define AMDGPU_TTM_VRAM_MAX_DW_READ    (size_t)128
 
-
-/**
- * amdgpu_init_mem_type - Initialize a memory manager for a specific type of
- * memory request.
- *
- * @bdev: The TTM BO device object (contains a reference to amdgpu_device)
- * @type: The type of memory requested
- * @man: The memory type manager for each domain
- *
- * This is called by ttm_bo_init_mm() when a buffer object is being
- * initialized.
- */
-static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
-                               struct ttm_mem_type_manager *man)
+static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
+                                   unsigned int type,
+                                   uint64_t size)
 {
-       struct amdgpu_device *adev;
-
-       adev = amdgpu_ttm_adev(bdev);
-
-       switch (type) {
-       case TTM_PL_SYSTEM:
-               /* System memory */
-               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case TTM_PL_TT:
-               /* GTT memory  */
-               man->func = &amdgpu_gtt_mgr_func;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-               break;
-       case TTM_PL_VRAM:
-               /* "On-card" video ram */
-               man->func = &amdgpu_vram_mgr_func;
-               man->flags = TTM_MEMTYPE_FLAG_FIXED |
-                            TTM_MEMTYPE_FLAG_MAPPABLE;
-               man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
-               man->default_caching = TTM_PL_FLAG_WC;
-               break;
-       case AMDGPU_PL_GDS:
-       case AMDGPU_PL_GWS:
-       case AMDGPU_PL_OA:
-               /* On-chip GDS memory*/
-               man->func = &ttm_bo_manager_func;
-               man->flags = TTM_MEMTYPE_FLAG_FIXED;
-               man->available_caching = TTM_PL_FLAG_UNCACHED;
-               man->default_caching = TTM_PL_FLAG_UNCACHED;
-               break;
-       default:
-               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
-               return -EINVAL;
-       }
-       return 0;
+       return ttm_range_man_init(&adev->mman.bdev, type,
+                                 TTM_PL_FLAG_UNCACHED, TTM_PL_FLAG_UNCACHED,
+                                 false, size >> PAGE_SHIFT);
 }
 
 /**
@@ -231,9 +183,9 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp)
  * Assign the memory from new_mem to the memory of the buffer object bo.
  */
 static void amdgpu_move_null(struct ttm_buffer_object *bo,
-                            struct ttm_mem_reg *new_mem)
+                            struct ttm_resource *new_mem)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
 
        BUG_ON(old_mem->mm_node != NULL);
        *old_mem = *new_mem;
@@ -250,7 +202,7 @@ static void amdgpu_move_null(struct ttm_buffer_object *bo,
  */
 static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo,
                                    struct drm_mm_node *mm_node,
-                                   struct ttm_mem_reg *mem)
+                                   struct ttm_resource *mem)
 {
        uint64_t addr = 0;
 
@@ -270,7 +222,7 @@ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo,
  * @offset: The offset that drm_mm_node is used for finding.
  *
  */
-static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem,
+static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_resource *mem,
                                               uint64_t *offset)
 {
        struct drm_mm_node *mm_node = mem->mm_node;
@@ -298,7 +250,7 @@ static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem,
  * the physical address for local memory.
  */
 static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
-                                struct ttm_mem_reg *mem,
+                                struct ttm_resource *mem,
                                 struct drm_mm_node *mm_node,
                                 unsigned num_pages, uint64_t offset,
                                 unsigned window, struct amdgpu_ring *ring,
@@ -522,8 +474,8 @@ error:
  */
 static int amdgpu_move_blit(struct ttm_buffer_object *bo,
                            bool evict, bool no_wait_gpu,
-                           struct ttm_mem_reg *new_mem,
-                           struct ttm_mem_reg *old_mem)
+                           struct ttm_resource *new_mem,
+                           struct ttm_resource *old_mem)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
        struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
@@ -582,10 +534,10 @@ error:
  */
 static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
                                struct ttm_operation_ctx *ctx,
-                               struct ttm_mem_reg *new_mem)
+                               struct ttm_resource *new_mem)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
-       struct ttm_mem_reg tmp_mem;
+       struct ttm_resource *old_mem = &bo->mem;
+       struct ttm_resource tmp_mem;
        struct ttm_place placements;
        struct ttm_placement placement;
        int r;
@@ -627,7 +579,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
        /* move BO (in tmp_mem) to new_mem */
        r = ttm_bo_move_ttm(bo, ctx, new_mem);
 out_cleanup:
-       ttm_bo_mem_put(bo, &tmp_mem);
+       ttm_resource_free(bo, &tmp_mem);
        return r;
 }
 
@@ -638,10 +590,10 @@ out_cleanup:
  */
 static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
                                struct ttm_operation_ctx *ctx,
-                               struct ttm_mem_reg *new_mem)
+                               struct ttm_resource *new_mem)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
-       struct ttm_mem_reg tmp_mem;
+       struct ttm_resource *old_mem = &bo->mem;
+       struct ttm_resource tmp_mem;
        struct ttm_placement placement;
        struct ttm_place placements;
        int r;
@@ -674,7 +626,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
                goto out_cleanup;
        }
 out_cleanup:
-       ttm_bo_mem_put(bo, &tmp_mem);
+       ttm_resource_free(bo, &tmp_mem);
        return r;
 }
 
@@ -684,7 +636,7 @@ out_cleanup:
  * Called by amdgpu_bo_move()
  */
 static bool amdgpu_mem_visible(struct amdgpu_device *adev,
-                              struct ttm_mem_reg *mem)
+                              struct ttm_resource *mem)
 {
        struct drm_mm_node *nodes = mem->mm_node;
 
@@ -694,7 +646,7 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev,
        if (mem->mem_type != TTM_PL_VRAM)
                return false;
 
-       /* ttm_mem_reg_ioremap only supports contiguous memory */
+       /* ttm_resource_ioremap only supports contiguous memory */
        if (nodes->size != mem->num_pages)
                return false;
 
@@ -709,11 +661,11 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev,
  */
 static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
                          struct ttm_operation_ctx *ctx,
-                         struct ttm_mem_reg *new_mem)
+                         struct ttm_resource *new_mem)
 {
        struct amdgpu_device *adev;
        struct amdgpu_bo *abo;
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
        int r;
 
        /* Can't move a pinned BO */
@@ -795,9 +747,8 @@ memcpy:
  *
  * Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault()
  */
-static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
 {
-       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
        struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
        struct drm_mm_node *mm_node = mem->mm_node;
 
@@ -806,8 +757,7 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
        mem->bus.size = mem->num_pages << PAGE_SHIFT;
        mem->bus.base = 0;
        mem->bus.is_iomem = false;
-       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
-               return -EINVAL;
+
        switch (mem->mem_type) {
        case TTM_PL_SYSTEM:
                /* system memory */
@@ -821,7 +771,7 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
                        return -EINVAL;
                /* Only physically contiguous buffers apply. In a contiguous
                 * buffer, size of the first mm_node would match the number of
-                * pages in ttm_mem_reg.
+                * pages in ttm_resource.
                 */
                if (adev->mman.aper_base_kaddr &&
                    (mm_node->size == mem->num_pages))
@@ -1166,7 +1116,7 @@ gart_bind_fail:
  * This handles binding GTT memory to the device address space.
  */
 static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
-                                  struct ttm_mem_reg *bo_mem)
+                                  struct ttm_resource *bo_mem)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
        struct amdgpu_ttm_tt *gtt = (void*)ttm;
@@ -1217,7 +1167,7 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
        struct ttm_operation_ctx ctx = { false, false };
        struct amdgpu_ttm_tt *gtt = (void*)bo->ttm;
-       struct ttm_mem_reg tmp;
+       struct ttm_resource tmp;
        struct ttm_placement placement;
        struct ttm_place placements;
        uint64_t addr, flags;
@@ -1254,11 +1204,11 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
                gtt->offset = (u64)tmp.start << PAGE_SHIFT;
                r = amdgpu_ttm_gart_bind(adev, bo, flags);
                if (unlikely(r)) {
-                       ttm_bo_mem_put(bo, &tmp);
+                       ttm_resource_free(bo, &tmp);
                        return r;
                }
 
-               ttm_bo_mem_put(bo, &bo->mem);
+               ttm_resource_free(bo, &bo->mem);
                bo->mem = tmp;
        }
 
@@ -1457,21 +1407,26 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm)
  * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current
  * task
  *
- * @ttm: The ttm_tt object to bind this userptr object to
+ * @bo: The ttm_buffer_object to bind this userptr to
  * @addr:  The address in the current tasks VM space to use
  * @flags: Requirements of userptr object.
  *
  * Called by amdgpu_gem_userptr_ioctl() to bind userptr pages
  * to current task
  */
-int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
-                             uint32_t flags)
+int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
+                             uint64_t addr, uint32_t flags)
 {
-       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct amdgpu_ttm_tt *gtt;
 
-       if (gtt == NULL)
-               return -EINVAL;
+       if (!bo->ttm) {
+               /* TODO: We want a separate TTM object type for userptrs */
+               bo->ttm = amdgpu_ttm_tt_create(bo, 0);
+               if (bo->ttm == NULL)
+                       return -ENOMEM;
+       }
 
+       gtt = (void*)bo->ttm;
        gtt->userptr = addr;
        gtt->userflags = flags;
 
@@ -1557,7 +1512,7 @@ bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
  *
  * Figure out the flags to use for a VM PDE (Page Directory Entry).
  */
-uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
+uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem)
 {
        uint64_t flags = 0;
 
@@ -1583,7 +1538,7 @@ uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
  * Figure out the flags to use for a VM PTE (Page Table Entry).
  */
 uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
-                                struct ttm_mem_reg *mem)
+                                struct ttm_resource *mem)
 {
        uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem);
 
@@ -1741,7 +1696,6 @@ static struct ttm_bo_driver amdgpu_bo_driver = {
        .ttm_tt_create = &amdgpu_ttm_tt_create,
        .ttm_tt_populate = &amdgpu_ttm_tt_populate,
        .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
-       .init_mem_type = &amdgpu_init_mem_type,
        .eviction_valuable = amdgpu_ttm_bo_eviction_valuable,
        .evict_flags = &amdgpu_evict_flags,
        .move = &amdgpu_bo_move,
@@ -1936,8 +1890,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
        adev->mman.bdev.no_retry = true;
 
        /* Initialize VRAM pool with all of VRAM divided into pages */
-       r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM,
-                               adev->gmc.real_vram_size >> PAGE_SHIFT);
+       r = amdgpu_vram_mgr_init(adev);
        if (r) {
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
@@ -2004,7 +1957,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
                gtt_size = (uint64_t)amdgpu_gtt_size << 20;
 
        /* Initialize GTT memory pool */
-       r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_TT, gtt_size >> PAGE_SHIFT);
+       r = amdgpu_gtt_mgr_init(adev, gtt_size);
        if (r) {
                DRM_ERROR("Failed initializing GTT heap.\n");
                return r;
@@ -2013,22 +1966,19 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
                 (unsigned)(gtt_size / (1024 * 1024)));
 
        /* Initialize various on-chip memory pools */
-       r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS,
-                          adev->gds.gds_size);
+       r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size);
        if (r) {
                DRM_ERROR("Failed initializing GDS heap.\n");
                return r;
        }
 
-       r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS,
-                          adev->gds.gws_size);
+       r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size);
        if (r) {
                DRM_ERROR("Failed initializing gws heap.\n");
                return r;
        }
 
-       r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA,
-                          adev->gds.oa_size);
+       r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size);
        if (r) {
                DRM_ERROR("Failed initializing oa heap.\n");
                return r;
@@ -2064,11 +2014,11 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
                iounmap(adev->mman.aper_base_kaddr);
        adev->mman.aper_base_kaddr = NULL;
 
-       ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM);
-       ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT);
-       ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS);
-       ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
-       ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
+       amdgpu_vram_mgr_fini(adev);
+       amdgpu_gtt_mgr_fini(adev);
+       ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);
+       ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS);
+       ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA);
        ttm_bo_device_release(&adev->mman.bdev);
        adev->mman.initialized = false;
        DRM_INFO("amdgpu: ttm finalized\n");
@@ -2085,7 +2035,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
  */
 void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
 {
-       struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM];
+       struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
        uint64_t size;
        int r;
 
@@ -2307,7 +2257,7 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data)
        unsigned ttm_pl = (uintptr_t)node->info_ent->data;
        struct drm_device *dev = node->minor->dev;
        struct amdgpu_device *adev = dev->dev_private;
-       struct ttm_mem_type_manager *man = &adev->mman.bdev.man[ttm_pl];
+       struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, ttm_pl);
        struct drm_printer p = drm_seq_file_printer(m);
 
        man->func->debug(man, &p);
index 17c8d0d..7ba2be3 100644 (file)
 
 #define AMDGPU_POISON  0xd0bed0be
 
+struct amdgpu_vram_mgr {
+       struct ttm_resource_manager manager;
+       struct drm_mm mm;
+       spinlock_t lock;
+       atomic64_t usage;
+       atomic64_t vis_usage;
+};
+
+struct amdgpu_gtt_mgr {
+       struct ttm_resource_manager manager;
+       struct drm_mm mm;
+       spinlock_t lock;
+       atomic64_t available;
+};
+
 struct amdgpu_mman {
        struct ttm_bo_device            bdev;
        bool                            mem_global_referenced;
@@ -59,24 +74,29 @@ struct amdgpu_mman {
        struct mutex                            gtt_window_lock;
        /* Scheduler entity for buffer moves */
        struct drm_sched_entity                 entity;
+
+       struct amdgpu_vram_mgr vram_mgr;
+       struct amdgpu_gtt_mgr gtt_mgr;
 };
 
 struct amdgpu_copy_mem {
        struct ttm_buffer_object        *bo;
-       struct ttm_mem_reg              *mem;
+       struct ttm_resource             *mem;
        unsigned long                   offset;
 };
 
-extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func;
-extern const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func;
+int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size);
+void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev);
+int amdgpu_vram_mgr_init(struct amdgpu_device *adev);
+void amdgpu_vram_mgr_fini(struct amdgpu_device *adev);
 
-bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem);
-uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man);
-int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man);
+bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem);
+uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man);
+int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man);
 
 u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo);
 int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
-                             struct ttm_mem_reg *mem,
+                             struct ttm_resource *mem,
                              struct device *dev,
                              enum dma_data_direction dir,
                              struct sg_table **sgt);
@@ -84,8 +104,8 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
                              struct device *dev,
                              enum dma_data_direction dir,
                              struct sg_table *sgt);
-uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man);
-uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man);
+uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man);
+uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man);
 
 int amdgpu_ttm_init(struct amdgpu_device *adev);
 void amdgpu_ttm_late_init(struct amdgpu_device *adev);
@@ -130,8 +150,8 @@ static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
 #endif
 
 void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages);
-int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
-                                    uint32_t flags);
+int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
+                             uint64_t addr, uint32_t flags);
 bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm);
 struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm);
 bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
@@ -140,9 +160,9 @@ bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm,
                                       int *last_invalidated);
 bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm);
 bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
-uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem);
+uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem);
 uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
-                                struct ttm_mem_reg *mem);
+                                struct ttm_resource *mem);
 
 int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
 
index 71e005c..8bc2253 100644 (file)
@@ -1765,7 +1765,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
        struct amdgpu_vm *vm = bo_va->base.vm;
        struct amdgpu_bo_va_mapping *mapping;
        dma_addr_t *pages_addr = NULL;
-       struct ttm_mem_reg *mem;
+       struct ttm_resource *mem;
        struct drm_mm_node *nodes;
        struct dma_fence **last_update;
        struct dma_resv *resv;
index 134cc36..7574be6 100644 (file)
 #include "amdgpu_atomfirmware.h"
 #include "atom.h"
 
-struct amdgpu_vram_mgr {
-       struct drm_mm mm;
-       spinlock_t lock;
-       atomic64_t usage;
-       atomic64_t vis_usage;
-};
+static inline struct amdgpu_vram_mgr *to_vram_mgr(struct ttm_resource_manager *man)
+{
+       return container_of(man, struct amdgpu_vram_mgr, manager);
+}
+
+static inline struct amdgpu_device *to_amdgpu_device(struct amdgpu_vram_mgr *mgr)
+{
+       return container_of(mgr, struct amdgpu_device, mman.vram_mgr);
+}
 
 /**
  * DOC: mem_info_vram_total
@@ -82,9 +85,9 @@ static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
-
+       struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
        return snprintf(buf, PAGE_SIZE, "%llu\n",
-               amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
+                       amdgpu_vram_mgr_usage(man));
 }
 
 /**
@@ -100,9 +103,9 @@ static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
-
+       struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
        return snprintf(buf, PAGE_SIZE, "%llu\n",
-               amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]));
+                       amdgpu_vram_mgr_vis_usage(man));
 }
 
 static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev,
@@ -158,6 +161,8 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = {
        NULL
 };
 
+static const struct ttm_resource_manager_func amdgpu_vram_mgr_func;
+
 /**
  * amdgpu_vram_mgr_init - init VRAM manager and DRM MM
  *
@@ -166,26 +171,29 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = {
  *
  * Allocate and initialize the VRAM manager.
  */
-static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
-                               unsigned long p_size)
+int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
-       struct amdgpu_vram_mgr *mgr;
+       struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
+       struct ttm_resource_manager *man = &mgr->manager;
        int ret;
 
-       mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
-       if (!mgr)
-               return -ENOMEM;
+       man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+       man->default_caching = TTM_PL_FLAG_WC;
 
-       drm_mm_init(&mgr->mm, 0, p_size);
+       ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT);
+
+       man->func = &amdgpu_vram_mgr_func;
+
+       drm_mm_init(&mgr->mm, 0, man->size);
        spin_lock_init(&mgr->lock);
-       man->priv = mgr;
 
        /* Add the two VRAM-related sysfs files */
        ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes);
        if (ret)
                DRM_ERROR("Failed to register sysfs\n");
 
+       ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
+       ttm_resource_manager_set_used(man, true);
        return 0;
 }
 
@@ -197,18 +205,26 @@ static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
  * Destroy and free the VRAM manager, returns -EBUSY if ranges are still
  * allocated inside it.
  */
-static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
+void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
-       struct amdgpu_vram_mgr *mgr = man->priv;
+       struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
+       struct ttm_resource_manager *man = &mgr->manager;
+       int ret;
+
+       ttm_resource_manager_set_used(man, false);
+
+       ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man);
+       if (ret)
+               return;
 
        spin_lock(&mgr->lock);
        drm_mm_takedown(&mgr->mm);
        spin_unlock(&mgr->lock);
-       kfree(mgr);
-       man->priv = NULL;
+
        sysfs_remove_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes);
-       return 0;
+
+       ttm_resource_manager_cleanup(man);
+       ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL);
 }
 
 /**
@@ -243,7 +259,7 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
 u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
-       struct ttm_mem_reg *mem = &bo->tbo.mem;
+       struct ttm_resource *mem = &bo->tbo.mem;
        struct drm_mm_node *nodes = mem->mm_node;
        unsigned pages = mem->num_pages;
        u64 usage;
@@ -263,13 +279,13 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 /**
  * amdgpu_vram_mgr_virt_start - update virtual start address
  *
- * @mem: ttm_mem_reg to update
+ * @mem: ttm_resource to update
  * @node: just allocated node
  *
  * Calculate a virtual BO start address to easily check if everything is CPU
  * accessible.
  */
-static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem,
+static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
                                       struct drm_mm_node *node)
 {
        unsigned long start;
@@ -292,13 +308,13 @@ static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem,
  *
  * Allocate VRAM for the given BO.
  */
-static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
+static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                               struct ttm_buffer_object *tbo,
                               const struct ttm_place *place,
-                              struct ttm_mem_reg *mem)
+                              struct ttm_resource *mem)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
-       struct amdgpu_vram_mgr *mgr = man->priv;
+       struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+       struct amdgpu_device *adev = to_amdgpu_device(mgr);
        struct drm_mm *mm = &mgr->mm;
        struct drm_mm_node *nodes;
        enum drm_mm_insert_mode mode;
@@ -410,11 +426,11 @@ error:
  *
  * Free the allocated VRAM again.
  */
-static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
-                               struct ttm_mem_reg *mem)
+static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
+                               struct ttm_resource *mem)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
-       struct amdgpu_vram_mgr *mgr = man->priv;
+       struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+       struct amdgpu_device *adev = to_amdgpu_device(mgr);
        struct drm_mm_node *nodes = mem->mm_node;
        uint64_t usage = 0, vis_usage = 0;
        unsigned pages = mem->num_pages;
@@ -451,7 +467,7 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
  * Allocate and fill a sg table from a VRAM allocation.
  */
 int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
-                             struct ttm_mem_reg *mem,
+                             struct ttm_resource *mem,
                              struct device *dev,
                              enum dma_data_direction dir,
                              struct sg_table **sgt)
@@ -544,9 +560,9 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
  *
  * Returns how many bytes are used in this domain.
  */
-uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
+uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man)
 {
-       struct amdgpu_vram_mgr *mgr = man->priv;
+       struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
 
        return atomic64_read(&mgr->usage);
 }
@@ -558,9 +574,9 @@ uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
  *
  * Returns how many bytes are used in the visible part of VRAM
  */
-uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
+uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man)
 {
-       struct amdgpu_vram_mgr *mgr = man->priv;
+       struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
 
        return atomic64_read(&mgr->vis_usage);
 }
@@ -573,10 +589,10 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
  *
  * Dump the table content using printk.
  */
-static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
+static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
                                  struct drm_printer *printer)
 {
-       struct amdgpu_vram_mgr *mgr = man->priv;
+       struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
 
        spin_lock(&mgr->lock);
        drm_mm_print(&mgr->mm, printer);
@@ -587,10 +603,8 @@ static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
                   amdgpu_vram_mgr_vis_usage(man) >> 20);
 }
 
-const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = {
-       .init           = amdgpu_vram_mgr_init,
-       .takedown       = amdgpu_vram_mgr_fini,
-       .get_node       = amdgpu_vram_mgr_new,
-       .put_node       = amdgpu_vram_mgr_del,
-       .debug          = amdgpu_vram_mgr_debug
+static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
+       .alloc  = amdgpu_vram_mgr_new,
+       .free   = amdgpu_vram_mgr_del,
+       .debug  = amdgpu_vram_mgr_debug
 };
index 9b74cfd..900b272 100644 (file)
@@ -328,6 +328,22 @@ static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connect
                              buf[0], buf[1], buf[2]);
 }
 
+static void amdgpu_atombios_dp_ds_ports(struct amdgpu_connector *amdgpu_connector)
+{
+       struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
+       int ret;
+
+       if (dig_connector->dpcd[DP_DPCD_REV] > 0x10) {
+               ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux,
+                                      DP_DOWNSTREAM_PORT_0,
+                                      dig_connector->downstream_ports,
+                                      DP_MAX_DOWNSTREAM_PORTS);
+               if (ret)
+                       memset(dig_connector->downstream_ports, 0,
+                              DP_MAX_DOWNSTREAM_PORTS);
+       }
+}
+
 int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
 {
        struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
@@ -343,7 +359,7 @@ int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
                              dig_connector->dpcd);
 
                amdgpu_atombios_dp_probe_oui(amdgpu_connector);
-
+               amdgpu_atombios_dp_ds_ports(amdgpu_connector);
                return 0;
        }
 
index e4b33c6..fd96faf 100644 (file)
@@ -127,6 +127,42 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
 static int amdgpu_dm_init(struct amdgpu_device *adev);
 static void amdgpu_dm_fini(struct amdgpu_device *adev);
 
+static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
+{
+       switch (link->dpcd_caps.dongle_type) {
+       case DISPLAY_DONGLE_NONE:
+               return DRM_MODE_SUBCONNECTOR_Native;
+       case DISPLAY_DONGLE_DP_VGA_CONVERTER:
+               return DRM_MODE_SUBCONNECTOR_VGA;
+       case DISPLAY_DONGLE_DP_DVI_CONVERTER:
+       case DISPLAY_DONGLE_DP_DVI_DONGLE:
+               return DRM_MODE_SUBCONNECTOR_DVID;
+       case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
+       case DISPLAY_DONGLE_DP_HDMI_DONGLE:
+               return DRM_MODE_SUBCONNECTOR_HDMIA;
+       case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
+       default:
+               return DRM_MODE_SUBCONNECTOR_Unknown;
+       }
+}
+
+static void update_subconnector_property(struct amdgpu_dm_connector *aconnector)
+{
+       struct dc_link *link = aconnector->dc_link;
+       struct drm_connector *connector = &aconnector->base;
+       enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+
+       if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+               return;
+
+       if (aconnector->dc_sink)
+               subconnector = get_subconnector_type(link);
+
+       drm_object_property_set_value(&connector->base,
+                       connector->dev->mode_config.dp_subconnector_property,
+                       subconnector);
+}
+
 /*
  * initializes drm_device display related structures, based on the information
  * provided by DAL. The drm strcutures are: drm_crtc, drm_connector,
@@ -2095,7 +2131,6 @@ void amdgpu_dm_update_connector_after_detect(
        if (aconnector->mst_mgr.mst_state == true)
                return;
 
-
        sink = aconnector->dc_link->local_sink;
        if (sink)
                dc_sink_retain(sink);
@@ -2221,6 +2256,8 @@ void amdgpu_dm_update_connector_after_detect(
 
        mutex_unlock(&dev->mode_config.mutex);
 
+       update_subconnector_property(aconnector);
+
        if (sink)
                dc_sink_release(sink);
 }
@@ -4756,6 +4793,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
        else
                connected = (aconnector->base.force == DRM_FORCE_ON);
 
+       update_subconnector_property(aconnector);
+
        return (connected ? connector_status_connected :
                        connector_status_disconnected);
 }
index e85b58f..a61a294 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/version.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_dp_helper.h>
 #include "dm_services.h"
 #include "amdgpu.h"
 #include "amdgpu_dm.h"
@@ -431,6 +432,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
                16,
                4,
                aconnector->connector_id);
+
+       drm_connector_attach_dp_subconnector_property(&aconnector->base);
 }
 
 int dm_mst_get_pbn_divider(struct dc_link *link)
index acf0d23..6c96f74 100644 (file)
@@ -47,7 +47,7 @@ static void ast_cursor_fini(struct ast_private *ast)
 
 static void ast_cursor_release(struct drm_device *dev, void *ptr)
 {
-       struct ast_private *ast = dev->dev_private;
+       struct ast_private *ast = to_ast_private(dev);
 
        ast_cursor_fini(ast);
 }
@@ -57,7 +57,7 @@ static void ast_cursor_release(struct drm_device *dev, void *ptr)
  */
 int ast_cursor_init(struct ast_private *ast)
 {
-       struct drm_device *dev = ast->dev;
+       struct drm_device *dev = &ast->base;
        size_t size, i;
        struct drm_gem_vram_object *gbo;
        void __iomem *vaddr;
@@ -168,7 +168,7 @@ static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int h
 
 int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb)
 {
-       struct drm_device *dev = ast->dev;
+       struct drm_device *dev = &ast->base;
        struct drm_gem_vram_object *gbo;
        int ret;
        void *src;
@@ -217,7 +217,7 @@ static void ast_cursor_set_base(struct ast_private *ast, u64 address)
 
 void ast_cursor_page_flip(struct ast_private *ast)
 {
-       struct drm_device *dev = ast->dev;
+       struct drm_device *dev = &ast->base;
        struct drm_gem_vram_object *gbo;
        s64 off;
 
index 4b85a50..88121c0 100644 (file)
@@ -8,11 +8,24 @@
 
 MODULE_FIRMWARE("ast_dp501_fw.bin");
 
+static void ast_release_firmware(void *data)
+{
+       struct ast_private *ast = data;
+
+       release_firmware(ast->dp501_fw);
+       ast->dp501_fw = NULL;
+}
+
 static int ast_load_dp501_microcode(struct drm_device *dev)
 {
        struct ast_private *ast = to_ast_private(dev);
+       int ret;
+
+       ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
+       if (ret)
+               return ret;
 
-       return request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
+       return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast);
 }
 
 static void send_ack(struct ast_private *ast)
@@ -435,11 +448,3 @@ void ast_init_3rdtx(struct drm_device *dev)
                }
        }
 }
-
-void ast_release_firmware(struct drm_device *dev)
-{
-       struct ast_private *ast = to_ast_private(dev);
-
-       release_firmware(ast->dp501_fw);
-       ast->dp501_fw = NULL;
-}
index 0b58f7a..f0b4af1 100644 (file)
@@ -43,9 +43,33 @@ int ast_modeset = -1;
 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
 module_param_named(modeset, ast_modeset, int, 0400);
 
-#define PCI_VENDOR_ASPEED 0x1a03
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_FOPS(ast_fops);
+
+static struct drm_driver ast_driver = {
+       .driver_features = DRIVER_ATOMIC |
+                          DRIVER_GEM |
+                          DRIVER_MODESET,
+
+       .fops = &ast_fops,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+
+       DRM_GEM_VRAM_DRIVER
+};
+
+/*
+ * PCI driver
+ */
 
-static struct drm_driver driver;
+#define PCI_VENDOR_ASPEED 0x1a03
 
 #define AST_VGA_DEVICE(id, info) {             \
        .class = PCI_BASE_CLASS_DISPLAY << 16,  \
@@ -56,13 +80,13 @@ static struct drm_driver driver;
        .subdevice = PCI_ANY_ID,                \
        .driver_data = (unsigned long) info }
 
-static const struct pci_device_id pciidlist[] = {
+static const struct pci_device_id ast_pciidlist[] = {
        AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
        AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
        {0, 0, 0},
 };
 
-MODULE_DEVICE_TABLE(pci, pciidlist);
+MODULE_DEVICE_TABLE(pci, ast_pciidlist);
 
 static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
 {
@@ -85,6 +109,7 @@ static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
 
 static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       struct ast_private *ast;
        struct drm_device *dev;
        int ret;
 
@@ -94,41 +119,25 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                return ret;
 
-       dev = drm_dev_alloc(&driver, &pdev->dev);
-       if (IS_ERR(dev))
-               return  PTR_ERR(dev);
-
-       dev->pdev = pdev;
-       pci_set_drvdata(pdev, dev);
-
-       ret = ast_driver_load(dev, ent->driver_data);
-       if (ret)
-               goto err_drm_dev_put;
+       ast = ast_device_create(&ast_driver, pdev, ent->driver_data);
+       if (IS_ERR(ast))
+               return PTR_ERR(ast);
+       dev = &ast->base;
 
        ret = drm_dev_register(dev, ent->driver_data);
        if (ret)
-               goto err_ast_driver_unload;
+               return ret;
 
        drm_fbdev_generic_setup(dev, 32);
 
        return 0;
-
-err_ast_driver_unload:
-       ast_driver_unload(dev);
-err_drm_dev_put:
-       drm_dev_put(dev);
-       return ret;
-
 }
 
-static void
-ast_pci_remove(struct pci_dev *pdev)
+static void ast_pci_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
 
        drm_dev_unregister(dev);
-       ast_driver_unload(dev);
-       drm_dev_put(dev);
 }
 
 static int ast_drm_freeze(struct drm_device *dev)
@@ -217,30 +226,12 @@ static const struct dev_pm_ops ast_pm_ops = {
 
 static struct pci_driver ast_pci_driver = {
        .name = DRIVER_NAME,
-       .id_table = pciidlist,
+       .id_table = ast_pciidlist,
        .probe = ast_pci_probe,
        .remove = ast_pci_remove,
        .driver.pm = &ast_pm_ops,
 };
 
-DEFINE_DRM_GEM_FOPS(ast_fops);
-
-static struct drm_driver driver = {
-       .driver_features = DRIVER_ATOMIC |
-                          DRIVER_GEM |
-                          DRIVER_MODESET,
-
-       .fops = &ast_fops,
-       .name = DRIVER_NAME,
-       .desc = DRIVER_DESC,
-       .date = DRIVER_DATE,
-       .major = DRIVER_MAJOR,
-       .minor = DRIVER_MINOR,
-       .patchlevel = DRIVER_PATCHLEVEL,
-
-       DRM_GEM_VRAM_DRIVER
-};
-
 static int __init ast_init(void)
 {
        if (vgacon_text_force() && ast_modeset == -1)
@@ -261,4 +252,3 @@ module_exit(ast_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL and additional rights");
-
index e3a264a..c1af6b7 100644 (file)
@@ -98,9 +98,25 @@ enum ast_tx_chip {
 #define AST_HWC_SIGNATURE_HOTSPOTX     0x14
 #define AST_HWC_SIGNATURE_HOTSPOTY     0x18
 
+struct ast_i2c_chan {
+       struct i2c_adapter adapter;
+       struct drm_device *dev;
+       struct i2c_algo_bit_data bit;
+};
+
+struct ast_connector {
+       struct drm_connector base;
+       struct ast_i2c_chan *i2c;
+};
+
+static inline struct ast_connector *
+to_ast_connector(struct drm_connector *connector)
+{
+       return container_of(connector, struct ast_connector, base);
+}
 
 struct ast_private {
-       struct drm_device *dev;
+       struct drm_device base;
 
        void __iomem *regs;
        void __iomem *ioregs;
@@ -119,9 +135,11 @@ struct ast_private {
                unsigned int next_index;
        } cursor;
 
-       struct drm_encoder encoder;
        struct drm_plane primary_plane;
        struct drm_plane cursor_plane;
+       struct drm_crtc crtc;
+       struct drm_encoder encoder;
+       struct ast_connector connector;
 
        bool support_wide_screen;
        enum {
@@ -138,11 +156,12 @@ struct ast_private {
 
 static inline struct ast_private *to_ast_private(struct drm_device *dev)
 {
-       return dev->dev_private;
+       return container_of(dev, struct ast_private, base);
 }
 
-int ast_driver_load(struct drm_device *dev, unsigned long flags);
-void ast_driver_unload(struct drm_device *dev);
+struct ast_private *ast_device_create(struct drm_driver *drv,
+                                     struct pci_dev *pdev,
+                                     unsigned long flags);
 
 #define AST_IO_AR_PORT_WRITE           (0x40)
 #define AST_IO_MISC_PORT_WRITE         (0x42)
@@ -226,19 +245,6 @@ static inline void ast_open_key(struct ast_private *ast)
 
 #define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
 
-struct ast_i2c_chan {
-       struct i2c_adapter adapter;
-       struct drm_device *dev;
-       struct i2c_algo_bit_data bit;
-};
-
-struct ast_connector {
-       struct drm_connector base;
-       struct ast_i2c_chan *i2c;
-};
-
-#define to_ast_connector(x) container_of(x, struct ast_connector, base)
-
 struct ast_vbios_stdtable {
        u8 misc;
        u8 seq[4];
@@ -305,7 +311,6 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
 bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
 u8 ast_get_dp501_max_clk(struct drm_device *dev);
 void ast_init_3rdtx(struct drm_device *dev);
-void ast_release_firmware(struct drm_device *dev);
 
 /* ast_cursor.c */
 int ast_cursor_init(struct ast_private *ast);
index dd12b55..d62749a 100644 (file)
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
 #include <drm/drm_gem.h>
 #include <drm/drm_gem_vram_helper.h>
+#include <drm/drm_managed.h>
 
 #include "ast_drv.h"
 
@@ -230,11 +232,11 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
                        ast->tx_chip_type = AST_TX_SIL164;
                        break;
                case 0x08:
-                       ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL);
+                       ast->dp501_fw_addr = drmm_kzalloc(dev, 32*1024, GFP_KERNEL);
                        if (ast->dp501_fw_addr) {
                                /* backup firmware */
                                if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) {
-                                       kfree(ast->dp501_fw_addr);
+                                       drmm_kfree(dev, ast->dp501_fw_addr);
                                        ast->dp501_fw_addr = NULL;
                                }
                        }
@@ -378,24 +380,38 @@ static int ast_get_dram_info(struct drm_device *dev)
        return 0;
 }
 
-int ast_driver_load(struct drm_device *dev, unsigned long flags)
+/*
+ * Run this function as part of the HW device cleanup; not
+ * when the DRM device gets released.
+ */
+static void ast_device_release(void *data)
 {
+       struct ast_private *ast = data;
+
+       /* enable standard VGA decode */
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04);
+}
+
+struct ast_private *ast_device_create(struct drm_driver *drv,
+                                     struct pci_dev *pdev,
+                                     unsigned long flags)
+{
+       struct drm_device *dev;
        struct ast_private *ast;
        bool need_post;
        int ret = 0;
 
-       ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
-       if (!ast)
-               return -ENOMEM;
+       ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base);
+       if (IS_ERR(ast))
+               return ast;
+       dev = &ast->base;
 
-       dev->dev_private = ast;
-       ast->dev = dev;
+       dev->pdev = pdev;
+       pci_set_drvdata(pdev, dev);
 
        ast->regs = pci_iomap(dev->pdev, 1, 0);
-       if (!ast->regs) {
-               ret = -EIO;
-               goto out_free;
-       }
+       if (!ast->regs)
+               return ERR_PTR(-EIO);
 
        /*
         * If we don't have IO space at all, use MMIO now and
@@ -410,17 +426,16 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
        /* "map" IO regs if the above hasn't done so already */
        if (!ast->ioregs) {
                ast->ioregs = pci_iomap(dev->pdev, 2, 0);
-               if (!ast->ioregs) {
-                       ret = -EIO;
-                       goto out_free;
-               }
+               if (!ast->ioregs)
+                       return ERR_PTR(-EIO);
        }
 
        ast_detect_chip(dev, &need_post);
 
        ret = ast_get_dram_info(dev);
        if (ret)
-               goto out_free;
+               return ERR_PTR(ret);
+
        drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n",
                 ast->mclk, ast->dram_type, ast->dram_bus_width);
 
@@ -429,28 +444,15 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
 
        ret = ast_mm_init(ast);
        if (ret)
-               goto out_free;
+               return ERR_PTR(ret);
 
        ret = ast_mode_config_init(ast);
        if (ret)
-               goto out_free;
+               return ERR_PTR(ret);
 
-       return 0;
-out_free:
-       kfree(ast);
-       dev->dev_private = NULL;
-       return ret;
-}
-
-void ast_driver_unload(struct drm_device *dev)
-{
-       struct ast_private *ast = to_ast_private(dev);
-
-       /* enable standard VGA decode */
-       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04);
-
-       ast_release_firmware(dev);
-       kfree(ast->dp501_fw_addr);
+       ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast);
+       if (ret)
+               return ERR_PTR(ret);
 
-       kfree(ast);
+       return ast;
 }
index 9186ec3..8392ebd 100644 (file)
@@ -85,9 +85,9 @@ static void ast_mm_release(struct drm_device *dev, void *ptr)
 
 int ast_mm_init(struct ast_private *ast)
 {
+       struct drm_device *dev = &ast->base;
        u32 vram_size;
        int ret;
-       struct drm_device *dev = ast->dev;
 
        vram_size = ast_get_vram_size(ast);
 
index 154cd87..62fe682 100644 (file)
@@ -663,7 +663,7 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,
 {
        struct drm_plane_state *state = plane->state;
        struct drm_framebuffer *fb = state->fb;
-       struct ast_private *ast = plane->dev->dev_private;
+       struct ast_private *ast = to_ast_private(plane->dev);
        unsigned int offset_x, offset_y;
 
        offset_x = AST_MAX_HWC_WIDTH - fb->width;
@@ -831,12 +831,6 @@ static void ast_crtc_reset(struct drm_crtc *crtc)
        __drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
 }
 
-static void ast_crtc_destroy(struct drm_crtc *crtc)
-{
-       drm_crtc_cleanup(crtc);
-       kfree(crtc);
-}
-
 static struct drm_crtc_state *
 ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 {
@@ -872,7 +866,7 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
 static const struct drm_crtc_funcs ast_crtc_funcs = {
        .reset = ast_crtc_reset,
        .gamma_set = drm_atomic_helper_legacy_gamma_set,
-       .destroy = ast_crtc_destroy,
+       .destroy = drm_crtc_cleanup,
        .set_config = drm_atomic_helper_set_config,
        .page_flip = drm_atomic_helper_page_flip,
        .atomic_duplicate_state = ast_crtc_atomic_duplicate_state,
@@ -882,27 +876,19 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
 static int ast_crtc_init(struct drm_device *dev)
 {
        struct ast_private *ast = to_ast_private(dev);
-       struct drm_crtc *crtc;
+       struct drm_crtc *crtc = &ast->crtc;
        int ret;
 
-       crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
-       if (!crtc)
-               return -ENOMEM;
-
        ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane,
                                        &ast->cursor_plane, &ast_crtc_funcs,
                                        NULL);
        if (ret)
-               goto err_kfree;
+               return ret;
 
        drm_mode_crtc_set_gamma_size(crtc, 256);
        drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);
 
        return 0;
-
-err_kfree:
-       kfree(crtc);
-       return ret;
 }
 
 /*
@@ -1021,7 +1007,6 @@ static void ast_connector_destroy(struct drm_connector *connector)
        struct ast_connector *ast_connector = to_ast_connector(connector);
        ast_i2c_destroy(ast_connector->i2c);
        drm_connector_cleanup(connector);
-       kfree(connector);
 }
 
 static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
@@ -1039,15 +1024,11 @@ static const struct drm_connector_funcs ast_connector_funcs = {
 
 static int ast_connector_init(struct drm_device *dev)
 {
-       struct ast_connector *ast_connector;
-       struct drm_connector *connector;
-       struct drm_encoder *encoder;
-
-       ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL);
-       if (!ast_connector)
-               return -ENOMEM;
+       struct ast_private *ast = to_ast_private(dev);
+       struct ast_connector *ast_connector = &ast->connector;
+       struct drm_connector *connector = &ast_connector->base;
+       struct drm_encoder *encoder = &ast->encoder;
 
-       connector = &ast_connector->base;
        ast_connector->i2c = ast_i2c_create(dev);
        if (!ast_connector->i2c)
                drm_err(dev, "failed to add ddc bus for connector\n");
@@ -1064,7 +1045,6 @@ static int ast_connector_init(struct drm_device *dev)
 
        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 
-       encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head);
        drm_connector_attach_encoder(connector, encoder);
 
        return 0;
@@ -1083,7 +1063,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = {
 
 int ast_mode_config_init(struct ast_private *ast)
 {
-       struct drm_device *dev = ast->dev;
+       struct drm_device *dev = &ast->base;
        int ret;
 
        ret = ast_cursor_init(ast);
@@ -1099,7 +1079,7 @@ int ast_mode_config_init(struct ast_private *ast)
        dev->mode_config.min_height = 0;
        dev->mode_config.preferred_depth = 24;
        dev->mode_config.prefer_shadow = 1;
-       dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0);
+       dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
 
        if (ast->chip == AST2100 ||
            ast->chip == AST2200 ||
index c043fe7..8902c2f 100644 (file)
@@ -365,12 +365,12 @@ static void ast_init_dram_reg(struct drm_device *dev)
 
 void ast_post_gpu(struct drm_device *dev)
 {
-       u32 reg;
        struct ast_private *ast = to_ast_private(dev);
+       u32 reg;
 
-       pci_read_config_dword(ast->dev->pdev, 0x04, &reg);
+       pci_read_config_dword(dev->pdev, 0x04, &reg);
        reg |= 0x3;
-       pci_write_config_dword(ast->dev->pdev, 0x04, reg);
+       pci_write_config_dword(dev->pdev, 0x04, reg);
 
        ast_enable_vga(dev);
        ast_open_key(ast);
index 43271c2..e8672cf 100644 (file)
@@ -48,6 +48,19 @@ config DRM_DISPLAY_CONNECTOR
          on ARM-based platforms. Saying Y here when this driver is not needed
          will not cause any issue.
 
+config DRM_LONTIUM_LT9611
+       tristate "Lontium LT9611 DSI/HDMI bridge"
+       select SND_SOC_HDMI_CODEC if SND_SOC
+       depends on OF
+       select DRM_PANEL_BRIDGE
+       select DRM_KMS_HELPER
+       select REGMAP_I2C
+       help
+         Driver for Lontium LT9611 DSI to HDMI bridge
+         chip driver that converts dual DSI and I2S to
+         HDMI signals
+         Please say Y if you have such hardware.
+
 config DRM_LVDS_CODEC
        tristate "Transparent LVDS encoders and decoders support"
        depends on OF
@@ -181,6 +194,16 @@ config DRM_TOSHIBA_TC358768
        help
          Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver.
 
+config DRM_TOSHIBA_TC358775
+       tristate "Toshiba TC358775 DSI/LVDS bridge"
+       depends on OF
+       select DRM_KMS_HELPER
+       select REGMAP_I2C
+       select DRM_PANEL
+       select DRM_MIPI_DSI
+       help
+         Toshiba TC358775 DSI/LVDS bridge chip driver.
+
 config DRM_TI_TFP410
        tristate "TI TFP410 DVI/HDMI bridge"
        depends on OF
index d63d4b7..5f65f3d 100644 (file)
@@ -2,6 +2,7 @@
 obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
 obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
 obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
+obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
 obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
@@ -15,6 +16,7 @@ obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
 obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o
+obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
 obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
 obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
index f082b4e..d9164fa 100644 (file)
@@ -507,10 +507,6 @@ static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs =
 static void
 anx6345_connector_destroy(struct drm_connector *connector)
 {
-       struct anx6345 *anx6345 = connector_to_anx6345(connector);
-
-       if (anx6345->panel)
-               drm_panel_detach(anx6345->panel);
        drm_connector_cleanup(connector);
 }
 
@@ -575,14 +571,6 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge,
                return err;
        }
 
-       if (anx6345->panel) {
-               err = drm_panel_attach(anx6345->panel, &anx6345->connector);
-               if (err) {
-                       DRM_ERROR("Failed to attach panel: %d\n", err);
-                       return err;
-               }
-       }
-
        return 0;
 }
 
index 76736fb..aa1bb86 100644 (file)
@@ -1265,14 +1265,6 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
                }
        }
 
-       if (dp->plat_data->panel) {
-               ret = drm_panel_attach(dp->plat_data->panel, &dp->connector);
-               if (ret) {
-                       DRM_ERROR("Failed to attach panel\n");
-                       return ret;
-               }
-       }
-
        return 0;
 }
 
@@ -1803,7 +1795,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
        if (dp->plat_data->panel) {
                if (drm_panel_unprepare(dp->plat_data->panel))
                        DRM_ERROR("failed to turnoff the panel\n");
-               drm_panel_detach(dp->plat_data->panel);
        }
 
        drm_dp_aux_unregister(&dp->aux);
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
new file mode 100644 (file)
index 0000000..1009fc4
--- /dev/null
@@ -0,0 +1,1230 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020. Linaro Limited.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/hdmi-codec.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#define EDID_SEG_SIZE  256
+#define EDID_LEN       32
+#define EDID_LOOP      8
+#define KEY_DDC_ACCS_DONE 0x02
+#define DDC_NO_ACK     0x50
+
+#define LT9611_4LANES  0
+
+struct lt9611 {
+       struct device *dev;
+       struct drm_bridge bridge;
+       struct drm_connector connector;
+
+       struct regmap *regmap;
+
+       struct device_node *dsi0_node;
+       struct device_node *dsi1_node;
+       struct mipi_dsi_device *dsi0;
+       struct mipi_dsi_device *dsi1;
+       struct platform_device *audio_pdev;
+
+       bool ac_mode;
+
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *enable_gpio;
+
+       bool power_on;
+       bool sleep;
+
+       struct regulator_bulk_data supplies[2];
+
+       struct i2c_client *client;
+
+       enum drm_connector_status status;
+
+       u8 edid_buf[EDID_SEG_SIZE];
+       u32 vic;
+};
+
+#define LT9611_PAGE_CONTROL    0xff
+
+static const struct regmap_range_cfg lt9611_ranges[] = {
+       {
+               .name = "register_range",
+               .range_min =  0,
+               .range_max = 0x85ff,
+               .selector_reg = LT9611_PAGE_CONTROL,
+               .selector_mask = 0xff,
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = 0x100,
+       },
+};
+
+static const struct regmap_config lt9611_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xffff,
+       .ranges = lt9611_ranges,
+       .num_ranges = ARRAY_SIZE(lt9611_ranges),
+};
+
+struct lt9611_mode {
+       u16 hdisplay;
+       u16 vdisplay;
+       u8 vrefresh;
+       u8 lanes;
+       u8 intfs;
+};
+
+static struct lt9611_mode lt9611_modes[] = {
+       { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */
+       { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */
+       { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */
+       { 1920, 1080, 24, 3, 1 },
+       { 720, 480, 60, 4, 1 },
+       { 720, 576, 50, 2, 1 },
+       { 640, 480, 60, 2, 1 },
+};
+
+static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge)
+{
+       return container_of(bridge, struct lt9611, bridge);
+}
+
+static struct lt9611 *connector_to_lt9611(struct drm_connector *connector)
+{
+       return container_of(connector, struct lt9611, connector);
+}
+
+static int lt9611_mipi_input_analog(struct lt9611 *lt9611)
+{
+       const struct reg_sequence reg_cfg[] = {
+               { 0x8106, 0x40 }, /* port A rx current */
+               { 0x810a, 0xfe }, /* port A ldo voltage set */
+               { 0x810b, 0xbf }, /* enable port A lprx */
+               { 0x8111, 0x40 }, /* port B rx current */
+               { 0x8115, 0xfe }, /* port B ldo voltage set */
+               { 0x8116, 0xbf }, /* enable port B lprx */
+
+               { 0x811c, 0x03 }, /* PortA clk lane no-LP mode */
+               { 0x8120, 0x03 }, /* PortB clk lane with-LP mode */
+       };
+
+       return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+}
+
+static int lt9611_mipi_input_digital(struct lt9611 *lt9611,
+                                    const struct drm_display_mode *mode)
+{
+       struct reg_sequence reg_cfg[] = {
+               { 0x8300, LT9611_4LANES },
+               { 0x830a, 0x00 },
+               { 0x824f, 0x80 },
+               { 0x8250, 0x10 },
+               { 0x8302, 0x0a },
+               { 0x8306, 0x0a },
+       };
+
+       if (mode->hdisplay == 3840)
+               reg_cfg[1].def = 0x03;
+
+       return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+}
+
+static void lt9611_mipi_video_setup(struct lt9611 *lt9611,
+                                   const struct drm_display_mode *mode)
+{
+       u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
+       u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
+
+       h_total = mode->htotal;
+       v_total = mode->vtotal;
+
+       hactive = mode->hdisplay;
+       hsync_len = mode->hsync_end - mode->hsync_start;
+       hfront_porch = mode->hsync_start - mode->hdisplay;
+       hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
+
+       vactive = mode->vdisplay;
+       vsync_len = mode->vsync_end - mode->vsync_start;
+       vfront_porch = mode->vsync_start - mode->vdisplay;
+       vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
+
+       regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256));
+       regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256));
+
+       regmap_write(lt9611->regmap, 0x830f, (u8)(vactive / 256));
+       regmap_write(lt9611->regmap, 0x8310, (u8)(vactive % 256));
+
+       regmap_write(lt9611->regmap, 0x8311, (u8)(h_total / 256));
+       regmap_write(lt9611->regmap, 0x8312, (u8)(h_total % 256));
+
+       regmap_write(lt9611->regmap, 0x8313, (u8)(hactive / 256));
+       regmap_write(lt9611->regmap, 0x8314, (u8)(hactive % 256));
+
+       regmap_write(lt9611->regmap, 0x8315, (u8)(vsync_len % 256));
+       regmap_write(lt9611->regmap, 0x8316, (u8)(hsync_len % 256));
+
+       regmap_write(lt9611->regmap, 0x8317, (u8)(vfront_porch % 256));
+
+       regmap_write(lt9611->regmap, 0x8318, (u8)(vsync_porch % 256));
+
+       regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256));
+
+       regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256));
+       regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256));
+}
+
+static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode)
+{
+       const struct reg_sequence reg_cfg[] = {
+               { 0x830b, 0x01 },
+               { 0x830c, 0x10 },
+               { 0x8348, 0x00 },
+               { 0x8349, 0x81 },
+
+               /* stage 1 */
+               { 0x8321, 0x4a },
+               { 0x8324, 0x71 },
+               { 0x8325, 0x30 },
+               { 0x832a, 0x01 },
+
+               /* stage 2 */
+               { 0x834a, 0x40 },
+               { 0x831d, 0x10 },
+
+               /* MK limit */
+               { 0x832d, 0x38 },
+               { 0x8331, 0x08 },
+       };
+       const struct reg_sequence reg_cfg2[] = {
+               { 0x830b, 0x03 },
+               { 0x830c, 0xd0 },
+               { 0x8348, 0x03 },
+               { 0x8349, 0xe0 },
+               { 0x8324, 0x72 },
+               { 0x8325, 0x00 },
+               { 0x832a, 0x01 },
+               { 0x834a, 0x10 },
+               { 0x831d, 0x10 },
+               { 0x8326, 0x37 },
+       };
+
+       regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+
+       switch (mode->hdisplay) {
+       case 640:
+               regmap_write(lt9611->regmap, 0x8326, 0x14);
+               break;
+       case 1920:
+               regmap_write(lt9611->regmap, 0x8326, 0x37);
+               break;
+       case 3840:
+               regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2));
+               break;
+       }
+
+       /* pcr rst */
+       regmap_write(lt9611->regmap, 0x8011, 0x5a);
+       regmap_write(lt9611->regmap, 0x8011, 0xfa);
+}
+
+static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode)
+{
+       unsigned int pclk = mode->clock;
+       const struct reg_sequence reg_cfg[] = {
+               /* txpll init */
+               { 0x8123, 0x40 },
+               { 0x8124, 0x64 },
+               { 0x8125, 0x80 },
+               { 0x8126, 0x55 },
+               { 0x812c, 0x37 },
+               { 0x812f, 0x01 },
+               { 0x8126, 0x55 },
+               { 0x8127, 0x66 },
+               { 0x8128, 0x88 },
+       };
+
+       regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+
+       if (pclk > 150000)
+               regmap_write(lt9611->regmap, 0x812d, 0x88);
+       else if (pclk > 70000)
+               regmap_write(lt9611->regmap, 0x812d, 0x99);
+       else
+               regmap_write(lt9611->regmap, 0x812d, 0xaa);
+
+       /*
+        * first divide pclk by 2 first
+        *  - write divide by 64k to 19:16 bits which means shift by 17
+        *  - write divide by 256 to 15:8 bits which means shift by 9
+        *  - write remainder to 7:0 bits, which means shift by 1
+        */
+       regmap_write(lt9611->regmap, 0x82e3, pclk >> 17); /* pclk[19:16] */
+       regmap_write(lt9611->regmap, 0x82e4, pclk >> 9);  /* pclk[15:8]  */
+       regmap_write(lt9611->regmap, 0x82e5, pclk >> 1);  /* pclk[7:0]   */
+
+       regmap_write(lt9611->regmap, 0x82de, 0x20);
+       regmap_write(lt9611->regmap, 0x82de, 0xe0);
+
+       regmap_write(lt9611->regmap, 0x8016, 0xf1);
+       regmap_write(lt9611->regmap, 0x8016, 0xf3);
+
+       return 0;
+}
+
+static int lt9611_read_video_check(struct lt9611 *lt9611, unsigned int reg)
+{
+       unsigned int temp, temp2;
+       int ret;
+
+       ret = regmap_read(lt9611->regmap, reg, &temp);
+       if (ret)
+               return ret;
+       temp <<= 8;
+       ret = regmap_read(lt9611->regmap, reg + 1, &temp2);
+       if (ret)
+               return ret;
+
+       return (temp + temp2);
+}
+
+static int lt9611_video_check(struct lt9611 *lt9611)
+{
+       u32 v_total, vactive, hactive_a, hactive_b, h_total_sysclk;
+       int temp;
+
+       /* top module video check */
+
+       /* vactive */
+       temp = lt9611_read_video_check(lt9611, 0x8282);
+       if (temp < 0)
+               goto end;
+       vactive = temp;
+
+       /* v_total */
+       temp = lt9611_read_video_check(lt9611, 0x826c);
+       if (temp < 0)
+               goto end;
+       v_total = temp;
+
+       /* h_total_sysclk */
+       temp = lt9611_read_video_check(lt9611, 0x8286);
+       if (temp < 0)
+               goto end;
+       h_total_sysclk = temp;
+
+       /* hactive_a */
+       temp = lt9611_read_video_check(lt9611, 0x8382);
+       if (temp < 0)
+               goto end;
+       hactive_a = temp / 3;
+
+       /* hactive_b */
+       temp = lt9611_read_video_check(lt9611, 0x8386);
+       if (temp < 0)
+               goto end;
+       hactive_b = temp / 3;
+
+       dev_info(lt9611->dev,
+                "video check: hactive_a=%d, hactive_b=%d, vactive=%d, v_total=%d, h_total_sysclk=%d\n",
+                hactive_a, hactive_b, vactive, v_total, h_total_sysclk);
+
+       return 0;
+
+end:
+       dev_err(lt9611->dev, "read video check error\n");
+       return temp;
+}
+
+static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611)
+{
+       regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic);
+       regmap_write(lt9611->regmap, 0x8447, lt9611->vic);
+       regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */
+
+       regmap_write(lt9611->regmap, 0x82d6, 0x8c);
+       regmap_write(lt9611->regmap, 0x82d7, 0x04);
+}
+
+static void lt9611_hdmi_tx_phy(struct lt9611 *lt9611)
+{
+       struct reg_sequence reg_cfg[] = {
+               { 0x8130, 0x6a },
+               { 0x8131, 0x44 }, /* HDMI DC mode */
+               { 0x8132, 0x4a },
+               { 0x8133, 0x0b },
+               { 0x8134, 0x00 },
+               { 0x8135, 0x00 },
+               { 0x8136, 0x00 },
+               { 0x8137, 0x44 },
+               { 0x813f, 0x0f },
+               { 0x8140, 0xa0 },
+               { 0x8141, 0xa0 },
+               { 0x8142, 0xa0 },
+               { 0x8143, 0xa0 },
+               { 0x8144, 0x0a },
+       };
+
+       /* HDMI AC mode */
+       if (lt9611->ac_mode)
+               reg_cfg[2].def = 0x73;
+
+       regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+}
+
+static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id)
+{
+       struct lt9611 *lt9611 = dev_id;
+       unsigned int irq_flag0 = 0;
+       unsigned int irq_flag3 = 0;
+
+       regmap_read(lt9611->regmap, 0x820f, &irq_flag3);
+       regmap_read(lt9611->regmap, 0x820c, &irq_flag0);
+
+       /* hpd changed low */
+       if (irq_flag3 & 0x80) {
+               dev_info(lt9611->dev, "hdmi cable disconnected\n");
+
+               regmap_write(lt9611->regmap, 0x8207, 0xbf);
+               regmap_write(lt9611->regmap, 0x8207, 0x3f);
+       }
+
+       /* hpd changed high */
+       if (irq_flag3 & 0x40) {
+               dev_info(lt9611->dev, "hdmi cable connected\n");
+
+               regmap_write(lt9611->regmap, 0x8207, 0x7f);
+               regmap_write(lt9611->regmap, 0x8207, 0x3f);
+       }
+
+       if (irq_flag3 & 0xc0 && lt9611->bridge.dev)
+               drm_kms_helper_hotplug_event(lt9611->bridge.dev);
+
+       /* video input changed */
+       if (irq_flag0 & 0x01) {
+               dev_info(lt9611->dev, "video input changed\n");
+               regmap_write(lt9611->regmap, 0x829e, 0xff);
+               regmap_write(lt9611->regmap, 0x829e, 0xf7);
+               regmap_write(lt9611->regmap, 0x8204, 0xff);
+               regmap_write(lt9611->regmap, 0x8204, 0xfe);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void lt9611_enable_hpd_interrupts(struct lt9611 *lt9611)
+{
+       unsigned int val;
+
+       regmap_read(lt9611->regmap, 0x8203, &val);
+
+       val &= ~0xc0;
+       regmap_write(lt9611->regmap, 0x8203, val);
+       regmap_write(lt9611->regmap, 0x8207, 0xff); /* clear */
+       regmap_write(lt9611->regmap, 0x8207, 0x3f);
+}
+
+static void lt9611_sleep_setup(struct lt9611 *lt9611)
+{
+       const struct reg_sequence sleep_setup[] = {
+               { 0x8024, 0x76 },
+               { 0x8023, 0x01 },
+               { 0x8157, 0x03 }, /* set addr pin as output */
+               { 0x8149, 0x0b },
+               { 0x8151, 0x30 }, /* disable IRQ */
+               { 0x8102, 0x48 }, /* MIPI Rx power down */
+               { 0x8123, 0x80 },
+               { 0x8130, 0x00 },
+               { 0x8100, 0x01 }, /* bandgap power down */
+               { 0x8101, 0x00 }, /* system clk power down */
+       };
+
+       regmap_multi_reg_write(lt9611->regmap,
+                              sleep_setup, ARRAY_SIZE(sleep_setup));
+       lt9611->sleep = true;
+}
+
+static int lt9611_power_on(struct lt9611 *lt9611)
+{
+       int ret;
+       const struct reg_sequence seq[] = {
+               /* LT9611_System_Init */
+               { 0x8101, 0x18 }, /* sel xtal clock */
+
+               /* timer for frequency meter */
+               { 0x821b, 0x69 }, /* timer 2 */
+               { 0x821c, 0x78 },
+               { 0x82cb, 0x69 }, /* timer 1 */
+               { 0x82cc, 0x78 },
+
+               /* irq init */
+               { 0x8251, 0x01 },
+               { 0x8258, 0x0a }, /* hpd irq */
+               { 0x8259, 0x80 }, /* hpd debounce width */
+               { 0x829e, 0xf7 }, /* video check irq */
+
+               /* power consumption for work */
+               { 0x8004, 0xf0 },
+               { 0x8006, 0xf0 },
+               { 0x800a, 0x80 },
+               { 0x800b, 0x40 },
+               { 0x800d, 0xef },
+               { 0x8011, 0xfa },
+       };
+
+       if (lt9611->power_on)
+               return 0;
+
+       ret = regmap_multi_reg_write(lt9611->regmap, seq, ARRAY_SIZE(seq));
+       if (!ret)
+               lt9611->power_on = true;
+
+       return ret;
+}
+
+static int lt9611_power_off(struct lt9611 *lt9611)
+{
+       int ret;
+
+       ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);
+       if (!ret)
+               lt9611->power_on = false;
+
+       return ret;
+}
+
+static void lt9611_reset(struct lt9611 *lt9611)
+{
+       gpiod_set_value_cansleep(lt9611->reset_gpio, 1);
+       msleep(20);
+
+       gpiod_set_value_cansleep(lt9611->reset_gpio, 0);
+       msleep(20);
+
+       gpiod_set_value_cansleep(lt9611->reset_gpio, 1);
+       msleep(100);
+}
+
+static void lt9611_assert_5v(struct lt9611 *lt9611)
+{
+       if (!lt9611->enable_gpio)
+               return;
+
+       gpiod_set_value_cansleep(lt9611->enable_gpio, 1);
+       msleep(20);
+}
+
+static int lt9611_regulator_init(struct lt9611 *lt9611)
+{
+       int ret;
+
+       lt9611->supplies[0].supply = "vdd";
+       lt9611->supplies[1].supply = "vcc";
+
+       ret = devm_regulator_bulk_get(lt9611->dev, 2, lt9611->supplies);
+       if (ret < 0)
+               return ret;
+
+       return regulator_set_load(lt9611->supplies[0].consumer, 300000);
+}
+
+static int lt9611_regulator_enable(struct lt9611 *lt9611)
+{
+       int ret;
+
+       ret = regulator_enable(lt9611->supplies[0].consumer);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(1000, 10000);
+
+       ret = regulator_enable(lt9611->supplies[1].consumer);
+       if (ret < 0) {
+               regulator_disable(lt9611->supplies[0].consumer);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) {
+               if (lt9611_modes[i].hdisplay == mode->hdisplay &&
+                   lt9611_modes[i].vdisplay == mode->vdisplay &&
+                   lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) {
+                       return &lt9611_modes[i];
+               }
+       }
+
+       return NULL;
+}
+
+/* connector funcs */
+static enum drm_connector_status
+lt9611_connector_detect(struct drm_connector *connector, bool force)
+{
+       struct lt9611 *lt9611 = connector_to_lt9611(connector);
+       unsigned int reg_val = 0;
+       int connected = 0;
+
+       regmap_read(lt9611->regmap, 0x825e, &reg_val);
+       connected  = (reg_val & BIT(2));
+
+       lt9611->status = connected ?  connector_status_connected :
+                               connector_status_disconnected;
+
+       return lt9611->status;
+}
+
+static int lt9611_read_edid(struct lt9611 *lt9611)
+{
+       unsigned int temp;
+       int ret = 0;
+       int i, j;
+
+       /* memset to clear old buffer, if any */
+       memset(lt9611->edid_buf, 0, sizeof(lt9611->edid_buf));
+
+       regmap_write(lt9611->regmap, 0x8503, 0xc9);
+
+       /* 0xA0 is EDID device address */
+       regmap_write(lt9611->regmap, 0x8504, 0xa0);
+       /* 0x00 is EDID offset address */
+       regmap_write(lt9611->regmap, 0x8505, 0x00);
+
+       /* length for read */
+       regmap_write(lt9611->regmap, 0x8506, EDID_LEN);
+       regmap_write(lt9611->regmap, 0x8514, 0x7f);
+
+       for (i = 0; i < EDID_LOOP; i++) {
+               /* offset address */
+               regmap_write(lt9611->regmap, 0x8505, i * EDID_LEN);
+               regmap_write(lt9611->regmap, 0x8507, 0x36);
+               regmap_write(lt9611->regmap, 0x8507, 0x31);
+               regmap_write(lt9611->regmap, 0x8507, 0x37);
+               usleep_range(5000, 10000);
+
+               regmap_read(lt9611->regmap, 0x8540, &temp);
+
+               if (temp & KEY_DDC_ACCS_DONE) {
+                       for (j = 0; j < EDID_LEN; j++) {
+                               regmap_read(lt9611->regmap, 0x8583, &temp);
+                               lt9611->edid_buf[i * EDID_LEN + j] = temp;
+                       }
+
+               } else if (temp & DDC_NO_ACK) { /* DDC No Ack or Abitration lost */
+                       dev_err(lt9611->dev, "read edid failed: no ack\n");
+                       ret = -EIO;
+                       goto end;
+
+               } else {
+                       dev_err(lt9611->dev, "read edid failed: access not done\n");
+                       ret = -EIO;
+                       goto end;
+               }
+       }
+
+end:
+       regmap_write(lt9611->regmap, 0x8507, 0x1f);
+       return ret;
+}
+
+static int
+lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+       struct lt9611 *lt9611 = data;
+       int ret;
+
+       if (len > 128)
+               return -EINVAL;
+
+       /* supports up to 1 extension block */
+       /* TODO: add support for more extension blocks */
+       if (block > 1)
+               return -EINVAL;
+
+       if (block == 0) {
+               ret = lt9611_read_edid(lt9611);
+               if (ret) {
+                       dev_err(lt9611->dev, "edid read failed\n");
+                       return ret;
+               }
+       }
+
+       block %= 2;
+       memcpy(buf, lt9611->edid_buf + (block * 128), len);
+
+       return 0;
+}
+
+static int lt9611_connector_get_modes(struct drm_connector *connector)
+{
+       struct lt9611 *lt9611 = connector_to_lt9611(connector);
+       unsigned int count;
+       struct edid *edid;
+
+       lt9611_power_on(lt9611);
+       edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611);
+       drm_connector_update_edid_property(connector, edid);
+       count = drm_add_edid_modes(connector, edid);
+       kfree(edid);
+
+       return count;
+}
+
+static enum drm_mode_status
+lt9611_connector_mode_valid(struct drm_connector *connector,
+                           struct drm_display_mode *mode)
+{
+       struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode);
+
+       return lt9611_mode ? MODE_OK : MODE_BAD;
+}
+
+/* bridge funcs */
+static void lt9611_bridge_enable(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+       if (lt9611_power_on(lt9611)) {
+               dev_err(lt9611->dev, "power on failed\n");
+               return;
+       }
+
+       lt9611_mipi_input_analog(lt9611);
+       lt9611_hdmi_tx_digital(lt9611);
+       lt9611_hdmi_tx_phy(lt9611);
+
+       msleep(500);
+
+       lt9611_video_check(lt9611);
+
+       /* Enable HDMI output */
+       regmap_write(lt9611->regmap, 0x8130, 0xea);
+}
+
+static void lt9611_bridge_disable(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+       int ret;
+
+       /* Disable HDMI output */
+       ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);
+       if (ret) {
+               dev_err(lt9611->dev, "video on failed\n");
+               return;
+       }
+
+       if (lt9611_power_off(lt9611)) {
+               dev_err(lt9611->dev, "power on failed\n");
+               return;
+       }
+}
+
+static struct
+drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = {
+       .get_modes = lt9611_connector_get_modes,
+       .mode_valid = lt9611_connector_mode_valid,
+};
+
+static const struct drm_connector_funcs lt9611_bridge_connector_funcs = {
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = lt9611_connector_detect,
+       .destroy = drm_connector_cleanup,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
+                                                struct device_node *dsi_node)
+{
+       const struct mipi_dsi_device_info info = { "lt9611", 0, NULL };
+       struct mipi_dsi_device *dsi;
+       struct mipi_dsi_host *host;
+       int ret;
+
+       host = of_find_mipi_dsi_host_by_node(dsi_node);
+       if (!host) {
+               dev_err(lt9611->dev, "failed to find dsi host\n");
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+
+       dsi = mipi_dsi_device_register_full(host, &info);
+       if (IS_ERR(dsi)) {
+               dev_err(lt9611->dev, "failed to create dsi device\n");
+               return dsi;
+       }
+
+       dsi->lanes = 4;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+                         MIPI_DSI_MODE_VIDEO_HSE;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0) {
+               dev_err(lt9611->dev, "failed to attach dsi to host\n");
+               mipi_dsi_device_unregister(dsi);
+               return ERR_PTR(ret);
+       }
+
+       return dsi;
+}
+
+static void lt9611_bridge_detach(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+       if (lt9611->dsi1) {
+               mipi_dsi_detach(lt9611->dsi1);
+               mipi_dsi_device_unregister(lt9611->dsi1);
+       }
+
+       mipi_dsi_detach(lt9611->dsi0);
+       mipi_dsi_device_unregister(lt9611->dsi0);
+}
+
+static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611)
+{
+       int ret;
+
+       ret = drm_connector_init(bridge->dev, &lt9611->connector,
+                                &lt9611_bridge_connector_funcs,
+                                DRM_MODE_CONNECTOR_HDMIA);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               return ret;
+       }
+
+       drm_connector_helper_add(&lt9611->connector,
+                                &lt9611_bridge_connector_helper_funcs);
+       drm_connector_attach_encoder(&lt9611->connector, bridge->encoder);
+
+       if (!bridge->encoder) {
+               DRM_ERROR("Parent encoder object not found");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int lt9611_bridge_attach(struct drm_bridge *bridge,
+                               enum drm_bridge_attach_flags flags)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+       int ret;
+
+       if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+               ret = lt9611_connector_init(bridge, lt9611);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Attach primary DSI */
+       lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node);
+       if (IS_ERR(lt9611->dsi0))
+               return PTR_ERR(lt9611->dsi0);
+
+       /* Attach secondary DSI, if specified */
+       if (lt9611->dsi1_node) {
+               lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node);
+               if (IS_ERR(lt9611->dsi1)) {
+                       ret = PTR_ERR(lt9611->dsi1);
+                       goto err_unregister_dsi0;
+               }
+       }
+
+       return 0;
+
+err_unregister_dsi0:
+       lt9611_bridge_detach(bridge);
+       drm_connector_cleanup(&lt9611->connector);
+       mipi_dsi_device_unregister(lt9611->dsi0);
+
+       return ret;
+}
+
+static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge,
+                                                    const struct drm_display_info *info,
+                                                    const struct drm_display_mode *mode)
+{
+       struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode);
+
+       return lt9611_mode ? MODE_OK : MODE_BAD;
+}
+
+static void lt9611_bridge_pre_enable(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+       if (!lt9611->sleep)
+               return;
+
+       lt9611_reset(lt9611);
+       regmap_write(lt9611->regmap, 0x80ee, 0x01);
+
+       lt9611->sleep = false;
+}
+
+static void lt9611_bridge_post_disable(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+       lt9611_sleep_setup(lt9611);
+}
+
+static void lt9611_bridge_mode_set(struct drm_bridge *bridge,
+                                  const struct drm_display_mode *mode,
+                                  const struct drm_display_mode *adj_mode)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+       struct hdmi_avi_infoframe avi_frame;
+       int ret;
+
+       lt9611_bridge_pre_enable(bridge);
+
+       lt9611_mipi_input_digital(lt9611, mode);
+       lt9611_pll_setup(lt9611, mode);
+       lt9611_mipi_video_setup(lt9611, mode);
+       lt9611_pcr_setup(lt9611, mode);
+
+       ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
+                                                      &lt9611->connector,
+                                                      mode);
+       if (!ret)
+               lt9611->vic = avi_frame.video_code;
+}
+
+static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+       unsigned int reg_val = 0;
+       int connected;
+
+       regmap_read(lt9611->regmap, 0x825e, &reg_val);
+       connected  = reg_val & BIT(2);
+
+       lt9611->status = connected ?  connector_status_connected :
+                               connector_status_disconnected;
+
+       return lt9611->status;
+}
+
+static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge,
+                                          struct drm_connector *connector)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+       lt9611_power_on(lt9611);
+       return drm_do_get_edid(connector, lt9611_get_edid_block, lt9611);
+}
+
+static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+       struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+
+       lt9611_enable_hpd_interrupts(lt9611);
+}
+
+static const struct drm_bridge_funcs lt9611_bridge_funcs = {
+       .attach = lt9611_bridge_attach,
+       .detach = lt9611_bridge_detach,
+       .mode_valid = lt9611_bridge_mode_valid,
+       .enable = lt9611_bridge_enable,
+       .disable = lt9611_bridge_disable,
+       .post_disable = lt9611_bridge_post_disable,
+       .mode_set = lt9611_bridge_mode_set,
+       .detect = lt9611_bridge_detect,
+       .get_edid = lt9611_bridge_get_edid,
+       .hpd_enable = lt9611_bridge_hpd_enable,
+};
+
+static int lt9611_parse_dt(struct device *dev,
+                          struct lt9611 *lt9611)
+{
+       lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 1, -1);
+       if (!lt9611->dsi0_node) {
+               dev_err(lt9611->dev, "failed to get remote node for primary dsi\n");
+               return -ENODEV;
+       }
+
+       lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 2, -1);
+
+       lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode");
+
+       return 0;
+}
+
+static int lt9611_gpio_init(struct lt9611 *lt9611)
+{
+       struct device *dev = lt9611->dev;
+
+       lt9611->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(lt9611->reset_gpio)) {
+               dev_err(dev, "failed to acquire reset gpio\n");
+               return PTR_ERR(lt9611->reset_gpio);
+       }
+
+       lt9611->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+                                                     GPIOD_OUT_LOW);
+       if (IS_ERR(lt9611->enable_gpio)) {
+               dev_err(dev, "failed to acquire enable gpio\n");
+               return PTR_ERR(lt9611->enable_gpio);
+       }
+
+       return 0;
+}
+
+static int lt9611_read_device_rev(struct lt9611 *lt9611)
+{
+       unsigned int rev;
+       int ret;
+
+       regmap_write(lt9611->regmap, 0x80ee, 0x01);
+       ret = regmap_read(lt9611->regmap, 0x8002, &rev);
+       if (ret)
+               dev_err(lt9611->dev, "failed to read revision: %d\n", ret);
+       else
+               dev_info(lt9611->dev, "LT9611 revision: 0x%x\n", rev);
+
+       return ret;
+}
+
+static int lt9611_hdmi_hw_params(struct device *dev, void *data,
+                                struct hdmi_codec_daifmt *fmt,
+                                struct hdmi_codec_params *hparms)
+{
+       struct lt9611 *lt9611 = data;
+
+       if (hparms->sample_rate == 48000)
+               regmap_write(lt9611->regmap, 0x840f, 0x2b);
+       else if (hparms->sample_rate == 96000)
+               regmap_write(lt9611->regmap, 0x840f, 0xab);
+       else
+               return -EINVAL;
+
+       regmap_write(lt9611->regmap, 0x8435, 0x00);
+       regmap_write(lt9611->regmap, 0x8436, 0x18);
+       regmap_write(lt9611->regmap, 0x8437, 0x00);
+
+       return 0;
+}
+
+static int lt9611_audio_startup(struct device *dev, void *data)
+{
+       struct lt9611 *lt9611 = data;
+
+       regmap_write(lt9611->regmap, 0x82d6, 0x8c);
+       regmap_write(lt9611->regmap, 0x82d7, 0x04);
+
+       regmap_write(lt9611->regmap, 0x8406, 0x08);
+       regmap_write(lt9611->regmap, 0x8407, 0x10);
+
+       regmap_write(lt9611->regmap, 0x8434, 0xd5);
+
+       return 0;
+}
+
+static void lt9611_audio_shutdown(struct device *dev, void *data)
+{
+       struct lt9611 *lt9611 = data;
+
+       regmap_write(lt9611->regmap, 0x8406, 0x00);
+       regmap_write(lt9611->regmap, 0x8407, 0x00);
+}
+
+static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+                                     struct device_node *endpoint)
+{
+       struct of_endpoint of_ep;
+       int ret;
+
+       ret = of_graph_parse_endpoint(endpoint, &of_ep);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * HDMI sound should be located as reg = <2>
+        * Then, it is sound port 0
+        */
+       if (of_ep.port == 2)
+               return 0;
+
+       return -EINVAL;
+}
+
+static const struct hdmi_codec_ops lt9611_codec_ops = {
+       .hw_params      = lt9611_hdmi_hw_params,
+       .audio_shutdown = lt9611_audio_shutdown,
+       .audio_startup  = lt9611_audio_startup,
+       .get_dai_id     = lt9611_hdmi_i2s_get_dai_id,
+};
+
+static struct hdmi_codec_pdata codec_data = {
+       .ops = &lt9611_codec_ops,
+       .max_i2s_channels = 8,
+       .i2s = 1,
+};
+
+static int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611)
+{
+       codec_data.data = lt9611;
+       lt9611->audio_pdev =
+               platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+                                             PLATFORM_DEVID_AUTO,
+                                             &codec_data, sizeof(codec_data));
+
+       return PTR_ERR_OR_ZERO(lt9611->audio_pdev);
+}
+
+static void lt9611_audio_exit(struct lt9611 *lt9611)
+{
+       if (lt9611->audio_pdev) {
+               platform_device_unregister(lt9611->audio_pdev);
+               lt9611->audio_pdev = NULL;
+       }
+}
+
+static int lt9611_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lt9611 *lt9611;
+       struct device *dev = &client->dev;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(dev, "device doesn't support I2C\n");
+               return -ENODEV;
+       }
+
+       lt9611 = devm_kzalloc(dev, sizeof(*lt9611), GFP_KERNEL);
+       if (!lt9611)
+               return -ENOMEM;
+
+       lt9611->dev = &client->dev;
+       lt9611->client = client;
+       lt9611->sleep = false;
+
+       lt9611->regmap = devm_regmap_init_i2c(client, &lt9611_regmap_config);
+       if (IS_ERR(lt9611->regmap)) {
+               dev_err(lt9611->dev, "regmap i2c init failed\n");
+               return PTR_ERR(lt9611->regmap);
+       }
+
+       ret = lt9611_parse_dt(&client->dev, lt9611);
+       if (ret) {
+               dev_err(dev, "failed to parse device tree\n");
+               return ret;
+       }
+
+       ret = lt9611_gpio_init(lt9611);
+       if (ret < 0)
+               goto err_of_put;
+
+       ret = lt9611_regulator_init(lt9611);
+       if (ret < 0)
+               goto err_of_put;
+
+       lt9611_assert_5v(lt9611);
+
+       ret = lt9611_regulator_enable(lt9611);
+       if (ret)
+               goto err_of_put;
+
+       lt9611_reset(lt9611);
+
+       ret = lt9611_read_device_rev(lt9611);
+       if (ret) {
+               dev_err(dev, "failed to read chip rev\n");
+               goto err_disable_regulators;
+       }
+
+       ret = devm_request_threaded_irq(dev, client->irq, NULL,
+                                       lt9611_irq_thread_handler,
+                                       IRQF_ONESHOT, "lt9611", lt9611);
+       if (ret) {
+               dev_err(dev, "failed to request irq\n");
+               goto err_disable_regulators;
+       }
+
+       i2c_set_clientdata(client, lt9611);
+
+       lt9611->bridge.funcs = &lt9611_bridge_funcs;
+       lt9611->bridge.of_node = client->dev.of_node;
+       lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
+                            DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES;
+       lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
+
+       drm_bridge_add(&lt9611->bridge);
+
+       lt9611_enable_hpd_interrupts(lt9611);
+
+       return lt9611_audio_init(dev, lt9611);
+
+err_disable_regulators:
+       regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);
+
+err_of_put:
+       of_node_put(lt9611->dsi1_node);
+       of_node_put(lt9611->dsi0_node);
+
+       return ret;
+}
+
+static int lt9611_remove(struct i2c_client *client)
+{
+       struct lt9611 *lt9611 = i2c_get_clientdata(client);
+
+       disable_irq(client->irq);
+       lt9611_audio_exit(lt9611);
+       drm_bridge_remove(&lt9611->bridge);
+
+       regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);
+
+       of_node_put(lt9611->dsi1_node);
+       of_node_put(lt9611->dsi0_node);
+
+       return 0;
+}
+
+static struct i2c_device_id lt9611_id[] = {
+       { "lontium,lt9611", 0 },
+       {}
+};
+
+static const struct of_device_id lt9611_match_table[] = {
+       { .compatible = "lontium,lt9611" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lt9611_match_table);
+
+static struct i2c_driver lt9611_driver = {
+       .driver = {
+               .name = "lt9611",
+               .of_match_table = lt9611_match_table,
+       },
+       .probe = lt9611_probe,
+       .remove = lt9611_remove,
+       .id_table = lt9611_id,
+};
+module_i2c_driver(lt9611_driver);
+
+MODULE_LICENSE("GPL v2");
index 6200f12..61a24f2 100644 (file)
@@ -61,7 +61,6 @@ struct ge_b850v3_lvds {
        struct drm_bridge bridge;
        struct i2c_client *stdp4028_i2c;
        struct i2c_client *stdp2690_i2c;
-       struct edid *edid;
 };
 
 static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr;
@@ -131,22 +130,26 @@ err:
        return NULL;
 }
 
-static int ge_b850v3_lvds_get_modes(struct drm_connector *connector)
+static struct edid *ge_b850v3_lvds_get_edid(struct drm_bridge *bridge,
+                                           struct drm_connector *connector)
 {
        struct i2c_client *client;
-       int num_modes = 0;
 
        client = ge_b850v3_lvds_ptr->stdp2690_i2c;
 
-       kfree(ge_b850v3_lvds_ptr->edid);
-       ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client);
+       return (struct edid *)stdp2690_get_edid(client);
+}
 
-       if (ge_b850v3_lvds_ptr->edid) {
-               drm_connector_update_edid_property(connector,
-                                                     ge_b850v3_lvds_ptr->edid);
-               num_modes = drm_add_edid_modes(connector,
-                                              ge_b850v3_lvds_ptr->edid);
-       }
+static int ge_b850v3_lvds_get_modes(struct drm_connector *connector)
+{
+       struct edid *edid;
+       int num_modes;
+
+       edid = ge_b850v3_lvds_get_edid(&ge_b850v3_lvds_ptr->bridge, connector);
+
+       drm_connector_update_edid_property(connector, edid);
+       num_modes = drm_add_edid_modes(connector, edid);
+       kfree(edid);
 
        return num_modes;
 }
@@ -163,8 +166,7 @@ drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = {
        .mode_valid = ge_b850v3_lvds_mode_valid,
 };
 
-static enum drm_connector_status ge_b850v3_lvds_detect(
-               struct drm_connector *connector, bool force)
+static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge)
 {
        struct i2c_client *stdp4028_i2c =
                        ge_b850v3_lvds_ptr->stdp4028_i2c;
@@ -182,6 +184,12 @@ static enum drm_connector_status ge_b850v3_lvds_detect(
        return connector_status_unknown;
 }
 
+static enum drm_connector_status ge_b850v3_lvds_detect(struct drm_connector *connector,
+                                                      bool force)
+{
+       return ge_b850v3_lvds_bridge_detect(&ge_b850v3_lvds_ptr->bridge);
+}
+
 static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = ge_b850v3_lvds_detect,
@@ -191,34 +199,11 @@ static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
-static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
-{
-       struct i2c_client *stdp4028_i2c
-                       = ge_b850v3_lvds_ptr->stdp4028_i2c;
-
-       i2c_smbus_write_word_data(stdp4028_i2c,
-                                 STDP4028_DPTX_IRQ_STS_REG,
-                                 STDP4028_DPTX_IRQ_CLEAR);
-
-       if (ge_b850v3_lvds_ptr->connector.dev)
-               drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->connector.dev);
-
-       return IRQ_HANDLED;
-}
-
-static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
-                                enum drm_bridge_attach_flags flags)
+static int ge_b850v3_lvds_create_connector(struct drm_bridge *bridge)
 {
        struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector;
-       struct i2c_client *stdp4028_i2c
-                       = ge_b850v3_lvds_ptr->stdp4028_i2c;
        int ret;
 
-       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-               DRM_ERROR("Fix bridge driver to make connector optional!");
-               return -EINVAL;
-       }
-
        if (!bridge->encoder) {
                DRM_ERROR("Parent encoder object not found");
                return -ENODEV;
@@ -237,9 +222,29 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
                return ret;
        }
 
-       ret = drm_connector_attach_encoder(connector, bridge->encoder);
-       if (ret)
-               return ret;
+       return drm_connector_attach_encoder(connector, bridge->encoder);
+}
+
+static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
+{
+       struct i2c_client *stdp4028_i2c
+                       = ge_b850v3_lvds_ptr->stdp4028_i2c;
+
+       i2c_smbus_write_word_data(stdp4028_i2c,
+                                 STDP4028_DPTX_IRQ_STS_REG,
+                                 STDP4028_DPTX_IRQ_CLEAR);
+
+       if (ge_b850v3_lvds_ptr->bridge.dev)
+               drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->bridge.dev);
+
+       return IRQ_HANDLED;
+}
+
+static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
+                                enum drm_bridge_attach_flags flags)
+{
+       struct i2c_client *stdp4028_i2c
+                       = ge_b850v3_lvds_ptr->stdp4028_i2c;
 
        /* Configures the bridge to re-enable interrupts after each ack. */
        i2c_smbus_write_word_data(stdp4028_i2c,
@@ -251,11 +256,16 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
                                  STDP4028_DPTX_IRQ_EN_REG,
                                  STDP4028_DPTX_IRQ_CONFIG);
 
-       return 0;
+       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+               return 0;
+
+       return ge_b850v3_lvds_create_connector(bridge);
 }
 
 static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = {
        .attach = ge_b850v3_lvds_attach,
+       .detect = ge_b850v3_lvds_bridge_detect,
+       .get_edid = ge_b850v3_lvds_get_edid,
 };
 
 static int ge_b850v3_lvds_init(struct device *dev)
@@ -291,8 +301,6 @@ static void ge_b850v3_lvds_remove(void)
 
        drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
 
-       kfree(ge_b850v3_lvds_ptr->edid);
-
        ge_b850v3_lvds_ptr = NULL;
 out:
        mutex_unlock(&ge_b850v3_lvds_dev_mutex);
@@ -310,6 +318,9 @@ static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
 
        /* drm bridge initialization */
        ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs;
+       ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT |
+                                        DRM_BRIDGE_OP_EDID;
+       ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
        ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node;
        drm_bridge_add(&ge_b850v3_lvds_ptr->bridge);
 
index 438e566..e941c11 100644 (file)
@@ -29,8 +29,7 @@ struct ptn3460_bridge {
        struct drm_connector connector;
        struct i2c_client *client;
        struct drm_bridge bridge;
-       struct edid *edid;
-       struct drm_panel *panel;
+       struct drm_bridge *panel_bridge;
        struct gpio_desc *gpio_pd_n;
        struct gpio_desc *gpio_rst_n;
        u32 edid_emulation;
@@ -127,11 +126,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
        usleep_range(10, 20);
        gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
 
-       if (drm_panel_prepare(ptn_bridge->panel)) {
-               DRM_ERROR("failed to prepare panel\n");
-               return;
-       }
-
        /*
         * There's a bug in the PTN chip where it falsely asserts hotplug before
         * it is fully functional. We're forced to wait for the maximum start up
@@ -146,16 +140,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
        ptn_bridge->enabled = true;
 }
 
-static void ptn3460_enable(struct drm_bridge *bridge)
-{
-       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
-
-       if (drm_panel_enable(ptn_bridge->panel)) {
-               DRM_ERROR("failed to enable panel\n");
-               return;
-       }
-}
-
 static void ptn3460_disable(struct drm_bridge *bridge)
 {
        struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
@@ -165,36 +149,18 @@ static void ptn3460_disable(struct drm_bridge *bridge)
 
        ptn_bridge->enabled = false;
 
-       if (drm_panel_disable(ptn_bridge->panel)) {
-               DRM_ERROR("failed to disable panel\n");
-               return;
-       }
-
        gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
        gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
 }
 
-static void ptn3460_post_disable(struct drm_bridge *bridge)
-{
-       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 
-       if (drm_panel_unprepare(ptn_bridge->panel)) {
-               DRM_ERROR("failed to unprepare panel\n");
-               return;
-       }
-}
-
-static int ptn3460_get_modes(struct drm_connector *connector)
+static struct edid *ptn3460_get_edid(struct drm_bridge *bridge,
+                                    struct drm_connector *connector)
 {
-       struct ptn3460_bridge *ptn_bridge;
-       u8 *edid;
-       int ret, num_modes = 0;
+       struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
        bool power_off;
-
-       ptn_bridge = connector_to_ptn3460(connector);
-
-       if (ptn_bridge->edid)
-               return drm_add_edid_modes(connector, ptn_bridge->edid);
+       u8 *edid;
+       int ret;
 
        power_off = !ptn_bridge->enabled;
        ptn3460_pre_enable(&ptn_bridge->bridge);
@@ -202,30 +168,40 @@ static int ptn3460_get_modes(struct drm_connector *connector)
        edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
        if (!edid) {
                DRM_ERROR("Failed to allocate EDID\n");
-               return 0;
+               goto out;
        }
 
        ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
-                       EDID_LENGTH);
+                                EDID_LENGTH);
        if (ret) {
                kfree(edid);
+               edid = NULL;
                goto out;
        }
 
-       ptn_bridge->edid = (struct edid *)edid;
-       drm_connector_update_edid_property(connector, ptn_bridge->edid);
-
-       num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
-
 out:
        if (power_off)
                ptn3460_disable(&ptn_bridge->bridge);
 
+       return (struct edid *)edid;
+}
+
+static int ptn3460_connector_get_modes(struct drm_connector *connector)
+{
+       struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
+       struct edid *edid;
+       int num_modes;
+
+       edid = ptn3460_get_edid(&ptn_bridge->bridge, connector);
+       drm_connector_update_edid_property(connector, edid);
+       num_modes = drm_add_edid_modes(connector, edid);
+       kfree(edid);
+
        return num_modes;
 }
 
 static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
-       .get_modes = ptn3460_get_modes,
+       .get_modes = ptn3460_connector_get_modes,
 };
 
 static const struct drm_connector_funcs ptn3460_connector_funcs = {
@@ -242,10 +218,14 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
        struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
        int ret;
 
-       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-               DRM_ERROR("Fix bridge driver to make connector optional!");
-               return -EINVAL;
-       }
+       /* Let this driver create connector if requested */
+       ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge,
+                               bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (ret < 0)
+               return ret;
+
+       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+               return 0;
 
        if (!bridge->encoder) {
                DRM_ERROR("Parent encoder object not found");
@@ -265,9 +245,6 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
        drm_connector_attach_encoder(&ptn_bridge->connector,
                                                        bridge->encoder);
 
-       if (ptn_bridge->panel)
-               drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
-
        drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
 
        return ret;
@@ -275,10 +252,9 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
 
 static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
        .pre_enable = ptn3460_pre_enable,
-       .enable = ptn3460_enable,
        .disable = ptn3460_disable,
-       .post_disable = ptn3460_post_disable,
        .attach = ptn3460_bridge_attach,
+       .get_edid = ptn3460_get_edid,
 };
 
 static int ptn3460_probe(struct i2c_client *client,
@@ -286,6 +262,8 @@ static int ptn3460_probe(struct i2c_client *client,
 {
        struct device *dev = &client->dev;
        struct ptn3460_bridge *ptn_bridge;
+       struct drm_bridge *panel_bridge;
+       struct drm_panel *panel;
        int ret;
 
        ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
@@ -293,10 +271,15 @@ static int ptn3460_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
-       ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ptn_bridge->panel, NULL);
+       ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL);
        if (ret)
                return ret;
 
+       panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+       if (IS_ERR(panel_bridge))
+               return PTR_ERR(panel_bridge);
+
+       ptn_bridge->panel_bridge = panel_bridge;
        ptn_bridge->client = client;
 
        ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown",
@@ -327,6 +310,8 @@ static int ptn3460_probe(struct i2c_client *client,
        }
 
        ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+       ptn_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
+       ptn_bridge->bridge.type = DRM_MODE_CONNECTOR_LVDS;
        ptn_bridge->bridge.of_node = dev->of_node;
        drm_bridge_add(&ptn_bridge->bridge);
 
index 1e63ed6..0ddc375 100644 (file)
@@ -82,18 +82,11 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
        drm_connector_attach_encoder(&panel_bridge->connector,
                                          bridge->encoder);
 
-       ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
 static void panel_bridge_detach(struct drm_bridge *bridge)
 {
-       struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
-       drm_panel_detach(panel_bridge->panel);
 }
 
 static void panel_bridge_pre_enable(struct drm_bridge *bridge)
index d789ea2..614b19f 100644 (file)
 #endif
 
 struct ps8622_bridge {
-       struct drm_connector connector;
        struct i2c_client *client;
        struct drm_bridge bridge;
-       struct drm_panel *panel;
+       struct drm_bridge *panel_bridge;
        struct regulator *v12;
        struct backlight_device *bl;
 
@@ -64,12 +63,6 @@ static inline struct ps8622_bridge *
        return container_of(bridge, struct ps8622_bridge, bridge);
 }
 
-static inline struct ps8622_bridge *
-               connector_to_ps8622(struct drm_connector *connector)
-{
-       return container_of(connector, struct ps8622_bridge, connector);
-}
-
 static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
 {
        int ret;
@@ -365,11 +358,6 @@ static void ps8622_pre_enable(struct drm_bridge *bridge)
                        DRM_ERROR("fails to enable ps8622->v12");
        }
 
-       if (drm_panel_prepare(ps8622->panel)) {
-               DRM_ERROR("failed to prepare panel\n");
-               return;
-       }
-
        gpiod_set_value(ps8622->gpio_slp, 1);
 
        /*
@@ -399,24 +387,9 @@ static void ps8622_pre_enable(struct drm_bridge *bridge)
        ps8622->enabled = true;
 }
 
-static void ps8622_enable(struct drm_bridge *bridge)
-{
-       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
-
-       if (drm_panel_enable(ps8622->panel)) {
-               DRM_ERROR("failed to enable panel\n");
-               return;
-       }
-}
-
 static void ps8622_disable(struct drm_bridge *bridge)
 {
-       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
-
-       if (drm_panel_disable(ps8622->panel)) {
-               DRM_ERROR("failed to disable panel\n");
-               return;
-       }
+       /* Delay after panel is disabled */
        msleep(PS8622_PWMO_END_T12_MS);
 }
 
@@ -436,11 +409,6 @@ static void ps8622_post_disable(struct drm_bridge *bridge)
         */
        gpiod_set_value(ps8622->gpio_slp, 0);
 
-       if (drm_panel_unprepare(ps8622->panel)) {
-               DRM_ERROR("failed to unprepare panel\n");
-               return;
-       }
-
        if (ps8622->v12)
                regulator_disable(ps8622->v12);
 
@@ -455,67 +423,17 @@ static void ps8622_post_disable(struct drm_bridge *bridge)
        msleep(PS8622_POWER_OFF_T17_MS);
 }
 
-static int ps8622_get_modes(struct drm_connector *connector)
-{
-       struct ps8622_bridge *ps8622;
-
-       ps8622 = connector_to_ps8622(connector);
-
-       return drm_panel_get_modes(ps8622->panel, connector);
-}
-
-static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
-       .get_modes = ps8622_get_modes,
-};
-
-static const struct drm_connector_funcs ps8622_connector_funcs = {
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .destroy = drm_connector_cleanup,
-       .reset = drm_atomic_helper_connector_reset,
-       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
 static int ps8622_attach(struct drm_bridge *bridge,
                         enum drm_bridge_attach_flags flags)
 {
        struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
-       int ret;
-
-       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-               DRM_ERROR("Fix bridge driver to make connector optional!");
-               return -EINVAL;
-       }
 
-       if (!bridge->encoder) {
-               DRM_ERROR("Parent encoder object not found");
-               return -ENODEV;
-       }
-
-       ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
-       ret = drm_connector_init(bridge->dev, &ps8622->connector,
-                       &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-       if (ret) {
-               DRM_ERROR("Failed to initialize connector with drm\n");
-               return ret;
-       }
-       drm_connector_helper_add(&ps8622->connector,
-                                       &ps8622_connector_helper_funcs);
-       drm_connector_register(&ps8622->connector);
-       drm_connector_attach_encoder(&ps8622->connector,
-                                                       bridge->encoder);
-
-       if (ps8622->panel)
-               drm_panel_attach(ps8622->panel, &ps8622->connector);
-
-       drm_helper_hpd_irq_event(ps8622->connector.dev);
-
-       return ret;
+       return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge,
+                                &ps8622->bridge, flags);
 }
 
 static const struct drm_bridge_funcs ps8622_bridge_funcs = {
        .pre_enable = ps8622_pre_enable,
-       .enable = ps8622_enable,
        .disable = ps8622_disable,
        .post_disable = ps8622_post_disable,
        .attach = ps8622_attach,
@@ -533,16 +451,23 @@ static int ps8622_probe(struct i2c_client *client,
 {
        struct device *dev = &client->dev;
        struct ps8622_bridge *ps8622;
+       struct drm_bridge *panel_bridge;
+       struct drm_panel *panel;
        int ret;
 
        ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
        if (!ps8622)
                return -ENOMEM;
 
-       ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL);
+       ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL);
        if (ret)
                return ret;
 
+       panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+       if (IS_ERR(panel_bridge))
+               return PTR_ERR(panel_bridge);
+
+       ps8622->panel_bridge = panel_bridge;
        ps8622->client = client;
 
        ps8622->v12 = devm_regulator_get(dev, "vdd12");
@@ -595,6 +520,7 @@ static int ps8622_probe(struct i2c_client *client,
        }
 
        ps8622->bridge.funcs = &ps8622_bridge_funcs;
+       ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS;
        ps8622->bridge.of_node = dev->of_node;
        drm_bridge_add(&ps8622->bridge);
 
index 5ac1430..d89394b 100644 (file)
@@ -153,10 +153,9 @@ static const char * const tc358764_supplies[] = {
 struct tc358764 {
        struct device *dev;
        struct drm_bridge bridge;
-       struct drm_connector connector;
        struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)];
        struct gpio_desc *gpio_reset;
-       struct drm_panel *panel;
+       struct drm_bridge *panel_bridge;
        int error;
 };
 
@@ -210,12 +209,6 @@ static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge)
        return container_of(bridge, struct tc358764, bridge);
 }
 
-static inline
-struct tc358764 *connector_to_tc358764(struct drm_connector *connector)
-{
-       return container_of(connector, struct tc358764, connector);
-}
-
 static int tc358764_init(struct tc358764 *ctx)
 {
        u32 v = 0;
@@ -278,43 +271,11 @@ static void tc358764_reset(struct tc358764 *ctx)
        usleep_range(1000, 2000);
 }
 
-static int tc358764_get_modes(struct drm_connector *connector)
-{
-       struct tc358764 *ctx = connector_to_tc358764(connector);
-
-       return drm_panel_get_modes(ctx->panel, connector);
-}
-
-static const
-struct drm_connector_helper_funcs tc358764_connector_helper_funcs = {
-       .get_modes = tc358764_get_modes,
-};
-
-static const struct drm_connector_funcs tc358764_connector_funcs = {
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .destroy = drm_connector_cleanup,
-       .reset = drm_atomic_helper_connector_reset,
-       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static void tc358764_disable(struct drm_bridge *bridge)
-{
-       struct tc358764 *ctx = bridge_to_tc358764(bridge);
-       int ret = drm_panel_disable(bridge_to_tc358764(bridge)->panel);
-
-       if (ret < 0)
-               dev_err(ctx->dev, "error disabling panel (%d)\n", ret);
-}
-
 static void tc358764_post_disable(struct drm_bridge *bridge)
 {
        struct tc358764 *ctx = bridge_to_tc358764(bridge);
        int ret;
 
-       ret = drm_panel_unprepare(ctx->panel);
-       if (ret < 0)
-               dev_err(ctx->dev, "error unpreparing panel (%d)\n", ret);
        tc358764_reset(ctx);
        usleep_range(10000, 15000);
        ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
@@ -335,73 +296,28 @@ static void tc358764_pre_enable(struct drm_bridge *bridge)
        ret = tc358764_init(ctx);
        if (ret < 0)
                dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
-       ret = drm_panel_prepare(ctx->panel);
-       if (ret < 0)
-               dev_err(ctx->dev, "error preparing panel (%d)\n", ret);
-}
-
-static void tc358764_enable(struct drm_bridge *bridge)
-{
-       struct tc358764 *ctx = bridge_to_tc358764(bridge);
-       int ret = drm_panel_enable(ctx->panel);
-
-       if (ret < 0)
-               dev_err(ctx->dev, "error enabling panel (%d)\n", ret);
 }
 
 static int tc358764_attach(struct drm_bridge *bridge,
                           enum drm_bridge_attach_flags flags)
-{
-       struct tc358764 *ctx = bridge_to_tc358764(bridge);
-       struct drm_device *drm = bridge->dev;
-       int ret;
-
-       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-               DRM_ERROR("Fix bridge driver to make connector optional!");
-               return -EINVAL;
-       }
-
-       ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
-       ret = drm_connector_init(drm, &ctx->connector,
-                                &tc358764_connector_funcs,
-                                DRM_MODE_CONNECTOR_LVDS);
-       if (ret) {
-               DRM_ERROR("Failed to initialize connector\n");
-               return ret;
-       }
-
-       drm_connector_helper_add(&ctx->connector,
-                                &tc358764_connector_helper_funcs);
-       drm_connector_attach_encoder(&ctx->connector, bridge->encoder);
-       drm_panel_attach(ctx->panel, &ctx->connector);
-       ctx->connector.funcs->reset(&ctx->connector);
-       drm_connector_register(&ctx->connector);
-
-       return 0;
-}
-
-static void tc358764_detach(struct drm_bridge *bridge)
 {
        struct tc358764 *ctx = bridge_to_tc358764(bridge);
 
-       drm_connector_unregister(&ctx->connector);
-       drm_panel_detach(ctx->panel);
-       ctx->panel = NULL;
-       drm_connector_put(&ctx->connector);
+       return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
+                                bridge, flags);
 }
 
 static const struct drm_bridge_funcs tc358764_bridge_funcs = {
-       .disable = tc358764_disable,
        .post_disable = tc358764_post_disable,
-       .enable = tc358764_enable,
        .pre_enable = tc358764_pre_enable,
        .attach = tc358764_attach,
-       .detach = tc358764_detach,
 };
 
 static int tc358764_parse_dt(struct tc358764 *ctx)
 {
+       struct drm_bridge *panel_bridge;
        struct device *dev = ctx->dev;
+       struct drm_panel *panel;
        int ret;
 
        ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
@@ -410,12 +326,16 @@ static int tc358764_parse_dt(struct tc358764 *ctx)
                return PTR_ERR(ctx->gpio_reset);
        }
 
-       ret = drm_of_find_panel_or_bridge(ctx->dev->of_node, 1, 0, &ctx->panel,
-                                         NULL);
-       if (ret && ret != -EPROBE_DEFER)
-               dev_err(dev, "cannot find panel (%d)\n", ret);
+       ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
+       if (ret)
+               return ret;
 
-       return ret;
+       panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+       if (IS_ERR(panel_bridge))
+               return PTR_ERR(panel_bridge);
+
+       ctx->panel_bridge = panel_bridge;
+       return 0;
 }
 
 static int tc358764_configure_regulators(struct tc358764 *ctx)
@@ -461,6 +381,7 @@ static int tc358764_probe(struct mipi_dsi_device *dsi)
                return ret;
 
        ctx->bridge.funcs = &tc358764_bridge_funcs;
+       ctx->bridge.type = DRM_MODE_CONNECTOR_LVDS;
        ctx->bridge.of_node = dev->of_node;
 
        drm_bridge_add(&ctx->bridge);
index c2777b2..34a3e4e 100644 (file)
@@ -244,14 +244,12 @@ struct tc_data {
        struct drm_dp_aux       aux;
 
        struct drm_bridge       bridge;
+       struct drm_bridge       *panel_bridge;
        struct drm_connector    connector;
-       struct drm_panel        *panel;
 
        /* link settings */
        struct tc_edp_link      link;
 
-       /* display edid */
-       struct edid             *edid;
        /* current mode */
        struct drm_display_mode mode;
 
@@ -1236,13 +1234,6 @@ static int tc_stream_disable(struct tc_data *tc)
        return 0;
 }
 
-static void tc_bridge_pre_enable(struct drm_bridge *bridge)
-{
-       struct tc_data *tc = bridge_to_tc(bridge);
-
-       drm_panel_prepare(tc->panel);
-}
-
 static void tc_bridge_enable(struct drm_bridge *bridge)
 {
        struct tc_data *tc = bridge_to_tc(bridge);
@@ -1266,8 +1257,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
                tc_main_link_disable(tc);
                return;
        }
-
-       drm_panel_enable(tc->panel);
 }
 
 static void tc_bridge_disable(struct drm_bridge *bridge)
@@ -1275,8 +1264,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
        struct tc_data *tc = bridge_to_tc(bridge);
        int ret;
 
-       drm_panel_disable(tc->panel);
-
        ret = tc_stream_disable(tc);
        if (ret < 0)
                dev_err(tc->dev, "main link stream stop error: %d\n", ret);
@@ -1286,13 +1273,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
                dev_err(tc->dev, "main link disable error: %d\n", ret);
 }
 
-static void tc_bridge_post_disable(struct drm_bridge *bridge)
-{
-       struct tc_data *tc = bridge_to_tc(bridge);
-
-       drm_panel_unprepare(tc->panel);
-}
-
 static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
                                 const struct drm_display_mode *mode,
                                 struct drm_display_mode *adj)
@@ -1335,11 +1315,19 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge,
        tc->mode = *mode;
 }
 
+static struct edid *tc_get_edid(struct drm_bridge *bridge,
+                               struct drm_connector *connector)
+{
+       struct tc_data *tc = bridge_to_tc(bridge);
+
+       return drm_get_edid(connector, &tc->aux.ddc);
+}
+
 static int tc_connector_get_modes(struct drm_connector *connector)
 {
        struct tc_data *tc = connector_to_tc(connector);
+       int num_modes;
        struct edid *edid;
-       int count;
        int ret;
 
        ret = tc_get_display_props(tc);
@@ -1348,42 +1336,30 @@ static int tc_connector_get_modes(struct drm_connector *connector)
                return 0;
        }
 
-       count = drm_panel_get_modes(tc->panel, connector);
-       if (count > 0)
-               return count;
-
-       edid = drm_get_edid(connector, &tc->aux.ddc);
-
-       kfree(tc->edid);
-       tc->edid = edid;
-       if (!edid)
-               return 0;
+       if (tc->panel_bridge) {
+               num_modes = drm_bridge_get_modes(tc->panel_bridge, connector);
+               if (num_modes > 0)
+                       return num_modes;
+       }
 
-       drm_connector_update_edid_property(connector, edid);
-       count = drm_add_edid_modes(connector, edid);
+       edid = tc_get_edid(&tc->bridge, connector);
+       num_modes = drm_add_edid_modes(connector, edid);
+       kfree(edid);
 
-       return count;
+       return num_modes;
 }
 
 static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
        .get_modes = tc_connector_get_modes,
 };
 
-static enum drm_connector_status tc_connector_detect(struct drm_connector *connector,
-                                                    bool force)
+static enum drm_connector_status tc_bridge_detect(struct drm_bridge *bridge)
 {
-       struct tc_data *tc = connector_to_tc(connector);
+       struct tc_data *tc = bridge_to_tc(bridge);
        bool conn;
        u32 val;
        int ret;
 
-       if (tc->hpd_pin < 0) {
-               if (tc->panel)
-                       return connector_status_connected;
-               else
-                       return connector_status_unknown;
-       }
-
        ret = regmap_read(tc->regmap, GPIOI, &val);
        if (ret)
                return connector_status_unknown;
@@ -1396,6 +1372,20 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne
                return connector_status_disconnected;
 }
 
+static enum drm_connector_status
+tc_connector_detect(struct drm_connector *connector, bool force)
+{
+       struct tc_data *tc = connector_to_tc(connector);
+
+       if (tc->hpd_pin >= 0)
+               return tc_bridge_detect(&tc->bridge);
+
+       if (tc->panel_bridge)
+               return connector_status_connected;
+       else
+               return connector_status_unknown;
+}
+
 static const struct drm_connector_funcs tc_connector_funcs = {
        .detect = tc_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
@@ -1413,16 +1403,20 @@ static int tc_bridge_attach(struct drm_bridge *bridge,
        struct drm_device *drm = bridge->dev;
        int ret;
 
-       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
-               DRM_ERROR("Fix bridge driver to make connector optional!");
-               return -EINVAL;
+       if (tc->panel_bridge) {
+               /* If a connector is required then this driver shall create it */
+               ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+                                       &tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+               if (ret)
+                       return ret;
        }
 
+       if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+               return 0;
+
        /* Create DP/eDP connector */
        drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs);
-       ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs,
-                                tc->panel ? DRM_MODE_CONNECTOR_eDP :
-                                DRM_MODE_CONNECTOR_DisplayPort);
+       ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, tc->bridge.type);
        if (ret)
                return ret;
 
@@ -1435,9 +1429,6 @@ static int tc_bridge_attach(struct drm_bridge *bridge,
                                               DRM_CONNECTOR_POLL_DISCONNECT;
        }
 
-       if (tc->panel)
-               drm_panel_attach(tc->panel, &tc->connector);
-
        drm_display_info_set_bus_formats(&tc->connector.display_info,
                                         &bus_format, 1);
        tc->connector.display_info.bus_flags =
@@ -1453,11 +1444,11 @@ static const struct drm_bridge_funcs tc_bridge_funcs = {
        .attach = tc_bridge_attach,
        .mode_valid = tc_mode_valid,
        .mode_set = tc_bridge_mode_set,
-       .pre_enable = tc_bridge_pre_enable,
        .enable = tc_bridge_enable,
        .disable = tc_bridge_disable,
-       .post_disable = tc_bridge_post_disable,
        .mode_fixup = tc_bridge_mode_fixup,
+       .detect = tc_bridge_detect,
+       .get_edid = tc_get_edid,
 };
 
 static bool tc_readable_reg(struct device *dev, unsigned int reg)
@@ -1547,6 +1538,7 @@ static irqreturn_t tc_irq_handler(int irq, void *arg)
 static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
+       struct drm_panel *panel;
        struct tc_data *tc;
        int ret;
 
@@ -1557,10 +1549,23 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
        tc->dev = dev;
 
        /* port@2 is the output port */
-       ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &tc->panel, NULL);
+       ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
        if (ret && ret != -ENODEV)
                return ret;
 
+       if (panel) {
+               struct drm_bridge *panel_bridge;
+
+               panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+               if (IS_ERR(panel_bridge))
+                       return PTR_ERR(panel_bridge);
+
+               tc->panel_bridge = panel_bridge;
+               tc->bridge.type = DRM_MODE_CONNECTOR_eDP;
+       } else {
+               tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
+       }
+
        /* Shut down GPIO is optional */
        tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
        if (IS_ERR(tc->sd_gpio))
@@ -1680,6 +1685,10 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return ret;
 
        tc->bridge.funcs = &tc_bridge_funcs;
+       if (tc->hpd_pin >= 0)
+               tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
+       tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+
        tc->bridge.of_node = dev->of_node;
        drm_bridge_add(&tc->bridge);
 
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
new file mode 100644 (file)
index 0000000..7da15cd
--- /dev/null
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TC358775 DSI to LVDS bridge driver
+ *
+ * Copyright (C) 2020 SMART Wireless Computing
+ * Author: Vinay Simha BN <simhavcs@gmail.com>
+ *
+ */
+/* #define DEBUG */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <asm/unaligned.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#define FLD_VAL(val, start, end) FIELD_PREP(GENMASK(start, end), val)
+
+/* Registers */
+
+/* DSI D-PHY Layer Registers */
+#define D0W_DPHYCONTTX  0x0004  /* Data Lane 0 DPHY Tx Control */
+#define CLW_DPHYCONTRX  0x0020  /* Clock Lane DPHY Rx Control */
+#define D0W_DPHYCONTRX  0x0024  /* Data Lane 0 DPHY Rx Control */
+#define D1W_DPHYCONTRX  0x0028  /* Data Lane 1 DPHY Rx Control */
+#define D2W_DPHYCONTRX  0x002C  /* Data Lane 2 DPHY Rx Control */
+#define D3W_DPHYCONTRX  0x0030  /* Data Lane 3 DPHY Rx Control */
+#define COM_DPHYCONTRX  0x0038  /* DPHY Rx Common Control */
+#define CLW_CNTRL       0x0040  /* Clock Lane Control */
+#define D0W_CNTRL       0x0044  /* Data Lane 0 Control */
+#define D1W_CNTRL       0x0048  /* Data Lane 1 Control */
+#define D2W_CNTRL       0x004C  /* Data Lane 2 Control */
+#define D3W_CNTRL       0x0050  /* Data Lane 3 Control */
+#define DFTMODE_CNTRL   0x0054  /* DFT Mode Control */
+
+/* DSI PPI Layer Registers */
+#define PPI_STARTPPI    0x0104  /* START control bit of PPI-TX function. */
+#define PPI_START_FUNCTION      1
+
+#define PPI_BUSYPPI     0x0108
+#define PPI_LINEINITCNT 0x0110  /* Line Initialization Wait Counter  */
+#define PPI_LPTXTIMECNT 0x0114
+#define PPI_LANEENABLE  0x0134  /* Enables each lane at the PPI layer. */
+#define PPI_TX_RX_TA    0x013C  /* DSI Bus Turn Around timing parameters */
+
+/* Analog timer function enable */
+#define PPI_CLS_ATMR    0x0140  /* Delay for Clock Lane in LPRX  */
+#define PPI_D0S_ATMR    0x0144  /* Delay for Data Lane 0 in LPRX */
+#define PPI_D1S_ATMR    0x0148  /* Delay for Data Lane 1 in LPRX */
+#define PPI_D2S_ATMR    0x014C  /* Delay for Data Lane 2 in LPRX */
+#define PPI_D3S_ATMR    0x0150  /* Delay for Data Lane 3 in LPRX */
+
+#define PPI_D0S_CLRSIPOCOUNT    0x0164  /* For lane 0 */
+#define PPI_D1S_CLRSIPOCOUNT    0x0168  /* For lane 1 */
+#define PPI_D2S_CLRSIPOCOUNT    0x016C  /* For lane 2 */
+#define PPI_D3S_CLRSIPOCOUNT    0x0170  /* For lane 3 */
+
+#define CLS_PRE         0x0180  /* Digital Counter inside of PHY IO */
+#define D0S_PRE         0x0184  /* Digital Counter inside of PHY IO */
+#define D1S_PRE         0x0188  /* Digital Counter inside of PHY IO */
+#define D2S_PRE         0x018C  /* Digital Counter inside of PHY IO */
+#define D3S_PRE         0x0190  /* Digital Counter inside of PHY IO */
+#define CLS_PREP        0x01A0  /* Digital Counter inside of PHY IO */
+#define D0S_PREP        0x01A4  /* Digital Counter inside of PHY IO */
+#define D1S_PREP        0x01A8  /* Digital Counter inside of PHY IO */
+#define D2S_PREP        0x01AC  /* Digital Counter inside of PHY IO */
+#define D3S_PREP        0x01B0  /* Digital Counter inside of PHY IO */
+#define CLS_ZERO        0x01C0  /* Digital Counter inside of PHY IO */
+#define D0S_ZERO        0x01C4  /* Digital Counter inside of PHY IO */
+#define D1S_ZERO        0x01C8  /* Digital Counter inside of PHY IO */
+#define D2S_ZERO        0x01CC  /* Digital Counter inside of PHY IO */
+#define D3S_ZERO        0x01D0  /* Digital Counter inside of PHY IO */
+
+#define PPI_CLRFLG      0x01E0  /* PRE Counters has reached set values */
+#define PPI_CLRSIPO     0x01E4  /* Clear SIPO values, Slave mode use only. */
+#define HSTIMEOUT       0x01F0  /* HS Rx Time Out Counter */
+#define HSTIMEOUTENABLE 0x01F4  /* Enable HS Rx Time Out Counter */
+#define DSI_STARTDSI    0x0204  /* START control bit of DSI-TX function */
+#define DSI_RX_START   1
+
+#define DSI_BUSYDSI     0x0208
+#define DSI_LANEENABLE  0x0210  /* Enables each lane at the Protocol layer. */
+#define DSI_LANESTATUS0 0x0214  /* Displays lane is in HS RX mode. */
+#define DSI_LANESTATUS1 0x0218  /* Displays lane is in ULPS or STOP state */
+
+#define DSI_INTSTATUS   0x0220  /* Interrupt Status */
+#define DSI_INTMASK     0x0224  /* Interrupt Mask */
+#define DSI_INTCLR      0x0228  /* Interrupt Clear */
+#define DSI_LPTXTO      0x0230  /* Low Power Tx Time Out Counter */
+
+#define DSIERRCNT       0x0300  /* DSI Error Count */
+#define APLCTRL         0x0400  /* Application Layer Control */
+#define RDPKTLN         0x0404  /* Command Read Packet Length */
+
+#define VPCTRL          0x0450  /* Video Path Control */
+#define HTIM1           0x0454  /* Horizontal Timing Control 1 */
+#define HTIM2           0x0458  /* Horizontal Timing Control 2 */
+#define VTIM1           0x045C  /* Vertical Timing Control 1 */
+#define VTIM2           0x0460  /* Vertical Timing Control 2 */
+#define VFUEN           0x0464  /* Video Frame Timing Update Enable */
+#define VFUEN_EN       BIT(0)  /* Upload Enable */
+
+/* Mux Input Select for LVDS LINK Input */
+#define LV_MX0003        0x0480  /* Bit 0 to 3 */
+#define LV_MX0407        0x0484  /* Bit 4 to 7 */
+#define LV_MX0811        0x0488  /* Bit 8 to 11 */
+#define LV_MX1215        0x048C  /* Bit 12 to 15 */
+#define LV_MX1619        0x0490  /* Bit 16 to 19 */
+#define LV_MX2023        0x0494  /* Bit 20 to 23 */
+#define LV_MX2427        0x0498  /* Bit 24 to 27 */
+#define LV_MX(b0, b1, b2, b3)  (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \
+                               FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24))
+
+/* Input bit numbers used in mux registers */
+enum {
+       LVI_R0,
+       LVI_R1,
+       LVI_R2,
+       LVI_R3,
+       LVI_R4,
+       LVI_R5,
+       LVI_R6,
+       LVI_R7,
+       LVI_G0,
+       LVI_G1,
+       LVI_G2,
+       LVI_G3,
+       LVI_G4,
+       LVI_G5,
+       LVI_G6,
+       LVI_G7,
+       LVI_B0,
+       LVI_B1,
+       LVI_B2,
+       LVI_B3,
+       LVI_B4,
+       LVI_B5,
+       LVI_B6,
+       LVI_B7,
+       LVI_HS,
+       LVI_VS,
+       LVI_DE,
+       LVI_L0
+};
+
+#define LVCFG           0x049C  /* LVDS Configuration  */
+#define LVPHY0          0x04A0  /* LVDS PHY 0 */
+#define LV_PHY0_RST(v)          FLD_VAL(v, 22, 22) /* PHY reset */
+#define LV_PHY0_IS(v)           FLD_VAL(v, 15, 14)
+#define LV_PHY0_ND(v)           FLD_VAL(v, 4, 0) /* Frequency range select */
+#define LV_PHY0_PRBS_ON(v)      FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */
+
+#define LVPHY1          0x04A4  /* LVDS PHY 1 */
+#define SYSSTAT         0x0500  /* System Status  */
+#define SYSRST          0x0504  /* System Reset  */
+
+#define SYS_RST_I2CS   BIT(0) /* Reset I2C-Slave controller */
+#define SYS_RST_I2CM   BIT(1) /* Reset I2C-Master controller */
+#define SYS_RST_LCD    BIT(2) /* Reset LCD controller */
+#define SYS_RST_BM     BIT(3) /* Reset Bus Management controller */
+#define SYS_RST_DSIRX  BIT(4) /* Reset DSI-RX and App controller */
+#define SYS_RST_REG    BIT(5) /* Reset Register module */
+
+/* GPIO Registers */
+#define GPIOC           0x0520  /* GPIO Control  */
+#define GPIOO           0x0524  /* GPIO Output  */
+#define GPIOI           0x0528  /* GPIO Input  */
+
+/* I2C Registers */
+#define I2CTIMCTRL      0x0540  /* I2C IF Timing and Enable Control */
+#define I2CMADDR        0x0544  /* I2C Master Addressing */
+#define WDATAQ          0x0548  /* Write Data Queue */
+#define RDATAQ          0x054C  /* Read Data Queue */
+
+/* Chip ID and Revision ID Register */
+#define IDREG           0x0580
+
+#define LPX_PERIOD             4
+#define TTA_GET                        0x40000
+#define TTA_SURE               6
+#define SINGLE_LINK            1
+#define DUAL_LINK              2
+
+#define TC358775XBG_ID  0x00007500
+
+/* Debug Registers */
+#define DEBUG00         0x05A0  /* Debug */
+#define DEBUG01         0x05A4  /* LVDS Data */
+
+#define DSI_CLEN_BIT           BIT(0)
+#define DIVIDE_BY_3            3 /* PCLK=DCLK/3 */
+#define DIVIDE_BY_6            6 /* PCLK=DCLK/6 */
+#define LVCFG_LVEN_BIT         BIT(0)
+
+#define L0EN BIT(1)
+
+#define TC358775_VPCTRL_VSDELAY__MASK  0x3FF00000
+#define TC358775_VPCTRL_VSDELAY__SHIFT 20
+static inline u32 TC358775_VPCTRL_VSDELAY(uint32_t val)
+{
+       return ((val) << TC358775_VPCTRL_VSDELAY__SHIFT) &
+                       TC358775_VPCTRL_VSDELAY__MASK;
+}
+
+#define TC358775_VPCTRL_OPXLFMT__MASK  0x00000100
+#define TC358775_VPCTRL_OPXLFMT__SHIFT 8
+static inline u32 TC358775_VPCTRL_OPXLFMT(uint32_t val)
+{
+       return ((val) << TC358775_VPCTRL_OPXLFMT__SHIFT) &
+                       TC358775_VPCTRL_OPXLFMT__MASK;
+}
+
+#define TC358775_VPCTRL_MSF__MASK      0x00000001
+#define TC358775_VPCTRL_MSF__SHIFT     0
+static inline u32 TC358775_VPCTRL_MSF(uint32_t val)
+{
+       return ((val) << TC358775_VPCTRL_MSF__SHIFT) &
+                       TC358775_VPCTRL_MSF__MASK;
+}
+
+#define TC358775_LVCFG_PCLKDIV__MASK   0x000000f0
+#define TC358775_LVCFG_PCLKDIV__SHIFT  4
+static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val)
+{
+       return ((val) << TC358775_LVCFG_PCLKDIV__SHIFT) &
+                       TC358775_LVCFG_PCLKDIV__MASK;
+}
+
+#define TC358775_LVCFG_LVDLINK__MASK                         0x00000002
+#define TC358775_LVCFG_LVDLINK__SHIFT                        0
+static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val)
+{
+       return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) &
+                       TC358775_LVCFG_LVDLINK__MASK;
+}
+
+enum tc358775_ports {
+       TC358775_DSI_IN,
+       TC358775_LVDS_OUT0,
+       TC358775_LVDS_OUT1,
+};
+
+struct tc_data {
+       struct i2c_client       *i2c;
+       struct device           *dev;
+
+       struct drm_bridge       bridge;
+       struct drm_bridge       *panel_bridge;
+
+       struct device_node *host_node;
+       struct mipi_dsi_device *dsi;
+       u8 num_dsi_lanes;
+
+       struct regulator        *vdd;
+       struct regulator        *vddio;
+       struct gpio_desc        *reset_gpio;
+       struct gpio_desc        *stby_gpio;
+       u8                      lvds_link; /* single-link or dual-link */
+       u8                      bpc;
+};
+
+static inline struct tc_data *bridge_to_tc(struct drm_bridge *b)
+{
+       return container_of(b, struct tc_data, bridge);
+}
+
+static void tc_bridge_pre_enable(struct drm_bridge *bridge)
+{
+       struct tc_data *tc = bridge_to_tc(bridge);
+       struct device *dev = &tc->dsi->dev;
+       int ret;
+
+       ret = regulator_enable(tc->vddio);
+       if (ret < 0)
+               dev_err(dev, "regulator vddio enable failed, %d\n", ret);
+       usleep_range(10000, 11000);
+
+       ret = regulator_enable(tc->vdd);
+       if (ret < 0)
+               dev_err(dev, "regulator vdd enable failed, %d\n", ret);
+       usleep_range(10000, 11000);
+
+       gpiod_set_value(tc->stby_gpio, 0);
+       usleep_range(10000, 11000);
+
+       gpiod_set_value(tc->reset_gpio, 0);
+       usleep_range(10, 20);
+}
+
+static void tc_bridge_post_disable(struct drm_bridge *bridge)
+{
+       struct tc_data *tc = bridge_to_tc(bridge);
+       struct device *dev = &tc->dsi->dev;
+       int ret;
+
+       gpiod_set_value(tc->reset_gpio, 1);
+       usleep_range(10, 20);
+
+       gpiod_set_value(tc->stby_gpio, 1);
+       usleep_range(10000, 11000);
+
+       ret = regulator_disable(tc->vdd);
+       if (ret < 0)
+               dev_err(dev, "regulator vdd disable failed, %d\n", ret);
+       usleep_range(10000, 11000);
+
+       ret = regulator_disable(tc->vddio);
+       if (ret < 0)
+               dev_err(dev, "regulator vddio disable failed, %d\n", ret);
+       usleep_range(10000, 11000);
+}
+
+static void d2l_read(struct i2c_client *i2c, u16 addr, u32 *val)
+{
+       int ret;
+       u8 buf_addr[2];
+
+       put_unaligned_be16(addr, buf_addr);
+       ret = i2c_master_send(i2c, buf_addr, sizeof(buf_addr));
+       if (ret < 0)
+               goto fail;
+
+       ret = i2c_master_recv(i2c, (u8 *)val, sizeof(*val));
+       if (ret < 0)
+               goto fail;
+
+       pr_debug("d2l: I2C : addr:%04x value:%08x\n", addr, *val);
+
+fail:
+       dev_err(&i2c->dev, "Error %d reading from subaddress 0x%x\n",
+               ret, addr);
+}
+
+static void d2l_write(struct i2c_client *i2c, u16 addr, u32 val)
+{
+       u8 data[6];
+       int ret;
+
+       put_unaligned_be16(addr, data);
+       put_unaligned_le32(val, data + 2);
+
+       ret = i2c_master_send(i2c, data, ARRAY_SIZE(data));
+       if (ret < 0)
+               dev_err(&i2c->dev, "Error %d writing to subaddress 0x%x\n",
+                       ret, addr);
+}
+
+/* helper function to access bus_formats */
+static struct drm_connector *get_connector(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->encoder == encoder)
+                       return connector;
+
+       return NULL;
+}
+
+static void tc_bridge_enable(struct drm_bridge *bridge)
+{
+       struct tc_data *tc = bridge_to_tc(bridge);
+       u32 hback_porch, hsync_len, hfront_porch, hactive, htime1, htime2;
+       u32 vback_porch, vsync_len, vfront_porch, vactive, vtime1, vtime2;
+       u32 val = 0;
+       u16 dsiclk, clkdiv, byteclk, t1, t2, t3, vsdelay;
+       struct drm_display_mode *mode;
+       struct drm_connector *connector = get_connector(bridge->encoder);
+
+       mode = &bridge->encoder->crtc->state->adjusted_mode;
+
+       hback_porch = mode->htotal - mode->hsync_end;
+       hsync_len  = mode->hsync_end - mode->hsync_start;
+       vback_porch = mode->vtotal - mode->vsync_end;
+       vsync_len  = mode->vsync_end - mode->vsync_start;
+
+       htime1 = (hback_porch << 16) + hsync_len;
+       vtime1 = (vback_porch << 16) + vsync_len;
+
+       hfront_porch = mode->hsync_start - mode->hdisplay;
+       hactive = mode->hdisplay;
+       vfront_porch = mode->vsync_start - mode->vdisplay;
+       vactive = mode->vdisplay;
+
+       htime2 = (hfront_porch << 16) + hactive;
+       vtime2 = (vfront_porch << 16) + vactive;
+
+       d2l_read(tc->i2c, IDREG, &val);
+
+       dev_info(tc->dev, "DSI2LVDS Chip ID.%02x Revision ID. %02x **\n",
+                (val >> 8) & 0xFF, val & 0xFF);
+
+       d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM |
+                 SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS);
+       usleep_range(30000, 40000);
+
+       d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
+       d2l_write(tc->i2c, PPI_LPTXTIMECNT, LPX_PERIOD);
+       d2l_write(tc->i2c, PPI_D0S_CLRSIPOCOUNT, 3);
+       d2l_write(tc->i2c, PPI_D1S_CLRSIPOCOUNT, 3);
+       d2l_write(tc->i2c, PPI_D2S_CLRSIPOCOUNT, 3);
+       d2l_write(tc->i2c, PPI_D3S_CLRSIPOCOUNT, 3);
+
+       val = ((L0EN << tc->num_dsi_lanes) - L0EN) | DSI_CLEN_BIT;
+       d2l_write(tc->i2c, PPI_LANEENABLE, val);
+       d2l_write(tc->i2c, DSI_LANEENABLE, val);
+
+       d2l_write(tc->i2c, PPI_STARTPPI, PPI_START_FUNCTION);
+       d2l_write(tc->i2c, DSI_STARTDSI, DSI_RX_START);
+
+       if (tc->bpc == 8)
+               val = TC358775_VPCTRL_OPXLFMT(1);
+       else /* bpc = 6; */
+               val = TC358775_VPCTRL_MSF(1);
+
+       dsiclk = mode->crtc_clock * 3 * tc->bpc / tc->num_dsi_lanes / 1000;
+       clkdiv = dsiclk / DIVIDE_BY_3 * tc->lvds_link;
+       byteclk = dsiclk / 4;
+       t1 = hactive * (tc->bpc * 3 / 8) / tc->num_dsi_lanes;
+       t2 = ((100000 / clkdiv)) * (hactive + hback_porch + hsync_len + hfront_porch) / 1000;
+       t3 = ((t2 * byteclk) / 100) - (hactive * (tc->bpc * 3 / 8) /
+               tc->num_dsi_lanes);
+
+       vsdelay = (clkdiv * (t1 + t3) / byteclk) - hback_porch - hsync_len - hactive;
+
+       val |= TC358775_VPCTRL_VSDELAY(vsdelay);
+       d2l_write(tc->i2c, VPCTRL, val);
+
+       d2l_write(tc->i2c, HTIM1, htime1);
+       d2l_write(tc->i2c, VTIM1, vtime1);
+       d2l_write(tc->i2c, HTIM2, htime2);
+       d2l_write(tc->i2c, VTIM2, vtime2);
+
+       d2l_write(tc->i2c, VFUEN, VFUEN_EN);
+       d2l_write(tc->i2c, SYSRST, SYS_RST_LCD);
+       d2l_write(tc->i2c, LVPHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_ND(6));
+
+       dev_dbg(tc->dev, "bus_formats %04x bpc %d\n",
+               connector->display_info.bus_formats[0],
+               tc->bpc);
+       /*
+        * Default hardware register settings of tc358775 configured
+        * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format
+        */
+       if (connector->display_info.bus_formats[0] ==
+               MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) {
+               /* VESA-24 */
+               d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
+               d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0));
+               d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7));
+               d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
+               d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2));
+               d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
+               d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6));
+       } else { /*  MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */
+               d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3));
+               d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0));
+               d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0));
+               d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0));
+               d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2));
+               d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0));
+               d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0));
+       }
+
+       d2l_write(tc->i2c, VFUEN, VFUEN_EN);
+
+       val = LVCFG_LVEN_BIT;
+       if (tc->lvds_link == DUAL_LINK) {
+               val |= TC358775_LVCFG_LVDLINK(1);
+               val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_6);
+       } else {
+               val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_3);
+       };
+       d2l_write(tc->i2c, LVCFG, val);
+}
+
+static enum drm_mode_status
+tc_mode_valid(struct drm_bridge *bridge,
+             const struct drm_display_info *info,
+             const struct drm_display_mode *mode)
+{
+       struct tc_data *tc = bridge_to_tc(bridge);
+
+       /*
+        * Maximum pixel clock speed 135MHz for single-link
+        * 270MHz for dual-link
+        */
+       if ((mode->clock > 135000 && tc->lvds_link == SINGLE_LINK) ||
+           (mode->clock > 270000 && tc->lvds_link == DUAL_LINK))
+               return MODE_CLOCK_HIGH;
+
+       switch (info->bus_formats[0]) {
+       case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+       case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+               /* RGB888 */
+               tc->bpc = 8;
+               break;
+       case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+               /* RGB666 */
+               tc->bpc = 6;
+               break;
+       default:
+               dev_warn(tc->dev,
+                        "unsupported LVDS bus format 0x%04x\n",
+                        info->bus_formats[0]);
+               return MODE_NOMODE;
+       }
+
+       return MODE_OK;
+}
+
+static int tc358775_parse_dt(struct device_node *np, struct tc_data *tc)
+{
+       struct device_node *endpoint;
+       struct device_node *parent;
+       struct device_node *remote;
+       struct property *prop;
+       int len = 0;
+
+       /*
+        * To get the data-lanes of dsi, we need to access the dsi0_out of port1
+        *  of dsi0 endpoint from bridge port0 of d2l_in
+        */
+       endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node,
+                                                TC358775_DSI_IN, -1);
+       if (endpoint) {
+               /* dsi0_out node */
+               parent = of_graph_get_remote_port_parent(endpoint);
+               of_node_put(endpoint);
+               if (parent) {
+                       /* dsi0 port 1 */
+                       endpoint = of_graph_get_endpoint_by_regs(parent, 1, -1);
+                       of_node_put(parent);
+                       if (endpoint) {
+                               prop = of_find_property(endpoint, "data-lanes",
+                                                       &len);
+                               of_node_put(endpoint);
+                               if (!prop) {
+                                       dev_err(tc->dev,
+                                               "failed to find data lane\n");
+                                       return -EPROBE_DEFER;
+                               }
+                       }
+               }
+       }
+
+       tc->num_dsi_lanes = len / sizeof(u32);
+
+       if (tc->num_dsi_lanes < 1 || tc->num_dsi_lanes > 4)
+               return -EINVAL;
+
+       tc->host_node = of_graph_get_remote_node(np, 0, 0);
+       if (!tc->host_node)
+               return -ENODEV;
+
+       of_node_put(tc->host_node);
+
+       tc->lvds_link = SINGLE_LINK;
+       endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node,
+                                                TC358775_LVDS_OUT1, -1);
+       if (endpoint) {
+               remote = of_graph_get_remote_port_parent(endpoint);
+               of_node_put(endpoint);
+
+               if (remote) {
+                       if (of_device_is_available(remote))
+                               tc->lvds_link = DUAL_LINK;
+                       of_node_put(remote);
+               }
+       }
+
+       dev_dbg(tc->dev, "no.of dsi lanes: %d\n", tc->num_dsi_lanes);
+       dev_dbg(tc->dev, "operating in %d-link mode\n", tc->lvds_link);
+
+       return 0;
+}
+
+static int tc_bridge_attach(struct drm_bridge *bridge,
+                           enum drm_bridge_attach_flags flags)
+{
+       struct tc_data *tc = bridge_to_tc(bridge);
+       struct device *dev = &tc->i2c->dev;
+       struct mipi_dsi_host *host;
+       struct mipi_dsi_device *dsi;
+       int ret;
+
+       const struct mipi_dsi_device_info info = { .type = "tc358775",
+                                                       .channel = 0,
+                                                       .node = NULL,
+                                               };
+
+       host = of_find_mipi_dsi_host_by_node(tc->host_node);
+       if (!host) {
+               dev_err(dev, "failed to find dsi host\n");
+               return -EPROBE_DEFER;
+       }
+
+       dsi = mipi_dsi_device_register_full(host, &info);
+       if (IS_ERR(dsi)) {
+               dev_err(dev, "failed to create dsi device\n");
+               ret = PTR_ERR(dsi);
+               goto err_dsi_device;
+       }
+
+       tc->dsi = dsi;
+
+       dsi->lanes = tc->num_dsi_lanes;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0) {
+               dev_err(dev, "failed to attach dsi to host\n");
+               goto err_dsi_attach;
+       }
+
+       /* Attach the panel-bridge to the dsi bridge */
+       return drm_bridge_attach(bridge->encoder, tc->panel_bridge,
+                                &tc->bridge, flags);
+err_dsi_attach:
+       mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+       return ret;
+}
+
+static const struct drm_bridge_funcs tc_bridge_funcs = {
+       .attach = tc_bridge_attach,
+       .pre_enable = tc_bridge_pre_enable,
+       .enable = tc_bridge_enable,
+       .mode_valid = tc_mode_valid,
+       .post_disable = tc_bridge_post_disable,
+};
+
+static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct drm_panel *panel;
+       struct tc_data *tc;
+       int ret;
+
+       tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
+       if (!tc)
+               return -ENOMEM;
+
+       tc->dev = dev;
+       tc->i2c = client;
+
+       ret = drm_of_find_panel_or_bridge(dev->of_node, TC358775_LVDS_OUT0,
+                                         0, &panel, NULL);
+       if (ret < 0)
+               return ret;
+       if (!panel)
+               return -ENODEV;
+
+       tc->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+       if (IS_ERR(tc->panel_bridge))
+               return PTR_ERR(tc->panel_bridge);
+
+       ret = tc358775_parse_dt(dev->of_node, tc);
+       if (ret)
+               return ret;
+
+       tc->vddio = devm_regulator_get(dev, "vddio-supply");
+       if (IS_ERR(tc->vddio)) {
+               ret = PTR_ERR(tc->vddio);
+               dev_err(dev, "vddio-supply not found\n");
+               return ret;
+       }
+
+       tc->vdd = devm_regulator_get(dev, "vdd-supply");
+       if (IS_ERR(tc->vdd)) {
+               ret = PTR_ERR(tc->vddio);
+               dev_err(dev, "vdd-supply not found\n");
+               return ret;
+       }
+
+       tc->stby_gpio = devm_gpiod_get(dev, "stby", GPIOD_OUT_HIGH);
+       if (IS_ERR(tc->stby_gpio)) {
+               ret = PTR_ERR(tc->stby_gpio);
+               dev_err(dev, "cannot get stby-gpio %d\n", ret);
+               return ret;
+       }
+
+       tc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(tc->reset_gpio)) {
+               ret = PTR_ERR(tc->reset_gpio);
+               dev_err(dev, "cannot get reset-gpios %d\n", ret);
+               return ret;
+       }
+
+       tc->bridge.funcs = &tc_bridge_funcs;
+       tc->bridge.of_node = dev->of_node;
+       drm_bridge_add(&tc->bridge);
+
+       i2c_set_clientdata(client, tc);
+
+       return 0;
+}
+
+static int tc_remove(struct i2c_client *client)
+{
+       struct tc_data *tc = i2c_get_clientdata(client);
+
+       drm_bridge_remove(&tc->bridge);
+
+       return 0;
+}
+
+static const struct i2c_device_id tc358775_i2c_ids[] = {
+       { "tc358775", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids);
+
+static const struct of_device_id tc358775_of_ids[] = {
+       { .compatible = "toshiba,tc358775", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tc358775_of_ids);
+
+static struct i2c_driver tc358775_driver = {
+       .driver = {
+               .name = "tc358775",
+               .of_match_table = tc358775_of_ids,
+       },
+       .id_table = tc358775_i2c_ids,
+       .probe = tc_probe,
+       .remove = tc_remove,
+};
+module_i2c_driver(tc358775_driver);
+
+MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
+MODULE_DESCRIPTION("TC358775 DSI/LVDS bridge driver");
+MODULE_LICENSE("GPL v2");
index 86b9f0f..454544e 100644 (file)
@@ -394,9 +394,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge,
        }
        pdata->dsi = dsi;
 
-       /* attach panel to bridge */
-       drm_panel_attach(pdata->panel, &pdata->connector);
-
        return 0;
 
 err_dsi_attach:
index 00e40a2..3d48ad1 100644 (file)
@@ -850,7 +850,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
 DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
 
 static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
-       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I, TV-out and DP */
        { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
        { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
 };
@@ -867,7 +867,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
 DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
 
 static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
-       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I, TV-out and DP */
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
@@ -876,6 +876,19 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
 DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
                 drm_tv_subconnector_enum_list)
 
+static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = {
+       { DRM_MODE_SUBCONNECTOR_Unknown,     "Unknown"   }, /* DVI-I, TV-out and DP */
+       { DRM_MODE_SUBCONNECTOR_VGA,         "VGA"       }, /* DP */
+       { DRM_MODE_SUBCONNECTOR_DVID,        "DVI-D"     }, /* DP */
+       { DRM_MODE_SUBCONNECTOR_HDMIA,       "HDMI"      }, /* DP */
+       { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP"        }, /* DP */
+       { DRM_MODE_SUBCONNECTOR_Wireless,    "Wireless"  }, /* DP */
+       { DRM_MODE_SUBCONNECTOR_Native,      "Native"    }, /* DP */
+};
+
+DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name,
+                drm_dp_subconnector_enum_list)
+
 static const struct drm_prop_enum_list hdmi_colorspaces[] = {
        /* For Default case, driver will set the colorspace */
        { DRM_MODE_COLORIMETRY_DEFAULT, "Default" },
@@ -1217,6 +1230,14 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
  *     can also expose this property to external outputs, in which case they
  *     must support "None", which should be the default (since external screens
  *     have a built-in scaler).
+ *
+ * subconnector:
+ *     This property is used by DVI-I, TVout and DisplayPort to indicate different
+ *     connector subtypes. Enum values more or less match with those from main
+ *     connector types.
+ *     For DVI-I and TVout there is also a matching property "select subconnector"
+ *     allowing to switch between signal types.
+ *     DP subconnector corresponds to a downstream port.
  */
 
 int drm_connector_create_standard_properties(struct drm_device *dev)
@@ -1305,6 +1326,30 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
 
+/**
+ * drm_connector_attach_dp_subconnector_property - create subconnector property for DP
+ * @connector: drm_connector to attach property
+ *
+ * Called by a driver when DP connector is created.
+ */
+void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector)
+{
+       struct drm_mode_config *mode_config = &connector->dev->mode_config;
+
+       if (!mode_config->dp_subconnector_property)
+               mode_config->dp_subconnector_property =
+                       drm_property_create_enum(connector->dev,
+                               DRM_MODE_PROP_IMMUTABLE,
+                               "subconnector",
+                               drm_dp_subconnector_enum_list,
+                               ARRAY_SIZE(drm_dp_subconnector_enum_list));
+
+       drm_object_attach_property(&connector->base,
+                                  mode_config->dp_subconnector_property,
+                                  DRM_MODE_SUBCONNECTOR_Unknown);
+}
+EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
+
 /**
  * DOC: HDMI connector properties
  *
index a3c82e7..4c21cf6 100644 (file)
@@ -597,6 +597,77 @@ void drm_dp_downstream_debug(struct seq_file *m,
 }
 EXPORT_SYMBOL(drm_dp_downstream_debug);
 
+/**
+ * drm_dp_subconnector_type() - get DP branch device type
+ *
+ */
+enum drm_mode_subconnector
+drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                        const u8 port_cap[4])
+{
+       int type;
+       if (!drm_dp_is_branch(dpcd))
+               return DRM_MODE_SUBCONNECTOR_Native;
+       /* DP 1.0 approach */
+       if (dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) {
+               type = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+                      DP_DWN_STRM_PORT_TYPE_MASK;
+
+               switch (type) {
+               case DP_DWN_STRM_PORT_TYPE_TMDS:
+                       /* Can be HDMI or DVI-D, DVI-D is a safer option */
+                       return DRM_MODE_SUBCONNECTOR_DVID;
+               case DP_DWN_STRM_PORT_TYPE_ANALOG:
+                       /* Can be VGA or DVI-A, VGA is more popular */
+                       return DRM_MODE_SUBCONNECTOR_VGA;
+               case DP_DWN_STRM_PORT_TYPE_DP:
+                       return DRM_MODE_SUBCONNECTOR_DisplayPort;
+               case DP_DWN_STRM_PORT_TYPE_OTHER:
+               default:
+                       return DRM_MODE_SUBCONNECTOR_Unknown;
+               }
+       }
+       type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
+
+       switch (type) {
+       case DP_DS_PORT_TYPE_DP:
+       case DP_DS_PORT_TYPE_DP_DUALMODE:
+               return DRM_MODE_SUBCONNECTOR_DisplayPort;
+       case DP_DS_PORT_TYPE_VGA:
+               return DRM_MODE_SUBCONNECTOR_VGA;
+       case DP_DS_PORT_TYPE_DVI:
+               return DRM_MODE_SUBCONNECTOR_DVID;
+       case DP_DS_PORT_TYPE_HDMI:
+               return DRM_MODE_SUBCONNECTOR_HDMIA;
+       case DP_DS_PORT_TYPE_WIRELESS:
+               return DRM_MODE_SUBCONNECTOR_Wireless;
+       case DP_DS_PORT_TYPE_NON_EDID:
+       default:
+               return DRM_MODE_SUBCONNECTOR_Unknown;
+       }
+}
+EXPORT_SYMBOL(drm_dp_subconnector_type);
+
+/**
+ * drm_mode_set_dp_subconnector_property - set subconnector for DP connector
+ *
+ * Called by a driver on every detect event.
+ */
+void drm_dp_set_subconnector_property(struct drm_connector *connector,
+                                     enum drm_connector_status status,
+                                     const u8 *dpcd,
+                                     const u8 port_cap[4])
+{
+       enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+
+       if (status == connector_status_connected)
+               subconnector = drm_dp_subconnector_type(dpcd, port_cap);
+       drm_object_property_set_value(&connector->base,
+                       connector->dev->mode_config.dp_subconnector_property,
+                       subconnector);
+}
+EXPORT_SYMBOL(drm_dp_set_subconnector_property);
+
 /*
  * I2C-over-AUX implementation
  */
index 3296ed3..b410930 100644 (file)
@@ -653,7 +653,7 @@ static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo,
 
 static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo,
                                               bool evict,
-                                              struct ttm_mem_reg *new_mem)
+                                              struct ttm_resource *new_mem)
 {
        struct ttm_bo_kmap_obj *kmap = &gbo->kmap;
 
@@ -1004,28 +1004,6 @@ err_ttm_tt_init:
        return NULL;
 }
 
-static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
-                                  struct ttm_mem_type_manager *man)
-{
-       switch (type) {
-       case TTM_PL_SYSTEM:
-               man->flags = 0;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case TTM_PL_VRAM:
-               man->func = &ttm_bo_manager_func;
-               man->flags = TTM_MEMTYPE_FLAG_FIXED;
-               man->available_caching = TTM_PL_FLAG_UNCACHED |
-                                        TTM_PL_FLAG_WC;
-               man->default_caching = TTM_PL_FLAG_WC;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static void bo_driver_evict_flags(struct ttm_buffer_object *bo,
                                  struct ttm_placement *placement)
 {
@@ -1042,7 +1020,7 @@ static void bo_driver_evict_flags(struct ttm_buffer_object *bo,
 
 static void bo_driver_move_notify(struct ttm_buffer_object *bo,
                                  bool evict,
-                                 struct ttm_mem_reg *new_mem)
+                                 struct ttm_resource *new_mem)
 {
        struct drm_gem_vram_object *gbo;
 
@@ -1056,7 +1034,7 @@ static void bo_driver_move_notify(struct ttm_buffer_object *bo,
 }
 
 static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
-                                   struct ttm_mem_reg *mem)
+                                   struct ttm_resource *mem)
 {
        struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev);
 
@@ -1083,9 +1061,6 @@ static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
 
 static struct ttm_bo_driver bo_driver = {
        .ttm_tt_create = bo_driver_ttm_tt_create,
-       .ttm_tt_populate = ttm_pool_populate,
-       .ttm_tt_unpopulate = ttm_pool_unpopulate,
-       .init_mem_type = bo_driver_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = bo_driver_evict_flags,
        .move_notify = bo_driver_move_notify,
@@ -1100,12 +1075,10 @@ static int drm_vram_mm_debugfs(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_vram_mm *vmm = node->minor->dev->vram_mm;
-       struct drm_mm *mm = vmm->bdev.man[TTM_PL_VRAM].priv;
+       struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM);
        struct drm_printer p = drm_seq_file_printer(m);
 
-       spin_lock(&ttm_bo_glob.lru_lock);
-       drm_mm_print(mm, &p);
-       spin_unlock(&ttm_bo_glob.lru_lock);
+       ttm_resource_manager_debug(man, &p);
        return 0;
 }
 
@@ -1142,7 +1115,10 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
        if (ret)
                return ret;
 
-       ret = ttm_bo_init_mm(&vmm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT);
+       ret = ttm_range_man_init(&vmm->bdev, TTM_PL_VRAM,
+                                TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC,
+                                TTM_PL_FLAG_WC, false,
+                                vram_size >> PAGE_SHIFT);
        if (ret)
                return ret;
 
@@ -1151,6 +1127,7 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
 
 static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm)
 {
+       ttm_range_man_fini(&vmm->bdev, TTM_PL_VRAM);
        ttm_bo_device_release(&vmm->bdev);
 }
 
index 8c7bac8..ba11c36 100644 (file)
@@ -70,16 +70,12 @@ EXPORT_SYMBOL(drm_panel_init);
  *
  * Add a panel to the global registry so that it can be looked up by display
  * drivers.
- *
- * Return: 0 on success or a negative error code on failure.
  */
-int drm_panel_add(struct drm_panel *panel)
+void drm_panel_add(struct drm_panel *panel)
 {
        mutex_lock(&panel_lock);
        list_add_tail(&panel->list, &panel_list);
        mutex_unlock(&panel_lock);
-
-       return 0;
 }
 EXPORT_SYMBOL(drm_panel_add);
 
@@ -97,42 +93,6 @@ void drm_panel_remove(struct drm_panel *panel)
 }
 EXPORT_SYMBOL(drm_panel_remove);
 
-/**
- * drm_panel_attach - attach a panel to a connector
- * @panel: DRM panel
- * @connector: DRM connector
- *
- * After obtaining a pointer to a DRM panel a display driver calls this
- * function to attach a panel to a connector.
- *
- * An error is returned if the panel is already attached to another connector.
- *
- * When unloading, the driver should detach from the panel by calling
- * drm_panel_detach().
- *
- * Return: 0 on success or a negative error code on failure.
- */
-int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector)
-{
-       return 0;
-}
-EXPORT_SYMBOL(drm_panel_attach);
-
-/**
- * drm_panel_detach - detach a panel from a connector
- * @panel: DRM panel
- *
- * Detaches a panel from the connector it is attached to. If a panel is not
- * attached to any connector this is effectively a no-op.
- *
- * This function should not be called by the panel device itself. It
- * is only for the drm device that called drm_panel_attach().
- */
-void drm_panel_detach(struct drm_panel *panel)
-{
-}
-EXPORT_SYMBOL(drm_panel_detach);
-
 /**
  * drm_panel_prepare - power on a panel
  * @panel: DRM panel
index 3bf7397..6e74e67 100644 (file)
@@ -297,7 +297,7 @@ void drm_syncobj_add_point(struct drm_syncobj *syncobj,
        prev = drm_syncobj_fence_get(syncobj);
        /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */
        if (prev && prev->seqno >= point)
-               DRM_ERROR("You are adding an unorder point to timeline!\n");
+               DRM_DEBUG("You are adding an unorder point to timeline!\n");
        dma_fence_chain_init(chain, prev, fence, point);
        rcu_assign_pointer(syncobj->fence, &chain->base);
 
index 7ba5354..741323a 100644 (file)
@@ -42,11 +42,6 @@ static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
 static enum drm_connector_status
 exynos_dpi_detect(struct drm_connector *connector, bool force)
 {
-       struct exynos_dpi *ctx = connector_to_dpi(connector);
-
-       if (ctx->panel)
-               drm_panel_attach(ctx->panel, &ctx->connector);
-
        return connector_status_connected;
 }
 
@@ -249,8 +244,5 @@ int exynos_dpi_remove(struct drm_encoder *encoder)
 
        exynos_dpi_disable(&ctx->encoder);
 
-       if (ctx->panel)
-               drm_panel_detach(ctx->panel);
-
        return 0;
 }
index ee96a95..db0eab5 100644 (file)
@@ -1551,12 +1551,10 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
                }
 
                dsi->panel = of_drm_find_panel(device->dev.of_node);
-               if (IS_ERR(dsi->panel)) {
+               if (IS_ERR(dsi->panel))
                        dsi->panel = NULL;
-               } else {
-                       drm_panel_attach(dsi->panel, &dsi->connector);
+               else
                        dsi->connector.status = connector_status_connected;
-               }
        }
 
        /*
@@ -1596,7 +1594,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
        if (dsi->panel) {
                mutex_lock(&drm->mode_config.mutex);
                exynos_dsi_disable(&dsi->encoder);
-               drm_panel_detach(dsi->panel);
                dsi->panel = NULL;
                dsi->connector.status = connector_status_disconnected;
                mutex_unlock(&drm->mode_config.mutex);
index 9b0c473..4d4a715 100644 (file)
@@ -40,10 +40,7 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
 
 static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector)
 {
-       struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector);
-
        drm_connector_unregister(connector);
-       drm_panel_detach(fsl_con->panel);
        drm_connector_cleanup(connector);
 }
 
@@ -101,12 +98,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev,
        if (ret < 0)
                goto err_sysfs;
 
-       ret = drm_panel_attach(panel, connector);
-       if (ret) {
-               dev_err(fsl_dev->dev, "failed to attach panel\n");
-               goto err_sysfs;
-       }
-
        return 0;
 
 err_sysfs:
index f350ac1..2f3486f 100644 (file)
@@ -366,7 +366,7 @@ static enum drm_mode_status mdfld_dsi_connector_mode_valid(struct drm_connector
        /**
         * FIXME: current DC has no fitting unit, reject any mode setting
         * request
-        * Will figure out a way to do up-scaling(pannel fitting) later.
+        * Will figure out a way to do up-scaling(panel fitting) later.
         **/
        if (fixed_mode) {
                if (mode->hdisplay != fixed_mode->hdisplay)
@@ -531,7 +531,7 @@ void mdfld_dsi_output_init(struct drm_device *dev,
        dsi_config->connector = dsi_connector;
 
        if (!dsi_config->fixed_mode) {
-               DRM_ERROR("No pannel fixed mode was found\n");
+               DRM_ERROR("No panel fixed mode was found\n");
                goto dsi_init_err0;
        }
 
index 06e44f4..907f966 100644 (file)
@@ -125,7 +125,7 @@ struct psb_intel_sdvo {
        bool is_lvds;
 
        /**
-        * This is sdvo fixed pannel mode pointer
+        * This is sdvo fixed panel mode pointer
         */
        struct drm_display_mode *sdvo_lvds_fixed_mode;
 
index cc70e83..d9062a3 100644 (file)
@@ -17,9 +17,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_gem_vram_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
 #include "hibmc_drm_drv.h"
@@ -160,37 +157,6 @@ static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
        .atomic_update = hibmc_plane_atomic_update,
 };
 
-static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
-{
-       struct drm_device *dev = priv->dev;
-       struct drm_plane *plane;
-       int ret = 0;
-
-       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
-       if (!plane) {
-               DRM_ERROR("failed to alloc memory when init plane\n");
-               return ERR_PTR(-ENOMEM);
-       }
-       /*
-        * plane init
-        * TODO: Now only support primary plane, overlay planes
-        * need to do.
-        */
-       ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
-                                      channel_formats1,
-                                      ARRAY_SIZE(channel_formats1),
-                                      NULL,
-                                      DRM_PLANE_TYPE_PRIMARY,
-                                      NULL);
-       if (ret) {
-               DRM_ERROR("failed to init plane: %d\n", ret);
-               return ERR_PTR(ret);
-       }
-
-       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
-       return plane;
-}
-
 static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms)
 {
        struct hibmc_drm_private *priv = crtc->dev->dev_private;
@@ -537,22 +503,24 @@ static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
 int hibmc_de_init(struct hibmc_drm_private *priv)
 {
        struct drm_device *dev = priv->dev;
-       struct drm_crtc *crtc;
-       struct drm_plane *plane;
+       struct drm_crtc *crtc = &priv->crtc;
+       struct drm_plane *plane = &priv->primary_plane;
        int ret;
 
-       plane = hibmc_plane_init(priv);
-       if (IS_ERR(plane)) {
-               DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
-               return PTR_ERR(plane);
-       }
+       ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
+                                      channel_formats1,
+                                      ARRAY_SIZE(channel_formats1),
+                                      NULL,
+                                      DRM_PLANE_TYPE_PRIMARY,
+                                      NULL);
 
-       crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
-       if (!crtc) {
-               DRM_ERROR("failed to alloc memory when init crtc\n");
-               return -ENOMEM;
+       if (ret) {
+               DRM_ERROR("failed to init plane: %d\n", ret);
+               return ret;
        }
 
+       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+
        ret = drm_crtc_init_with_planes(dev, crtc, plane,
                                        NULL, &hibmc_crtc_funcs, NULL);
        if (ret) {
index eea13e6..1ae360d 100644 (file)
  *     Jianhua Li <lijianhua@huawei.com>
  */
 
-#include <linux/console.h>
-#include <linux/module.h>
 #include <linux/pci.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_vram_helper.h>
 #include <drm/drm_irq.h>
 #include <drm/drm_managed.h>
-#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
 #include "hibmc_drm_drv.h"
@@ -254,9 +249,8 @@ static int hibmc_unload(struct drm_device *dev)
 
        if (dev->irq_enabled)
                drm_irq_uninstall(dev);
-       if (priv->msi_enabled)
-               pci_disable_msi(dev->pdev);
 
+       pci_disable_msi(dev->pdev);
        hibmc_kms_fini(priv);
        hibmc_mm_fini(priv);
        dev->dev_private = NULL;
@@ -294,12 +288,10 @@ static int hibmc_load(struct drm_device *dev)
                goto err;
        }
 
-       priv->msi_enabled = 0;
        ret = pci_enable_msi(dev->pdev);
        if (ret) {
                DRM_WARN("enabling MSI failed: %d\n", ret);
        } else {
-               priv->msi_enabled = 1;
                ret = drm_irq_install(dev, dev->pdev->irq);
                if (ret)
                        DRM_WARN("install irq failed: %d\n", ret);
index 6097687..197485e 100644 (file)
@@ -25,10 +25,11 @@ struct hibmc_drm_private {
        void __iomem   *fb_map;
        unsigned long  fb_base;
        unsigned long  fb_size;
-       bool msi_enabled;
 
        /* drm */
        struct drm_device  *dev;
+       struct drm_plane primary_plane;
+       struct drm_crtc crtc;
        struct drm_encoder encoder;
        struct drm_connector connector;
        bool mode_config_initialized;
index 2ca69c3..ed12f61 100644 (file)
  *     Jianhua Li <lijianhua@huawei.com>
  */
 
-#include <drm/drm_gem_vram_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_crtc_helper.h>
 #include <drm/drm_print.h>
 
 #include "hibmc_drm_drv.h"
index d6295eb..79c27f9 100644 (file)
@@ -6243,6 +6243,11 @@ out:
         */
        intel_display_power_flush_work(dev_priv);
 
+       if (!intel_dp_is_edp(intel_dp))
+               drm_dp_set_subconnector_property(connector,
+                                                status,
+                                                intel_dp->dpcd,
+                                                intel_dp->downstream_ports);
        return status;
 }
 
@@ -7312,6 +7317,9 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
        enum port port = dp_to_dig_port(intel_dp)->base.port;
 
+       if (!intel_dp_is_edp(intel_dp))
+               drm_connector_attach_dp_subconnector_property(connector);
+
        if (!IS_G4X(dev_priv) && port != PORT_A)
                intel_attach_force_audio_property(connector);
 
index 8791d60..af757d1 100644 (file)
@@ -455,13 +455,6 @@ static int imx_ldb_register(struct drm_device *drm,
                drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
        }
 
-       if (imx_ldb_ch->panel) {
-               ret = drm_panel_attach(imx_ldb_ch->panel,
-                                      &imx_ldb_ch->connector);
-               if (ret)
-                       return ret;
-       }
-
        return 0;
 }
 
@@ -702,9 +695,6 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
        for (i = 0; i < 2; i++) {
                struct imx_ldb_channel *channel = &imx_ldb->channel[i];
 
-               if (channel->panel)
-                       drm_panel_detach(channel->panel);
-
                kfree(channel->edid);
                i2c_put_adapter(channel->ddc);
        }
index a831b5b..8232f51 100644 (file)
@@ -289,9 +289,6 @@ static int imx_pd_register(struct drm_device *drm,
                                   DRM_MODE_CONNECTOR_DPI);
        }
 
-       if (imxpd->panel)
-               drm_panel_attach(imxpd->panel, &imxpd->connector);
-
        if (imxpd->next_bridge) {
                ret = drm_bridge_attach(encoder, imxpd->next_bridge,
                                        &imxpd->bridge, 0);
@@ -357,9 +354,6 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
 {
        struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
 
-       if (imxpd->panel)
-               drm_panel_detach(imxpd->panel);
-
        kfree(imxpd->edid);
 }
 
index ada990a..5dab9c3 100644 (file)
@@ -199,26 +199,20 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
 {
        struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
        struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL;
-       long rate;
-
-       if (!drm_atomic_crtc_needs_modeset(state))
-               return 0;
-
-       if (state->mode.hdisplay > priv->soc_info->max_width ||
-           state->mode.vdisplay > priv->soc_info->max_height)
-               return -EINVAL;
 
-       rate = clk_round_rate(priv->pix_clk,
-                             state->adjusted_mode.clock * 1000);
-       if (rate < 0)
-               return rate;
-
-       if (priv->soc_info->has_osd) {
+       if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) {
                f1_state = drm_atomic_get_plane_state(state->state, &priv->f1);
+               if (IS_ERR(f1_state))
+                       return PTR_ERR(f1_state);
+
                f0_state = drm_atomic_get_plane_state(state->state, &priv->f0);
+               if (IS_ERR(f0_state))
+                       return PTR_ERR(f0_state);
 
                if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) {
                        ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane);
+                       if (IS_ERR(ipu_state))
+                               return PTR_ERR(ipu_state);
 
                        /* IPU and F1 planes cannot be enabled at the same time. */
                        if (f1_state->fb && ipu_state->fb) {
@@ -235,6 +229,24 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
        return 0;
 }
 
+static enum drm_mode_status
+ingenic_drm_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
+{
+       struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
+       long rate;
+
+       if (mode->hdisplay > priv->soc_info->max_width)
+               return MODE_BAD_HVALUE;
+       if (mode->vdisplay > priv->soc_info->max_height)
+               return MODE_BAD_VVALUE;
+
+       rate = clk_round_rate(priv->pix_clk, mode->clock * 1000);
+       if (rate < 0)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
 static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc,
                                          struct drm_crtc_state *oldstate)
 {
@@ -648,6 +660,7 @@ static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs = {
        .atomic_begin           = ingenic_drm_crtc_atomic_begin,
        .atomic_flush           = ingenic_drm_crtc_atomic_flush,
        .atomic_check           = ingenic_drm_crtc_atomic_check,
+       .mode_valid             = ingenic_drm_crtc_mode_valid,
 };
 
 static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = {
index 7a0a8bd..fc8c6e9 100644 (file)
@@ -35,6 +35,7 @@ struct soc_info {
        const u32 *formats;
        size_t num_formats;
        bool has_bicubic;
+       bool manual_restart;
 
        void (*set_coefs)(struct ingenic_ipu *ipu, unsigned int reg,
                          unsigned int sharpness, bool downscale,
@@ -48,6 +49,7 @@ struct ingenic_ipu {
        struct regmap *map;
        struct clk *clk;
        const struct soc_info *soc_info;
+       bool clk_enabled;
 
        unsigned int num_w, num_h, denom_w, denom_h;
 
@@ -287,12 +289,23 @@ static void ingenic_ipu_plane_atomic_update(struct drm_plane *plane,
        const struct drm_format_info *finfo;
        u32 ctrl, stride = 0, coef_index = 0, format = 0;
        bool needs_modeset, upscaling_w, upscaling_h;
+       int err;
 
        if (!state || !state->fb)
                return;
 
        finfo = drm_format_info(state->fb->format->format);
 
+       if (!ipu->clk_enabled) {
+               err = clk_enable(ipu->clk);
+               if (err) {
+                       dev_err(ipu->dev, "Unable to enable clock: %d\n", err);
+                       return;
+               }
+
+               ipu->clk_enabled = true;
+       }
+
        /* Reset all the registers if needed */
        needs_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state);
        if (needs_modeset) {
@@ -577,6 +590,11 @@ static void ingenic_ipu_plane_atomic_disable(struct drm_plane *plane,
        regmap_clear_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CHIP_EN);
 
        ingenic_drm_plane_disable(ipu->master, plane);
+
+       if (ipu->clk_enabled) {
+               clk_disable(ipu->clk);
+               ipu->clk_enabled = false;
+       }
 }
 
 static const struct drm_plane_helper_funcs ingenic_ipu_plane_helper_funcs = {
@@ -645,7 +663,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg)
        unsigned int dummy;
 
        /* dummy read allows CPU to reconfigure IPU */
-       regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy);
+       if (ipu->soc_info->manual_restart)
+               regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy);
 
        /* ACK interrupt */
        regmap_write(ipu->map, JZ_REG_IPU_STATUS, 0);
@@ -656,7 +675,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg)
        regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v);
 
        /* Run IPU for the new frame */
-       regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN);
+       if (ipu->soc_info->manual_restart)
+               regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN);
 
        drm_crtc_handle_vblank(crtc);
 
@@ -758,9 +778,9 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d)
        drm_object_attach_property(&plane->base, ipu->sharpness_prop,
                                   ipu->sharpness);
 
-       err = clk_prepare_enable(ipu->clk);
+       err = clk_prepare(ipu->clk);
        if (err) {
-               dev_err(dev, "Unable to enable clock\n");
+               dev_err(dev, "Unable to prepare clock\n");
                return err;
        }
 
@@ -772,7 +792,7 @@ static void ingenic_ipu_unbind(struct device *dev,
 {
        struct ingenic_ipu *ipu = dev_get_drvdata(dev);
 
-       clk_disable_unprepare(ipu->clk);
+       clk_unprepare(ipu->clk);
 }
 
 static const struct component_ops ingenic_ipu_ops = {
@@ -792,10 +812,16 @@ static int ingenic_ipu_remove(struct platform_device *pdev)
 }
 
 static const u32 jz4725b_ipu_formats[] = {
+       /*
+        * While officially supported, packed YUV 4:2:2 formats can cause
+        * random hardware crashes on JZ4725B under certain circumstances.
+        * It seems to happen with some specific resize ratios.
+        * Until a proper workaround or fix is found, disable these formats.
        DRM_FORMAT_YUYV,
        DRM_FORMAT_YVYU,
        DRM_FORMAT_UYVY,
        DRM_FORMAT_VYUY,
+       */
        DRM_FORMAT_YUV411,
        DRM_FORMAT_YUV420,
        DRM_FORMAT_YUV422,
@@ -806,6 +832,7 @@ static const struct soc_info jz4725b_soc_info = {
        .formats        = jz4725b_ipu_formats,
        .num_formats    = ARRAY_SIZE(jz4725b_ipu_formats),
        .has_bicubic    = false,
+       .manual_restart = true,
        .set_coefs      = jz4725b_set_coefs,
 };
 
@@ -831,6 +858,7 @@ static const struct soc_info jz4760_soc_info = {
        .formats        = jz4760_ipu_formats,
        .num_formats    = ARRAY_SIZE(jz4760_ipu_formats),
        .has_bicubic    = true,
+       .manual_restart = false,
        .set_coefs      = jz4760_set_coefs,
 };
 
index 93be766..eec5965 100644 (file)
@@ -1,13 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config DRM_MGAG200
-       tristate "Kernel modesetting driver for MGA G200 server engines"
+       tristate "Matrox G200"
        depends on DRM && PCI && MMU
        select DRM_GEM_SHMEM_HELPER
        select DRM_KMS_HELPER
        help
-        This is a KMS driver for the MGA G200 server chips, it
-        does not support the original MGA G200 or any of the desktop
-        chips. It requires 0.3.0 of the modesetting userspace driver,
-        and a version of mga driver that will fail on KMS enabled
-        devices.
-
+        This is a KMS driver for Matrox G200 chips. It supports the original
+        MGA G200 desktop chips and the server variants. It requires 0.3.0
+        of the modesetting userspace driver, and a version of mga driver
+        that will fail on KMS enabled devices.
index e19660f..b282b0e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/vmalloc.h>
 
 #include <drm/drm_drv.h>
 #include <drm/drm_file.h>
@@ -36,6 +37,7 @@ static struct drm_driver mgag200_driver = {
        .major = DRIVER_MAJOR,
        .minor = DRIVER_MINOR,
        .patchlevel = DRIVER_PATCHLEVEL,
+       .gem_create_object = drm_gem_shmem_create_object_cached,
        DRM_GEM_SHMEM_DRIVER_OPS,
 };
 
@@ -43,18 +45,66 @@ static struct drm_driver mgag200_driver = {
  * DRM device
  */
 
-static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
+static bool mgag200_has_sgram(struct mga_device *mdev)
 {
        struct drm_device *dev = &mdev->base;
-       int ret, option;
+       u32 option;
+       int ret;
 
-       mdev->flags = mgag200_flags_from_driver_data(flags);
-       mdev->type = mgag200_type_from_driver_data(flags);
+       ret = pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
+       if (drm_WARN(dev, ret, "failed to read PCI config dword: %d\n", ret))
+               return false;
 
-       pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
-       mdev->has_sdram = !(option & (1 << 14));
+       return !!(option & PCI_MGA_OPTION_HARDPWMSK);
+}
 
-       /* BAR 0 is the framebuffer, BAR 1 contains registers */
+static int mgag200_regs_init(struct mga_device *mdev)
+{
+       struct drm_device *dev = &mdev->base;
+       u32 option, option2;
+       u8 crtcext3;
+
+       switch (mdev->type) {
+       case G200_PCI:
+       case G200_AGP:
+               if (mgag200_has_sgram(mdev))
+                       option = 0x4049cd21;
+               else
+                       option = 0x40499121;
+               option2 = 0x00008000;
+               break;
+       case G200_SE_A:
+       case G200_SE_B:
+               option = 0x40049120;
+               if (mgag200_has_sgram(mdev))
+                       option |= PCI_MGA_OPTION_HARDPWMSK;
+               option2 = 0x00008000;
+               break;
+       case G200_WB:
+       case G200_EW3:
+               option = 0x41049120;
+               option2 = 0x0000b000;
+               break;
+       case G200_EV:
+               option = 0x00000120;
+               option2 = 0x0000b000;
+               break;
+       case G200_EH:
+       case G200_EH3:
+               option = 0x00000120;
+               option2 = 0x0000b000;
+               break;
+       default:
+               option = 0;
+               option2 = 0;
+       }
+
+       if (option)
+               pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
+       if (option2)
+               pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
+
+       /* BAR 1 contains registers */
        mdev->rmmio_base = pci_resource_start(dev->pdev, 1);
        mdev->rmmio_size = pci_resource_len(dev->pdev, 1);
 
@@ -68,12 +118,163 @@ static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
        if (mdev->rmmio == NULL)
                return -ENOMEM;
 
-       /* stash G200 SE model number for later use */
-       if (IS_G200_SE(mdev)) {
-               mdev->unique_rev_id = RREG32(0x1e24);
-               drm_dbg(dev, "G200 SE unique revision id is 0x%x\n",
-                       mdev->unique_rev_id);
+       RREG_ECRT(0x03, crtcext3);
+       crtcext3 |= MGAREG_CRTCEXT3_MGAMODE;
+       WREG_ECRT(0x03, crtcext3);
+
+       return 0;
+}
+
+static void mgag200_g200_interpret_bios(struct mga_device *mdev,
+                                       const unsigned char *bios,
+                                       size_t size)
+{
+       static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'};
+       static const unsigned int expected_length[6] = {
+               0, 64, 64, 64, 128, 128
+       };
+       struct drm_device *dev = &mdev->base;
+       const unsigned char *pins;
+       unsigned int pins_len, version;
+       int offset;
+       int tmp;
+
+       /* Test for MATROX string. */
+       if (size < 45 + sizeof(matrox))
+               return;
+       if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0)
+               return;
+
+       /* Get the PInS offset. */
+       if (size < MGA_BIOS_OFFSET + 2)
+               return;
+       offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET];
+
+       /* Get PInS data structure. */
+
+       if (size < offset + 6)
+               return;
+       pins = bios + offset;
+       if (pins[0] == 0x2e && pins[1] == 0x41) {
+               version = pins[5];
+               pins_len = pins[2];
+       } else {
+               version = 1;
+               pins_len = pins[0] + (pins[1] << 8);
+       }
+
+       if (version < 1 || version > 5) {
+               drm_warn(dev, "Unknown BIOS PInS version: %d\n", version);
+               return;
+       }
+       if (pins_len != expected_length[version]) {
+               drm_warn(dev, "Unexpected BIOS PInS size: %d expeced: %d\n",
+                        pins_len, expected_length[version]);
+               return;
        }
+       if (size < offset + pins_len)
+               return;
+
+       drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n",
+                   version, pins_len);
+
+       /* Extract the clock values */
+
+       switch (version) {
+       case 1:
+               tmp = pins[24] + (pins[25] << 8);
+               if (tmp)
+                       mdev->model.g200.pclk_max = tmp * 10;
+               break;
+       case 2:
+               if (pins[41] != 0xff)
+                       mdev->model.g200.pclk_max = (pins[41] + 100) * 1000;
+               break;
+       case 3:
+               if (pins[36] != 0xff)
+                       mdev->model.g200.pclk_max = (pins[36] + 100) * 1000;
+               if (pins[52] & 0x20)
+                       mdev->model.g200.ref_clk = 14318;
+               break;
+       case 4:
+               if (pins[39] != 0xff)
+                       mdev->model.g200.pclk_max = pins[39] * 4 * 1000;
+               if (pins[92] & 0x01)
+                       mdev->model.g200.ref_clk = 14318;
+               break;
+       case 5:
+               tmp = pins[4] ? 8000 : 6000;
+               if (pins[123] != 0xff)
+                       mdev->model.g200.pclk_min = pins[123] * tmp;
+               if (pins[38] != 0xff)
+                       mdev->model.g200.pclk_max = pins[38] * tmp;
+               if (pins[110] & 0x01)
+                       mdev->model.g200.ref_clk = 14318;
+               break;
+       default:
+               break;
+       }
+}
+
+static void mgag200_g200_init_refclk(struct mga_device *mdev)
+{
+       struct drm_device *dev = &mdev->base;
+       unsigned char __iomem *rom;
+       unsigned char *bios;
+       size_t size;
+
+       mdev->model.g200.pclk_min = 50000;
+       mdev->model.g200.pclk_max = 230000;
+       mdev->model.g200.ref_clk = 27050;
+
+       rom = pci_map_rom(dev->pdev, &size);
+       if (!rom)
+               return;
+
+       bios = vmalloc(size);
+       if (!bios)
+               goto out;
+       memcpy_fromio(bios, rom, size);
+
+       if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa)
+               mgag200_g200_interpret_bios(mdev, bios, size);
+
+       drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n",
+                   mdev->model.g200.pclk_min, mdev->model.g200.pclk_max,
+                   mdev->model.g200.ref_clk);
+
+       vfree(bios);
+out:
+       pci_unmap_rom(dev->pdev, rom);
+}
+
+static void mgag200_g200se_init_unique_id(struct mga_device *mdev)
+{
+       struct drm_device *dev = &mdev->base;
+
+       /* stash G200 SE model number for later use */
+       mdev->model.g200se.unique_rev_id = RREG32(0x1e24);
+
+       drm_dbg(dev, "G200 SE unique revision id is 0x%x\n",
+               mdev->model.g200se.unique_rev_id);
+}
+
+static int mgag200_device_init(struct mga_device *mdev, unsigned long flags)
+{
+       struct drm_device *dev = &mdev->base;
+       int ret;
+
+       mdev->flags = mgag200_flags_from_driver_data(flags);
+       mdev->type = mgag200_type_from_driver_data(flags);
+
+       ret = mgag200_regs_init(mdev);
+       if (ret)
+               return ret;
+
+       if (mdev->type == G200_PCI || mdev->type == G200_AGP)
+               mgag200_g200_init_refclk(mdev);
+       else if (IS_G200_SE(mdev))
+               mgag200_g200se_init_unique_id(mdev);
 
        ret = mgag200_mm_init(mdev);
        if (ret)
@@ -116,6 +317,8 @@ mgag200_device_create(struct pci_dev *pdev, unsigned long flags)
  */
 
 static const struct pci_device_id mgag200_pciidlist[] = {
+       { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI },
+       { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP },
        { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD},
        { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
index 3817520..749a075 100644 (file)
@@ -38,6 +38,8 @@
 #define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg))
 #define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg))
 
+#define MGA_BIOS_OFFSET                0x7ffc
+
 #define ATTR_INDEX 0x1fc0
 #define ATTR_DATA 0x1fc1
 
@@ -129,6 +131,8 @@ struct mga_mc {
 };
 
 enum mga_type {
+       G200_PCI,
+       G200_AGP,
        G200_SE_A,
        G200_SE_B,
        G200_WB,
@@ -161,14 +165,23 @@ struct mga_device {
        size_t                          vram_fb_available;
 
        enum mga_type                   type;
-       int                             has_sdram;
 
        int bpp_shifts[4];
 
        int fb_mtrr;
 
-       /* SE model number stored in reg 0x1e24 */
-       u32 unique_rev_id;
+       union {
+               struct {
+                       long ref_clk;
+                       long pclk_min;
+                       long pclk_max;
+               } g200;
+               struct {
+                       /* SE model number stored in reg 0x1e24 */
+                       u32 unique_rev_id;
+               } g200se;
+       } model;
+
 
        struct mga_connector connector;
        struct drm_simple_display_pipe display_pipe;
index 7b69392..641f1aa 100644 (file)
@@ -90,9 +90,17 @@ static void mgag200_mm_release(struct drm_device *dev, void *ptr)
 int mgag200_mm_init(struct mga_device *mdev)
 {
        struct drm_device *dev = &mdev->base;
+       u8 misc;
        resource_size_t start, len;
        int ret;
 
+       WREG_ECRT(0x04, 0x00);
+
+       misc = RREG8(MGA_MISC_IN);
+       misc |= MGAREG_MISC_RAMMAPEN |
+               MGAREG_MISC_HIGH_PG_SEL;
+       WREG8(MGA_MISC_OUT, misc);
+
        /* BAR 0 is VRAM */
        start = pci_resource_start(dev->pdev, 0);
        len = pci_resource_len(dev->pdev, 0);
index e0d037a..38672f9 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/pci.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_state_helper.h>
@@ -109,10 +108,82 @@ static inline void mga_wait_busy(struct mga_device *mdev)
        } while ((status & 0x01) && time_before(jiffies, timeout));
 }
 
+/*
+ * PLL setup
+ */
+
+static int mgag200_g200_set_plls(struct mga_device *mdev, long clock)
+{
+       struct drm_device *dev = &mdev->base;
+       const int post_div_max = 7;
+       const int in_div_min = 1;
+       const int in_div_max = 6;
+       const int feed_div_min = 7;
+       const int feed_div_max = 127;
+       u8 testm, testn;
+       u8 n = 0, m = 0, p, s;
+       long f_vco;
+       long computed;
+       long delta, tmp_delta;
+       long ref_clk = mdev->model.g200.ref_clk;
+       long p_clk_min = mdev->model.g200.pclk_min;
+       long p_clk_max =  mdev->model.g200.pclk_max;
+
+       if (clock > p_clk_max) {
+               drm_err(dev, "Pixel Clock %ld too high\n", clock);
+               return 1;
+       }
+
+       if (clock < p_clk_min >> 3)
+               clock = p_clk_min >> 3;
+
+       f_vco = clock;
+       for (p = 0;
+            p <= post_div_max && f_vco < p_clk_min;
+            p = (p << 1) + 1, f_vco <<= 1)
+               ;
+
+       delta = clock;
+
+       for (testm = in_div_min; testm <= in_div_max; testm++) {
+               for (testn = feed_div_min; testn <= feed_div_max; testn++) {
+                       computed = ref_clk * (testn + 1) / (testm + 1);
+                       if (computed < f_vco)
+                               tmp_delta = f_vco - computed;
+                       else
+                               tmp_delta = computed - f_vco;
+                       if (tmp_delta < delta) {
+                               delta = tmp_delta;
+                               m = testm;
+                               n = testn;
+                       }
+               }
+       }
+       f_vco = ref_clk * (n + 1) / (m + 1);
+       if (f_vco < 100000)
+               s = 0;
+       else if (f_vco < 140000)
+               s = 1;
+       else if (f_vco < 180000)
+               s = 2;
+       else
+               s = 3;
+
+       drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
+                   clock, f_vco, m, n, p, s);
+
+       WREG_DAC(MGA1064_PIX_PLLC_M, m);
+       WREG_DAC(MGA1064_PIX_PLLC_N, n);
+       WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3)));
+
+       return 0;
+}
+
 #define P_ARRAY_SIZE 9
 
 static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
 {
+       u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
        unsigned int vcomax, vcomin, pllreffreq;
        unsigned int delta, tmpdelta, permitteddelta;
        unsigned int testp, testm, testn;
@@ -122,7 +193,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
        unsigned int fvv;
        unsigned int i;
 
-       if (mdev->unique_rev_id <= 0x03) {
+       if (unique_rev_id <= 0x03) {
 
                m = n = p = 0;
                vcomax = 320000;
@@ -220,7 +291,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
        WREG_DAC(MGA1064_PIX_PLLC_N, n);
        WREG_DAC(MGA1064_PIX_PLLC_P, p);
 
-       if (mdev->unique_rev_id >= 0x04) {
+       if (unique_rev_id >= 0x04) {
                WREG_DAC(0x1a, 0x09);
                msleep(20);
                WREG_DAC(0x1a, 0x01);
@@ -717,6 +788,9 @@ static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock)
        u8 misc;
 
        switch(mdev->type) {
+       case G200_PCI:
+       case G200_AGP:
+               return mgag200_g200_set_plls(mdev, clock);
        case G200_SE_A:
        case G200_SE_B:
                return mga_g200se_set_plls(mdev, clock);
@@ -877,45 +951,6 @@ static void mgag200_set_startadd(struct mga_device *mdev,
        WREG_ECRT(0x00, crtcext0);
 }
 
-static void mgag200_set_pci_regs(struct mga_device *mdev)
-{
-       uint32_t option = 0, option2 = 0;
-       struct drm_device *dev = &mdev->base;
-
-       switch (mdev->type) {
-       case G200_SE_A:
-       case G200_SE_B:
-               if (mdev->has_sdram)
-                       option = 0x40049120;
-               else
-                       option = 0x4004d120;
-               option2 = 0x00008000;
-               break;
-       case G200_WB:
-       case G200_EW3:
-               option = 0x41049120;
-               option2 = 0x0000b000;
-               break;
-       case G200_EV:
-               option = 0x00000120;
-               option2 = 0x0000b000;
-               break;
-       case G200_EH:
-       case G200_EH3:
-               option = 0x00000120;
-               option2 = 0x0000b000;
-               break;
-       case G200_ER:
-               break;
-       }
-
-       if (option)
-               pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
-
-       if (option2)
-               pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
-}
-
 static void mgag200_set_dac_regs(struct mga_device *mdev)
 {
        size_t i;
@@ -933,6 +968,12 @@ static void mgag200_set_dac_regs(struct mga_device *mdev)
        };
 
        switch (mdev->type) {
+       case G200_PCI:
+       case G200_AGP:
+               dacvalue[MGA1064_SYS_PLL_M] = 0x04;
+               dacvalue[MGA1064_SYS_PLL_N] = 0x2D;
+               dacvalue[MGA1064_SYS_PLL_P] = 0x19;
+               break;
        case G200_SE_A:
        case G200_SE_B:
                dacvalue[MGA1064_VREF_CTL] = 0x03;
@@ -986,9 +1027,8 @@ static void mgag200_set_dac_regs(struct mga_device *mdev)
 
 static void mgag200_init_regs(struct mga_device *mdev)
 {
-       u8 crtc11, crtcext3, crtcext4, misc;
+       u8 crtc11, misc;
 
-       mgag200_set_pci_regs(mdev);
        mgag200_set_dac_regs(mdev);
 
        WREG_SEQ(2, 0x0f);
@@ -1002,14 +1042,6 @@ static void mgag200_init_regs(struct mga_device *mdev)
        WREG_CRT(14, 0);
        WREG_CRT(15, 0);
 
-       RREG_ECRT(0x03, crtcext3);
-
-       crtcext3 |= BIT(7); /* enable MGA mode */
-       crtcext4 = 0x00;
-
-       WREG_ECRT(0x03, crtcext3);
-       WREG_ECRT(0x04, crtcext4);
-
        RREG_CRT(0x11, crtc11);
        crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT |
                    MGAREG_CRTC11_VINTEN |
@@ -1023,9 +1055,7 @@ static void mgag200_init_regs(struct mga_device *mdev)
                WREG_ECRT(0x34, 0x5);
 
        misc = RREG8(MGA_MISC_IN);
-       misc |= MGAREG_MISC_IOADSEL |
-               MGAREG_MISC_RAMMAPEN |
-               MGAREG_MISC_HIGH_PG_SEL;
+       misc |= MGAREG_MISC_IOADSEL;
        WREG8(MGA_MISC_OUT, misc);
 }
 
@@ -1234,12 +1264,13 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
                                        const struct drm_display_mode *mode,
                                        const struct drm_framebuffer *fb)
 {
+       u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
        unsigned int hiprilvl;
        u8 crtcext6;
 
-       if  (mdev->unique_rev_id >= 0x04) {
+       if  (unique_rev_id >= 0x04) {
                hiprilvl = 0;
-       } else if (mdev->unique_rev_id >= 0x02) {
+       } else if (unique_rev_id >= 0x02) {
                unsigned int bpp;
                unsigned long mb;
 
@@ -1264,7 +1295,7 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
                else
                        hiprilvl = 5;
 
-       } else if (mdev->unique_rev_id >= 0x01) {
+       } else if (unique_rev_id >= 0x01) {
                hiprilvl = 3;
        } else {
                hiprilvl = 4;
@@ -1388,7 +1419,9 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
        int bpp = 32;
 
        if (IS_G200_SE(mdev)) {
-               if (mdev->unique_rev_id == 0x01) {
+               u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
+
+               if (unique_rev_id == 0x01) {
                        if (mode->hdisplay > 1600)
                                return MODE_VIRTUAL_X;
                        if (mode->vdisplay > 1200)
@@ -1396,7 +1429,7 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
                        if (mga_vga_calculate_mode_bandwidth(mode, bpp)
                                > (24400 * 1024))
                                return MODE_BANDWIDTH;
-               } else if (mdev->unique_rev_id == 0x02) {
+               } else if (unique_rev_id == 0x02) {
                        if (mode->hdisplay > 1920)
                                return MODE_VIRTUAL_X;
                        if (mode->vdisplay > 1200)
index c3b7bca..977be05 100644 (file)
 #define MGAREG_CRTCEXT1_VSYNCOFF       BIT(5)
 #define MGAREG_CRTCEXT1_HSYNCOFF       BIT(4)
 
+#define MGAREG_CRTCEXT3_MGAMODE                BIT(7)
+
 /* Cursor X and Y position */
 #define MGA_CURPOSXL 0x3c0c
 #define MGA_CURPOSXH 0x3c0d
 #define PCI_MGA_OPTION2                0x50
 #define PCI_MGA_OPTION3                0x54
 
+#define PCI_MGA_OPTION_HARDPWMSK       BIT(14)
+
 #define RAMDAC_OFFSET          0x3c00
 
 /* TVP3026 direct registers */
index c7df71e..7288041 100644 (file)
@@ -50,14 +50,9 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
        struct drm_panel *panel = mdp4_lvds_connector->panel;
        int ret = 0;
 
-       if (panel) {
-               drm_panel_attach(panel, connector);
-
+       if (panel)
                ret = drm_panel_get_modes(panel, connector);
 
-               drm_panel_detach(panel);
-       }
-
        return ret;
 }
 
index 4b363bd..1d28dfb 100644 (file)
@@ -328,7 +328,6 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
         * In dual DSI mode, we have one connector that can be
         * attached to the drm_panel.
         */
-       drm_panel_attach(panel, connector);
        num = drm_panel_get_modes(panel, connector);
        if (!num)
                return 0;
index 0dca8f2..0143d53 100644 (file)
@@ -5,7 +5,7 @@ config DRM_MXS
          Choose this option to select drivers for MXS FB devices
 
 config DRM_MXSFB
-       tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller"
+       tristate "i.MX (e)LCDIF LCD controller"
        depends on DRM && OF
        depends on COMMON_CLK
        select DRM_MXS
@@ -13,8 +13,10 @@ config DRM_MXSFB
        select DRM_KMS_FB_HELPER
        select DRM_KMS_CMA_HELPER
        select DRM_PANEL
+       select DRM_PANEL_BRIDGE
        help
-         Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB
-         LCD controller.
+         Choose this option if you have an LCDIF or eLCDIF LCD controller.
+         Those devices are found in various i.MX SoC (including i.MX23,
+         i.MX28, i.MX6SX, i.MX7 and i.MX8M).
 
          If M is selected the module will be called mxsfb.
index ff6e358..26d1538 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
-mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o
+mxsfb-y := mxsfb_drv.o mxsfb_kms.o
 obj-$(CONFIG_DRM_MXSFB)        += mxsfb.o
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
deleted file mode 100644 (file)
index b69ace8..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- *
- * This code is based on drivers/video/fbdev/mxsfb.c :
- * Copyright (C) 2010 Juergen Beisert, Pengutronix
- * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/iopoll.h>
-#include <linux/of_graph.h>
-#include <linux/platform_data/simplefb.h>
-
-#include <video/videomode.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-#include <drm/drm_vblank.h>
-
-#include "mxsfb_drv.h"
-#include "mxsfb_regs.h"
-
-#define MXS_SET_ADDR           0x4
-#define MXS_CLR_ADDR           0x8
-#define MODULE_CLKGATE         BIT(30)
-#define MODULE_SFTRST          BIT(31)
-/* 1 second delay should be plenty of time for block reset */
-#define RESET_TIMEOUT          1000000
-
-static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
-{
-       return (val & mxsfb->devdata->hs_wdth_mask) <<
-               mxsfb->devdata->hs_wdth_shift;
-}
-
-/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
-static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
-{
-       struct drm_crtc *crtc = &mxsfb->pipe.crtc;
-       struct drm_device *drm = crtc->dev;
-       const u32 format = crtc->primary->state->fb->format->format;
-       u32 ctrl, ctrl1;
-
-       ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
-
-       /*
-        * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
-        * match the selected mode here. This differs from the original
-        * MXSFB driver, which had the option to configure the bus width
-        * to arbitrary value. This limitation should not pose an issue.
-        */
-
-       /* CTRL1 contains IRQ config and status bits, preserve those. */
-       ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
-       ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
-
-       switch (format) {
-       case DRM_FORMAT_RGB565:
-               dev_dbg(drm->dev, "Setting up RGB565 mode\n");
-               ctrl |= CTRL_SET_WORD_LENGTH(0);
-               ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
-               break;
-       case DRM_FORMAT_XRGB8888:
-               dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
-               ctrl |= CTRL_SET_WORD_LENGTH(3);
-               /* Do not use packed pixels = one pixel per word instead. */
-               ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
-               break;
-       default:
-               dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
-               return -EINVAL;
-       }
-
-       writel(ctrl1, mxsfb->base + LCDC_CTRL1);
-       writel(ctrl, mxsfb->base + LCDC_CTRL);
-
-       return 0;
-}
-
-static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
-{
-       struct drm_crtc *crtc = &mxsfb->pipe.crtc;
-       struct drm_device *drm = crtc->dev;
-       u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-       u32 reg;
-
-       reg = readl(mxsfb->base + LCDC_CTRL);
-
-       if (mxsfb->connector->display_info.num_bus_formats)
-               bus_format = mxsfb->connector->display_info.bus_formats[0];
-
-       DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
-                            bus_format);
-
-       reg &= ~CTRL_BUS_WIDTH_MASK;
-       switch (bus_format) {
-       case MEDIA_BUS_FMT_RGB565_1X16:
-               reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
-               break;
-       case MEDIA_BUS_FMT_RGB666_1X18:
-               reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
-               break;
-       case MEDIA_BUS_FMT_RGB888_1X24:
-               reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
-               break;
-       default:
-               dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
-               break;
-       }
-       writel(reg, mxsfb->base + LCDC_CTRL);
-}
-
-static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
-{
-       u32 reg;
-
-       if (mxsfb->clk_disp_axi)
-               clk_prepare_enable(mxsfb->clk_disp_axi);
-       clk_prepare_enable(mxsfb->clk);
-
-       /* If it was disabled, re-enable the mode again */
-       writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
-
-       /* Enable the SYNC signals first, then the DMA engine */
-       reg = readl(mxsfb->base + LCDC_VDCTRL4);
-       reg |= VDCTRL4_SYNC_SIGNALS_ON;
-       writel(reg, mxsfb->base + LCDC_VDCTRL4);
-
-       writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
-}
-
-static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
-{
-       u32 reg;
-
-       /*
-        * Even if we disable the controller here, it will still continue
-        * until its FIFOs are running out of data
-        */
-       writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
-
-       readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
-                          0, 1000);
-
-       reg = readl(mxsfb->base + LCDC_VDCTRL4);
-       reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
-       writel(reg, mxsfb->base + LCDC_VDCTRL4);
-
-       clk_disable_unprepare(mxsfb->clk);
-       if (mxsfb->clk_disp_axi)
-               clk_disable_unprepare(mxsfb->clk_disp_axi);
-}
-
-/*
- * Clear the bit and poll it cleared.  This is usually called with
- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
- * (bit 30).
- */
-static int clear_poll_bit(void __iomem *addr, u32 mask)
-{
-       u32 reg;
-
-       writel(mask, addr + MXS_CLR_ADDR);
-       return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
-}
-
-static int mxsfb_reset_block(void __iomem *reset_addr)
-{
-       int ret;
-
-       ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
-       if (ret)
-               return ret;
-
-       writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
-
-       ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
-       if (ret)
-               return ret;
-
-       return clear_poll_bit(reset_addr, MODULE_CLKGATE);
-}
-
-static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
-{
-       struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb;
-       struct drm_gem_cma_object *gem;
-
-       if (!fb)
-               return 0;
-
-       gem = drm_fb_cma_get_gem_obj(fb, 0);
-       if (!gem)
-               return 0;
-
-       return gem->paddr;
-}
-
-static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
-{
-       struct drm_device *drm = mxsfb->pipe.crtc.dev;
-       struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
-       u32 bus_flags = mxsfb->connector->display_info.bus_flags;
-       u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
-       int err;
-
-       /*
-        * It seems, you can't re-program the controller if it is still
-        * running. This may lead to shifted pictures (FIFO issue?), so
-        * first stop the controller and drain its FIFOs.
-        */
-
-       /* Mandatory eLCDIF reset as per the Reference Manual */
-       err = mxsfb_reset_block(mxsfb->base);
-       if (err)
-               return;
-
-       /* Clear the FIFOs */
-       writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
-
-       err = mxsfb_set_pixel_fmt(mxsfb);
-       if (err)
-               return;
-
-       clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
-
-       if (mxsfb->bridge && mxsfb->bridge->timings)
-               bus_flags = mxsfb->bridge->timings->input_bus_flags;
-
-       DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
-                            m->crtc_clock,
-                            (int)(clk_get_rate(mxsfb->clk) / 1000));
-       DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
-                            bus_flags);
-       DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
-
-       writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
-              TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
-              mxsfb->base + mxsfb->devdata->transfer_count);
-
-       vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
-
-       vdctrl0 = VDCTRL0_ENABLE_PRESENT |      /* Always in DOTCLOCK mode */
-                 VDCTRL0_VSYNC_PERIOD_UNIT |
-                 VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
-                 VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
-       if (m->flags & DRM_MODE_FLAG_PHSYNC)
-               vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
-       if (m->flags & DRM_MODE_FLAG_PVSYNC)
-               vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
-       /* Make sure Data Enable is high active by default */
-       if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
-               vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
-       /*
-        * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
-        * controllers VDCTRL0_DOTCLK is display centric.
-        * Drive on positive edge       -> display samples on falling edge
-        * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
-        */
-       if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
-               vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
-
-       writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
-
-       mxsfb_set_bus_fmt(mxsfb);
-
-       /* Frame length in lines. */
-       writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
-
-       /* Line length in units of clocks or pixels. */
-       hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
-       writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
-              VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
-              mxsfb->base + LCDC_VDCTRL2);
-
-       writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
-              SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
-              mxsfb->base + LCDC_VDCTRL3);
-
-       writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
-              mxsfb->base + LCDC_VDCTRL4);
-}
-
-void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
-{
-       dma_addr_t paddr;
-
-       mxsfb_enable_axi_clk(mxsfb);
-       mxsfb_crtc_mode_set_nofb(mxsfb);
-
-       /* Write cur_buf as well to avoid an initial corrupt frame */
-       paddr = mxsfb_get_fb_paddr(mxsfb);
-       if (paddr) {
-               writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
-               writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
-       }
-
-       mxsfb_enable_controller(mxsfb);
-}
-
-void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
-{
-       mxsfb_disable_controller(mxsfb);
-       mxsfb_disable_axi_clk(mxsfb);
-}
-
-void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
-                              struct drm_plane_state *state)
-{
-       struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
-       struct drm_crtc *crtc = &pipe->crtc;
-       struct drm_pending_vblank_event *event;
-       dma_addr_t paddr;
-
-       spin_lock_irq(&crtc->dev->event_lock);
-       event = crtc->state->event;
-       if (event) {
-               crtc->state->event = NULL;
-
-               if (drm_crtc_vblank_get(crtc) == 0) {
-                       drm_crtc_arm_vblank_event(crtc, event);
-               } else {
-                       drm_crtc_send_vblank_event(crtc, event);
-               }
-       }
-       spin_unlock_irq(&crtc->dev->event_lock);
-
-       paddr = mxsfb_get_fb_paddr(mxsfb);
-       if (paddr) {
-               mxsfb_enable_axi_clk(mxsfb);
-               writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
-               mxsfb_disable_axi_clk(mxsfb);
-       }
-}
index 508764f..8c549c3 100644 (file)
@@ -9,30 +9,24 @@
  */
 
 #include <linux/clk.h>
-#include <linux/component.h>
 #include <linux/dma-mapping.h>
-#include <linux/list.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
-#include <linux/of_graph.h>
-#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/dma-resv.h>
-#include <linux/spinlock.h>
 
-#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
 #include <drm/drm_drv.h>
-#include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_irq.h>
+#include <drm/drm_mode_config.h>
 #include <drm/drm_of.h>
-#include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 #include <drm/drm_vblank.h>
 
 #include "mxsfb_drv.h"
 enum mxsfb_devtype {
        MXSFB_V3,
        MXSFB_V4,
+       /*
+        * Starting at i.MX6 the hardware version register is gone, use the
+        * i.MX family number as the version.
+        */
+       MXSFB_V6,
 };
 
 static const struct mxsfb_devdata mxsfb_devdata[] = {
@@ -48,38 +47,28 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
                .transfer_count = LCDC_V3_TRANSFER_COUNT,
                .cur_buf        = LCDC_V3_CUR_BUF,
                .next_buf       = LCDC_V3_NEXT_BUF,
-               .debug0         = LCDC_V3_DEBUG0,
                .hs_wdth_mask   = 0xff,
                .hs_wdth_shift  = 24,
-               .ipversion      = 3,
+               .has_overlay    = false,
        },
        [MXSFB_V4] = {
                .transfer_count = LCDC_V4_TRANSFER_COUNT,
                .cur_buf        = LCDC_V4_CUR_BUF,
                .next_buf       = LCDC_V4_NEXT_BUF,
-               .debug0         = LCDC_V4_DEBUG0,
                .hs_wdth_mask   = 0x3fff,
                .hs_wdth_shift  = 18,
-               .ipversion      = 4,
+               .has_overlay    = false,
+       },
+       [MXSFB_V6] = {
+               .transfer_count = LCDC_V4_TRANSFER_COUNT,
+               .cur_buf        = LCDC_V4_CUR_BUF,
+               .next_buf       = LCDC_V4_NEXT_BUF,
+               .hs_wdth_mask   = 0x3fff,
+               .hs_wdth_shift  = 18,
+               .has_overlay    = true,
        },
 };
 
-static const uint32_t mxsfb_formats[] = {
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_RGB565
-};
-
-static const uint64_t mxsfb_modifiers[] = {
-       DRM_FORMAT_MOD_LINEAR,
-       DRM_FORMAT_MOD_INVALID
-};
-
-static struct mxsfb_drm_private *
-drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
-{
-       return container_of(pipe, struct mxsfb_drm_private, pipe);
-}
-
 void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
 {
        if (mxsfb->clk_axi)
@@ -102,101 +91,51 @@ static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = {
        .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 };
 
-static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
-                             struct drm_crtc_state *crtc_state,
-                             struct drm_plane_state *plane_state)
+static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb)
 {
-       struct drm_connector *connector;
-       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
-       struct drm_device *drm = pipe->plane.dev;
-
-       if (!mxsfb->connector) {
-               list_for_each_entry(connector,
-                                   &drm->mode_config.connector_list,
-                                   head)
-                       if (connector->encoder == &mxsfb->pipe.encoder) {
-                               mxsfb->connector = connector;
-                               break;
-                       }
-       }
-
-       if (!mxsfb->connector) {
-               dev_warn(drm->dev, "No connector attached, using default\n");
-               mxsfb->connector = &mxsfb->panel_connector;
-       }
-
-       pm_runtime_get_sync(drm->dev);
-       drm_panel_prepare(mxsfb->panel);
-       mxsfb_crtc_enable(mxsfb);
-       drm_panel_enable(mxsfb->panel);
-}
+       struct drm_device *drm = mxsfb->drm;
+       struct drm_connector_list_iter iter;
+       struct drm_panel *panel;
+       struct drm_bridge *bridge;
+       int ret;
 
-static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
-{
-       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
-       struct drm_device *drm = pipe->plane.dev;
-       struct drm_crtc *crtc = &pipe->crtc;
-       struct drm_pending_vblank_event *event;
-
-       drm_panel_disable(mxsfb->panel);
-       mxsfb_crtc_disable(mxsfb);
-       drm_panel_unprepare(mxsfb->panel);
-       pm_runtime_put_sync(drm->dev);
+       ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel,
+                                         &bridge);
+       if (ret)
+               return ret;
 
-       spin_lock_irq(&drm->event_lock);
-       event = crtc->state->event;
-       if (event) {
-               crtc->state->event = NULL;
-               drm_crtc_send_vblank_event(crtc, event);
+       if (panel) {
+               bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel,
+                                                        DRM_MODE_CONNECTOR_DPI);
+               if (IS_ERR(bridge))
+                       return PTR_ERR(bridge);
        }
-       spin_unlock_irq(&drm->event_lock);
 
-       if (mxsfb->connector != &mxsfb->panel_connector)
-               mxsfb->connector = NULL;
-}
-
-static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
-                             struct drm_plane_state *plane_state)
-{
-       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+       if (!bridge)
+               return -ENODEV;
 
-       mxsfb_plane_atomic_update(mxsfb, plane_state);
-}
+       ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0);
+       if (ret) {
+               DRM_DEV_ERROR(drm->dev,
+                             "failed to attach bridge: %d\n", ret);
+               return ret;
+       }
 
-static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
-{
-       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+       mxsfb->bridge = bridge;
 
-       /* Clear and enable VBLANK IRQ */
-       mxsfb_enable_axi_clk(mxsfb);
-       writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
-       writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
-       mxsfb_disable_axi_clk(mxsfb);
+       /*
+        * Get hold of the connector. This is a bit of a hack, until the bridge
+        * API gives us bus flags and formats.
+        */
+       drm_connector_list_iter_begin(drm, &iter);
+       mxsfb->connector = drm_connector_list_iter_next(&iter);
+       drm_connector_list_iter_end(&iter);
 
        return 0;
 }
 
-static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
-{
-       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
-
-       /* Disable and clear VBLANK IRQ */
-       mxsfb_enable_axi_clk(mxsfb);
-       writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
-       writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
-       mxsfb_disable_axi_clk(mxsfb);
-}
-
-static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
-       .enable         = mxsfb_pipe_enable,
-       .disable        = mxsfb_pipe_disable,
-       .update         = mxsfb_pipe_update,
-       .prepare_fb     = drm_gem_fb_simple_display_pipe_prepare_fb,
-       .enable_vblank  = mxsfb_pipe_enable_vblank,
-       .disable_vblank = mxsfb_pipe_disable_vblank,
-};
-
-static int mxsfb_load(struct drm_device *drm)
+static int mxsfb_load(struct drm_device *drm,
+                     const struct mxsfb_devdata *devdata)
 {
        struct platform_device *pdev = to_platform_device(drm->dev);
        struct mxsfb_drm_private *mxsfb;
@@ -207,8 +146,9 @@ static int mxsfb_load(struct drm_device *drm)
        if (!mxsfb)
                return -ENOMEM;
 
+       mxsfb->drm = drm;
        drm->dev_private = mxsfb;
-       mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+       mxsfb->devdata = devdata;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mxsfb->base = devm_ioremap_resource(drm->dev, res);
@@ -233,50 +173,28 @@ static int mxsfb_load(struct drm_device *drm)
 
        pm_runtime_enable(drm->dev);
 
-       ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
-       if (ret < 0) {
-               dev_err(drm->dev, "Failed to initialise vblank\n");
-               goto err_vblank;
-       }
-
        /* Modeset init */
        drm_mode_config_init(drm);
 
-       ret = mxsfb_create_output(drm);
+       ret = mxsfb_kms_init(mxsfb);
        if (ret < 0) {
-               dev_err(drm->dev, "Failed to create outputs\n");
+               dev_err(drm->dev, "Failed to initialize KMS pipeline\n");
                goto err_vblank;
        }
 
-       ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
-                       mxsfb_formats, ARRAY_SIZE(mxsfb_formats),
-                       mxsfb_modifiers, mxsfb->connector);
+       ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (ret < 0) {
-               dev_err(drm->dev, "Cannot setup simple display pipe\n");
+               dev_err(drm->dev, "Failed to initialise vblank\n");
                goto err_vblank;
        }
 
-       /*
-        * Attach panel only if there is one.
-        * If there is no panel attach, it must be a bridge. In this case, we
-        * need a reference to its connector for a proper initialization.
-        * We will do this check in pipe->enable(), since the connector won't
-        * be attached to an encoder until then.
-        */
+       /* Start with vertical blanking interrupt reporting disabled. */
+       drm_crtc_vblank_off(&mxsfb->crtc);
 
-       if (mxsfb->panel) {
-               ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
-               if (ret) {
-                       dev_err(drm->dev, "Cannot connect panel: %d\n", ret);
-                       goto err_vblank;
-               }
-       } else if (mxsfb->bridge) {
-               ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
-                                                           mxsfb->bridge);
-               if (ret) {
-                       dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
-                       goto err_vblank;
-               }
+       ret = mxsfb_attach_bridge(mxsfb);
+       if (ret) {
+               dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
+               goto err_vblank;
        }
 
        drm->mode_config.min_width      = MXSFB_MIN_XRES;
@@ -294,7 +212,7 @@ static int mxsfb_load(struct drm_device *drm)
 
        if (ret < 0) {
                dev_err(drm->dev, "Failed to install IRQ handler\n");
-               goto err_irq;
+               goto err_vblank;
        }
 
        drm_kms_helper_poll_init(drm);
@@ -305,8 +223,6 @@ static int mxsfb_load(struct drm_device *drm)
 
        return 0;
 
-err_irq:
-       drm_panel_detach(mxsfb->panel);
 err_vblank:
        pm_runtime_disable(drm->dev);
 
@@ -327,11 +243,13 @@ static void mxsfb_unload(struct drm_device *drm)
        pm_runtime_disable(drm->dev);
 }
 
-static void mxsfb_irq_preinstall(struct drm_device *drm)
+static void mxsfb_irq_disable(struct drm_device *drm)
 {
        struct mxsfb_drm_private *mxsfb = drm->dev_private;
 
-       mxsfb_pipe_disable_vblank(&mxsfb->pipe);
+       mxsfb_enable_axi_clk(mxsfb);
+       mxsfb->crtc.funcs->disable_vblank(&mxsfb->crtc);
+       mxsfb_disable_axi_clk(mxsfb);
 }
 
 static irqreturn_t mxsfb_irq_handler(int irq, void *data)
@@ -340,17 +258,13 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data)
        struct mxsfb_drm_private *mxsfb = drm->dev_private;
        u32 reg;
 
-       mxsfb_enable_axi_clk(mxsfb);
-
        reg = readl(mxsfb->base + LCDC_CTRL1);
 
        if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
-               drm_crtc_handle_vblank(&mxsfb->pipe.crtc);
+               drm_crtc_handle_vblank(&mxsfb->crtc);
 
        writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
 
-       mxsfb_disable_axi_clk(mxsfb);
-
        return IRQ_HANDLED;
 }
 
@@ -359,8 +273,8 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
 static struct drm_driver mxsfb_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
        .irq_handler            = mxsfb_irq_handler,
-       .irq_preinstall         = mxsfb_irq_preinstall,
-       .irq_uninstall          = mxsfb_irq_preinstall,
+       .irq_preinstall         = mxsfb_irq_disable,
+       .irq_uninstall          = mxsfb_irq_disable,
        DRM_GEM_CMA_DRIVER_OPS,
        .fops   = &fops,
        .name   = "mxsfb-drm",
@@ -370,18 +284,10 @@ static struct drm_driver mxsfb_driver = {
        .minor  = 0,
 };
 
-static const struct platform_device_id mxsfb_devtype[] = {
-       { .name = "imx23-fb", .driver_data = MXSFB_V3, },
-       { .name = "imx28-fb", .driver_data = MXSFB_V4, },
-       { .name = "imx6sx-fb", .driver_data = MXSFB_V4, },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
-
 static const struct of_device_id mxsfb_dt_ids[] = {
-       { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
-       { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
-       { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], },
+       { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], },
+       { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], },
+       { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
@@ -396,14 +302,11 @@ static int mxsfb_probe(struct platform_device *pdev)
        if (!pdev->dev.of_node)
                return -ENODEV;
 
-       if (of_id)
-               pdev->id_entry = of_id->data;
-
        drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev);
        if (IS_ERR(drm))
                return PTR_ERR(drm);
 
-       ret = mxsfb_load(drm);
+       ret = mxsfb_load(drm, of_id->data);
        if (ret)
                goto err_free;
 
@@ -457,7 +360,6 @@ static const struct dev_pm_ops mxsfb_pm_ops = {
 static struct platform_driver mxsfb_platform_driver = {
        .probe          = mxsfb_probe,
        .remove         = mxsfb_remove,
-       .id_table       = mxsfb_devtype,
        .driver = {
                .name           = "mxsfb",
                .of_match_table = mxsfb_dt_ids,
index 0b65b51..399d23e 100644 (file)
@@ -8,14 +8,20 @@
 #ifndef __MXSFB_DRV_H__
 #define __MXSFB_DRV_H__
 
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_plane.h>
+
+struct clk;
+
 struct mxsfb_devdata {
-       unsigned int     transfer_count;
-       unsigned int     cur_buf;
-       unsigned int     next_buf;
-       unsigned int     debug0;
-       unsigned int     hs_wdth_mask;
-       unsigned int     hs_wdth_shift;
-       unsigned int     ipversion;
+       unsigned int    transfer_count;
+       unsigned int    cur_buf;
+       unsigned int    next_buf;
+       unsigned int    hs_wdth_mask;
+       unsigned int    hs_wdth_shift;
+       bool            has_overlay;
 };
 
 struct mxsfb_drm_private {
@@ -26,22 +32,26 @@ struct mxsfb_drm_private {
        struct clk                      *clk_axi;
        struct clk                      *clk_disp_axi;
 
-       struct drm_simple_display_pipe  pipe;
-       struct drm_connector            panel_connector;
+       struct drm_device               *drm;
+       struct {
+               struct drm_plane        primary;
+               struct drm_plane        overlay;
+       } planes;
+       struct drm_crtc                 crtc;
+       struct drm_encoder              encoder;
        struct drm_connector            *connector;
-       struct drm_panel                *panel;
        struct drm_bridge               *bridge;
 };
 
-int mxsfb_setup_crtc(struct drm_device *dev);
-int mxsfb_create_output(struct drm_device *dev);
+static inline struct mxsfb_drm_private *
+to_mxsfb_drm_private(struct drm_device *drm)
+{
+       return drm->dev_private;
+}
 
 void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb);
 void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb);
 
-void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
-void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
-void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
-                              struct drm_plane_state *state);
+int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb);
 
 #endif /* __MXSFB_DRV_H__ */
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
new file mode 100644 (file)
index 0000000..b721b8b
--- /dev/null
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+/* 1 second delay should be plenty of time for block reset */
+#define RESET_TIMEOUT          1000000
+
+/* -----------------------------------------------------------------------------
+ * CRTC
+ */
+
+static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
+{
+       return (val & mxsfb->devdata->hs_wdth_mask) <<
+               mxsfb->devdata->hs_wdth_shift;
+}
+
+/*
+ * Setup the MXSFB registers for decoding the pixels out of the framebuffer and
+ * outputting them on the bus.
+ */
+static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb)
+{
+       struct drm_device *drm = mxsfb->drm;
+       const u32 format = mxsfb->crtc.primary->state->fb->format->format;
+       u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+       u32 ctrl, ctrl1;
+
+       if (mxsfb->connector->display_info.num_bus_formats)
+               bus_format = mxsfb->connector->display_info.bus_formats[0];
+
+       DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
+                            bus_format);
+
+       ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
+
+       /* CTRL1 contains IRQ config and status bits, preserve those. */
+       ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
+       ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+
+       switch (format) {
+       case DRM_FORMAT_RGB565:
+               dev_dbg(drm->dev, "Setting up RGB565 mode\n");
+               ctrl |= CTRL_WORD_LENGTH_16;
+               ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+               break;
+       case DRM_FORMAT_XRGB8888:
+               dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
+               ctrl |= CTRL_WORD_LENGTH_24;
+               /* Do not use packed pixels = one pixel per word instead. */
+               ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+               break;
+       }
+
+       switch (bus_format) {
+       case MEDIA_BUS_FMT_RGB565_1X16:
+               ctrl |= CTRL_BUS_WIDTH_16;
+               break;
+       case MEDIA_BUS_FMT_RGB666_1X18:
+               ctrl |= CTRL_BUS_WIDTH_18;
+               break;
+       case MEDIA_BUS_FMT_RGB888_1X24:
+               ctrl |= CTRL_BUS_WIDTH_24;
+               break;
+       default:
+               dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
+               break;
+       }
+
+       writel(ctrl1, mxsfb->base + LCDC_CTRL1);
+       writel(ctrl, mxsfb->base + LCDC_CTRL);
+}
+
+static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
+{
+       u32 reg;
+
+       if (mxsfb->clk_disp_axi)
+               clk_prepare_enable(mxsfb->clk_disp_axi);
+       clk_prepare_enable(mxsfb->clk);
+
+       /* If it was disabled, re-enable the mode again */
+       writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
+
+       /* Enable the SYNC signals first, then the DMA engine */
+       reg = readl(mxsfb->base + LCDC_VDCTRL4);
+       reg |= VDCTRL4_SYNC_SIGNALS_ON;
+       writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+       writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
+}
+
+static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
+{
+       u32 reg;
+
+       /*
+        * Even if we disable the controller here, it will still continue
+        * until its FIFOs are running out of data
+        */
+       writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+       readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
+                          0, 1000);
+
+       reg = readl(mxsfb->base + LCDC_VDCTRL4);
+       reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+       writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+       clk_disable_unprepare(mxsfb->clk);
+       if (mxsfb->clk_disp_axi)
+               clk_disable_unprepare(mxsfb->clk_disp_axi);
+}
+
+/*
+ * Clear the bit and poll it cleared.  This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
+ */
+static int clear_poll_bit(void __iomem *addr, u32 mask)
+{
+       u32 reg;
+
+       writel(mask, addr + REG_CLR);
+       return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
+}
+
+static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb)
+{
+       int ret;
+
+       ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
+       if (ret)
+               return ret;
+
+       writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+       ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
+       if (ret)
+               return ret;
+
+       return clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE);
+}
+
+static dma_addr_t mxsfb_get_fb_paddr(struct drm_plane *plane)
+{
+       struct drm_framebuffer *fb = plane->state->fb;
+       struct drm_gem_cma_object *gem;
+
+       if (!fb)
+               return 0;
+
+       gem = drm_fb_cma_get_gem_obj(fb, 0);
+       if (!gem)
+               return 0;
+
+       return gem->paddr;
+}
+
+static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
+{
+       struct drm_device *drm = mxsfb->crtc.dev;
+       struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
+       u32 bus_flags = mxsfb->connector->display_info.bus_flags;
+       u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
+       int err;
+
+       /*
+        * It seems, you can't re-program the controller if it is still
+        * running. This may lead to shifted pictures (FIFO issue?), so
+        * first stop the controller and drain its FIFOs.
+        */
+
+       /* Mandatory eLCDIF reset as per the Reference Manual */
+       err = mxsfb_reset_block(mxsfb);
+       if (err)
+               return;
+
+       /* Clear the FIFOs */
+       writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+       if (mxsfb->devdata->has_overlay)
+               writel(0, mxsfb->base + LCDC_AS_CTRL);
+
+       mxsfb_set_formats(mxsfb);
+
+       clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
+
+       if (mxsfb->bridge && mxsfb->bridge->timings)
+               bus_flags = mxsfb->bridge->timings->input_bus_flags;
+
+       DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
+                            m->crtc_clock,
+                            (int)(clk_get_rate(mxsfb->clk) / 1000));
+       DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
+                            bus_flags);
+       DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
+
+       writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
+              TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
+              mxsfb->base + mxsfb->devdata->transfer_count);
+
+       vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
+
+       vdctrl0 = VDCTRL0_ENABLE_PRESENT |      /* Always in DOTCLOCK mode */
+                 VDCTRL0_VSYNC_PERIOD_UNIT |
+                 VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+                 VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
+       if (m->flags & DRM_MODE_FLAG_PHSYNC)
+               vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+       if (m->flags & DRM_MODE_FLAG_PVSYNC)
+               vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+       /* Make sure Data Enable is high active by default */
+       if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
+               vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+       /*
+        * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
+        * controllers VDCTRL0_DOTCLK is display centric.
+        * Drive on positive edge       -> display samples on falling edge
+        * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
+        */
+       if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
+               vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+       writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
+
+       /* Frame length in lines. */
+       writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
+
+       /* Line length in units of clocks or pixels. */
+       hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
+       writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
+              VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
+              mxsfb->base + LCDC_VDCTRL2);
+
+       writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
+              SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
+              mxsfb->base + LCDC_VDCTRL3);
+
+       writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
+              mxsfb->base + LCDC_VDCTRL4);
+}
+
+static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *state)
+{
+       bool has_primary = state->plane_mask &
+                          drm_plane_mask(crtc->primary);
+
+       /* The primary plane has to be enabled when the CRTC is active. */
+       if (state->active && !has_primary)
+               return -EINVAL;
+
+       /* TODO: Is this needed ? */
+       return drm_atomic_add_affected_planes(state->state, crtc);
+}
+
+static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_state)
+{
+       struct drm_pending_vblank_event *event;
+
+       event = crtc->state->event;
+       crtc->state->event = NULL;
+
+       if (!event)
+               return;
+
+       spin_lock_irq(&crtc->dev->event_lock);
+       if (drm_crtc_vblank_get(crtc) == 0)
+               drm_crtc_arm_vblank_event(crtc, event);
+       else
+               drm_crtc_send_vblank_event(crtc, event);
+       spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *old_state)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+       struct drm_device *drm = mxsfb->drm;
+       dma_addr_t paddr;
+
+       pm_runtime_get_sync(drm->dev);
+       mxsfb_enable_axi_clk(mxsfb);
+
+       drm_crtc_vblank_on(crtc);
+
+       mxsfb_crtc_mode_set_nofb(mxsfb);
+
+       /* Write cur_buf as well to avoid an initial corrupt frame */
+       paddr = mxsfb_get_fb_paddr(crtc->primary);
+       if (paddr) {
+               writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
+               writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
+       }
+
+       mxsfb_enable_controller(mxsfb);
+}
+
+static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
+                                     struct drm_crtc_state *old_state)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+       struct drm_device *drm = mxsfb->drm;
+       struct drm_pending_vblank_event *event;
+
+       mxsfb_disable_controller(mxsfb);
+
+       spin_lock_irq(&drm->event_lock);
+       event = crtc->state->event;
+       if (event) {
+               crtc->state->event = NULL;
+               drm_crtc_send_vblank_event(crtc, event);
+       }
+       spin_unlock_irq(&drm->event_lock);
+
+       drm_crtc_vblank_off(crtc);
+
+       mxsfb_disable_axi_clk(mxsfb);
+       pm_runtime_put_sync(drm->dev);
+}
+
+static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+       /* Clear and enable VBLANK IRQ */
+       writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+       writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+       return 0;
+}
+
+static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+       /* Disable and clear VBLANK IRQ */
+       writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+       writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+}
+
+static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = {
+       .atomic_check = mxsfb_crtc_atomic_check,
+       .atomic_flush = mxsfb_crtc_atomic_flush,
+       .atomic_enable = mxsfb_crtc_atomic_enable,
+       .atomic_disable = mxsfb_crtc_atomic_disable,
+};
+
+static const struct drm_crtc_funcs mxsfb_crtc_funcs = {
+       .reset = drm_atomic_helper_crtc_reset,
+       .destroy = drm_crtc_cleanup,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+       .enable_vblank = mxsfb_crtc_enable_vblank,
+       .disable_vblank = mxsfb_crtc_disable_vblank,
+};
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
+static const struct drm_encoder_funcs mxsfb_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+/* -----------------------------------------------------------------------------
+ * Planes
+ */
+
+static int mxsfb_plane_atomic_check(struct drm_plane *plane,
+                                   struct drm_plane_state *plane_state)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+       struct drm_crtc_state *crtc_state;
+
+       crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
+                                                  &mxsfb->crtc);
+
+       return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+                                                  DRM_PLANE_HELPER_NO_SCALING,
+                                                  DRM_PLANE_HELPER_NO_SCALING,
+                                                  false, true);
+}
+
+static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane,
+                                             struct drm_plane_state *old_pstate)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+       dma_addr_t paddr;
+
+       paddr = mxsfb_get_fb_paddr(plane);
+       if (paddr)
+               writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
+}
+
+static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
+                                             struct drm_plane_state *old_pstate)
+{
+       struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+       struct drm_plane_state *state = plane->state;
+       dma_addr_t paddr;
+       u32 ctrl;
+
+       paddr = mxsfb_get_fb_paddr(plane);
+       if (!paddr) {
+               writel(0, mxsfb->base + LCDC_AS_CTRL);
+               return;
+       }
+
+       /*
+        * HACK: The hardware seems to output 64 bytes of data of unknown
+        * origin, and then to proceed with the framebuffer. Until the reason
+        * is understood, live with the 16 initial invalid pixels on the first
+        * line and start 64 bytes within the framebuffer.
+        */
+       paddr += 64;
+
+       writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF);
+
+       /*
+        * If the plane was previously disabled, write LCDC_AS_BUF as well to
+        * provide the first buffer.
+        */
+       if (!old_pstate->fb)
+               writel(paddr, mxsfb->base + LCDC_AS_BUF);
+
+       ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255);
+
+       switch (state->fb->format->format) {
+       case DRM_FORMAT_XRGB4444:
+               ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+               break;
+       case DRM_FORMAT_ARGB4444:
+               ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+               break;
+       case DRM_FORMAT_XRGB1555:
+               ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+               break;
+       case DRM_FORMAT_ARGB1555:
+               ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+               break;
+       case DRM_FORMAT_RGB565:
+               ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+               break;
+       case DRM_FORMAT_XRGB8888:
+               ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+               break;
+       case DRM_FORMAT_ARGB8888:
+               ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+               break;
+       }
+
+       writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
+}
+
+static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
+       .atomic_check = mxsfb_plane_atomic_check,
+       .atomic_update = mxsfb_plane_primary_atomic_update,
+};
+
+static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
+       .atomic_check = mxsfb_plane_atomic_check,
+       .atomic_update = mxsfb_plane_overlay_atomic_update,
+};
+
+static const struct drm_plane_funcs mxsfb_plane_funcs = {
+       .update_plane           = drm_atomic_helper_update_plane,
+       .disable_plane          = drm_atomic_helper_disable_plane,
+       .destroy                = drm_plane_cleanup,
+       .reset                  = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
+};
+
+static const uint32_t mxsfb_primary_plane_formats[] = {
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_XRGB8888,
+};
+
+static const uint32_t mxsfb_overlay_plane_formats[] = {
+       DRM_FORMAT_XRGB4444,
+       DRM_FORMAT_ARGB4444,
+       DRM_FORMAT_XRGB1555,
+       DRM_FORMAT_ARGB1555,
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+};
+
+static const uint64_t mxsfb_modifiers[] = {
+       DRM_FORMAT_MOD_LINEAR,
+       DRM_FORMAT_MOD_INVALID
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb)
+{
+       struct drm_encoder *encoder = &mxsfb->encoder;
+       struct drm_crtc *crtc = &mxsfb->crtc;
+       int ret;
+
+       drm_plane_helper_add(&mxsfb->planes.primary,
+                            &mxsfb_plane_primary_helper_funcs);
+       ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1,
+                                      &mxsfb_plane_funcs,
+                                      mxsfb_primary_plane_formats,
+                                      ARRAY_SIZE(mxsfb_primary_plane_formats),
+                                      mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY,
+                                      NULL);
+       if (ret)
+               return ret;
+
+       if (mxsfb->devdata->has_overlay) {
+               drm_plane_helper_add(&mxsfb->planes.overlay,
+                                    &mxsfb_plane_overlay_helper_funcs);
+               ret = drm_universal_plane_init(mxsfb->drm,
+                                              &mxsfb->planes.overlay, 1,
+                                              &mxsfb_plane_funcs,
+                                              mxsfb_overlay_plane_formats,
+                                              ARRAY_SIZE(mxsfb_overlay_plane_formats),
+                                              mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY,
+                                              NULL);
+               if (ret)
+                       return ret;
+       }
+
+       drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs);
+       ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
+                                       &mxsfb->planes.primary, NULL,
+                                       &mxsfb_crtc_funcs, NULL);
+       if (ret)
+               return ret;
+
+       encoder->possible_crtcs = drm_crtc_mask(crtc);
+       return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs,
+                               DRM_MODE_ENCODER_NONE, NULL);
+}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c
deleted file mode 100644 (file)
index 9eca160..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- */
-
-#include <linux/of_graph.h>
-
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-
-#include "mxsfb_drv.h"
-
-static struct mxsfb_drm_private *
-drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
-{
-       return container_of(connector, struct mxsfb_drm_private,
-                           panel_connector);
-}
-
-static int mxsfb_panel_get_modes(struct drm_connector *connector)
-{
-       struct mxsfb_drm_private *mxsfb =
-                       drm_connector_to_mxsfb_drm_private(connector);
-
-       if (mxsfb->panel)
-               return drm_panel_get_modes(mxsfb->panel, connector);
-
-       return 0;
-}
-
-static const struct
-drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = {
-       .get_modes = mxsfb_panel_get_modes,
-};
-
-static enum drm_connector_status
-mxsfb_panel_connector_detect(struct drm_connector *connector, bool force)
-{
-       struct mxsfb_drm_private *mxsfb =
-                       drm_connector_to_mxsfb_drm_private(connector);
-
-       if (mxsfb->panel)
-               return connector_status_connected;
-
-       return connector_status_disconnected;
-}
-
-static void mxsfb_panel_connector_destroy(struct drm_connector *connector)
-{
-       struct mxsfb_drm_private *mxsfb =
-                       drm_connector_to_mxsfb_drm_private(connector);
-
-       if (mxsfb->panel)
-               drm_panel_detach(mxsfb->panel);
-
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
-       .detect                 = mxsfb_panel_connector_detect,
-       .fill_modes             = drm_helper_probe_single_connector_modes,
-       .destroy                = mxsfb_panel_connector_destroy,
-       .reset                  = drm_atomic_helper_connector_reset,
-       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
-};
-
-int mxsfb_create_output(struct drm_device *drm)
-{
-       struct mxsfb_drm_private *mxsfb = drm->dev_private;
-       int ret;
-
-       ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
-                                         &mxsfb->panel, &mxsfb->bridge);
-       if (ret)
-               return ret;
-
-       if (mxsfb->panel) {
-               mxsfb->connector = &mxsfb->panel_connector;
-               mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
-               mxsfb->connector->polled = 0;
-               drm_connector_helper_add(mxsfb->connector,
-                                        &mxsfb_panel_connector_helper_funcs);
-               ret = drm_connector_init(drm, mxsfb->connector,
-                                        &mxsfb_panel_connector_funcs,
-                                        DRM_MODE_CONNECTOR_Unknown);
-       }
-
-       return ret;
-}
index 932d7ea..55d28a2 100644 (file)
 #define LCDC_VDCTRL4                   0xb0
 #define LCDC_V4_DEBUG0                 0x1d0
 #define LCDC_V3_DEBUG0                 0x1f0
-
-#define CTRL_SFTRST                    (1 << 31)
-#define CTRL_CLKGATE                   (1 << 30)
-#define CTRL_BYPASS_COUNT              (1 << 19)
-#define CTRL_VSYNC_MODE                        (1 << 18)
-#define CTRL_DOTCLK_MODE               (1 << 17)
-#define CTRL_DATA_SELECT               (1 << 16)
-#define CTRL_SET_BUS_WIDTH(x)          (((x) & 0x3) << 10)
-#define CTRL_GET_BUS_WIDTH(x)          (((x) >> 10) & 0x3)
+#define LCDC_AS_CTRL                   0x210
+#define LCDC_AS_BUF                    0x220
+#define LCDC_AS_NEXT_BUF               0x230
+#define LCDC_AS_CLRKEYLOW              0x240
+#define LCDC_AS_CLRKEYHIGH             0x250
+
+#define CTRL_SFTRST                    BIT(31)
+#define CTRL_CLKGATE                   BIT(30)
+#define CTRL_BYPASS_COUNT              BIT(19)
+#define CTRL_VSYNC_MODE                        BIT(18)
+#define CTRL_DOTCLK_MODE               BIT(17)
+#define CTRL_DATA_SELECT               BIT(16)
+#define CTRL_BUS_WIDTH_16              (0 << 10)
+#define CTRL_BUS_WIDTH_8               (1 << 10)
+#define CTRL_BUS_WIDTH_18              (2 << 10)
+#define CTRL_BUS_WIDTH_24              (3 << 10)
 #define CTRL_BUS_WIDTH_MASK            (0x3 << 10)
-#define CTRL_SET_WORD_LENGTH(x)                (((x) & 0x3) << 8)
-#define CTRL_GET_WORD_LENGTH(x)                (((x) >> 8) & 0x3)
-#define CTRL_MASTER                    (1 << 5)
-#define CTRL_DF16                      (1 << 3)
-#define CTRL_DF18                      (1 << 2)
-#define CTRL_DF24                      (1 << 1)
-#define CTRL_RUN                       (1 << 0)
-
-#define CTRL1_FIFO_CLEAR               (1 << 21)
+#define CTRL_WORD_LENGTH_16            (0 << 8)
+#define CTRL_WORD_LENGTH_8             (1 << 8)
+#define CTRL_WORD_LENGTH_18            (2 << 8)
+#define CTRL_WORD_LENGTH_24            (3 << 8)
+#define CTRL_MASTER                    BIT(5)
+#define CTRL_DF16                      BIT(3)
+#define CTRL_DF18                      BIT(2)
+#define CTRL_DF24                      BIT(1)
+#define CTRL_RUN                       BIT(0)
+
+#define CTRL1_FIFO_CLEAR               BIT(21)
 #define CTRL1_SET_BYTE_PACKAGING(x)    (((x) & 0xf) << 16)
 #define CTRL1_GET_BYTE_PACKAGING(x)    (((x) >> 16) & 0xf)
-#define CTRL1_CUR_FRAME_DONE_IRQ_EN    (1 << 13)
-#define CTRL1_CUR_FRAME_DONE_IRQ       (1 << 9)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN    BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ       BIT(9)
 
 #define TRANSFER_COUNT_SET_VCOUNT(x)   (((x) & 0xffff) << 16)
 #define TRANSFER_COUNT_GET_VCOUNT(x)   (((x) >> 16) & 0xffff)
 #define TRANSFER_COUNT_SET_HCOUNT(x)   ((x) & 0xffff)
 #define TRANSFER_COUNT_GET_HCOUNT(x)   ((x) & 0xffff)
 
-#define VDCTRL0_ENABLE_PRESENT         (1 << 28)
-#define VDCTRL0_VSYNC_ACT_HIGH         (1 << 27)
-#define VDCTRL0_HSYNC_ACT_HIGH         (1 << 26)
-#define VDCTRL0_DOTCLK_ACT_FALLING     (1 << 25)
-#define VDCTRL0_ENABLE_ACT_HIGH                (1 << 24)
-#define VDCTRL0_VSYNC_PERIOD_UNIT      (1 << 21)
-#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
-#define VDCTRL0_HALF_LINE              (1 << 19)
-#define VDCTRL0_HALF_LINE_MODE         (1 << 18)
+#define VDCTRL0_ENABLE_PRESENT         BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH         BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH         BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING     BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH                BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT      BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20)
+#define VDCTRL0_HALF_LINE              BIT(19)
+#define VDCTRL0_HALF_LINE_MODE         BIT(18)
 #define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
 #define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
 
 #define VDCTRL2_SET_HSYNC_PERIOD(x)    ((x) & 0x3ffff)
 #define VDCTRL2_GET_HSYNC_PERIOD(x)    ((x) & 0x3ffff)
 
-#define VDCTRL3_MUX_SYNC_SIGNALS       (1 << 29)
-#define VDCTRL3_VSYNC_ONLY             (1 << 28)
+#define VDCTRL3_MUX_SYNC_SIGNALS       BIT(29)
+#define VDCTRL3_VSYNC_ONLY             BIT(28)
 #define SET_HOR_WAIT_CNT(x)            (((x) & 0xfff) << 16)
 #define GET_HOR_WAIT_CNT(x)            (((x) >> 16) & 0xfff)
 #define SET_VERT_WAIT_CNT(x)           ((x) & 0xffff)
 
 #define VDCTRL4_SET_DOTCLK_DLY(x)      (((x) & 0x7) << 29) /* v4 only */
 #define VDCTRL4_GET_DOTCLK_DLY(x)      (((x) >> 29) & 0x7) /* v4 only */
-#define VDCTRL4_SYNC_SIGNALS_ON                (1 << 18)
+#define VDCTRL4_SYNC_SIGNALS_ON                BIT(18)
 #define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
 
-#define DEBUG0_HSYNC                   (1 < 26)
-#define DEBUG0_VSYNC                   (1 < 25)
+#define DEBUG0_HSYNC                   BIT(26)
+#define DEBUG0_VSYNC                   BIT(25)
+
+#define AS_CTRL_PS_DISABLE             BIT(23)
+#define AS_CTRL_ALPHA_INVERT           BIT(20)
+#define AS_CTRL_ALPHA(a)               (((a) & 0xff) << 8)
+#define AS_CTRL_FORMAT_RGB565          (0xe << 4)
+#define AS_CTRL_FORMAT_RGB444          (0xd << 4)
+#define AS_CTRL_FORMAT_RGB555          (0xc << 4)
+#define AS_CTRL_FORMAT_ARGB4444                (0x9 << 4)
+#define AS_CTRL_FORMAT_ARGB1555                (0x8 << 4)
+#define AS_CTRL_FORMAT_RGB888          (0x4 << 4)
+#define AS_CTRL_FORMAT_ARGB8888                (0x0 << 4)
+#define AS_CTRL_ENABLE_COLORKEY                BIT(3)
+#define AS_CTRL_ALPHA_CTRL_ROP         (3 << 1)
+#define AS_CTRL_ALPHA_CTRL_MULTIPLY    (2 << 1)
+#define AS_CTRL_ALPHA_CTRL_OVERRIDE    (1 << 1)
+#define AS_CTRL_ALPHA_CTRL_EMBEDDED    (0 << 1)
+#define AS_CTRL_AS_ENABLE              BIT(0)
 
 #define MXSFB_MIN_XRES                 120
 #define MXSFB_MIN_YRES                 120
 #define MXSFB_MAX_XRES                 0xffff
 #define MXSFB_MAX_YRES                 0xffff
 
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define TRANSP 3
-
-#define STMLCDIF_8BIT  1 /* pixel data bus to the display is of 8 bit width */
-#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
-#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
-#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
-
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT        (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT  (1 << 7) /* negative edge sampling */
-
 #endif /* __MXSFB_REGS_H__ */
index 7806278..5392e5f 100644 (file)
@@ -646,66 +646,6 @@ nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
        return nouveau_sgdma_create_ttm(bo, page_flags);
 }
 
-static int
-nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
-                        struct ttm_mem_type_manager *man)
-{
-       struct nouveau_drm *drm = nouveau_bdev(bdev);
-       struct nvif_mmu *mmu = &drm->client.mmu;
-
-       switch (type) {
-       case TTM_PL_SYSTEM:
-               man->flags = 0;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case TTM_PL_VRAM:
-               man->flags = TTM_MEMTYPE_FLAG_FIXED;
-               man->available_caching = TTM_PL_FLAG_UNCACHED |
-                                        TTM_PL_FLAG_WC;
-               man->default_caching = TTM_PL_FLAG_WC;
-
-               if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-                       /* Some BARs do not support being ioremapped WC */
-                       const u8 type = mmu->type[drm->ttm.type_vram].type;
-                       if (type & NVIF_MEM_UNCACHED) {
-                               man->available_caching = TTM_PL_FLAG_UNCACHED;
-                               man->default_caching = TTM_PL_FLAG_UNCACHED;
-                       }
-
-                       man->func = &nouveau_vram_manager;
-                       man->use_io_reserve_lru = true;
-               } else {
-                       man->func = &ttm_bo_manager_func;
-               }
-               break;
-       case TTM_PL_TT:
-               if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
-                       man->func = &nouveau_gart_manager;
-               else
-               if (!drm->agp.bridge)
-                       man->func = &nv04_gart_manager;
-               else
-                       man->func = &ttm_bo_manager_func;
-
-               if (drm->agp.bridge) {
-                       man->flags = 0;
-                       man->available_caching = TTM_PL_FLAG_UNCACHED |
-                               TTM_PL_FLAG_WC;
-                       man->default_caching = TTM_PL_FLAG_WC;
-               } else {
-                       man->flags = 0;
-                       man->available_caching = TTM_PL_MASK_CACHING;
-                       man->default_caching = TTM_PL_FLAG_CACHED;
-               }
-
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static void
 nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 {
@@ -726,7 +666,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 
 static int
 nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
-                    struct ttm_mem_reg *reg)
+                    struct ttm_resource *reg)
 {
        struct nouveau_mem *old_mem = nouveau_mem(&bo->mem);
        struct nouveau_mem *new_mem = nouveau_mem(reg);
@@ -758,7 +698,7 @@ done:
 
 static int
 nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
-                    bool no_wait_gpu, struct ttm_mem_reg *new_reg)
+                    bool no_wait_gpu, struct ttm_resource *new_reg)
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct nouveau_channel *chan = drm->ttm.chan;
@@ -768,7 +708,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
 
        /* create temporary vmas for the transfer and attach them to the
         * old nvkm_mem node, these will get cleaned up after ttm has
-        * destroyed the ttm_mem_reg
+        * destroyed the ttm_resource
         */
        if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
                ret = nouveau_bo_move_prep(drm, bo, new_reg);
@@ -804,7 +744,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
                s32 oclass;
                int (*exec)(struct nouveau_channel *,
                            struct ttm_buffer_object *,
-                           struct ttm_mem_reg *, struct ttm_mem_reg *);
+                           struct ttm_resource *, struct ttm_resource *);
                int (*init)(struct nouveau_channel *, u32 handle);
        } _methods[] = {
                {  "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
@@ -865,7 +805,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
 
 static int
 nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
-                     bool no_wait_gpu, struct ttm_mem_reg *new_reg)
+                     bool no_wait_gpu, struct ttm_resource *new_reg)
 {
        struct ttm_operation_ctx ctx = { intr, no_wait_gpu };
        struct ttm_place placement_memtype = {
@@ -874,7 +814,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
                .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
        };
        struct ttm_placement placement;
-       struct ttm_mem_reg tmp_reg;
+       struct ttm_resource tmp_reg;
        int ret;
 
        placement.num_placement = placement.num_busy_placement = 1;
@@ -896,13 +836,13 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
 
        ret = ttm_bo_move_ttm(bo, &ctx, new_reg);
 out:
-       ttm_bo_mem_put(bo, &tmp_reg);
+       ttm_resource_free(bo, &tmp_reg);
        return ret;
 }
 
 static int
 nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
-                     bool no_wait_gpu, struct ttm_mem_reg *new_reg)
+                     bool no_wait_gpu, struct ttm_resource *new_reg)
 {
        struct ttm_operation_ctx ctx = { intr, no_wait_gpu };
        struct ttm_place placement_memtype = {
@@ -911,7 +851,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
                .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
        };
        struct ttm_placement placement;
-       struct ttm_mem_reg tmp_reg;
+       struct ttm_resource tmp_reg;
        int ret;
 
        placement.num_placement = placement.num_busy_placement = 1;
@@ -932,13 +872,13 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
                goto out;
 
 out:
-       ttm_bo_mem_put(bo, &tmp_reg);
+       ttm_resource_free(bo, &tmp_reg);
        return ret;
 }
 
 static void
 nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
-                    struct ttm_mem_reg *new_reg)
+                    struct ttm_resource *new_reg)
 {
        struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL;
        struct nouveau_bo *nvbo = nouveau_bo(bo);
@@ -970,7 +910,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
 }
 
 static int
-nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_reg,
+nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg,
                   struct nouveau_drm_tile **new_tile)
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -1006,11 +946,11 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
 static int
 nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
                struct ttm_operation_ctx *ctx,
-               struct ttm_mem_reg *new_reg)
+               struct ttm_resource *new_reg)
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct nouveau_bo *nvbo = nouveau_bo(bo);
-       struct ttm_mem_reg *old_reg = &bo->mem;
+       struct ttm_resource *old_reg = &bo->mem;
        struct nouveau_drm_tile *new_tile = NULL;
        int ret = 0;
 
@@ -1079,7 +1019,7 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 }
 
 static int
-nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
+nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
 {
        struct nouveau_drm *drm = nouveau_bdev(bdev);
        struct nvkm_device *device = nvxx_device(&drm->client.device);
@@ -1159,7 +1099,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
 }
 
 static void
-nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
+nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_resource *reg)
 {
        struct nouveau_drm *drm = nouveau_bdev(bdev);
        struct nouveau_mem *mem = nouveau_mem(reg);
@@ -1231,8 +1171,6 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
        struct device *dev;
-       unsigned i;
-       int r;
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
 
        if (ttm->state != tt_unpopulated)
@@ -1260,31 +1198,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
                return ttm_dma_populate((void *)ttm, dev, ctx);
        }
 #endif
-
-       r = ttm_pool_populate(ttm, ctx);
-       if (r) {
-               return r;
-       }
-
-       for (i = 0; i < ttm->num_pages; i++) {
-               dma_addr_t addr;
-
-               addr = dma_map_page(dev, ttm->pages[i], 0, PAGE_SIZE,
-                                   DMA_BIDIRECTIONAL);
-
-               if (dma_mapping_error(dev, addr)) {
-                       while (i--) {
-                               dma_unmap_page(dev, ttm_dma->dma_address[i],
-                                              PAGE_SIZE, DMA_BIDIRECTIONAL);
-                               ttm_dma->dma_address[i] = 0;
-                       }
-                       ttm_pool_unpopulate(ttm);
-                       return -EFAULT;
-               }
-
-               ttm_dma->dma_address[i] = addr;
-       }
-       return 0;
+       return ttm_populate_and_map_pages(dev, ttm_dma, ctx);
 }
 
 static void
@@ -1293,7 +1207,6 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
        struct device *dev;
-       unsigned i;
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
 
        if (slave)
@@ -1316,14 +1229,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
        }
 #endif
 
-       for (i = 0; i < ttm->num_pages; i++) {
-               if (ttm_dma->dma_address[i]) {
-                       dma_unmap_page(dev, ttm_dma->dma_address[i], PAGE_SIZE,
-                                      DMA_BIDIRECTIONAL);
-               }
-       }
-
-       ttm_pool_unpopulate(ttm);
+       ttm_unmap_and_unpopulate_pages(dev, ttm_dma);
 }
 
 void
@@ -1341,7 +1247,6 @@ struct ttm_bo_driver nouveau_bo_driver = {
        .ttm_tt_create = &nouveau_ttm_tt_create,
        .ttm_tt_populate = &nouveau_ttm_tt_populate,
        .ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
-       .init_mem_type = nouveau_bo_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = nouveau_bo_evict_flags,
        .move_notify = nouveau_bo_move_ntfy,
index 52489ce..aecb748 100644 (file)
@@ -139,28 +139,28 @@ nouveau_bo_new_pin_map(struct nouveau_cli *cli, u64 size, int align, u32 flags,
 
 int nv04_bo_move_init(struct nouveau_channel *, u32);
 int nv04_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 int nv50_bo_move_init(struct nouveau_channel *, u32);
 int nv50_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 int nv84_bo_move_exec(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 int nva3_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 int nvc0_bo_move_init(struct nouveau_channel *, u32);
 int nvc0_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 int nvc0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 int nve0_bo_move_init(struct nouveau_channel *, u32);
 int nve0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *,
-                     struct ttm_mem_reg *, struct ttm_mem_reg *);
+                     struct ttm_resource *, struct ttm_resource *);
 
 #define NVBO_WR32_(b,o,dr,f) nouveau_bo_wr32((b), (o)/4 + (dr), (f))
 #define NVBO_RD32_(b,o,dr)   nouveau_bo_rd32((b), (o)/4 + (dr))
index bf7ae2c..7390132 100644 (file)
@@ -36,7 +36,7 @@
 
 static inline uint32_t
 nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
-                     struct nouveau_channel *chan, struct ttm_mem_reg *reg)
+                     struct nouveau_channel *chan, struct ttm_resource *reg)
 {
        if (reg->mem_type == TTM_PL_TT)
                return NvDmaTT;
@@ -45,7 +45,7 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
 
 int
 nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nvif_push *push = chan->chan.push;
        u32 src_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, old_reg);
index f9b9b85..4c75c7b 100644 (file)
@@ -37,7 +37,7 @@
 
 int
 nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nouveau_mem *mem = nouveau_mem(old_reg);
        struct nvif_push *push = chan->chan.push;
index 1b5fd78..ed6c09d 100644 (file)
@@ -34,7 +34,7 @@
 
 int
 nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nouveau_mem *mem = nouveau_mem(old_reg);
        struct nvif_push *push = chan->chan.push;
index f0df172..dec29b2 100644 (file)
@@ -38,7 +38,7 @@
 
 int
 nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nouveau_mem *mem = nouveau_mem(old_reg);
        struct nvif_push *push = chan->chan.push;
index 52fefb3..776b049 100644 (file)
@@ -36,7 +36,7 @@
 
 int
 nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nvif_push *push = chan->chan.push;
        struct nouveau_mem *mem = nouveau_mem(old_reg);
index 34b79d5..8499f58 100644 (file)
@@ -31,7 +31,7 @@
 
 int
 nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nouveau_mem *mem = nouveau_mem(old_reg);
        struct nvif_push *push = chan->chan.push;
index 394e290..5752124 100644 (file)
@@ -36,7 +36,7 @@
 
 int
 nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
-                 struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
+                 struct ttm_resource *old_reg, struct ttm_resource *new_reg)
 {
        struct nouveau_mem *mem = nouveau_mem(old_reg);
        struct nvif_push *push = chan->chan.push;
index ae76a58..f63ac72 100644 (file)
@@ -157,7 +157,7 @@ struct nouveau_drm {
                atomic_t validate_sequence;
                int (*move)(struct nouveau_channel *,
                            struct ttm_buffer_object *,
-                           struct ttm_mem_reg *, struct ttm_mem_reg *);
+                           struct ttm_resource *, struct ttm_resource *);
                struct nouveau_channel *chan;
                struct nvif_object copy;
                int mtrr;
index b1bb542..269d870 100644 (file)
@@ -92,7 +92,7 @@ nouveau_mem_fini(struct nouveau_mem *mem)
 }
 
 int
-nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt)
+nouveau_mem_host(struct ttm_resource *reg, struct ttm_dma_tt *tt)
 {
        struct nouveau_mem *mem = nouveau_mem(reg);
        struct nouveau_cli *cli = mem->cli;
@@ -130,7 +130,7 @@ nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt)
 }
 
 int
-nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page)
+nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page)
 {
        struct nouveau_mem *mem = nouveau_mem(reg);
        struct nouveau_cli *cli = mem->cli;
@@ -173,7 +173,7 @@ nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page)
 }
 
 void
-nouveau_mem_del(struct ttm_mem_reg *reg)
+nouveau_mem_del(struct ttm_resource *reg)
 {
        struct nouveau_mem *mem = nouveau_mem(reg);
        nouveau_mem_fini(mem);
@@ -183,7 +183,7 @@ nouveau_mem_del(struct ttm_mem_reg *reg)
 
 int
 nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp,
-               struct ttm_mem_reg *reg)
+               struct ttm_resource *reg)
 {
        struct nouveau_mem *mem;
 
index f6d039e..3fe1cfe 100644 (file)
@@ -7,7 +7,7 @@ struct ttm_dma_tt;
 #include <nvif/vmm.h>
 
 static inline struct nouveau_mem *
-nouveau_mem(struct ttm_mem_reg *reg)
+nouveau_mem(struct ttm_resource *reg)
 {
        return reg->mm_node;
 }
@@ -21,10 +21,10 @@ struct nouveau_mem {
 };
 
 int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp,
-                   struct ttm_mem_reg *);
-void nouveau_mem_del(struct ttm_mem_reg *);
-int nouveau_mem_vram(struct ttm_mem_reg *, bool contig, u8 page);
-int nouveau_mem_host(struct ttm_mem_reg *, struct ttm_dma_tt *);
+                   struct ttm_resource *);
+void nouveau_mem_del(struct ttm_resource *);
+int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page);
+int nouveau_mem_host(struct ttm_resource *, struct ttm_dma_tt *);
 void nouveau_mem_fini(struct nouveau_mem *);
 int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *);
 #endif
index c3ccf66..eef75c5 100644 (file)
@@ -26,7 +26,7 @@ nouveau_sgdma_destroy(struct ttm_tt *ttm)
 }
 
 static int
-nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg)
+nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg)
 {
        struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
        struct nouveau_mem *mem = nouveau_mem(reg);
@@ -60,7 +60,7 @@ static struct ttm_backend_func nv04_sgdma_backend = {
 };
 
 static int
-nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg)
+nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg)
 {
        struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
        struct nouveau_mem *mem = nouveau_mem(reg);
index e89ea05..53c6f88 100644 (file)
 
 #include <core/tegra.h>
 
-static int
-nouveau_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
-{
-       return 0;
-}
-
-static int
-nouveau_manager_fini(struct ttm_mem_type_manager *man)
-{
-       return 0;
-}
-
 static void
-nouveau_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *reg)
+nouveau_manager_del(struct ttm_resource_manager *man, struct ttm_resource *reg)
 {
        nouveau_mem_del(reg);
 }
 
-static void
-nouveau_manager_debug(struct ttm_mem_type_manager *man,
-                     struct drm_printer *printer)
-{
-}
-
 static int
-nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
+nouveau_vram_manager_new(struct ttm_resource_manager *man,
                         struct ttm_buffer_object *bo,
                         const struct ttm_place *place,
-                        struct ttm_mem_reg *reg)
+                        struct ttm_resource *reg)
 {
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -81,19 +63,16 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
        return 0;
 }
 
-const struct ttm_mem_type_manager_func nouveau_vram_manager = {
-       .init = nouveau_manager_init,
-       .takedown = nouveau_manager_fini,
-       .get_node = nouveau_vram_manager_new,
-       .put_node = nouveau_manager_del,
-       .debug = nouveau_manager_debug,
+const struct ttm_resource_manager_func nouveau_vram_manager = {
+       .alloc = nouveau_vram_manager_new,
+       .free = nouveau_manager_del,
 };
 
 static int
-nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
+nouveau_gart_manager_new(struct ttm_resource_manager *man,
                         struct ttm_buffer_object *bo,
                         const struct ttm_place *place,
-                        struct ttm_mem_reg *reg)
+                        struct ttm_resource *reg)
 {
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -107,19 +86,16 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
        return 0;
 }
 
-const struct ttm_mem_type_manager_func nouveau_gart_manager = {
-       .init = nouveau_manager_init,
-       .takedown = nouveau_manager_fini,
-       .get_node = nouveau_gart_manager_new,
-       .put_node = nouveau_manager_del,
-       .debug = nouveau_manager_debug
+const struct ttm_resource_manager_func nouveau_gart_manager = {
+       .alloc = nouveau_gart_manager_new,
+       .free = nouveau_manager_del,
 };
 
 static int
-nv04_gart_manager_new(struct ttm_mem_type_manager *man,
+nv04_gart_manager_new(struct ttm_resource_manager *man,
                      struct ttm_buffer_object *bo,
                      const struct ttm_place *place,
-                     struct ttm_mem_reg *reg)
+                     struct ttm_resource *reg)
 {
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@@ -142,12 +118,9 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man,
        return 0;
 }
 
-const struct ttm_mem_type_manager_func nv04_gart_manager = {
-       .init = nouveau_manager_init,
-       .takedown = nouveau_manager_fini,
-       .get_node = nv04_gart_manager_new,
-       .put_node = nouveau_manager_del,
-       .debug = nouveau_manager_debug
+const struct ttm_resource_manager_func nv04_gart_manager = {
+       .alloc = nv04_gart_manager_new,
+       .free = nouveau_manager_del,
 };
 
 int
@@ -180,6 +153,113 @@ nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind)
        return 0;
 }
 
+static int
+nouveau_ttm_init_vram(struct nouveau_drm *drm)
+{
+       struct nvif_mmu *mmu = &drm->client.mmu;
+       if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
+               /* Some BARs do not support being ioremapped WC */
+               const u8 type = mmu->type[drm->ttm.type_vram].type;
+               struct ttm_resource_manager *man = kzalloc(sizeof(*man), GFP_KERNEL);
+               if (!man)
+                       return -ENOMEM;
+
+               man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+               man->default_caching = TTM_PL_FLAG_WC;
+
+               if (type & NVIF_MEM_UNCACHED) {
+                       man->available_caching = TTM_PL_FLAG_UNCACHED;
+                       man->default_caching = TTM_PL_FLAG_UNCACHED;
+               }
+
+               man->func = &nouveau_vram_manager;
+               man->use_io_reserve_lru = true;
+
+               ttm_resource_manager_init(man,
+                                         drm->gem.vram_available >> PAGE_SHIFT);
+               ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man);
+               ttm_resource_manager_set_used(man, true);
+               return 0;
+       } else {
+               return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_VRAM,
+                                         TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC,
+                                         TTM_PL_FLAG_WC, false,
+                                         drm->gem.vram_available >> PAGE_SHIFT);
+       }
+}
+
+static void
+nouveau_ttm_fini_vram(struct nouveau_drm *drm)
+{
+       struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM);
+
+       if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
+               ttm_resource_manager_set_used(man, false);
+               ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man);
+               ttm_resource_manager_cleanup(man);
+               ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, NULL);
+               kfree(man);
+       } else
+               ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_VRAM);
+}
+
+static int
+nouveau_ttm_init_gtt(struct nouveau_drm *drm)
+{
+       struct ttm_resource_manager *man;
+       unsigned long size_pages = drm->gem.gart_available >> PAGE_SHIFT;
+       unsigned available_caching, default_caching;
+       const struct ttm_resource_manager_func *func = NULL;
+       if (drm->agp.bridge) {
+               available_caching = TTM_PL_FLAG_UNCACHED |
+                       TTM_PL_FLAG_WC;
+               default_caching = TTM_PL_FLAG_WC;
+       } else {
+               available_caching = TTM_PL_MASK_CACHING;
+               default_caching = TTM_PL_FLAG_CACHED;
+       }
+
+       if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
+               func = &nouveau_gart_manager;
+       else if (!drm->agp.bridge)
+               func = &nv04_gart_manager;
+       else
+               return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_TT,
+                                         available_caching, default_caching,
+                                         true,
+                                         size_pages);
+
+       man = kzalloc(sizeof(*man), GFP_KERNEL);
+       if (!man)
+               return -ENOMEM;
+
+       man->func = func;
+       man->available_caching = available_caching;
+       man->default_caching = default_caching;
+       man->use_tt = true;
+       ttm_resource_manager_init(man, size_pages);
+       ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man);
+       ttm_resource_manager_set_used(man, true);
+       return 0;
+}
+
+static void
+nouveau_ttm_fini_gtt(struct nouveau_drm *drm)
+{
+       struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_TT);
+
+       if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA &&
+           drm->agp.bridge)
+               ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_TT);
+       else {
+               ttm_resource_manager_set_used(man, false);
+               ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man);
+               ttm_resource_manager_cleanup(man);
+               ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, NULL);
+               kfree(man);
+       }
+}
+
 int
 nouveau_ttm_init(struct nouveau_drm *drm)
 {
@@ -237,8 +317,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
        arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1),
                                   device->func->resource_size(device, 1));
 
-       ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
-                             drm->gem.vram_available >> PAGE_SHIFT);
+       ret = nouveau_ttm_init_vram(drm);
        if (ret) {
                NV_ERROR(drm, "VRAM mm init failed, %d\n", ret);
                return ret;
@@ -254,8 +333,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
                drm->gem.gart_available = drm->agp.size;
        }
 
-       ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT,
-                             drm->gem.gart_available >> PAGE_SHIFT);
+       ret = nouveau_ttm_init_gtt(drm);
        if (ret) {
                NV_ERROR(drm, "GART mm init failed, %d\n", ret);
                return ret;
@@ -271,8 +349,8 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
 {
        struct nvkm_device *device = nvxx_device(&drm->client.device);
 
-       ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
-       ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
+       nouveau_ttm_fini_vram(drm);
+       nouveau_ttm_fini_gtt(drm);
 
        ttm_bo_device_release(&drm->ttm.bdev);
 
index 0852807..eaf2546 100644 (file)
@@ -8,9 +8,9 @@ nouveau_bdev(struct ttm_bo_device *bd)
        return container_of(bd, struct nouveau_drm, ttm.bdev);
 }
 
-extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
-extern const struct ttm_mem_type_manager_func nouveau_gart_manager;
-extern const struct ttm_mem_type_manager_func nv04_gart_manager;
+extern const struct ttm_resource_manager_func nouveau_vram_manager;
+extern const struct ttm_resource_manager_func nouveau_gart_manager;
+extern const struct ttm_resource_manager_func nv04_gart_manager;
 
 struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo,
                                        u32 page_flags);
index cd1e87a..6b697ee 100644 (file)
@@ -78,7 +78,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
 {
        struct nv10_fence_priv *priv = chan->drm->fence;
        struct nv10_fence_chan *fctx;
-       struct ttm_mem_reg *reg = &priv->bo->bo.mem;
+       struct ttm_resource *reg = &priv->bo->bo.mem;
        u32 start = reg->start * PAGE_SIZE;
        u32 limit = start + reg->size - 1;
        int ret = 0;
index ebb7406..49b46f5 100644 (file)
@@ -37,7 +37,7 @@ nv50_fence_context_new(struct nouveau_channel *chan)
 {
        struct nv10_fence_priv *priv = chan->drm->fence;
        struct nv10_fence_chan *fctx;
-       struct ttm_mem_reg *reg = &priv->bo->bo.mem;
+       struct ttm_resource *reg = &priv->bo->bo.mem;
        u32 start = reg->start * PAGE_SIZE;
        u32 limit = start + reg->size - 1;
        int ret;
index 4526967..53d5e18 100644 (file)
@@ -349,13 +349,6 @@ static int omap_modeset_init(struct drm_device *dev)
 
                drm_connector_attach_encoder(pipe->connector, encoder);
 
-               if (pipe->output->panel) {
-                       ret = drm_panel_attach(pipe->output->panel,
-                                              pipe->connector);
-                       if (ret < 0)
-                               return ret;
-               }
-
                crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
                if (IS_ERR(crtc))
                        return PTR_ERR(crtc);
@@ -394,18 +387,8 @@ static int omap_modeset_init(struct drm_device *dev)
 
 static void omap_modeset_fini(struct drm_device *ddev)
 {
-       struct omap_drm_private *priv = ddev->dev_private;
-       unsigned int i;
-
        omap_drm_irq_uninstall(ddev);
 
-       for (i = 0; i < priv->num_pipes; i++) {
-               struct omap_drm_pipeline *pipe = &priv->pipes[i];
-
-               if (pipe->output->panel)
-                       drm_panel_detach(pipe->output->panel);
-       }
-
        drm_mode_config_cleanup(ddev);
 }
 
index 47b37fe..abb0788 100644 (file)
@@ -349,7 +349,9 @@ static int versatile_panel_probe(struct platform_device *pdev)
        drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&vpanel->panel);
+       drm_panel_add(&vpanel->panel);
+
+       return 0;
 }
 
 static const struct of_device_id versatile_panel_match[] = {
index 9a5b764..e95bc9f 100644 (file)
@@ -315,11 +315,7 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi)
                return ret;
        }
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0) {
-               dev_err(dev, "Failed to add panel: %d\n", ret);
-               return ret;
-       }
+       drm_panel_add(&ctx->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0) {
index 7c27bd5..d676b4c 100644 (file)
@@ -895,7 +895,9 @@ static int panel_add(struct panel_info *pinfo)
        if (ret)
                return ret;
 
-       return drm_panel_add(&pinfo->base);
+       drm_panel_add(&pinfo->base);
+
+       return 0;
 }
 
 static int panel_probe(struct mipi_dsi_device *dsi)
index e320aa3..c9729fd 100644 (file)
@@ -787,7 +787,9 @@ static int boe_panel_add(struct boe_panel *boe)
        boe->base.funcs = &boe_panel_funcs;
        boe->base.dev = &boe->dsi->dev;
 
-       return drm_panel_add(&boe->base);
+       drm_panel_add(&boe->base);
+
+       return 0;
 }
 
 static int boe_panel_probe(struct mipi_dsi_device *dsi)
index 5461065..0b7e82e 100644 (file)
@@ -477,9 +477,7 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&ctx->panel);
 
        dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
        dsi->format = MIPI_DSI_FMT_RGB888;
index 19a6274..f9edee6 100644 (file)
@@ -224,9 +224,7 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&ctx->panel);
 
        dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;
        dsi->format = MIPI_DSI_FMT_RGB888;
index 67a64d1..9688458 100644 (file)
@@ -892,7 +892,9 @@ static int ili9322_probe(struct spi_device *spi)
        drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&ili->panel);
+       drm_panel_add(&ili->panel);
+
+       return 0;
 }
 
 static int ili9322_remove(struct spi_device *spi)
index 3ed8635..066ef6c 100644 (file)
@@ -446,9 +446,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&ctx->panel);
 
        dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
        dsi->format = MIPI_DSI_FMT_RGB888;
index fdf030f..1a8e69c 100644 (file)
@@ -475,9 +475,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi,
        if (err)
                return err;
 
-       err = drm_panel_add(&innolux->base);
-       if (err < 0)
-               return err;
+       drm_panel_add(&innolux->base);
 
        mipi_dsi_set_drvdata(dsi, innolux);
        innolux->link = dsi;
index 1e3fd66..733010b 100644 (file)
@@ -440,9 +440,9 @@ static int jdi_panel_add(struct jdi_panel *jdi)
        drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
                       DRM_MODE_CONNECTOR_DSI);
 
-       ret = drm_panel_add(&jdi->base);
+       drm_panel_add(&jdi->base);
 
-       return ret;
+       return 0;
 }
 
 static void jdi_panel_del(struct jdi_panel *jdi)
index 0d397af..f42dc2c 100644 (file)
@@ -382,7 +382,9 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
        if (err)
                return err;
 
-       return drm_panel_add(&kingdisplay->base);
+       drm_panel_add(&kingdisplay->base);
+
+       return 0;
 }
 
 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
index 14456b9..f3183b6 100644 (file)
@@ -198,7 +198,9 @@ static int lb035q02_probe(struct spi_device *spi)
        drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&lcd->panel);
+       drm_panel_add(&lcd->panel);
+
+       return 0;
 }
 
 static int lb035q02_remove(struct spi_device *spi)
index aedc485..8e5160a 100644 (file)
@@ -261,7 +261,9 @@ static int lg4573_probe(struct spi_device *spi)
        drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&ctx->panel);
+       drm_panel_add(&ctx->panel);
+
+       return 0;
 }
 
 static int lg4573_remove(struct spi_device *spi)
index 5ce3f4a..41305c3 100644 (file)
@@ -227,9 +227,7 @@ static int panel_lvds_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&lvds->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&lvds->panel);
 
        dev_set_drvdata(lvds->dev, lvds);
        return 0;
index f894971..6e5ab1d 100644 (file)
@@ -207,7 +207,9 @@ static int nl8048_probe(struct spi_device *spi)
        drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&lcd->panel);
+       drm_panel_add(&lcd->panel);
+
+       return 0;
 }
 
 static int nl8048_remove(struct spi_device *spi)
index e98d54d..64c8cf2 100644 (file)
@@ -376,6 +376,10 @@ struct nt35510 {
 };
 
 /* Manufacturer command has strictly this byte sequence */
+static const u8 nt35510_mauc_mtp_read_param[] = { 0xAA, 0x55, 0x25, 0x01 };
+static const u8 nt35510_mauc_mtp_read_setting[] = { 0x01, 0x02, 0x00, 0x20,
+                                                   0x33, 0x13, 0x00, 0x40,
+                                                   0x00, 0x00, 0x23, 0x02 };
 static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 };
 static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 };
 static const u8 nt35510_vgh_on[] = { 0x01 };
@@ -698,6 +702,18 @@ static int nt35510_power_on(struct nt35510 *nt)
                usleep_range(120000, 140000);
        }
 
+       ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_PARAM,
+                               ARRAY_SIZE(nt35510_mauc_mtp_read_param),
+                               nt35510_mauc_mtp_read_param);
+       if (ret)
+               return ret;
+
+       ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_SETTING,
+                               ARRAY_SIZE(nt35510_mauc_mtp_read_setting),
+                               nt35510_mauc_mtp_read_setting);
+       if (ret)
+               return ret;
+
        ret = nt35510_read_id(nt);
        if (ret)
                return ret;
@@ -956,9 +972,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi)
                nt->panel.backlight = bl;
        }
 
-       ret = drm_panel_add(&nt->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&nt->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0)
index 91df050..3d15d99 100644 (file)
@@ -303,11 +303,7 @@ static int nt39016_probe(struct spi_device *spi)
        drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       err = drm_panel_add(&panel->drm_panel);
-       if (err < 0) {
-               dev_err(dev, "Failed to register panel");
-               return err;
-       }
+       drm_panel_add(&panel->drm_panel);
 
        return 0;
 }
index ecd76b5..cb5cb27 100644 (file)
@@ -283,7 +283,9 @@ static int lcd_olinuxino_probe(struct i2c_client *client,
        if (ret)
                return ret;
 
-       return drm_panel_add(&lcd->panel);
+       drm_panel_add(&lcd->panel);
+
+       return 0;
 }
 
 static int lcd_olinuxino_remove(struct i2c_client *client)
index 83e5aa4..45b975d 100644 (file)
@@ -164,7 +164,9 @@ static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587)
        if (ret)
                return ret;
 
-       return drm_panel_add(&osd101t2587->base);
+       drm_panel_add(&osd101t2587->base);
+
+       return 0;
 }
 
 static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi)
index 627dfcf..3c20bee 100644 (file)
@@ -206,7 +206,9 @@ static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
        if (ret)
                return ret;
 
-       return drm_panel_add(&wuxga_nt->base);
+       drm_panel_add(&wuxga_nt->base);
+
+       return 0;
 }
 
 static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
index e50ee26..5e9ccef 100644 (file)
@@ -361,7 +361,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
        struct rpi_touchscreen *ts;
        struct device_node *endpoint, *dsi_host_node;
        struct mipi_dsi_host *host;
-       int ret, ver;
+       int ver;
        struct mipi_dsi_device_info info = {
                .type = RPI_DSI_DRIVER_NAME,
                .channel = 0,
@@ -429,9 +429,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c,
        /* This appears last, as it's what will unblock the DSI host
         * driver's component bind function.
         */
-       ret = drm_panel_add(&ts->base);
-       if (ret)
-               return ret;
+       drm_panel_add(&ts->base);
 
        return 0;
 
index 57ff2b1..2ef3225 100644 (file)
@@ -609,9 +609,7 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi)
                       DRM_MODE_CONNECTOR_DSI);
        dev_set_drvdata(dev, panel);
 
-       ret = drm_panel_add(&panel->panel);
-       if (ret)
-               return ret;
+       drm_panel_add(&panel->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret)
index a7b0b3e..ea74958 100644 (file)
@@ -200,9 +200,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&ctx->panel);
 
        dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
        dsi->format = MIPI_DSI_FMT_RGB888;
index 9bb2e8c..358168e 100644 (file)
@@ -354,7 +354,9 @@ static int ld9040_probe(struct spi_device *spi)
        drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&ctx->panel);
+       drm_panel_add(&ctx->panel);
+
+       return 0;
 }
 
 static int ld9040_remove(struct spi_device *spi)
index f02645d..e88af6f 100644 (file)
@@ -212,9 +212,7 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi)
        drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs,
                       DRM_MODE_CONNECTOR_DSI);
 
-       ret = drm_panel_add(&s6->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&s6->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0)
index 80ef122..2c84036 100644 (file)
@@ -733,9 +733,7 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
        drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs,
                       DRM_MODE_CONNECTOR_DSI);
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               goto unregister_backlight;
+       drm_panel_add(&ctx->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0)
@@ -745,8 +743,6 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
 
 remove_panel:
        drm_panel_remove(&ctx->panel);
-
-unregister_backlight:
        backlight_device_unregister(ctx->bl_dev);
 
        return ret;
index 1247656..7a43eb3 100644 (file)
@@ -479,9 +479,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
        ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS;
        ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               goto unregister_backlight;
+       drm_panel_add(&ctx->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0)
@@ -491,8 +489,6 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
 
 remove_panel:
        drm_panel_remove(&ctx->panel);
-
-unregister_backlight:
        backlight_device_unregister(ctx->bl_dev);
 
        return ret;
index 6442134..e086efe 100644 (file)
@@ -479,7 +479,9 @@ static int s6e63m0_probe(struct spi_device *spi)
        if (ret < 0)
                return ret;
 
-       return drm_panel_add(&ctx->panel);
+       drm_panel_add(&ctx->panel);
+
+       return 0;
 }
 
 static int s6e63m0_remove(struct spi_device *spi)
index 485eabe..ea63799 100644 (file)
@@ -242,11 +242,7 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi)
        drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs,
                       DRM_MODE_CONNECTOR_DSI);
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0) {
-               dev_err(dev, "Failed to add panel: %d\n", ret);
-               return ret;
-       }
+       drm_panel_add(&ctx->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0) {
index 8a028d2..e36cb1a 100644 (file)
@@ -1020,9 +1020,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
        drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs,
                       DRM_MODE_CONNECTOR_DSI);
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&ctx->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0)
index e417dc4..0ee5085 100644 (file)
@@ -258,9 +258,7 @@ static int seiko_panel_probe(struct device *dev,
        if (err)
                return err;
 
-       err = drm_panel_add(&panel->base);
-       if (err < 0)
-               return err;
+       drm_panel_add(&panel->base);
 
        dev_set_drvdata(dev, panel);
 
index f07324b..f8cd2a4 100644 (file)
@@ -325,7 +325,9 @@ static int sharp_panel_add(struct sharp_panel *sharp)
        if (ret)
                return ret;
 
-       return drm_panel_add(&sharp->base);
+       drm_panel_add(&sharp->base);
+
+       return 0;
 }
 
 static void sharp_panel_del(struct sharp_panel *sharp)
index d7bf13b..94992f4 100644 (file)
@@ -187,7 +187,9 @@ static int ls037v7dw01_probe(struct platform_device *pdev)
        drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       return drm_panel_add(&lcd->panel);
+       drm_panel_add(&lcd->panel);
+
+       return 0;
 }
 
 static int ls037v7dw01_remove(struct platform_device *pdev)
index b2e5893..16dbf0f 100644 (file)
@@ -261,7 +261,9 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
        if (ret)
                return ret;
 
-       return drm_panel_add(&sharp_nt->base);
+       drm_panel_add(&sharp_nt->base);
+
+       return 0;
 }
 
 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
index cb6550d..ef8df83 100644 (file)
@@ -500,6 +500,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
        struct panel_simple *panel;
        struct display_timing dt;
        struct device_node *ddc;
+       int connector_type;
+       u32 bus_flags;
        int err;
 
        panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
@@ -549,8 +551,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
                        panel_simple_parse_panel_timing_node(dev, panel, &dt);
        }
 
-       if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-               /* Catch common mistakes for LVDS panels. */
+       connector_type = desc->connector_type;
+       /* Catch common mistakes for panels. */
+       switch (connector_type) {
+       case 0:
+               dev_warn(dev, "Specify missing connector_type\n");
+               connector_type = DRM_MODE_CONNECTOR_DPI;
+               break;
+       case DRM_MODE_CONNECTOR_LVDS:
                WARN_ON(desc->bus_flags &
                        ~(DRM_BUS_FLAG_DE_LOW |
                          DRM_BUS_FLAG_DE_HIGH |
@@ -564,18 +572,48 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
                WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG ||
                         desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) &&
                        desc->bpc != 8);
+               break;
+       case DRM_MODE_CONNECTOR_eDP:
+               if (desc->bus_format == 0)
+                       dev_warn(dev, "Specify missing bus_format\n");
+               if (desc->bpc != 6 && desc->bpc != 8)
+                       dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
+               break;
+       case DRM_MODE_CONNECTOR_DSI:
+               if (desc->bpc != 6 && desc->bpc != 8)
+                       dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
+               break;
+       case DRM_MODE_CONNECTOR_DPI:
+               bus_flags = DRM_BUS_FLAG_DE_LOW |
+                           DRM_BUS_FLAG_DE_HIGH |
+                           DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+                           DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+                           DRM_BUS_FLAG_DATA_MSB_TO_LSB |
+                           DRM_BUS_FLAG_DATA_LSB_TO_MSB |
+                           DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE |
+                           DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE;
+               if (desc->bus_flags & ~bus_flags)
+                       dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags);
+               if (!(desc->bus_flags & bus_flags))
+                       dev_warn(dev, "Specify missing bus_flags\n");
+               if (desc->bus_format == 0)
+                       dev_warn(dev, "Specify missing bus_format\n");
+               if (desc->bpc != 6 && desc->bpc != 8)
+                       dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
+               break;
+       default:
+               dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type);
+               connector_type = DRM_MODE_CONNECTOR_DPI;
+               break;
        }
 
-       drm_panel_init(&panel->base, dev, &panel_simple_funcs,
-                      desc->connector_type);
+       drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type);
 
        err = drm_panel_of_backlight(&panel->base);
        if (err)
                goto free_ddc;
 
-       err = drm_panel_add(&panel->base);
-       if (err < 0)
-               goto free_ddc;
+       drm_panel_add(&panel->base);
 
        dev_set_drvdata(dev, panel);
 
@@ -1191,10 +1229,14 @@ static const struct drm_display_mode boe_hv070wsa_mode = {
 static const struct panel_desc boe_hv070wsa = {
        .modes = &boe_hv070wsa_mode,
        .num_modes = 1,
+       .bpc = 8,
        .size = {
                .width = 154,
                .height = 90,
        },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+       .connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
 static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
@@ -1414,6 +1456,36 @@ static const struct panel_desc cdtech_s070wv95_ct16 = {
        },
 };
 
+static const struct display_timing chefree_ch101olhlwh_002_timing = {
+       .pixelclock = { 68900000, 71100000, 73400000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 65, 80, 95 },
+       .hback_porch = { 64, 79, 94 },
+       .hsync_len = { 1, 1, 1 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 7, 11, 14 },
+       .vback_porch = { 7, 11, 14 },
+       .vsync_len = { 1, 1, 1 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc chefree_ch101olhlwh_002 = {
+       .timings = &chefree_ch101olhlwh_002_timing,
+       .num_timings = 1,
+       .bpc = 8,
+       .size = {
+               .width = 217,
+               .height = 135,
+       },
+       .delay = {
+               .enable = 200,
+               .disable = 200,
+       },
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+       .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
 static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
        .clock = 66770,
        .hdisplay = 800,
@@ -3000,6 +3072,31 @@ static const struct panel_desc pda_91_00156_a0  = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
+static const struct drm_display_mode powertip_ph800480t013_idf02_mode = {
+       .clock = 24750,
+       .hdisplay = 800,
+       .hsync_start = 800 + 54,
+       .hsync_end = 800 + 54 + 2,
+       .htotal = 800 + 54 + 2 + 44,
+       .vdisplay = 480,
+       .vsync_start = 480 + 49,
+       .vsync_end = 480 + 49 + 2,
+       .vtotal = 480 + 49 + 2 + 22,
+};
+
+static const struct panel_desc powertip_ph800480t013_idf02  = {
+       .modes = &powertip_ph800480t013_idf02_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 152,
+               .height = 91,
+       },
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH |
+                    DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+                    DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+       .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
 
 static const struct drm_display_mode qd43003c0_40_mode = {
        .clock = 9000,
@@ -3820,6 +3917,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "cdtech,s070wv95-ct16",
                .data = &cdtech_s070wv95_ct16,
+       }, {
+               .compatible = "chefree,ch101olhlwh-002",
+               .data = &chefree_ch101olhlwh_002,
        }, {
                .compatible = "chunghwa,claa070wp03xg",
                .data = &chunghwa_claa070wp03xg,
@@ -4012,6 +4112,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "pda,91-00156-a0",
                .data = &pda_91_00156_a0,
+       }, {
+               .compatible = "powertip,ph800480t013-idf02",
+               .data = &powertip_ph800480t013_idf02,
        }, {
                .compatible = "qiaodian,qd43003c0-40",
                .data = &qd43003c0_40,
index 692041a..1246211 100644 (file)
@@ -380,9 +380,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&st7701->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&st7701->panel);
 
        mipi_dsi_set_drvdata(dsi, st7701);
        st7701->dsi = dsi;
index 3513ae4..61e5655 100644 (file)
@@ -382,9 +382,7 @@ static int st7789v_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       ret = drm_panel_add(&ctx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&ctx->panel);
 
        return 0;
 }
index 97a1b47..57575c4 100644 (file)
@@ -504,9 +504,7 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi)
        acx->bl->props.brightness = 512;
        acx->bl->props.power = FB_BLANK_POWERDOWN;
 
-       ret = drm_panel_add(&acx->panel);
-       if (ret < 0)
-               return ret;
+       drm_panel_add(&acx->panel);
 
        ret = mipi_dsi_attach(dsi);
        if (ret < 0) {
index fc6a7e4..e95fdfb 100644 (file)
@@ -650,12 +650,7 @@ static int acx565akm_probe(struct spi_device *spi)
        drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       ret = drm_panel_add(&lcd->panel);
-       if (ret < 0) {
-               if (lcd->has_bc)
-                       acx565akm_backlight_cleanup(lcd);
-               return ret;
-       }
+       drm_panel_add(&lcd->panel);
 
        return 0;
 }
index 58d683c..037c14f 100644 (file)
@@ -350,7 +350,9 @@ static int td028ttec1_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       return drm_panel_add(&lcd->panel);
+       drm_panel_add(&lcd->panel);
+
+       return 0;
 }
 
 static int td028ttec1_remove(struct spi_device *spi)
index 9b2a356..49e6c93 100644 (file)
@@ -460,11 +460,7 @@ static int td043mtea1_probe(struct spi_device *spi)
        drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs,
                       DRM_MODE_CONNECTOR_DPI);
 
-       ret = drm_panel_add(&lcd->panel);
-       if (ret < 0) {
-               sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group);
-               return ret;
-       }
+       drm_panel_add(&lcd->panel);
 
        return 0;
 }
index c7a2f0a..cd00cfa 100644 (file)
@@ -448,7 +448,9 @@ static int tpg110_probe(struct spi_device *spi)
 
        spi_set_drvdata(spi, tpg);
 
-       return drm_panel_add(&tpg->panel);
+       drm_panel_add(&tpg->panel);
+
+       return 0;
 }
 
 static int tpg110_remove(struct spi_device *spi)
index 4139870..8ab025d 100644 (file)
@@ -1,20 +1,29 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright 2019 Collabora ltd. */
+
+#include <linux/clk.h>
 #include <linux/devfreq.h>
 #include <linux/devfreq_cooling.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
 
 #include "panfrost_device.h"
 #include "panfrost_devfreq.h"
-#include "panfrost_features.h"
-#include "panfrost_issues.h"
-#include "panfrost_gpu.h"
-#include "panfrost_regs.h"
 
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev);
+static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq)
+{
+       ktime_t now, last;
+
+       now = ktime_get();
+       last = pfdevfreq->time_last_update;
+
+       if (pfdevfreq->busy_count > 0)
+               pfdevfreq->busy_time += ktime_sub(now, last);
+       else
+               pfdevfreq->idle_time += ktime_sub(now, last);
+
+       pfdevfreq->time_last_update = now;
+}
 
 static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
                                   u32 flags)
@@ -34,30 +43,37 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq,
        return 0;
 }
 
-static void panfrost_devfreq_reset(struct panfrost_device *pfdev)
+static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq)
 {
-       pfdev->devfreq.busy_time = 0;
-       pfdev->devfreq.idle_time = 0;
-       pfdev->devfreq.time_last_update = ktime_get();
+       pfdevfreq->busy_time = 0;
+       pfdevfreq->idle_time = 0;
+       pfdevfreq->time_last_update = ktime_get();
 }
 
 static int panfrost_devfreq_get_dev_status(struct device *dev,
                                           struct devfreq_dev_status *status)
 {
        struct panfrost_device *pfdev = dev_get_drvdata(dev);
-
-       panfrost_devfreq_update_utilization(pfdev);
+       struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+       unsigned long irqflags;
 
        status->current_frequency = clk_get_rate(pfdev->clock);
-       status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time,
-                                                  pfdev->devfreq.idle_time));
 
-       status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time);
+       spin_lock_irqsave(&pfdevfreq->lock, irqflags);
+
+       panfrost_devfreq_update_utilization(pfdevfreq);
+
+       status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time,
+                                                  pfdevfreq->idle_time));
+
+       status->busy_time = ktime_to_ns(pfdevfreq->busy_time);
+
+       panfrost_devfreq_reset(pfdevfreq);
 
-       panfrost_devfreq_reset(pfdev);
+       spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
 
-       dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time,
-               status->total_time,
+       dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
+               status->busy_time, status->total_time,
                status->busy_time / (status->total_time / 100),
                status->current_frequency / 1000 / 1000);
 
@@ -77,21 +93,43 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
        unsigned long cur_freq;
        struct device *dev = &pfdev->pdev->dev;
        struct devfreq *devfreq;
+       struct opp_table *opp_table;
        struct thermal_cooling_device *cooling;
+       struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+       opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
+                                             pfdev->comp->num_supplies);
+       if (IS_ERR(opp_table)) {
+               ret = PTR_ERR(opp_table);
+               /* Continue if the optional regulator is missing */
+               if (ret != -ENODEV) {
+                       DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
+                       goto err_fini;
+               }
+       } else {
+               pfdevfreq->regulators_opp_table = opp_table;
+       }
 
        ret = dev_pm_opp_of_add_table(dev);
-       if (ret == -ENODEV) /* Optional, continue without devfreq */
-               return 0;
-       else if (ret)
-               return ret;
+       if (ret) {
+               /* Optional, continue without devfreq */
+               if (ret == -ENODEV)
+                       ret = 0;
+               goto err_fini;
+       }
+       pfdevfreq->opp_of_table_added = true;
+
+       spin_lock_init(&pfdevfreq->lock);
 
-       panfrost_devfreq_reset(pfdev);
+       panfrost_devfreq_reset(pfdevfreq);
 
        cur_freq = clk_get_rate(pfdev->clock);
 
        opp = devfreq_recommended_opp(dev, &cur_freq, 0);
-       if (IS_ERR(opp))
-               return PTR_ERR(opp);
+       if (IS_ERR(opp)) {
+               ret = PTR_ERR(opp);
+               goto err_fini;
+       }
 
        panfrost_devfreq_profile.initial_freq = cur_freq;
        dev_pm_opp_put(opp);
@@ -100,75 +138,94 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
                                          DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
        if (IS_ERR(devfreq)) {
                DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
-               dev_pm_opp_of_remove_table(dev);
-               return PTR_ERR(devfreq);
+               ret = PTR_ERR(devfreq);
+               goto err_fini;
        }
-       pfdev->devfreq.devfreq = devfreq;
+       pfdevfreq->devfreq = devfreq;
 
        cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
        if (IS_ERR(cooling))
                DRM_DEV_INFO(dev, "Failed to register cooling device\n");
        else
-               pfdev->devfreq.cooling = cooling;
+               pfdevfreq->cooling = cooling;
 
        return 0;
+
+err_fini:
+       panfrost_devfreq_fini(pfdev);
+       return ret;
 }
 
 void panfrost_devfreq_fini(struct panfrost_device *pfdev)
 {
-       if (pfdev->devfreq.cooling)
-               devfreq_cooling_unregister(pfdev->devfreq.cooling);
-       dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
+       struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+       if (pfdevfreq->cooling) {
+               devfreq_cooling_unregister(pfdevfreq->cooling);
+               pfdevfreq->cooling = NULL;
+       }
+
+       if (pfdevfreq->opp_of_table_added) {
+               dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
+               pfdevfreq->opp_of_table_added = false;
+       }
+
+       if (pfdevfreq->regulators_opp_table) {
+               dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table);
+               pfdevfreq->regulators_opp_table = NULL;
+       }
 }
 
 void panfrost_devfreq_resume(struct panfrost_device *pfdev)
 {
-       if (!pfdev->devfreq.devfreq)
+       struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+       if (!pfdevfreq->devfreq)
                return;
 
-       panfrost_devfreq_reset(pfdev);
+       panfrost_devfreq_reset(pfdevfreq);
 
-       devfreq_resume_device(pfdev->devfreq.devfreq);
+       devfreq_resume_device(pfdevfreq->devfreq);
 }
 
 void panfrost_devfreq_suspend(struct panfrost_device *pfdev)
 {
-       if (!pfdev->devfreq.devfreq)
+       struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+
+       if (!pfdevfreq->devfreq)
                return;
 
-       devfreq_suspend_device(pfdev->devfreq.devfreq);
+       devfreq_suspend_device(pfdevfreq->devfreq);
 }
 
-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev)
+void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq)
 {
-       ktime_t now;
-       ktime_t last;
+       unsigned long irqflags;
 
-       if (!pfdev->devfreq.devfreq)
+       if (!pfdevfreq->devfreq)
                return;
 
-       now = ktime_get();
-       last = pfdev->devfreq.time_last_update;
+       spin_lock_irqsave(&pfdevfreq->lock, irqflags);
 
-       if (atomic_read(&pfdev->devfreq.busy_count) > 0)
-               pfdev->devfreq.busy_time += ktime_sub(now, last);
-       else
-               pfdev->devfreq.idle_time += ktime_sub(now, last);
+       panfrost_devfreq_update_utilization(pfdevfreq);
 
-       pfdev->devfreq.time_last_update = now;
-}
+       pfdevfreq->busy_count++;
 
-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev)
-{
-       panfrost_devfreq_update_utilization(pfdev);
-       atomic_inc(&pfdev->devfreq.busy_count);
+       spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
 }
 
-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev)
+void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq)
 {
-       int count;
+       unsigned long irqflags;
+
+       if (!pfdevfreq->devfreq)
+               return;
+
+       spin_lock_irqsave(&pfdevfreq->lock, irqflags);
+
+       panfrost_devfreq_update_utilization(pfdevfreq);
+
+       WARN_ON(--pfdevfreq->busy_count < 0);
 
-       panfrost_devfreq_update_utilization(pfdev);
-       count = atomic_dec_if_positive(&pfdev->devfreq.busy_count);
-       WARN_ON(count < 0);
+       spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
 }
index 0611bef..db6ea48 100644 (file)
@@ -4,13 +4,39 @@
 #ifndef __PANFROST_DEVFREQ_H__
 #define __PANFROST_DEVFREQ_H__
 
+#include <linux/spinlock.h>
+#include <linux/ktime.h>
+
+struct devfreq;
+struct opp_table;
+struct thermal_cooling_device;
+
+struct panfrost_device;
+
+struct panfrost_devfreq {
+       struct devfreq *devfreq;
+       struct opp_table *regulators_opp_table;
+       struct thermal_cooling_device *cooling;
+       bool opp_of_table_added;
+
+       ktime_t busy_time;
+       ktime_t idle_time;
+       ktime_t time_last_update;
+       int busy_count;
+       /*
+        * Protect busy_time, idle_time, time_last_update and busy_count
+        * because these can be updated concurrently between multiple jobs.
+        */
+       spinlock_t lock;
+};
+
 int panfrost_devfreq_init(struct panfrost_device *pfdev);
 void panfrost_devfreq_fini(struct panfrost_device *pfdev);
 
 void panfrost_devfreq_resume(struct panfrost_device *pfdev);
 void panfrost_devfreq_suspend(struct panfrost_device *pfdev);
 
-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev);
-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev);
+void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq);
+void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq);
 
 #endif /* __PANFROST_DEVFREQ_H__ */
index b172087..e689673 100644 (file)
@@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
 {
        int ret, i;
 
-       if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators),
-                       "Too many supplies in compatible structure.\n"))
-               return -EINVAL;
+       pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies,
+                                        sizeof(*pfdev->regulators),
+                                        GFP_KERNEL);
+       if (!pfdev->regulators)
+               return -ENOMEM;
 
        for (i = 0; i < pfdev->comp->num_supplies; i++)
                pfdev->regulators[i].supply = pfdev->comp->supply_names[i];
@@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
 
 static void panfrost_regulator_fini(struct panfrost_device *pfdev)
 {
-       regulator_bulk_disable(pfdev->comp->num_supplies,
-                       pfdev->regulators);
+       if (!pfdev->regulators)
+               return;
+
+       regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators);
 }
 
 static void panfrost_pm_domain_fini(struct panfrost_device *pfdev)
@@ -214,58 +218,70 @@ int panfrost_device_init(struct panfrost_device *pfdev)
                return err;
        }
 
-       err = panfrost_regulator_init(pfdev);
-       if (err)
-               goto err_out0;
+       err = panfrost_devfreq_init(pfdev);
+       if (err) {
+               if (err != -EPROBE_DEFER)
+                       dev_err(pfdev->dev, "devfreq init failed %d\n", err);
+               goto out_clk;
+       }
+
+       /* OPP will handle regulators */
+       if (!pfdev->pfdevfreq.opp_of_table_added) {
+               err = panfrost_regulator_init(pfdev);
+               if (err)
+                       goto out_devfreq;
+       }
 
        err = panfrost_reset_init(pfdev);
        if (err) {
                dev_err(pfdev->dev, "reset init failed %d\n", err);
-               goto err_out1;
+               goto out_regulator;
        }
 
        err = panfrost_pm_domain_init(pfdev);
        if (err)
-               goto err_out2;
+               goto out_reset;
 
        res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0);
        pfdev->iomem = devm_ioremap_resource(pfdev->dev, res);
        if (IS_ERR(pfdev->iomem)) {
                dev_err(pfdev->dev, "failed to ioremap iomem\n");
                err = PTR_ERR(pfdev->iomem);
-               goto err_out3;
+               goto out_pm_domain;
        }
 
        err = panfrost_gpu_init(pfdev);
        if (err)
-               goto err_out3;
+               goto out_pm_domain;
 
        err = panfrost_mmu_init(pfdev);
        if (err)
-               goto err_out4;
+               goto out_gpu;
 
        err = panfrost_job_init(pfdev);
        if (err)
-               goto err_out5;
+               goto out_mmu;
 
        err = panfrost_perfcnt_init(pfdev);
        if (err)
-               goto err_out6;
+               goto out_job;
 
        return 0;
-err_out6:
+out_job:
        panfrost_job_fini(pfdev);
-err_out5:
+out_mmu:
        panfrost_mmu_fini(pfdev);
-err_out4:
+out_gpu:
        panfrost_gpu_fini(pfdev);
-err_out3:
+out_pm_domain:
        panfrost_pm_domain_fini(pfdev);
-err_out2:
+out_reset:
        panfrost_reset_fini(pfdev);
-err_out1:
+out_regulator:
        panfrost_regulator_fini(pfdev);
-err_out0:
+out_devfreq:
+       panfrost_devfreq_fini(pfdev);
+out_clk:
        panfrost_clk_fini(pfdev);
        return err;
 }
@@ -278,6 +294,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev)
        panfrost_gpu_fini(pfdev);
        panfrost_pm_domain_fini(pfdev);
        panfrost_reset_fini(pfdev);
+       panfrost_devfreq_fini(pfdev);
        panfrost_regulator_fini(pfdev);
        panfrost_clk_fini(pfdev);
 }
index c30c719..953f753 100644 (file)
@@ -13,6 +13,8 @@
 #include <drm/drm_mm.h>
 #include <drm/gpu_scheduler.h>
 
+#include "panfrost_devfreq.h"
+
 struct panfrost_device;
 struct panfrost_mmu;
 struct panfrost_job_slot;
@@ -20,7 +22,6 @@ struct panfrost_job;
 struct panfrost_perfcnt;
 
 #define NUM_JOB_SLOTS 3
-#define MAX_REGULATORS 2
 #define MAX_PM_DOMAINS 3
 
 struct panfrost_features {
@@ -79,7 +80,7 @@ struct panfrost_device {
        void __iomem *iomem;
        struct clk *clock;
        struct clk *bus_clock;
-       struct regulator_bulk_data regulators[MAX_REGULATORS];
+       struct regulator_bulk_data *regulators;
        struct reset_control *rstc;
        /* pm_domains for devices with more than one. */
        struct device *pm_domain_devs[MAX_PM_DOMAINS];
@@ -107,14 +108,7 @@ struct panfrost_device {
        struct list_head shrinker_list;
        struct shrinker shrinker;
 
-       struct {
-               struct devfreq *devfreq;
-               struct thermal_cooling_device *cooling;
-               ktime_t busy_time;
-               ktime_t idle_time;
-               ktime_t time_last_update;
-               atomic_t busy_count;
-       } devfreq;
+       struct panfrost_devfreq pfdevfreq;
 };
 
 struct panfrost_mmu {
index ada51df..36463c8 100644 (file)
@@ -14,7 +14,6 @@
 #include <drm/drm_utils.h>
 
 #include "panfrost_device.h"
-#include "panfrost_devfreq.h"
 #include "panfrost_gem.h"
 #include "panfrost_mmu.h"
 #include "panfrost_job.h"
@@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev)
                goto err_out0;
        }
 
-       err = panfrost_devfreq_init(pfdev);
-       if (err) {
-               if (err != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "Fatal error during devfreq init\n");
-               goto err_out1;
-       }
-
        pm_runtime_set_active(pfdev->dev);
        pm_runtime_mark_last_busy(pfdev->dev);
        pm_runtime_enable(pfdev->dev);
@@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev)
         */
        err = drm_dev_register(ddev, 0);
        if (err < 0)
-               goto err_out2;
+               goto err_out1;
 
        panfrost_gem_shrinker_init(ddev);
 
        return 0;
 
-err_out2:
-       pm_runtime_disable(pfdev->dev);
-       panfrost_devfreq_fini(pfdev);
 err_out1:
+       pm_runtime_disable(pfdev->dev);
        panfrost_device_fini(pfdev);
 err_out0:
        drm_dev_put(ddev);
@@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev)
        panfrost_gem_shrinker_cleanup(ddev);
 
        pm_runtime_get_sync(pfdev->dev);
-       panfrost_devfreq_fini(pfdev);
        panfrost_device_fini(pfdev);
        pm_runtime_put_sync_suspend(pfdev->dev);
        pm_runtime_disable(pfdev->dev);
@@ -677,6 +666,7 @@ static const struct of_device_id dt_match[] = {
        { .compatible = "arm,mali-t830", .data = &default_data, },
        { .compatible = "arm,mali-t860", .data = &default_data, },
        { .compatible = "arm,mali-t880", .data = &default_data, },
+       { .compatible = "arm,mali-bifrost", .data = &default_data, },
        {}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
index f2c1ddc..e0f190e 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include "panfrost_device.h"
 #include "panfrost_features.h"
@@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev)
 
 u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev)
 {
-       if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION))
-               return gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
+       u32 flush_id;
+
+       if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) {
+               /* Flush reduction only makes sense when the GPU is kept powered on between jobs */
+               if (pm_runtime_get_if_in_use(pfdev->dev)) {
+                       flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
+                       pm_runtime_put(pfdev->dev);
+                       return flush_id;
+               }
+       }
+
        return 0;
 }
index 360146f..30e7b71 100644 (file)
@@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
        u64 jc_head = job->jc;
        int ret;
 
-       panfrost_devfreq_record_busy(pfdev);
+       panfrost_devfreq_record_busy(&pfdev->pfdevfreq);
 
        ret = pm_runtime_get_sync(pfdev->dev);
        if (ret < 0)
@@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job)
        for (i = 0; i < NUM_JOB_SLOTS; i++) {
                if (pfdev->jobs[i]) {
                        pm_runtime_put_noidle(pfdev->dev);
-                       panfrost_devfreq_record_idle(pfdev);
+                       panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
                        pfdev->jobs[i] = NULL;
                }
        }
@@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
                                pfdev->jobs[j] = NULL;
 
                                panfrost_mmu_as_put(pfdev, &job->file_priv->mmu);
-                               panfrost_devfreq_record_idle(pfdev);
+                               panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
 
                                dma_fence_signal_locked(job->done_fence);
                                pm_runtime_put_autosuspend(pfdev->dev);
@@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev)
        struct panfrost_job_slot *js = pfdev->js;
        int i;
 
-       /* Check whether the hardware is idle */
-       if (atomic_read(&pfdev->devfreq.busy_count))
-               return false;
-
        for (i = 0; i < NUM_JOB_SLOTS; i++) {
                /* If there are any jobs in the HW queue, we're not idle */
                if (atomic_read(&js->queue[i].sched.hw_rq_count))
index ec4695c..fdbc8d9 100644 (file)
@@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
 
        ret = pm_runtime_get_sync(pfdev->dev);
        if (ret < 0)
-               return ret;
+               goto err_put_pm;
 
        bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize);
-       if (IS_ERR(bo))
-               return PTR_ERR(bo);
+       if (IS_ERR(bo)) {
+               ret = PTR_ERR(bo);
+               goto err_put_pm;
+       }
 
        /* Map the perfcnt buf in the address space attached to file_priv. */
        ret = panfrost_gem_open(&bo->base, file_priv);
@@ -168,6 +170,8 @@ err_close_bo:
        panfrost_gem_close(&bo->base, file_priv);
 err_put_bo:
        drm_gem_object_put(&bo->base);
+err_put_pm:
+       pm_runtime_put(pfdev->dev);
        return ret;
 }
 
index 96e58fd..46b0d1c 100644 (file)
  */
 
 /**
- * DOC: ARM PrimeCell PL111 CLCD Driver
+ * DOC: ARM PrimeCell PL110 and PL111 CLCD Driver
  *
- * The PL111 is a simple LCD controller that can support TFT and STN
- * displays.  This driver exposes a standard KMS interface for them.
- *
- * This driver uses the same Device Tree binding as the fbdev CLCD
- * driver.  While the fbdev driver supports panels that may be
- * connected to the CLCD internally to the CLCD driver, in DRM the
- * panels get split out to drivers/gpu/drm/panels/.  This means that,
- * in converting from using fbdev to using DRM, you also need to write
- * a panel driver (which may be as simple as an entry in
- * panel-simple.c).
+ * The PL110/PL111 is a simple LCD controller that can support TFT
+ * and STN displays. This driver exposes a standard KMS interface
+ * for them.
  *
  * The driver currently doesn't expose the cursor.  The DRM API for
  * cursors requires support for 64x64 ARGB8888 cursor images, while
  * cursors.  While one could imagine trying to hack something together
  * to look at the ARGB8888 and program reasonable in monochrome, we
  * just don't expose the cursor at all instead, and leave cursor
- * support to the X11 software cursor layer.
+ * support to the application software cursor layer.
  *
  * TODO:
  *
  * - Fix race between setting plane base address and getting IRQ for
  *   vsync firing the pageflip completion.
  *
- * - Use the "max-memory-bandwidth" DT property to filter the
- *   supported formats.
- *
  * - Read back hardware state at boot to skip reprogramming the
  *   hardware when doing a no-op modeset.
  *
index 798f9dd..54e3c3a 100644 (file)
@@ -588,7 +588,7 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal
 {
        int ret;
 
-       ret = qxl_bo_reserve(surf, false);
+       ret = qxl_bo_reserve(surf);
        if (ret)
                return ret;
 
index 9691449..aae90a9 100644 (file)
@@ -350,7 +350,7 @@ int qxl_mode_dumb_mmap(struct drm_file *filp,
 int qxl_ttm_init(struct qxl_device *qdev);
 void qxl_ttm_fini(struct qxl_device *qdev);
 int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
-                          struct ttm_mem_reg *mem);
+                          struct ttm_resource *mem);
 
 /* qxl image */
 
index 8f605d5..5cea6ee 100644 (file)
@@ -322,7 +322,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
 
        qobj = gem_to_qxl_bo(gobj);
 
-       ret = qxl_bo_reserve(qobj, false);
+       ret = qxl_bo_reserve(qobj);
        if (ret)
                goto out;
 
index 80e7a17..f838b6d 100644 (file)
@@ -284,7 +284,7 @@ int qxl_bo_pin(struct qxl_bo *bo)
 {
        int r;
 
-       r = qxl_bo_reserve(bo, false);
+       r = qxl_bo_reserve(bo);
        if (r)
                return r;
 
@@ -302,7 +302,7 @@ int qxl_bo_unpin(struct qxl_bo *bo)
 {
        int r;
 
-       r = qxl_bo_reserve(bo, false);
+       r = qxl_bo_reserve(bo);
        if (r)
                return r;
 
index 21fa810..6b434e5 100644 (file)
 
 #include "qxl_drv.h"
 
-static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait)
+static inline int qxl_bo_reserve(struct qxl_bo *bo)
 {
        int r;
 
-       r = ttm_bo_reserve(&bo->tbo, true, no_wait, NULL);
+       r = ttm_bo_reserve(&bo->tbo, true, false, NULL);
        if (unlikely(r != 0)) {
                if (r != -ERESTARTSYS) {
                        struct drm_device *ddev = bo->tbo.base.dev;
index bf9dc45..dc31f3f 100644 (file)
@@ -48,31 +48,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
        return qdev;
 }
 
-static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
-                            struct ttm_mem_type_manager *man)
-{
-       switch (type) {
-       case TTM_PL_SYSTEM:
-               /* System memory */
-               man->flags = 0;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case TTM_PL_VRAM:
-       case TTM_PL_PRIV:
-               /* "On-card" video ram */
-               man->func = &ttm_bo_manager_func;
-               man->flags = TTM_MEMTYPE_FLAG_FIXED;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       default:
-               DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static void qxl_evict_flags(struct ttm_buffer_object *bo,
                                struct ttm_placement *placement)
 {
@@ -96,7 +71,7 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
 }
 
 int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
-                          struct ttm_mem_reg *mem)
+                          struct ttm_resource *mem)
 {
        struct qxl_device *qdev = qxl_get_qdev(bdev);
 
@@ -136,7 +111,7 @@ struct qxl_ttm_tt {
 };
 
 static int qxl_ttm_backend_bind(struct ttm_tt *ttm,
-                               struct ttm_mem_reg *bo_mem)
+                               struct ttm_resource *bo_mem)
 {
        struct qxl_ttm_tt *gtt = (void *)ttm;
 
@@ -188,9 +163,9 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
 }
 
 static void qxl_move_null(struct ttm_buffer_object *bo,
-                            struct ttm_mem_reg *new_mem)
+                            struct ttm_resource *new_mem)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
 
        BUG_ON(old_mem->mm_node != NULL);
        *old_mem = *new_mem;
@@ -199,9 +174,9 @@ static void qxl_move_null(struct ttm_buffer_object *bo,
 
 static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
                       struct ttm_operation_ctx *ctx,
-                      struct ttm_mem_reg *new_mem)
+                      struct ttm_resource *new_mem)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
        int ret;
 
        ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
@@ -217,7 +192,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
 
 static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
                               bool evict,
-                              struct ttm_mem_reg *new_mem)
+                              struct ttm_resource *new_mem)
 {
        struct qxl_bo *qbo;
        struct qxl_device *qdev;
@@ -233,7 +208,6 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
 
 static struct ttm_bo_driver qxl_bo_driver = {
        .ttm_tt_create = &qxl_ttm_tt_create,
-       .init_mem_type = &qxl_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = &qxl_evict_flags,
        .move = &qxl_bo_move,
@@ -241,6 +215,14 @@ static struct ttm_bo_driver qxl_bo_driver = {
        .move_notify = &qxl_bo_move_notify,
 };
 
+static int qxl_ttm_init_mem_type(struct qxl_device *qdev,
+                                unsigned int type,
+                                uint64_t size)
+{
+       return ttm_range_man_init(&qdev->mman.bdev, type, TTM_PL_MASK_CACHING,
+                                 TTM_PL_FLAG_CACHED, false, size);
+}
+
 int qxl_ttm_init(struct qxl_device *qdev)
 {
        int r;
@@ -258,14 +240,13 @@ int qxl_ttm_init(struct qxl_device *qdev)
        }
        /* NOTE: this includes the framebuffer (aka surface 0) */
        num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE;
-       r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM,
-                          num_io_pages);
+       r = qxl_ttm_init_mem_type(qdev, TTM_PL_VRAM, num_io_pages);
        if (r) {
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
        }
-       r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV,
-                          qdev->surfaceram_size / PAGE_SIZE);
+       r = qxl_ttm_init_mem_type(qdev, TTM_PL_PRIV,
+                                 qdev->surfaceram_size / PAGE_SIZE);
        if (r) {
                DRM_ERROR("Failed initializing Surfaces heap.\n");
                return r;
@@ -281,8 +262,8 @@ int qxl_ttm_init(struct qxl_device *qdev)
 
 void qxl_ttm_fini(struct qxl_device *qdev)
 {
-       ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM);
-       ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV);
+       ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_VRAM);
+       ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_PRIV);
        ttm_bo_device_release(&qdev->mman.bdev);
        DRM_INFO("qxl: ttm finalized\n");
 }
@@ -293,12 +274,10 @@ void qxl_ttm_fini(struct qxl_device *qdev)
 static int qxl_mm_dump_table(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *)m->private;
-       struct drm_mm *mm = (struct drm_mm *)node->info_ent->data;
+       struct ttm_resource_manager *man = (struct ttm_resource_manager *)node->info_ent->data;
        struct drm_printer p = drm_seq_file_printer(m);
 
-       spin_lock(&ttm_bo_glob.lru_lock);
-       drm_mm_print(mm, &p);
-       spin_unlock(&ttm_bo_glob.lru_lock);
+       ttm_resource_manager_debug(man, &p);
        return 0;
 }
 #endif
@@ -319,9 +298,9 @@ void qxl_ttm_debugfs_init(struct qxl_device *qdev)
                qxl_mem_types_list[i].show = &qxl_mm_dump_table;
                qxl_mem_types_list[i].driver_features = 0;
                if (i == 0)
-                       qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv;
+                       qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_VRAM);
                else
-                       qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV].priv;
+                       qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_PRIV);
 
        }
        qxl_debugfs_add_files(qdev, qxl_mem_types_list, i);
index b7c3fb2..cc4f58d 100644 (file)
@@ -2857,7 +2857,7 @@ int radeon_vm_clear_invalids(struct radeon_device *rdev,
                             struct radeon_vm *vm);
 int radeon_vm_bo_update(struct radeon_device *rdev,
                        struct radeon_bo_va *bo_va,
-                       struct ttm_mem_reg *mem);
+                       struct ttm_resource *mem);
 void radeon_vm_bo_invalidate(struct radeon_device *rdev,
                             struct radeon_bo *bo);
 struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
index 44157ad..7f5dfe0 100644 (file)
@@ -224,9 +224,9 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
 {
        struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_gem_info *args = data;
-       struct ttm_mem_type_manager *man;
+       struct ttm_resource_manager *man;
 
-       man = &rdev->mman.bdev.man[TTM_PL_VRAM];
+       man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM);
 
        args->vram_size = (u64)man->size << PAGE_SHIFT;
        args->vram_visible = rdev->mc.visible_vram_size;
index f3dee01..bb7582a 100644 (file)
@@ -775,7 +775,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
 
 void radeon_bo_move_notify(struct ttm_buffer_object *bo,
                           bool evict,
-                          struct ttm_mem_reg *new_mem)
+                          struct ttm_resource *new_mem)
 {
        struct radeon_bo *rbo;
 
index 60275b8..44b4724 100644 (file)
@@ -165,7 +165,7 @@ extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
                                bool force_drop);
 extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
                                  bool evict,
-                                 struct ttm_mem_reg *new_mem);
+                                 struct ttm_resource *new_mem);
 extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
 extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
index 004344d..31a06ec 100644 (file)
@@ -66,53 +66,20 @@ struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
        return rdev;
 }
 
-static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
-                               struct ttm_mem_type_manager *man)
+static int radeon_ttm_init_vram(struct radeon_device *rdev)
 {
-       struct radeon_device *rdev;
-
-       rdev = radeon_get_rdev(bdev);
+       return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_VRAM,
+                                 TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC,
+                                 TTM_PL_FLAG_WC, false,
+                                 rdev->mc.real_vram_size >> PAGE_SHIFT);
+}
 
-       switch (type) {
-       case TTM_PL_SYSTEM:
-               /* System memory */
-               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case TTM_PL_TT:
-               man->func = &ttm_bo_manager_func;
-               man->available_caching = TTM_PL_MASK_CACHING;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-#if IS_ENABLED(CONFIG_AGP)
-               if (rdev->flags & RADEON_IS_AGP) {
-                       if (!rdev->ddev->agp) {
-                               DRM_ERROR("AGP is not enabled for memory type %u\n",
-                                         (unsigned)type);
-                               return -EINVAL;
-                       }
-                       if (!rdev->ddev->agp->cant_use_aperture)
-                               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-                       man->available_caching = TTM_PL_FLAG_UNCACHED |
-                                                TTM_PL_FLAG_WC;
-                       man->default_caching = TTM_PL_FLAG_WC;
-               }
-#endif
-               break;
-       case TTM_PL_VRAM:
-               /* "On-card" video ram */
-               man->func = &ttm_bo_manager_func;
-               man->flags = TTM_MEMTYPE_FLAG_FIXED |
-                            TTM_MEMTYPE_FLAG_MAPPABLE;
-               man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
-               man->default_caching = TTM_PL_FLAG_WC;
-               break;
-       default:
-               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
-               return -EINVAL;
-       }
-       return 0;
+static int radeon_ttm_init_gtt(struct radeon_device *rdev)
+{
+       return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_TT,
+                                 TTM_PL_MASK_CACHING,
+                                 TTM_PL_FLAG_CACHED, true,
+                                 rdev->mc.gtt_size >> PAGE_SHIFT);
 }
 
 static void radeon_evict_flags(struct ttm_buffer_object *bo,
@@ -182,9 +149,9 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 }
 
 static void radeon_move_null(struct ttm_buffer_object *bo,
-                            struct ttm_mem_reg *new_mem)
+                            struct ttm_resource *new_mem)
 {
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
 
        BUG_ON(old_mem->mm_node != NULL);
        *old_mem = *new_mem;
@@ -193,8 +160,8 @@ static void radeon_move_null(struct ttm_buffer_object *bo,
 
 static int radeon_move_blit(struct ttm_buffer_object *bo,
                        bool evict, bool no_wait_gpu,
-                       struct ttm_mem_reg *new_mem,
-                       struct ttm_mem_reg *old_mem)
+                       struct ttm_resource *new_mem,
+                       struct ttm_resource *old_mem)
 {
        struct radeon_device *rdev;
        uint64_t old_start, new_start;
@@ -249,11 +216,11 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
 static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
                                bool evict, bool interruptible,
                                bool no_wait_gpu,
-                               struct ttm_mem_reg *new_mem)
+                               struct ttm_resource *new_mem)
 {
        struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
-       struct ttm_mem_reg *old_mem = &bo->mem;
-       struct ttm_mem_reg tmp_mem;
+       struct ttm_resource *old_mem = &bo->mem;
+       struct ttm_resource tmp_mem;
        struct ttm_place placements;
        struct ttm_placement placement;
        int r;
@@ -287,18 +254,18 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
        }
        r = ttm_bo_move_ttm(bo, &ctx, new_mem);
 out_cleanup:
-       ttm_bo_mem_put(bo, &tmp_mem);
+       ttm_resource_free(bo, &tmp_mem);
        return r;
 }
 
 static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
                                bool evict, bool interruptible,
                                bool no_wait_gpu,
-                               struct ttm_mem_reg *new_mem)
+                               struct ttm_resource *new_mem)
 {
        struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
-       struct ttm_mem_reg *old_mem = &bo->mem;
-       struct ttm_mem_reg tmp_mem;
+       struct ttm_resource *old_mem = &bo->mem;
+       struct ttm_resource tmp_mem;
        struct ttm_placement placement;
        struct ttm_place placements;
        int r;
@@ -325,17 +292,17 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
                goto out_cleanup;
        }
 out_cleanup:
-       ttm_bo_mem_put(bo, &tmp_mem);
+       ttm_resource_free(bo, &tmp_mem);
        return r;
 }
 
 static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
                          struct ttm_operation_ctx *ctx,
-                         struct ttm_mem_reg *new_mem)
+                         struct ttm_resource *new_mem)
 {
        struct radeon_device *rdev;
        struct radeon_bo *rbo;
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
        int r;
 
        r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
@@ -392,9 +359,8 @@ memcpy:
        return 0;
 }
 
-static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
 {
-       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
        struct radeon_device *rdev = radeon_get_rdev(bdev);
 
        mem->bus.addr = NULL;
@@ -402,8 +368,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
        mem->bus.size = mem->num_pages << PAGE_SHIFT;
        mem->bus.base = 0;
        mem->bus.is_iomem = false;
-       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
-               return -EINVAL;
+
        switch (mem->mem_type) {
        case TTM_PL_SYSTEM:
                /* system memory */
@@ -562,7 +527,7 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
 }
 
 static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
-                                  struct ttm_mem_reg *bo_mem)
+                                  struct ttm_resource *bo_mem)
 {
        struct radeon_ttm_tt *gtt = (void*)ttm;
        uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ |
@@ -760,7 +725,6 @@ static struct ttm_bo_driver radeon_bo_driver = {
        .ttm_tt_create = &radeon_ttm_tt_create,
        .ttm_tt_populate = &radeon_ttm_tt_populate,
        .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate,
-       .init_mem_type = &radeon_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = &radeon_evict_flags,
        .move = &radeon_bo_move,
@@ -785,8 +749,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
                return r;
        }
        rdev->mman.initialized = true;
-       r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM,
-                               rdev->mc.real_vram_size >> PAGE_SHIFT);
+
+       r = radeon_ttm_init_vram(rdev);
        if (r) {
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
@@ -811,8 +775,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
        }
        DRM_INFO("radeon: %uM of VRAM memory ready\n",
                 (unsigned) (rdev->mc.real_vram_size / (1024 * 1024)));
-       r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT,
-                               rdev->mc.gtt_size >> PAGE_SHIFT);
+
+       r = radeon_ttm_init_gtt(rdev);
        if (r) {
                DRM_ERROR("Failed initializing GTT heap.\n");
                return r;
@@ -843,8 +807,8 @@ void radeon_ttm_fini(struct radeon_device *rdev)
                }
                radeon_bo_unref(&rdev->stolen_vga_memory);
        }
-       ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM);
-       ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT);
+       ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_VRAM);
+       ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_TT);
        ttm_bo_device_release(&rdev->mman.bdev);
        radeon_gart_fini(rdev);
        rdev->mman.initialized = false;
@@ -855,12 +819,12 @@ void radeon_ttm_fini(struct radeon_device *rdev)
  * isn't running */
 void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size)
 {
-       struct ttm_mem_type_manager *man;
+       struct ttm_resource_manager *man;
 
        if (!rdev->mman.initialized)
                return;
 
-       man = &rdev->mman.bdev.man[TTM_PL_VRAM];
+       man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM);
        /* this just adjusts TTM size idea, which sets lpfn to the correct value */
        man->size = size >> PAGE_SHIFT;
 }
@@ -914,7 +878,7 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data)
        unsigned ttm_pl = *(int*)node->info_ent->data;
        struct drm_device *dev = node->minor->dev;
        struct radeon_device *rdev = dev->dev_private;
-       struct ttm_mem_type_manager *man = &rdev->mman.bdev.man[ttm_pl];
+       struct ttm_resource_manager *man = ttm_manager_type(&rdev->mman.bdev, ttm_pl);
        struct drm_printer p = drm_seq_file_printer(m);
 
        man->func->debug(man, &p);
index f60fae0..71e2c37 100644 (file)
@@ -911,7 +911,7 @@ static void radeon_vm_fence_pts(struct radeon_vm *vm,
  */
 int radeon_vm_bo_update(struct radeon_device *rdev,
                        struct radeon_bo_va *bo_va,
-                       struct ttm_mem_reg *mem)
+                       struct ttm_resource *mem)
 {
        struct radeon_vm *vm = bo_va->vm;
        struct radeon_ib ib;
index ab0d496..bced729 100644 (file)
@@ -677,15 +677,11 @@ static int rcar_lvds_attach(struct drm_bridge *bridge,
        if (ret < 0)
                return ret;
 
-       return drm_panel_attach(lvds->panel, connector);
+       return 0;
 }
 
 static void rcar_lvds_detach(struct drm_bridge *bridge)
 {
-       struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
-
-       if (lvds->panel)
-               drm_panel_detach(lvds->panel);
 }
 
 static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
index 63f9679..f292c6a 100644 (file)
@@ -634,13 +634,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
                                      "failed to attach encoder: %d\n", ret);
                        goto err_free_connector;
                }
-
-               ret = drm_panel_attach(lvds->panel, connector);
-               if (ret < 0) {
-                       DRM_DEV_ERROR(drm_dev->dev,
-                                     "failed to attach panel: %d\n", ret);
-                       goto err_free_connector;
-               }
        } else {
                ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0);
                if (ret) {
@@ -676,8 +669,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master,
 
        encoder_funcs = lvds->soc_data->helper_funcs;
        encoder_funcs->disable(&lvds->encoder);
-       if (lvds->panel)
-               drm_panel_detach(lvds->panel);
        pm_runtime_disable(dev);
        drm_connector_cleanup(&lvds->connector);
        drm_encoder_cleanup(&lvds->encoder);
index de4af77..ddb4184 100644 (file)
@@ -389,8 +389,6 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
                dvo->panel = of_drm_find_panel(dvo->panel_node);
                if (IS_ERR(dvo->panel))
                        dvo->panel = NULL;
-               else
-                       drm_panel_attach(dvo->panel, connector);
        }
 
        if (dvo->panel)
index ffda318..d06dd31 100644 (file)
@@ -54,9 +54,6 @@ static struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = {
 static void
 sun4i_lvds_connector_destroy(struct drm_connector *connector)
 {
-       struct sun4i_lvds *lvds = drm_connector_to_sun4i_lvds(connector);
-
-       drm_panel_detach(lvds->panel);
        drm_connector_cleanup(connector);
 }
 
@@ -141,12 +138,6 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon)
 
                drm_connector_attach_encoder(&lvds->connector,
                                                  &lvds->encoder);
-
-               ret = drm_panel_attach(lvds->panel, &lvds->connector);
-               if (ret) {
-                       dev_err(drm->dev, "Couldn't attach our panel\n");
-                       goto err_cleanup_connector;
-               }
        }
 
        if (bridge) {
index 5a7d439..23df1ec 100644 (file)
@@ -145,9 +145,6 @@ static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
 static void
 sun4i_rgb_connector_destroy(struct drm_connector *connector)
 {
-       struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
-
-       drm_panel_detach(rgb->panel);
        drm_connector_cleanup(connector);
 }
 
@@ -233,12 +230,6 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
 
                drm_connector_attach_encoder(&rgb->connector,
                                                  &rgb->encoder);
-
-               ret = drm_panel_attach(rgb->panel, &rgb->connector);
-               if (ret) {
-                       dev_err(drm->dev, "Couldn't attach our panel\n");
-                       goto err_cleanup_connector;
-               }
        }
 
        if (rgb->bridge) {
index aa67cb0..a78aebf 100644 (file)
@@ -973,7 +973,6 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
        dsi->panel = panel;
        dsi->device = device;
 
-       drm_panel_attach(dsi->panel, &dsi->connector);
        drm_kms_helper_hotplug_event(dsi->drm);
 
        dev_info(host->dev, "Attached device %s\n", device->name);
@@ -985,12 +984,10 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
                            struct mipi_dsi_device *device)
 {
        struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
-       struct drm_panel *panel = dsi->panel;
 
        dsi->panel = NULL;
        dsi->device = NULL;
 
-       drm_panel_detach(panel);
        drm_kms_helper_hotplug_event(dsi->drm);
 
        return 0;
index 3820e8d..3387de7 100644 (file)
@@ -1498,10 +1498,8 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
                if (IS_ERR(output->panel))
                        output->panel = NULL;
 
-               if (output->panel && output->connector.dev) {
-                       drm_panel_attach(output->panel, &output->connector);
+               if (output->panel && output->connector.dev)
                        drm_helper_hpd_irq_event(output->connector.dev);
-               }
        }
 
        return 0;
index e36e5e7..a3adb9e 100644 (file)
@@ -179,13 +179,6 @@ void tegra_output_remove(struct tegra_output *output)
 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
 {
        int connector_type;
-       int err;
-
-       if (output->panel) {
-               err = drm_panel_attach(output->panel, &output->connector);
-               if (err < 0)
-                       return err;
-       }
 
        /*
         * The connector is now registered and ready to receive hotplug events
@@ -220,9 +213,6 @@ void tegra_output_exit(struct tegra_output *output)
         */
        if (output->hpd_gpio)
                disable_irq(output->hpd_irq);
-
-       if (output->panel)
-               drm_panel_detach(output->panel);
 }
 
 void tegra_output_find_possible_crtcs(struct tegra_output *output,
index caea2a0..90c0da8 100644 (file)
@@ -4,7 +4,8 @@
 
 ttm-y := ttm_memory.o ttm_tt.o ttm_bo.o \
        ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
-       ttm_execbuf_util.o ttm_page_alloc.o ttm_bo_manager.o
+       ttm_execbuf_util.o ttm_page_alloc.o ttm_range_manager.o \
+       ttm_resource.o
 ttm-$(CONFIG_AGP) += ttm_agp_backend.o
 ttm-$(CONFIG_DRM_TTM_DMA_PAGE_POOL) += ttm_page_alloc_dma.o
 
index 38f1351..09fe80e 100644 (file)
@@ -48,7 +48,7 @@ struct ttm_agp_backend {
        struct agp_bridge_data *bridge;
 };
 
-static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
+static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem)
 {
        struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm);
        struct page *dummy_read_page = ttm_bo_glob.dummy_read_page;
index cc6a4e7..97ac662 100644 (file)
@@ -77,26 +77,12 @@ static inline int ttm_mem_type_from_place(const struct ttm_place *place,
        return 0;
 }
 
-static void ttm_mem_type_debug(struct ttm_bo_device *bdev, struct drm_printer *p,
-                              int mem_type)
-{
-       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
-
-       drm_printf(p, "    has_type: %d\n", man->has_type);
-       drm_printf(p, "    use_type: %d\n", man->use_type);
-       drm_printf(p, "    flags: 0x%08X\n", man->flags);
-       drm_printf(p, "    size: %llu\n", man->size);
-       drm_printf(p, "    available_caching: 0x%08X\n", man->available_caching);
-       drm_printf(p, "    default_caching: 0x%08X\n", man->default_caching);
-       if (mem_type != TTM_PL_SYSTEM)
-               (*man->func->debug)(man, p);
-}
-
 static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
                                        struct ttm_placement *placement)
 {
        struct drm_printer p = drm_debug_printer(TTM_PFX);
        int i, ret, mem_type;
+       struct ttm_resource_manager *man;
 
        drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n",
                   bo, bo->mem.num_pages, bo->mem.size >> 10,
@@ -108,7 +94,8 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
                        return;
                drm_printf(&p, "  placement[%d]=0x%08X (%d)\n",
                           i, placement->placement[i].flags, mem_type);
-               ttm_mem_type_debug(bo->bdev, &p, mem_type);
+               man = ttm_manager_type(bo->bdev, mem_type);
+               ttm_resource_manager_debug(man, &p);
        }
 }
 
@@ -145,10 +132,10 @@ static inline uint32_t ttm_bo_type_flags(unsigned type)
 }
 
 static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
-                                 struct ttm_mem_reg *mem)
+                                 struct ttm_resource *mem)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *man;
+       struct ttm_resource_manager *man;
 
        if (!list_empty(&bo->lru))
                return;
@@ -156,10 +143,10 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
        if (mem->placement & TTM_PL_FLAG_NO_EVICT)
                return;
 
-       man = &bdev->man[mem->mem_type];
+       man = ttm_manager_type(bdev, mem->mem_type);
        list_add_tail(&bo->lru, &man->lru[bo->priority]);
 
-       if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm &&
+       if (man->use_tt && bo->ttm &&
            !(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG |
                                     TTM_PAGE_FLAG_SWAPPED))) {
                list_add_tail(&bo->swap, &ttm_bo_glob.swap_lru[bo->priority]);
@@ -223,7 +210,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
 
        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
                struct ttm_lru_bulk_move_pos *pos = &bulk->tt[i];
-               struct ttm_mem_type_manager *man;
+               struct ttm_resource_manager *man;
 
                if (!pos->first)
                        continue;
@@ -231,14 +218,14 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
                dma_resv_assert_held(pos->first->base.resv);
                dma_resv_assert_held(pos->last->base.resv);
 
-               man = &pos->first->bdev->man[TTM_PL_TT];
+               man = ttm_manager_type(pos->first->bdev, TTM_PL_TT);
                list_bulk_move_tail(&man->lru[i], &pos->first->lru,
                                    &pos->last->lru);
        }
 
        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
                struct ttm_lru_bulk_move_pos *pos = &bulk->vram[i];
-               struct ttm_mem_type_manager *man;
+               struct ttm_resource_manager *man;
 
                if (!pos->first)
                        continue;
@@ -246,7 +233,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
                dma_resv_assert_held(pos->first->base.resv);
                dma_resv_assert_held(pos->last->base.resv);
 
-               man = &pos->first->bdev->man[TTM_PL_VRAM];
+               man = ttm_manager_type(pos->first->bdev, TTM_PL_VRAM);
                list_bulk_move_tail(&man->lru[i], &pos->first->lru,
                                    &pos->last->lru);
        }
@@ -268,12 +255,12 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk)
 EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail);
 
 static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
-                                 struct ttm_mem_reg *mem, bool evict,
+                                 struct ttm_resource *mem, bool evict,
                                  struct ttm_operation_ctx *ctx)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type];
-       struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type];
+       struct ttm_resource_manager *old_man = ttm_manager_type(bdev, bo->mem.mem_type);
+       struct ttm_resource_manager *new_man = ttm_manager_type(bdev, mem->mem_type);
        int ret;
 
        ret = ttm_mem_io_lock(old_man, true);
@@ -286,13 +273,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
         * Create and bind a ttm if required.
         */
 
-       if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
-               if (bo->ttm == NULL) {
-                       bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED);
-                       ret = ttm_tt_create(bo, zero);
-                       if (ret)
-                               goto out_err;
-               }
+       if (new_man->use_tt) {
+               /* Zero init the new TTM structure if the old location should
+                * have used one as well.
+                */
+               ret = ttm_tt_create(bo, old_man->use_tt);
+               if (ret)
+                       goto out_err;
 
                ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
                if (ret)
@@ -315,8 +302,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
        if (bdev->driver->move_notify)
                bdev->driver->move_notify(bo, evict, mem);
 
-       if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
-           !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
+       if (old_man->use_tt && new_man->use_tt)
                ret = ttm_bo_move_ttm(bo, ctx, mem);
        else if (bdev->driver->move)
                ret = bdev->driver->move(bo, evict, ctx, mem);
@@ -340,8 +326,8 @@ moved:
        return 0;
 
 out_err:
-       new_man = &bdev->man[bo->mem.mem_type];
-       if (new_man->flags & TTM_MEMTYPE_FLAG_FIXED) {
+       new_man = ttm_manager_type(bdev, bo->mem.mem_type);
+       if (!new_man->use_tt) {
                ttm_tt_destroy(bo->ttm);
                bo->ttm = NULL;
        }
@@ -364,7 +350,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
 
        ttm_tt_destroy(bo->ttm);
        bo->ttm = NULL;
-       ttm_bo_mem_put(bo, &bo->mem);
+       ttm_resource_free(bo, &bo->mem);
 }
 
 static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo)
@@ -552,7 +538,7 @@ static void ttm_bo_release(struct kref *kref)
        struct ttm_buffer_object *bo =
            container_of(kref, struct ttm_buffer_object, kref);
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type);
        size_t acc_size = bo->acc_size;
        int ret;
 
@@ -643,7 +629,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
                        struct ttm_operation_ctx *ctx)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_reg evict_mem;
+       struct ttm_resource evict_mem;
        struct ttm_placement placement;
        int ret = 0;
 
@@ -654,10 +640,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
        bdev->driver->evict_flags(bo, &placement);
 
        if (!placement.num_placement && !placement.num_busy_placement) {
-               ret = ttm_bo_pipeline_gutting(bo);
-               if (ret)
-                       return ret;
+               ttm_bo_wait(bo, false, false);
 
+               ttm_bo_cleanup_memtype_use(bo);
                return ttm_tt_create(bo, false);
        }
 
@@ -680,7 +665,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
        if (unlikely(ret)) {
                if (ret != -ERESTARTSYS)
                        pr_err("Buffer eviction failed\n");
-               ttm_bo_mem_put(bo, &evict_mem);
+               ttm_resource_free(bo, &evict_mem);
                goto out;
        }
        bo->evicted = true;
@@ -769,14 +754,13 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo,
        return r == -EDEADLK ? -EBUSY : r;
 }
 
-static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
-                              uint32_t mem_type,
-                              const struct ttm_place *place,
-                              struct ttm_operation_ctx *ctx,
-                              struct ww_acquire_ctx *ticket)
+int ttm_mem_evict_first(struct ttm_bo_device *bdev,
+                       struct ttm_resource_manager *man,
+                       const struct ttm_place *place,
+                       struct ttm_operation_ctx *ctx,
+                       struct ww_acquire_ctx *ticket)
 {
        struct ttm_buffer_object *bo = NULL, *busy_bo = NULL;
-       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
        bool locked = false;
        unsigned i;
        int ret;
@@ -842,38 +826,12 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
        return ret;
 }
 
-static int ttm_bo_mem_get(struct ttm_buffer_object *bo,
-                         const struct ttm_place *place,
-                         struct ttm_mem_reg *mem)
-{
-       struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
-
-       mem->mm_node = NULL;
-       if (!man->func || !man->func->get_node)
-               return 0;
-
-       return man->func->get_node(man, bo, place, mem);
-}
-
-void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
-{
-       struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
-
-       if (!man->func || !man->func->put_node)
-               return;
-
-       man->func->put_node(man, mem);
-       mem->mm_node = NULL;
-       mem->mem_type = TTM_PL_SYSTEM;
-}
-EXPORT_SYMBOL(ttm_bo_mem_put);
-
 /**
  * Add the last move fence to the BO and reserve a new shared slot.
  */
 static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
-                                struct ttm_mem_type_manager *man,
-                                struct ttm_mem_reg *mem,
+                                struct ttm_resource_manager *man,
+                                struct ttm_resource *mem,
                                 bool no_wait_gpu)
 {
        struct dma_fence *fence;
@@ -910,22 +868,22 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
  */
 static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
                                  const struct ttm_place *place,
-                                 struct ttm_mem_reg *mem,
+                                 struct ttm_resource *mem,
                                  struct ttm_operation_ctx *ctx)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
        struct ww_acquire_ctx *ticket;
        int ret;
 
        ticket = dma_resv_locking_ctx(bo->base.resv);
        do {
-               ret = ttm_bo_mem_get(bo, place, mem);
+               ret = ttm_resource_alloc(bo, place, mem);
                if (likely(!ret))
                        break;
                if (unlikely(ret != -ENOSPC))
                        return ret;
-               ret = ttm_mem_evict_first(bdev, mem->mem_type, place, ctx,
+               ret = ttm_mem_evict_first(bdev, man, place, ctx,
                                          ticket);
                if (unlikely(ret != 0))
                        return ret;
@@ -934,7 +892,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
        return ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu);
 }
 
-static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
+static uint32_t ttm_bo_select_caching(struct ttm_resource_manager *man,
                                      uint32_t cur_placement,
                                      uint32_t proposed_placement)
 {
@@ -959,7 +917,7 @@ static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
        return result;
 }
 
-static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
+static bool ttm_bo_mt_compatible(struct ttm_resource_manager *man,
                                 uint32_t mem_type,
                                 const struct ttm_place *place,
                                 uint32_t *masked_placement)
@@ -991,12 +949,12 @@ static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
  */
 static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
                                const struct ttm_place *place,
-                               struct ttm_mem_reg *mem,
+                               struct ttm_resource *mem,
                                struct ttm_operation_ctx *ctx)
 {
        struct ttm_bo_device *bdev = bo->bdev;
        uint32_t mem_type = TTM_PL_SYSTEM;
-       struct ttm_mem_type_manager *man;
+       struct ttm_resource_manager *man;
        uint32_t cur_flags = 0;
        int ret;
 
@@ -1004,8 +962,8 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
        if (ret)
                return ret;
 
-       man = &bdev->man[mem_type];
-       if (!man->has_type || !man->use_type)
+       man = ttm_manager_type(bdev, mem_type);
+       if (!man || !ttm_resource_manager_used(man))
                return -EBUSY;
 
        if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags))
@@ -1039,7 +997,7 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
  */
 int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                        struct ttm_placement *placement,
-                       struct ttm_mem_reg *mem,
+                       struct ttm_resource *mem,
                        struct ttm_operation_ctx *ctx)
 {
        struct ttm_bo_device *bdev = bo->bdev;
@@ -1052,7 +1010,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
 
        for (i = 0; i < placement->num_placement; ++i) {
                const struct ttm_place *place = &placement->placement[i];
-               struct ttm_mem_type_manager *man;
+               struct ttm_resource_manager *man;
 
                ret = ttm_bo_mem_placement(bo, place, mem, ctx);
                if (ret == -EBUSY)
@@ -1061,16 +1019,16 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                        goto error;
 
                type_found = true;
-               ret = ttm_bo_mem_get(bo, place, mem);
+               ret = ttm_resource_alloc(bo, place, mem);
                if (ret == -ENOSPC)
                        continue;
                if (unlikely(ret))
                        goto error;
 
-               man = &bdev->man[mem->mem_type];
+               man = ttm_manager_type(bdev, mem->mem_type);
                ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu);
                if (unlikely(ret)) {
-                       ttm_bo_mem_put(bo, mem);
+                       ttm_resource_free(bo, mem);
                        if (ret == -EBUSY)
                                continue;
 
@@ -1105,9 +1063,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
 
 error:
        if (bo->mem.mem_type == TTM_PL_SYSTEM && !list_empty(&bo->lru)) {
-               spin_lock(&ttm_bo_glob.lru_lock);
-               ttm_bo_move_to_lru_tail(bo, NULL);
-               spin_unlock(&ttm_bo_glob.lru_lock);
+               ttm_bo_move_to_lru_tail_unlocked(bo);
        }
 
        return ret;
@@ -1119,7 +1075,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
                              struct ttm_operation_ctx *ctx)
 {
        int ret = 0;
-       struct ttm_mem_reg mem;
+       struct ttm_resource mem;
 
        dma_resv_assert_held(bo->base.resv);
 
@@ -1139,13 +1095,13 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
        ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx);
 out_unlock:
        if (ret)
-               ttm_bo_mem_put(bo, &mem);
+               ttm_resource_free(bo, &mem);
        return ret;
 }
 
 static bool ttm_bo_places_compat(const struct ttm_place *places,
                                 unsigned num_placement,
-                                struct ttm_mem_reg *mem,
+                                struct ttm_resource *mem,
                                 uint32_t *new_flags)
 {
        unsigned i;
@@ -1168,7 +1124,7 @@ static bool ttm_bo_places_compat(const struct ttm_place *places,
 }
 
 bool ttm_bo_mem_compat(struct ttm_placement *placement,
-                      struct ttm_mem_reg *mem,
+                      struct ttm_resource *mem,
                       uint32_t *new_flags)
 {
        if (ttm_bo_places_compat(placement->placement, placement->num_placement,
@@ -1335,9 +1291,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
                return ret;
        }
 
-       spin_lock(&ttm_bo_glob.lru_lock);
-       ttm_bo_move_to_lru_tail(bo, NULL);
-       spin_unlock(&ttm_bo_glob.lru_lock);
+       ttm_bo_move_to_lru_tail_unlocked(bo);
 
        return ret;
 }
@@ -1426,144 +1380,24 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
 }
 EXPORT_SYMBOL(ttm_bo_create);
 
-static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
-                                  unsigned mem_type)
-{
-       struct ttm_operation_ctx ctx = {
-               .interruptible = false,
-               .no_wait_gpu = false,
-               .flags = TTM_OPT_FLAG_FORCE_ALLOC
-       };
-       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
-       struct ttm_bo_global *glob = &ttm_bo_glob;
-       struct dma_fence *fence;
-       int ret;
-       unsigned i;
-
-       /*
-        * Can't use standard list traversal since we're unlocking.
-        */
-
-       spin_lock(&glob->lru_lock);
-       for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
-               while (!list_empty(&man->lru[i])) {
-                       spin_unlock(&glob->lru_lock);
-                       ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx,
-                                                 NULL);
-                       if (ret)
-                               return ret;
-                       spin_lock(&glob->lru_lock);
-               }
-       }
-       spin_unlock(&glob->lru_lock);
-
-       spin_lock(&man->move_lock);
-       fence = dma_fence_get(man->move);
-       spin_unlock(&man->move_lock);
-
-       if (fence) {
-               ret = dma_fence_wait(fence, false);
-               dma_fence_put(fence);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
-{
-       struct ttm_mem_type_manager *man;
-       int ret = -EINVAL;
-
-       if (mem_type >= TTM_NUM_MEM_TYPES) {
-               pr_err("Illegal memory type %d\n", mem_type);
-               return ret;
-       }
-       man = &bdev->man[mem_type];
-
-       if (!man->has_type) {
-               pr_err("Trying to take down uninitialized memory manager type %u\n",
-                      mem_type);
-               return ret;
-       }
-
-       man->use_type = false;
-       man->has_type = false;
-
-       ret = 0;
-       if (mem_type > 0) {
-               ret = ttm_bo_force_list_clean(bdev, mem_type);
-               if (ret) {
-                       pr_err("Cleanup eviction failed\n");
-                       return ret;
-               }
-
-               ret = (*man->func->takedown)(man);
-       }
-
-       dma_fence_put(man->move);
-       man->move = NULL;
-
-       return ret;
-}
-EXPORT_SYMBOL(ttm_bo_clean_mm);
-
 int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type)
 {
-       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, mem_type);
 
        if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) {
                pr_err("Illegal memory manager memory type %u\n", mem_type);
                return -EINVAL;
        }
 
-       if (!man->has_type) {
+       if (!man) {
                pr_err("Memory type %u has not been initialized\n", mem_type);
                return 0;
        }
 
-       return ttm_bo_force_list_clean(bdev, mem_type);
+       return ttm_resource_manager_force_list_clean(bdev, man);
 }
 EXPORT_SYMBOL(ttm_bo_evict_mm);
 
-int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
-                       unsigned long p_size)
-{
-       int ret;
-       struct ttm_mem_type_manager *man;
-       unsigned i;
-
-       BUG_ON(type >= TTM_NUM_MEM_TYPES);
-       man = &bdev->man[type];
-       BUG_ON(man->has_type);
-       man->use_io_reserve_lru = false;
-       mutex_init(&man->io_reserve_mutex);
-       spin_lock_init(&man->move_lock);
-       INIT_LIST_HEAD(&man->io_reserve_lru);
-
-       ret = bdev->driver->init_mem_type(bdev, type, man);
-       if (ret)
-               return ret;
-       man->bdev = bdev;
-
-       if (type != TTM_PL_SYSTEM) {
-               ret = (*man->func->init)(man, p_size);
-               if (ret)
-                       return ret;
-       }
-       man->has_type = true;
-       man->use_type = true;
-       man->size = p_size;
-
-       for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
-               INIT_LIST_HEAD(&man->lru[i]);
-       man->move = NULL;
-
-       return 0;
-}
-EXPORT_SYMBOL(ttm_bo_init_mm);
-
 static void ttm_bo_global_kobj_release(struct kobject *kobj)
 {
        struct ttm_bo_global *glob =
@@ -1628,21 +1462,12 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
 {
        struct ttm_bo_global *glob = &ttm_bo_glob;
        int ret = 0;
-       unsigned i = TTM_NUM_MEM_TYPES;
-       struct ttm_mem_type_manager *man;
-
-       while (i--) {
-               man = &bdev->man[i];
-               if (man->has_type) {
-                       man->use_type = false;
-                       if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) {
-                               ret = -EBUSY;
-                               pr_err("DRM memory manager type %d is not clean\n",
-                                      i);
-                       }
-                       man->has_type = false;
-               }
-       }
+       unsigned i;
+       struct ttm_resource_manager *man;
+
+       man = ttm_manager_type(bdev, TTM_PL_SYSTEM);
+       ttm_resource_manager_set_used(man, false);
+       ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL);
 
        mutex_lock(&ttm_global_mutex);
        list_del(&bdev->device_list);
@@ -1655,7 +1480,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
 
        spin_lock(&glob->lru_lock);
        for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
-               if (list_empty(&bdev->man[0].lru[0]))
+               if (list_empty(&man->lru[0]))
                        pr_debug("Swap list %d was clean\n", i);
        spin_unlock(&glob->lru_lock);
 
@@ -1666,6 +1491,23 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
 }
 EXPORT_SYMBOL(ttm_bo_device_release);
 
+static void ttm_bo_init_sysman(struct ttm_bo_device *bdev)
+{
+       struct ttm_resource_manager *man = &bdev->sysman;
+
+       /*
+        * Initialize the system memory buffer type.
+        * Other types need to be driver / IOCTL initialized.
+        */
+       man->use_tt = true;
+       man->available_caching = TTM_PL_MASK_CACHING;
+       man->default_caching = TTM_PL_FLAG_CACHED;
+
+       ttm_resource_manager_init(man, 0);
+       ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man);
+       ttm_resource_manager_set_used(man, true);
+}
+
 int ttm_bo_device_init(struct ttm_bo_device *bdev,
                       struct ttm_bo_driver *driver,
                       struct address_space *mapping,
@@ -1684,15 +1526,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
 
        bdev->driver = driver;
 
-       memset(bdev->man, 0, sizeof(bdev->man));
-
-       /*
-        * Initialize the system memory buffer type.
-        * Other types need to be driver / IOCTL initialized.
-        */
-       ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0);
-       if (unlikely(ret != 0))
-               goto out_no_sys;
+       ttm_bo_init_sysman(bdev);
 
        bdev->vma_manager = vma_manager;
        INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
@@ -1704,9 +1538,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
        mutex_unlock(&ttm_global_mutex);
 
        return 0;
-out_no_sys:
-       ttm_bo_global_release();
-       return ret;
 }
 EXPORT_SYMBOL(ttm_bo_device_init);
 
@@ -1725,7 +1556,7 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo)
 void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type);
 
        ttm_mem_io_lock(man, false);
        ttm_bo_unmap_virtual_locked(bo);
@@ -1812,7 +1643,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
        if (bo->mem.mem_type != TTM_PL_SYSTEM ||
            bo->ttm->caching_state != tt_cached) {
                struct ttm_operation_ctx ctx = { false, false };
-               struct ttm_mem_reg evict_mem;
+               struct ttm_resource evict_mem;
 
                evict_mem = bo->mem;
                evict_mem.mm_node = NULL;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
deleted file mode 100644 (file)
index facd304..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR MIT */
-/**************************************************************************
- *
- * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-/*
- * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
- */
-
-#include <drm/ttm/ttm_module.h>
-#include <drm/ttm/ttm_bo_driver.h>
-#include <drm/ttm/ttm_placement.h>
-#include <drm/drm_mm.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-
-/**
- * Currently we use a spinlock for the lock, but a mutex *may* be
- * more appropriate to reduce scheduling latency if the range manager
- * ends up with very fragmented allocation patterns.
- */
-
-struct ttm_range_manager {
-       struct drm_mm mm;
-       spinlock_t lock;
-};
-
-static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
-                              struct ttm_buffer_object *bo,
-                              const struct ttm_place *place,
-                              struct ttm_mem_reg *mem)
-{
-       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
-       struct drm_mm *mm = &rman->mm;
-       struct drm_mm_node *node;
-       enum drm_mm_insert_mode mode;
-       unsigned long lpfn;
-       int ret;
-
-       lpfn = place->lpfn;
-       if (!lpfn)
-               lpfn = man->size;
-
-       node = kzalloc(sizeof(*node), GFP_KERNEL);
-       if (!node)
-               return -ENOMEM;
-
-       mode = DRM_MM_INSERT_BEST;
-       if (place->flags & TTM_PL_FLAG_TOPDOWN)
-               mode = DRM_MM_INSERT_HIGH;
-
-       spin_lock(&rman->lock);
-       ret = drm_mm_insert_node_in_range(mm, node,
-                                         mem->num_pages,
-                                         mem->page_alignment, 0,
-                                         place->fpfn, lpfn, mode);
-       spin_unlock(&rman->lock);
-
-       if (unlikely(ret)) {
-               kfree(node);
-       } else {
-               mem->mm_node = node;
-               mem->start = node->start;
-       }
-
-       return ret;
-}
-
-static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
-                               struct ttm_mem_reg *mem)
-{
-       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
-
-       if (mem->mm_node) {
-               spin_lock(&rman->lock);
-               drm_mm_remove_node(mem->mm_node);
-               spin_unlock(&rman->lock);
-
-               kfree(mem->mm_node);
-               mem->mm_node = NULL;
-       }
-}
-
-static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
-                          unsigned long p_size)
-{
-       struct ttm_range_manager *rman;
-
-       rman = kzalloc(sizeof(*rman), GFP_KERNEL);
-       if (!rman)
-               return -ENOMEM;
-
-       drm_mm_init(&rman->mm, 0, p_size);
-       spin_lock_init(&rman->lock);
-       man->priv = rman;
-       return 0;
-}
-
-static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
-{
-       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
-       struct drm_mm *mm = &rman->mm;
-
-       spin_lock(&rman->lock);
-       if (drm_mm_clean(mm)) {
-               drm_mm_takedown(mm);
-               spin_unlock(&rman->lock);
-               kfree(rman);
-               man->priv = NULL;
-               return 0;
-       }
-       spin_unlock(&rman->lock);
-       return -EBUSY;
-}
-
-static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
-                            struct drm_printer *printer)
-{
-       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
-
-       spin_lock(&rman->lock);
-       drm_mm_print(&rman->mm, printer);
-       spin_unlock(&rman->lock);
-}
-
-const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
-       .init = ttm_bo_man_init,
-       .takedown = ttm_bo_man_takedown,
-       .get_node = ttm_bo_man_get_node,
-       .put_node = ttm_bo_man_put_node,
-       .debug = ttm_bo_man_debug
-};
-EXPORT_SYMBOL(ttm_bo_manager_func);
index e6c8bd2..7b372ed 100644 (file)
@@ -47,15 +47,15 @@ struct ttm_transfer_obj {
 
 void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
 {
-       ttm_bo_mem_put(bo, &bo->mem);
+       ttm_resource_free(bo, &bo->mem);
 }
 
 int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
                   struct ttm_operation_ctx *ctx,
-                   struct ttm_mem_reg *new_mem)
+                   struct ttm_resource *new_mem)
 {
        struct ttm_tt *ttm = bo->ttm;
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
        int ret;
 
        if (old_mem->mem_type != TTM_PL_SYSTEM) {
@@ -91,7 +91,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
 }
 EXPORT_SYMBOL(ttm_bo_move_ttm);
 
-int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible)
+int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible)
 {
        if (likely(!man->use_io_reserve_lru))
                return 0;
@@ -103,7 +103,7 @@ int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible)
        return 0;
 }
 
-void ttm_mem_io_unlock(struct ttm_mem_type_manager *man)
+void ttm_mem_io_unlock(struct ttm_resource_manager *man)
 {
        if (likely(!man->use_io_reserve_lru))
                return;
@@ -111,7 +111,7 @@ void ttm_mem_io_unlock(struct ttm_mem_type_manager *man)
        mutex_unlock(&man->io_reserve_mutex);
 }
 
-static int ttm_mem_io_evict(struct ttm_mem_type_manager *man)
+static int ttm_mem_io_evict(struct ttm_resource_manager *man)
 {
        struct ttm_buffer_object *bo;
 
@@ -127,9 +127,9 @@ static int ttm_mem_io_evict(struct ttm_mem_type_manager *man)
 }
 
 int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
-                      struct ttm_mem_reg *mem)
+                      struct ttm_resource *mem)
 {
-       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
        int ret;
 
        if (mem->bus.io_reserved_count++)
@@ -149,7 +149,7 @@ retry:
 }
 
 void ttm_mem_io_free(struct ttm_bo_device *bdev,
-                    struct ttm_mem_reg *mem)
+                    struct ttm_resource *mem)
 {
        if (--mem->bus.io_reserved_count)
                return;
@@ -162,8 +162,8 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
 
 int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo)
 {
-       struct ttm_mem_type_manager *man = &bo->bdev->man[bo->mem.mem_type];
-       struct ttm_mem_reg *mem = &bo->mem;
+       struct ttm_resource_manager *man = ttm_manager_type(bo->bdev, bo->mem.mem_type);
+       struct ttm_resource *mem = &bo->mem;
        int ret;
 
        if (mem->bus.io_reserved_vm)
@@ -181,7 +181,7 @@ int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo)
 
 void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
 {
-       struct ttm_mem_reg *mem = &bo->mem;
+       struct ttm_resource *mem = &bo->mem;
 
        if (!mem->bus.io_reserved_vm)
                return;
@@ -191,11 +191,11 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
        ttm_mem_io_free(bo->bdev, mem);
 }
 
-static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev,
-                              struct ttm_mem_reg *mem,
+static int ttm_resource_ioremap(struct ttm_bo_device *bdev,
+                              struct ttm_resource *mem,
                               void **virtual)
 {
-       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
        int ret;
        void *addr;
 
@@ -226,13 +226,13 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev,
        return 0;
 }
 
-static void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev,
-                               struct ttm_mem_reg *mem,
+static void ttm_resource_iounmap(struct ttm_bo_device *bdev,
+                               struct ttm_resource *mem,
                                void *virtual)
 {
-       struct ttm_mem_type_manager *man;
+       struct ttm_resource_manager *man;
 
-       man = &bdev->man[mem->mem_type];
+       man = ttm_manager_type(bdev, mem->mem_type);
 
        if (virtual && mem->bus.addr == NULL)
                iounmap(virtual);
@@ -300,13 +300,13 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
 
 int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
                       struct ttm_operation_ctx *ctx,
-                      struct ttm_mem_reg *new_mem)
+                      struct ttm_resource *new_mem)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
        struct ttm_tt *ttm = bo->ttm;
-       struct ttm_mem_reg *old_mem = &bo->mem;
-       struct ttm_mem_reg old_copy = *old_mem;
+       struct ttm_resource *old_mem = &bo->mem;
+       struct ttm_resource old_copy = *old_mem;
        void *old_iomap;
        void *new_iomap;
        int ret;
@@ -319,10 +319,10 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
        if (ret)
                return ret;
 
-       ret = ttm_mem_reg_ioremap(bdev, old_mem, &old_iomap);
+       ret = ttm_resource_ioremap(bdev, old_mem, &old_iomap);
        if (ret)
                return ret;
-       ret = ttm_mem_reg_ioremap(bdev, new_mem, &new_iomap);
+       ret = ttm_resource_ioremap(bdev, new_mem, &new_iomap);
        if (ret)
                goto out;
 
@@ -384,21 +384,21 @@ out2:
        *old_mem = *new_mem;
        new_mem->mm_node = NULL;
 
-       if (man->flags & TTM_MEMTYPE_FLAG_FIXED) {
+       if (!man->use_tt) {
                ttm_tt_destroy(ttm);
                bo->ttm = NULL;
        }
 
 out1:
-       ttm_mem_reg_iounmap(bdev, old_mem, new_iomap);
+       ttm_resource_iounmap(bdev, old_mem, new_iomap);
 out:
-       ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap);
+       ttm_resource_iounmap(bdev, &old_copy, old_iomap);
 
        /*
         * On error, keep the mm node!
         */
        if (!ret)
-               ttm_bo_mem_put(bo, &old_copy);
+               ttm_resource_free(bo, &old_copy);
        return ret;
 }
 EXPORT_SYMBOL(ttm_bo_move_memcpy);
@@ -502,7 +502,7 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo,
                          unsigned long size,
                          struct ttm_bo_kmap_obj *map)
 {
-       struct ttm_mem_reg *mem = &bo->mem;
+       struct ttm_resource *mem = &bo->mem;
 
        if (bo->mem.bus.addr) {
                map->bo_kmap_type = ttm_bo_map_premapped;
@@ -526,7 +526,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
                           unsigned long num_pages,
                           struct ttm_bo_kmap_obj *map)
 {
-       struct ttm_mem_reg *mem = &bo->mem;
+       struct ttm_resource *mem = &bo->mem;
        struct ttm_operation_ctx ctx = {
                .interruptible = false,
                .no_wait_gpu = false
@@ -567,8 +567,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
                unsigned long start_page, unsigned long num_pages,
                struct ttm_bo_kmap_obj *map)
 {
-       struct ttm_mem_type_manager *man =
-               &bo->bdev->man[bo->mem.mem_type];
+       struct ttm_resource_manager *man =
+               ttm_manager_type(bo->bdev, bo->mem.mem_type);
        unsigned long offset, size;
        int ret;
 
@@ -597,8 +597,8 @@ EXPORT_SYMBOL(ttm_bo_kmap);
 void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
 {
        struct ttm_buffer_object *bo = map->bo;
-       struct ttm_mem_type_manager *man =
-               &bo->bdev->man[bo->mem.mem_type];
+       struct ttm_resource_manager *man =
+               ttm_manager_type(bo->bdev, bo->mem.mem_type);
 
        if (!map->virtual)
                return;
@@ -628,11 +628,11 @@ EXPORT_SYMBOL(ttm_bo_kunmap);
 int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                              struct dma_fence *fence,
                              bool evict,
-                             struct ttm_mem_reg *new_mem)
+                             struct ttm_resource *new_mem)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type);
+       struct ttm_resource *old_mem = &bo->mem;
        int ret;
        struct ttm_buffer_object *ghost_obj;
 
@@ -642,7 +642,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                if (ret)
                        return ret;
 
-               if (man->flags & TTM_MEMTYPE_FLAG_FIXED) {
+               if (!man->use_tt) {
                        ttm_tt_destroy(bo->ttm);
                        bo->ttm = NULL;
                }
@@ -671,7 +671,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                 * bo to be unbound and destroyed.
                 */
 
-               if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED))
+               if (man->use_tt)
                        ghost_obj->ttm = NULL;
                else
                        bo->ttm = NULL;
@@ -689,13 +689,13 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
 
 int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
                         struct dma_fence *fence, bool evict,
-                        struct ttm_mem_reg *new_mem)
+                        struct ttm_resource *new_mem)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_resource *old_mem = &bo->mem;
 
-       struct ttm_mem_type_manager *from = &bdev->man[old_mem->mem_type];
-       struct ttm_mem_type_manager *to = &bdev->man[new_mem->mem_type];
+       struct ttm_resource_manager *from = ttm_manager_type(bdev, old_mem->mem_type);
+       struct ttm_resource_manager *to = ttm_manager_type(bdev, new_mem->mem_type);
 
        int ret;
 
@@ -727,7 +727,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
                 * bo to be unbound and destroyed.
                 */
 
-               if (!(to->flags & TTM_MEMTYPE_FLAG_FIXED))
+               if (to->use_tt)
                        ghost_obj->ttm = NULL;
                else
                        bo->ttm = NULL;
@@ -735,7 +735,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
                dma_resv_unlock(&ghost_obj->base._resv);
                ttm_bo_put(ghost_obj);
 
-       } else if (from->flags & TTM_MEMTYPE_FLAG_FIXED) {
+       } else if (!from->use_tt) {
 
                /**
                 * BO doesn't have a TTM we need to bind/unbind. Just remember
@@ -765,7 +765,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
                if (ret)
                        return ret;
 
-               if (to->flags & TTM_MEMTYPE_FLAG_FIXED) {
+               if (!to->use_tt) {
                        ttm_tt_destroy(bo->ttm);
                        bo->ttm = NULL;
                }
index 33526c5..0b805f7 100644 (file)
@@ -281,8 +281,8 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
        pgoff_t i;
        vm_fault_t ret = VM_FAULT_NOPAGE;
        unsigned long address = vmf->address;
-       struct ttm_mem_type_manager *man =
-               &bdev->man[bo->mem.mem_type];
+       struct ttm_resource_manager *man =
+               ttm_manager_type(bdev, bo->mem.mem_type);
 
        /*
         * Refuse to fault imported pages. This should be handled
@@ -308,9 +308,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
                }
 
                if (bo->moving != moving) {
-                       spin_lock(&ttm_bo_glob.lru_lock);
-                       ttm_bo_move_to_lru_tail(bo, NULL);
-                       spin_unlock(&ttm_bo_glob.lru_lock);
+                       ttm_bo_move_to_lru_tail_unlocked(bo);
                }
                dma_fence_put(moving);
        }
index 1797f04..8a8f1a6 100644 (file)
@@ -93,7 +93,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
        list_for_each_entry(entry, list, head) {
                struct ttm_buffer_object *bo = entry->bo;
 
-               ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
+               ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket);
                if (ret == -EALREADY && dups) {
                        struct ttm_validate_buffer *safe = entry;
                        entry = list_prev_entry(entry, head);
@@ -119,13 +119,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
                ttm_eu_backoff_reservation_reverse(list, entry);
 
                if (ret == -EDEADLK) {
-                       if (intr) {
-                               ret = dma_resv_lock_slow_interruptible(bo->base.resv,
-                                                                                ticket);
-                       } else {
-                               dma_resv_lock_slow(bo->base.resv, ticket);
-                               ret = 0;
-                       }
+                       ret = ttm_bo_reserve_slowpath(bo, intr, ticket);
                }
 
                if (!ret && entry->num_shared)
@@ -133,8 +127,6 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
                                                                entry->num_shared);
 
                if (unlikely(ret != 0)) {
-                       if (ret == -EINTR)
-                               ret = -ERESTARTSYS;
                        if (ticket) {
                                ww_acquire_done(ticket);
                                ww_acquire_fini(ticket);
diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
new file mode 100644 (file)
index 0000000..770c898
--- /dev/null
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include <drm/ttm/ttm_module.h>
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_placement.h>
+#include <drm/drm_mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+/**
+ * Currently we use a spinlock for the lock, but a mutex *may* be
+ * more appropriate to reduce scheduling latency if the range manager
+ * ends up with very fragmented allocation patterns.
+ */
+
+struct ttm_range_manager {
+       struct ttm_resource_manager manager;
+       struct drm_mm mm;
+       spinlock_t lock;
+};
+
+static inline struct ttm_range_manager *to_range_manager(struct ttm_resource_manager *man)
+{
+       return container_of(man, struct ttm_range_manager, manager);
+}
+
+static int ttm_range_man_alloc(struct ttm_resource_manager *man,
+                              struct ttm_buffer_object *bo,
+                              const struct ttm_place *place,
+                              struct ttm_resource *mem)
+{
+       struct ttm_range_manager *rman = to_range_manager(man);
+       struct drm_mm *mm = &rman->mm;
+       struct drm_mm_node *node;
+       enum drm_mm_insert_mode mode;
+       unsigned long lpfn;
+       int ret;
+
+       lpfn = place->lpfn;
+       if (!lpfn)
+               lpfn = man->size;
+
+       node = kzalloc(sizeof(*node), GFP_KERNEL);
+       if (!node)
+               return -ENOMEM;
+
+       mode = DRM_MM_INSERT_BEST;
+       if (place->flags & TTM_PL_FLAG_TOPDOWN)
+               mode = DRM_MM_INSERT_HIGH;
+
+       spin_lock(&rman->lock);
+       ret = drm_mm_insert_node_in_range(mm, node,
+                                         mem->num_pages,
+                                         mem->page_alignment, 0,
+                                         place->fpfn, lpfn, mode);
+       spin_unlock(&rman->lock);
+
+       if (unlikely(ret)) {
+               kfree(node);
+       } else {
+               mem->mm_node = node;
+               mem->start = node->start;
+       }
+
+       return ret;
+}
+
+static void ttm_range_man_free(struct ttm_resource_manager *man,
+                              struct ttm_resource *mem)
+{
+       struct ttm_range_manager *rman = to_range_manager(man);
+
+       if (mem->mm_node) {
+               spin_lock(&rman->lock);
+               drm_mm_remove_node(mem->mm_node);
+               spin_unlock(&rman->lock);
+
+               kfree(mem->mm_node);
+               mem->mm_node = NULL;
+       }
+}
+
+static const struct ttm_resource_manager_func ttm_range_manager_func;
+
+int ttm_range_man_init(struct ttm_bo_device *bdev,
+                      unsigned type,
+                      uint32_t available_caching,
+                      uint32_t default_caching,
+                      bool use_tt,
+                      unsigned long p_size)
+{
+       struct ttm_resource_manager *man;
+       struct ttm_range_manager *rman;
+
+       rman = kzalloc(sizeof(*rman), GFP_KERNEL);
+       if (!rman)
+               return -ENOMEM;
+
+       man = &rman->manager;
+       man->available_caching = available_caching;
+       man->default_caching = default_caching;
+       man->use_tt = use_tt;
+
+       man->func = &ttm_range_manager_func;
+
+       ttm_resource_manager_init(man, p_size);
+
+       drm_mm_init(&rman->mm, 0, p_size);
+       spin_lock_init(&rman->lock);
+
+       ttm_set_driver_manager(bdev, type, &rman->manager);
+       ttm_resource_manager_set_used(man, true);
+       return 0;
+}
+EXPORT_SYMBOL(ttm_range_man_init);
+
+int ttm_range_man_fini(struct ttm_bo_device *bdev,
+                      unsigned type)
+{
+       struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
+       struct ttm_range_manager *rman = to_range_manager(man);
+       struct drm_mm *mm = &rman->mm;
+       int ret;
+
+       ttm_resource_manager_set_used(man, false);
+
+       ret = ttm_resource_manager_force_list_clean(bdev, man);
+       if (ret)
+               return ret;
+
+       spin_lock(&rman->lock);
+       drm_mm_clean(mm);
+       drm_mm_takedown(mm);
+       spin_unlock(&rman->lock);
+
+       ttm_resource_manager_cleanup(man);
+       ttm_set_driver_manager(bdev, type, NULL);
+       kfree(rman);
+       return 0;
+}
+EXPORT_SYMBOL(ttm_range_man_fini);
+
+static void ttm_range_man_debug(struct ttm_resource_manager *man,
+                               struct drm_printer *printer)
+{
+       struct ttm_range_manager *rman = to_range_manager(man);
+
+       spin_lock(&rman->lock);
+       drm_mm_print(&rman->mm, printer);
+       spin_unlock(&rman->lock);
+}
+
+static const struct ttm_resource_manager_func ttm_range_manager_func = {
+       .alloc = ttm_range_man_alloc,
+       .free = ttm_range_man_free,
+       .debug = ttm_range_man_debug
+};
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
new file mode 100644 (file)
index 0000000..33b6425
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Christian König
+ */
+
+#include <drm/ttm/ttm_resource.h>
+#include <drm/ttm/ttm_bo_driver.h>
+
+int ttm_resource_alloc(struct ttm_buffer_object *bo,
+                      const struct ttm_place *place,
+                      struct ttm_resource *res)
+{
+       struct ttm_resource_manager *man =
+               ttm_manager_type(bo->bdev, res->mem_type);
+
+       res->mm_node = NULL;
+       if (!man->func || !man->func->alloc)
+               return 0;
+
+       return man->func->alloc(man, bo, place, res);
+}
+
+void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res)
+{
+       struct ttm_resource_manager *man =
+               ttm_manager_type(bo->bdev, res->mem_type);
+
+       if (man->func && man->func->free)
+               man->func->free(man, res);
+
+       res->mm_node = NULL;
+       res->mem_type = TTM_PL_SYSTEM;
+}
+EXPORT_SYMBOL(ttm_resource_free);
+
+/**
+ * ttm_resource_manager_init
+ *
+ * @man: memory manager object to init
+ * @p_size: size managed area in pages.
+ *
+ * Initialise core parts of a manager object.
+ */
+void ttm_resource_manager_init(struct ttm_resource_manager *man,
+                              unsigned long p_size)
+{
+       unsigned i;
+
+       man->use_io_reserve_lru = false;
+       mutex_init(&man->io_reserve_mutex);
+       spin_lock_init(&man->move_lock);
+       INIT_LIST_HEAD(&man->io_reserve_lru);
+       man->size = p_size;
+
+       for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
+               INIT_LIST_HEAD(&man->lru[i]);
+       man->move = NULL;
+}
+EXPORT_SYMBOL(ttm_resource_manager_init);
+
+/*
+ * ttm_resource_manager_force_list_clean
+ *
+ * @bdev - device to use
+ * @man - manager to use
+ *
+ * Force all the objects out of a memory manager until clean.
+ * Part of memory manager cleanup sequence.
+ */
+int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev,
+                                         struct ttm_resource_manager *man)
+{
+       struct ttm_operation_ctx ctx = {
+               .interruptible = false,
+               .no_wait_gpu = false,
+               .flags = TTM_OPT_FLAG_FORCE_ALLOC
+       };
+       struct ttm_bo_global *glob = &ttm_bo_glob;
+       struct dma_fence *fence;
+       int ret;
+       unsigned i;
+
+       /*
+        * Can't use standard list traversal since we're unlocking.
+        */
+
+       spin_lock(&glob->lru_lock);
+       for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+               while (!list_empty(&man->lru[i])) {
+                       spin_unlock(&glob->lru_lock);
+                       ret = ttm_mem_evict_first(bdev, man, NULL, &ctx,
+                                                 NULL);
+                       if (ret)
+                               return ret;
+                       spin_lock(&glob->lru_lock);
+               }
+       }
+       spin_unlock(&glob->lru_lock);
+
+       spin_lock(&man->move_lock);
+       fence = dma_fence_get(man->move);
+       spin_unlock(&man->move_lock);
+
+       if (fence) {
+               ret = dma_fence_wait(fence, false);
+               dma_fence_put(fence);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ttm_resource_manager_force_list_clean);
+
+/**
+ * ttm_resource_manager_debug
+ *
+ * @man: manager type to dump.
+ * @p: printer to use for debug.
+ */
+void ttm_resource_manager_debug(struct ttm_resource_manager *man,
+                               struct drm_printer *p)
+{
+       drm_printf(p, "  use_type: %d\n", man->use_type);
+       drm_printf(p, "  use_tt: %d\n", man->use_tt);
+       drm_printf(p, "  size: %llu\n", man->size);
+       drm_printf(p, "  available_caching: 0x%08X\n", man->available_caching);
+       drm_printf(p, "  default_caching: 0x%08X\n", man->default_caching);
+       if (man->func && man->func->debug)
+               (*man->func->debug)(man, p);
+}
+EXPORT_SYMBOL(ttm_resource_manager_debug);
index 3437711..9aa4fbe 100644 (file)
@@ -314,7 +314,7 @@ void ttm_tt_unbind(struct ttm_tt *ttm)
        }
 }
 
-int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem,
+int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
                struct ttm_operation_ctx *ctx)
 {
        int ret = 0;
index 82a7dfd..9f7c261 100644 (file)
@@ -358,18 +358,7 @@ static struct platform_driver v3d_platform_driver = {
        },
 };
 
-static int __init v3d_drm_register(void)
-{
-       return platform_driver_register(&v3d_platform_driver);
-}
-
-static void __exit v3d_drm_unregister(void)
-{
-       platform_driver_unregister(&v3d_platform_driver);
-}
-
-module_init(v3d_drm_register);
-module_exit(v3d_drm_unregister);
+module_platform_driver(v3d_platform_driver);
 
 MODULE_ALIAS("platform:v3d-drm");
 MODULE_DESCRIPTION("Broadcom V3D DRM Driver");
index a775fed..313339b 100644 (file)
@@ -471,8 +471,8 @@ static int __init vgem_init(void)
 
 out_put:
        drm_dev_put(&vgem_device->drm);
+       platform_device_unregister(vgem_device->platform);
        return ret;
-
 out_unregister:
        platform_device_unregister(vgem_device->platform);
 out_free:
index 4af2f19..4f3b07a 100644 (file)
@@ -33,7 +33,7 @@ static uint32_t compute_crc(void *vaddr_out, struct vkms_composer *composer)
                                     + (i * composer->pitch)
                                     + (j * composer->cpp);
                        /* XRGB format ignores Alpha channel */
-                       memset(vaddr_out + src_offset + 24, 0,  8);
+                       bitmap_clear(vaddr_out + src_offset, 24, 8);
                        crc = crc32_le(crc, vaddr_out + src_offset,
                                       sizeof(u32));
                }
@@ -233,6 +233,22 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
        return 0;
 }
 
+static void vkms_set_composer(struct vkms_output *out, bool enabled)
+{
+       bool old_enabled;
+
+       if (enabled)
+               drm_crtc_vblank_get(&out->crtc);
+
+       spin_lock_irq(&out->lock);
+       old_enabled = out->composer_enabled;
+       out->composer_enabled = enabled;
+       spin_unlock_irq(&out->lock);
+
+       if (old_enabled)
+               drm_crtc_vblank_put(&out->crtc);
+}
+
 int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
 {
        struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
@@ -241,9 +257,7 @@ int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
 
        ret = vkms_crc_parse_source(src_name, &enabled);
 
-       spin_lock_irq(&out->lock);
-       out->composer_enabled = enabled;
-       spin_unlock_irq(&out->lock);
+       vkms_set_composer(out, enabled);
 
        return ret;
 }
index 57a8a39..83dd556 100644 (file)
@@ -190,8 +190,8 @@ static int __init vkms_init(void)
 
 out_put:
        drm_dev_put(&vkms_device->drm);
+       platform_device_unregister(vkms_device->platform);
        return ret;
-
 out_unregister:
        platform_device_unregister(vkms_device->platform);
 out_free:
index 1e59c01..3229451 100644 (file)
@@ -1135,14 +1135,14 @@ void vmw_bo_swap_notify(struct ttm_buffer_object *bo)
  * vmw_bo_move_notify - TTM move_notify_callback
  *
  * @bo: The TTM buffer object about to move.
- * @mem: The struct ttm_mem_reg indicating to what memory
+ * @mem: The struct ttm_resource indicating to what memory
  *       region the move is taking place.
  *
  * Detaches cached maps and device bindings that require that the
  * buffer doesn't move.
  */
 void vmw_bo_move_notify(struct ttm_buffer_object *bo,
-                       struct ttm_mem_reg *mem)
+                       struct ttm_resource *mem)
 {
        struct vmw_buffer_object *vbo;
 
index fb39826..e600128 100644 (file)
@@ -620,6 +620,29 @@ static int vmw_dma_masks(struct vmw_private *dev_priv)
        return ret;
 }
 
+static int vmw_vram_manager_init(struct vmw_private *dev_priv)
+{
+       int ret;
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       ret = vmw_thp_init(dev_priv);
+#else
+       ret = ttm_range_man_init(&dev_priv->bdev, TTM_PL_VRAM,
+                                TTM_PL_FLAG_CACHED, TTM_PL_FLAG_CACHED,
+                                false, dev_priv->vram_size >> PAGE_SHIFT);
+#endif
+       ttm_resource_manager_set_used(ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM), false);
+       return ret;
+}
+
+static void vmw_vram_manager_fini(struct vmw_private *dev_priv)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       vmw_thp_fini(dev_priv);
+#else
+       ttm_range_man_fini(&dev_priv->bdev, TTM_PL_VRAM);
+#endif
+}
+
 static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 {
        struct vmw_private *dev_priv;
@@ -859,23 +882,30 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                DRM_ERROR("Failed initializing TTM buffer object driver.\n");
                goto out_no_bdev;
        }
+       ttm_manager_type(&dev_priv->bdev, TTM_PL_SYSTEM)->available_caching =
+               TTM_PL_FLAG_CACHED;
 
        /*
         * Enable VRAM, but initially don't use it until SVGA is enabled and
         * unhidden.
         */
-       ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM,
-                            (dev_priv->vram_size >> PAGE_SHIFT));
+
+       ret = vmw_vram_manager_init(dev_priv);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Failed initializing memory manager for VRAM.\n");
                goto out_no_vram;
        }
-       dev_priv->bdev.man[TTM_PL_VRAM].use_type = false;
 
+       /*
+        * "Guest Memory Regions" is an aperture like feature with
+        *  one slot per bo. There is an upper limit of the number of
+        *  slots as well as the bo size.
+        */
        dev_priv->has_gmr = true;
+       /* TODO: This is most likely not correct */
        if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
-           refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
-                                        VMW_PL_GMR) != 0) {
+           refuse_dma ||
+           vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) {
                DRM_INFO("No GMR memory available. "
                         "Graphics memory resources are very limited.\n");
                dev_priv->has_gmr = false;
@@ -883,8 +913,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 
        if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) {
                dev_priv->has_mob = true;
-               if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
-                                  VMW_PL_MOB) != 0) {
+
+               if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) {
                        DRM_INFO("No MOB memory available. "
                                 "3D will be disabled.\n");
                        dev_priv->has_mob = false;
@@ -961,10 +991,10 @@ out_no_fifo:
        vmw_kms_close(dev_priv);
 out_no_kms:
        if (dev_priv->has_mob)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+               vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB);
        if (dev_priv->has_gmr)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
-       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+               vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR);
+       vmw_vram_manager_fini(dev_priv);
 out_no_vram:
        (void)ttm_bo_device_release(&dev_priv->bdev);
 out_no_bdev:
@@ -1012,12 +1042,12 @@ static void vmw_driver_unload(struct drm_device *dev)
        vmw_overlay_close(dev_priv);
 
        if (dev_priv->has_gmr)
-               (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
-       (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
+               vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR);
 
        vmw_release_device_early(dev_priv);
        if (dev_priv->has_mob)
-               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
+               vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB);
+       vmw_vram_manager_fini(dev_priv);
        (void) ttm_bo_device_release(&dev_priv->bdev);
        drm_vma_offset_manager_destroy(&dev_priv->vma_manager);
        vmw_release_device_late(dev_priv);
@@ -1159,10 +1189,12 @@ static void vmw_master_drop(struct drm_device *dev,
  */
 static void __vmw_svga_enable(struct vmw_private *dev_priv)
 {
+       struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
+
        spin_lock(&dev_priv->svga_lock);
-       if (!dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
+       if (!ttm_resource_manager_used(man)) {
                vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE);
-               dev_priv->bdev.man[TTM_PL_VRAM].use_type = true;
+               ttm_resource_manager_set_used(man, true);
        }
        spin_unlock(&dev_priv->svga_lock);
 }
@@ -1188,9 +1220,11 @@ void vmw_svga_enable(struct vmw_private *dev_priv)
  */
 static void __vmw_svga_disable(struct vmw_private *dev_priv)
 {
+       struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
+
        spin_lock(&dev_priv->svga_lock);
-       if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
-               dev_priv->bdev.man[TTM_PL_VRAM].use_type = false;
+       if (ttm_resource_manager_used(man)) {
+               ttm_resource_manager_set_used(man, false);
                vmw_write(dev_priv, SVGA_REG_ENABLE,
                          SVGA_REG_ENABLE_HIDE |
                          SVGA_REG_ENABLE_ENABLE);
@@ -1207,6 +1241,7 @@ static void __vmw_svga_disable(struct vmw_private *dev_priv)
  */
 void vmw_svga_disable(struct vmw_private *dev_priv)
 {
+       struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
        /*
         * Disabling SVGA will turn off device modesetting capabilities, so
         * notify KMS about that so that it doesn't cache atomic state that
@@ -1222,8 +1257,8 @@ void vmw_svga_disable(struct vmw_private *dev_priv)
        vmw_kms_lost_device(dev_priv->dev);
        ttm_write_lock(&dev_priv->reservation_sem, false);
        spin_lock(&dev_priv->svga_lock);
-       if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
-               dev_priv->bdev.man[TTM_PL_VRAM].use_type = false;
+       if (ttm_resource_manager_used(man)) {
+               ttm_resource_manager_set_used(man, false);
                spin_unlock(&dev_priv->svga_lock);
                if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM))
                        DRM_ERROR("Failed evicting VRAM buffers.\n");
index 3596f39..871ad73 100644 (file)
@@ -793,7 +793,7 @@ extern void vmw_resource_unreserve(struct vmw_resource *res,
                                   struct vmw_buffer_object *new_backup,
                                   unsigned long new_backup_offset);
 extern void vmw_query_move_notify(struct ttm_buffer_object *bo,
-                                 struct ttm_mem_reg *mem);
+                                 struct ttm_resource *mem);
 extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob);
 extern void vmw_resource_evict_all(struct vmw_private *dev_priv);
 extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo);
@@ -878,7 +878,7 @@ extern void vmw_bo_fence_single(struct ttm_buffer_object *bo,
 extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo);
 extern void vmw_bo_unmap(struct vmw_buffer_object *vbo);
 extern void vmw_bo_move_notify(struct ttm_buffer_object *bo,
-                              struct ttm_mem_reg *mem);
+                              struct ttm_resource *mem);
 extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
 extern struct vmw_buffer_object *
 vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle);
@@ -1019,10 +1019,12 @@ extern struct ttm_placement vmw_mob_placement;
 extern struct ttm_placement vmw_mob_ne_placement;
 extern struct ttm_placement vmw_nonfixed_placement;
 extern struct ttm_bo_driver vmw_bo_driver;
-extern int vmw_bo_map_dma(struct ttm_buffer_object *bo);
-extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo);
 extern const struct vmw_sg_table *
 vmw_bo_sg_table(struct ttm_buffer_object *bo);
+extern int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
+                                     unsigned long bo_size,
+                                     struct ttm_buffer_object **bo_p);
+
 extern void vmw_piter_start(struct vmw_piter *viter,
                            const struct vmw_sg_table *vsgt,
                            unsigned long p_offs);
@@ -1219,7 +1221,8 @@ int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
  * GMR Id manager
  */
 
-extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func;
+int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type);
+void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type);
 
 /**
  * Prime - vmwgfx_prime.c
@@ -1518,9 +1521,8 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
 
 /* Transparent hugepage support - vmwgfx_thp.c */
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-extern const struct ttm_mem_type_manager_func vmw_thp_func;
-#else
-#define vmw_thp_func ttm_bo_manager_func
+extern int vmw_thp_init(struct vmw_private *dev_priv);
+void vmw_thp_fini(struct vmw_private *dev_priv);
 #endif
 
 /**
index 4a76fc7..bb76acb 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kernel.h>
 
 struct vmwgfx_gmrid_man {
+       struct ttm_resource_manager manager;
        spinlock_t lock;
        struct ida gmr_ida;
        uint32_t max_gmr_ids;
@@ -44,13 +45,17 @@ struct vmwgfx_gmrid_man {
        uint32_t used_gmr_pages;
 };
 
-static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
+static struct vmwgfx_gmrid_man *to_gmrid_manager(struct ttm_resource_manager *man)
+{
+       return container_of(man, struct vmwgfx_gmrid_man, manager);
+}
+
+static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man,
                                  struct ttm_buffer_object *bo,
                                  const struct ttm_place *place,
-                                 struct ttm_mem_reg *mem)
+                                 struct ttm_resource *mem)
 {
-       struct vmwgfx_gmrid_man *gman =
-               (struct vmwgfx_gmrid_man *)man->priv;
+       struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
        int id;
 
        id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
@@ -79,11 +84,10 @@ nospace:
        return -ENOSPC;
 }
 
-static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
-                                  struct ttm_mem_reg *mem)
+static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man,
+                                  struct ttm_resource *mem)
 {
-       struct vmwgfx_gmrid_man *gman =
-               (struct vmwgfx_gmrid_man *)man->priv;
+       struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
 
        if (mem->mm_node) {
                ida_free(&gman->gmr_ida, mem->start);
@@ -94,22 +98,30 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
        }
 }
 
-static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
-                             unsigned long p_size)
+static const struct ttm_resource_manager_func vmw_gmrid_manager_func;
+
+int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type)
 {
-       struct vmw_private *dev_priv =
-               container_of(man->bdev, struct vmw_private, bdev);
+       struct ttm_resource_manager *man;
        struct vmwgfx_gmrid_man *gman =
                kzalloc(sizeof(*gman), GFP_KERNEL);
 
        if (unlikely(!gman))
                return -ENOMEM;
 
+       man = &gman->manager;
+
+       man->func = &vmw_gmrid_manager_func;
+       man->available_caching = TTM_PL_FLAG_CACHED;
+       man->default_caching = TTM_PL_FLAG_CACHED;
+       /* TODO: This is most likely not correct */
+       man->use_tt = true;
+       ttm_resource_manager_init(man, 0);
        spin_lock_init(&gman->lock);
        gman->used_gmr_pages = 0;
        ida_init(&gman->gmr_ida);
 
-       switch (p_size) {
+       switch (type) {
        case VMW_PL_GMR:
                gman->max_gmr_ids = dev_priv->max_gmr_ids;
                gman->max_gmr_pages = dev_priv->max_gmr_pages;
@@ -121,32 +133,29 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
        default:
                BUG();
        }
-       man->priv = (void *) gman;
+       ttm_set_driver_manager(&dev_priv->bdev, type, &gman->manager);
+       ttm_resource_manager_set_used(man, true);
        return 0;
 }
 
-static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
+void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type)
 {
-       struct vmwgfx_gmrid_man *gman =
-               (struct vmwgfx_gmrid_man *)man->priv;
+       struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, type);
+       struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man);
 
-       if (gman) {
-               ida_destroy(&gman->gmr_ida);
-               kfree(gman);
-       }
-       return 0;
-}
+       ttm_resource_manager_set_used(man, false);
+
+       ttm_resource_manager_force_list_clean(&dev_priv->bdev, man);
+
+       ttm_resource_manager_cleanup(man);
+
+       ttm_set_driver_manager(&dev_priv->bdev, type, NULL);
+       ida_destroy(&gman->gmr_ida);
+       kfree(gman);
 
-static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
-                               struct drm_printer *printer)
-{
-       drm_printf(printer, "No debug info available for the GMR id manager\n");
 }
 
-const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
-       .init = vmw_gmrid_man_init,
-       .takedown = vmw_gmrid_man_takedown,
-       .get_node = vmw_gmrid_man_get_node,
-       .put_node = vmw_gmrid_man_put_node,
-       .debug = vmw_gmrid_man_debug
+static const struct ttm_resource_manager_func vmw_gmrid_manager_func = {
+       .alloc = vmw_gmrid_man_get_node,
+       .free = vmw_gmrid_man_put_node,
 };
index e8eb429..7f95ed6 100644 (file)
@@ -238,10 +238,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
        unsigned long offset;
        unsigned long bo_size;
        struct vmw_otable *otables = batch->otables;
-       struct ttm_operation_ctx ctx = {
-               .interruptible = false,
-               .no_wait_gpu = false
-       };
        SVGAOTableType i;
        int ret;
 
@@ -255,24 +251,9 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
                bo_size += otables[i].size;
        }
 
-       ret = ttm_bo_create(&dev_priv->bdev, bo_size,
-                           ttm_bo_type_device,
-                           &vmw_sys_ne_placement,
-                           0, false, &batch->otable_bo);
-
-       if (unlikely(ret != 0))
-               goto out_no_bo;
-
-       ret = ttm_bo_reserve(batch->otable_bo, false, true, NULL);
-       BUG_ON(ret != 0);
-       ret = vmw_bo_driver.ttm_tt_populate(batch->otable_bo->ttm, &ctx);
-       if (unlikely(ret != 0))
-               goto out_unreserve;
-       ret = vmw_bo_map_dma(batch->otable_bo);
+       ret = vmw_bo_create_and_populate(dev_priv, bo_size, &batch->otable_bo);
        if (unlikely(ret != 0))
-               goto out_unreserve;
-
-       ttm_bo_unreserve(batch->otable_bo);
+               return ret;
 
        offset = 0;
        for (i = 0; i < batch->num_otables; ++i) {
@@ -289,8 +270,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv,
 
        return 0;
 
-out_unreserve:
-       ttm_bo_unreserve(batch->otable_bo);
 out_no_setup:
        for (i = 0; i < batch->num_otables; ++i) {
                if (batch->otables[i].enabled)
@@ -300,7 +279,6 @@ out_no_setup:
 
        ttm_bo_put(batch->otable_bo);
        batch->otable_bo = NULL;
-out_no_bo:
        return ret;
 }
 
@@ -432,41 +410,9 @@ struct vmw_mob *vmw_mob_create(unsigned long data_pages)
 static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
                               struct vmw_mob *mob)
 {
-       int ret;
-       struct ttm_operation_ctx ctx = {
-               .interruptible = false,
-               .no_wait_gpu = false
-       };
-
        BUG_ON(mob->pt_bo != NULL);
 
-       ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE,
-                           ttm_bo_type_device,
-                           &vmw_sys_ne_placement,
-                           0, false, &mob->pt_bo);
-       if (unlikely(ret != 0))
-               return ret;
-
-       ret = ttm_bo_reserve(mob->pt_bo, false, true, NULL);
-
-       BUG_ON(ret != 0);
-       ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm, &ctx);
-       if (unlikely(ret != 0))
-               goto out_unreserve;
-       ret = vmw_bo_map_dma(mob->pt_bo);
-       if (unlikely(ret != 0))
-               goto out_unreserve;
-
-       ttm_bo_unreserve(mob->pt_bo);
-
-       return 0;
-
-out_unreserve:
-       ttm_bo_unreserve(mob->pt_bo);
-       ttm_bo_put(mob->pt_bo);
-       mob->pt_bo = NULL;
-
-       return ret;
+       return vmw_bo_create_and_populate(dev_priv, mob->num_pages * PAGE_SIZE, &mob->pt_bo);
 }
 
 /**
index c844103..c0f1560 100644 (file)
@@ -855,7 +855,7 @@ int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob)
  * states from the device.
  */
 void vmw_query_move_notify(struct ttm_buffer_object *bo,
-                          struct ttm_mem_reg *mem)
+                          struct ttm_resource *mem)
 {
        struct vmw_buffer_object *dx_query_mob;
        struct ttm_bo_device *bdev = bo->bdev;
index b7c816b..3c00a9e 100644 (file)
  * @lock: Manager lock.
  */
 struct vmw_thp_manager {
+       struct ttm_resource_manager manager;
        struct drm_mm mm;
        spinlock_t lock;
 };
 
+static struct vmw_thp_manager *to_thp_manager(struct ttm_resource_manager *man)
+{
+       return container_of(man, struct vmw_thp_manager, manager);
+}
+
 static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node,
                                  unsigned long align_pages,
                                  const struct ttm_place *place,
-                                 struct ttm_mem_reg *mem,
+                                 struct ttm_resource *mem,
                                  unsigned long lpfn,
                                  enum drm_mm_insert_mode mode)
 {
@@ -38,12 +44,12 @@ static int vmw_thp_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node,
        return -ENOSPC;
 }
 
-static int vmw_thp_get_node(struct ttm_mem_type_manager *man,
+static int vmw_thp_get_node(struct ttm_resource_manager *man,
                            struct ttm_buffer_object *bo,
                            const struct ttm_place *place,
-                           struct ttm_mem_reg *mem)
+                           struct ttm_resource *mem)
 {
-       struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+       struct vmw_thp_manager *rman = to_thp_manager(man);
        struct drm_mm *mm = &rman->mm;
        struct drm_mm_node *node;
        unsigned long align_pages;
@@ -100,10 +106,10 @@ found_unlock:
 
 
 
-static void vmw_thp_put_node(struct ttm_mem_type_manager *man,
-                            struct ttm_mem_reg *mem)
+static void vmw_thp_put_node(struct ttm_resource_manager *man,
+                            struct ttm_resource *mem)
 {
-       struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+       struct vmw_thp_manager *rman = to_thp_manager(man);
 
        if (mem->mm_node) {
                spin_lock(&rman->lock);
@@ -115,52 +121,63 @@ static void vmw_thp_put_node(struct ttm_mem_type_manager *man,
        }
 }
 
-static int vmw_thp_init(struct ttm_mem_type_manager *man,
-                       unsigned long p_size)
+int vmw_thp_init(struct vmw_private *dev_priv)
 {
+       struct ttm_resource_manager *man;
        struct vmw_thp_manager *rman;
 
        rman = kzalloc(sizeof(*rman), GFP_KERNEL);
        if (!rman)
                return -ENOMEM;
 
-       drm_mm_init(&rman->mm, 0, p_size);
+       man = &rman->manager;
+       man->available_caching = TTM_PL_FLAG_CACHED;
+       man->default_caching = TTM_PL_FLAG_CACHED;
+
+       ttm_resource_manager_init(man,
+                                 dev_priv->vram_size >> PAGE_SHIFT);
+
+       drm_mm_init(&rman->mm, 0, man->size);
        spin_lock_init(&rman->lock);
-       man->priv = rman;
+
+       ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, &rman->manager);
+       ttm_resource_manager_set_used(man, true);
        return 0;
 }
 
-static int vmw_thp_takedown(struct ttm_mem_type_manager *man)
+void vmw_thp_fini(struct vmw_private *dev_priv)
 {
-       struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+       struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM);
+       struct vmw_thp_manager *rman = to_thp_manager(man);
        struct drm_mm *mm = &rman->mm;
+       int ret;
+
+       ttm_resource_manager_set_used(man, false);
 
+       ret = ttm_resource_manager_force_list_clean(&dev_priv->bdev, man);
+       if (ret)
+               return;
        spin_lock(&rman->lock);
-       if (drm_mm_clean(mm)) {
-               drm_mm_takedown(mm);
-               spin_unlock(&rman->lock);
-               kfree(rman);
-               man->priv = NULL;
-               return 0;
-       }
+       drm_mm_clean(mm);
+       drm_mm_takedown(mm);
        spin_unlock(&rman->lock);
-       return -EBUSY;
+       ttm_resource_manager_cleanup(man);
+       ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, NULL);
+       kfree(rman);
 }
 
-static void vmw_thp_debug(struct ttm_mem_type_manager *man,
+static void vmw_thp_debug(struct ttm_resource_manager *man,
                          struct drm_printer *printer)
 {
-       struct vmw_thp_manager *rman = (struct vmw_thp_manager *) man->priv;
+       struct vmw_thp_manager *rman = to_thp_manager(man);
 
        spin_lock(&rman->lock);
        drm_mm_print(&rman->mm, printer);
        spin_unlock(&rman->lock);
 }
 
-const struct ttm_mem_type_manager_func vmw_thp_func = {
-       .init = vmw_thp_init,
-       .takedown = vmw_thp_takedown,
-       .get_node = vmw_thp_get_node,
-       .put_node = vmw_thp_put_node,
+const struct ttm_resource_manager_func vmw_thp_func = {
+       .alloc = vmw_thp_get_node,
+       .free = vmw_thp_put_node,
        .debug = vmw_thp_debug
 };
index ab524ab..7247347 100644 (file)
@@ -519,43 +519,6 @@ static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
        vmw_tt->mapped = false;
 }
 
-
-/**
- * vmw_bo_map_dma - Make sure buffer object pages are visible to the device
- *
- * @bo: Pointer to a struct ttm_buffer_object
- *
- * Wrapper around vmw_ttm_map_dma, that takes a TTM buffer object pointer
- * instead of a pointer to a struct vmw_ttm_backend as argument.
- * Note that the buffer object must be either pinned or reserved before
- * calling this function.
- */
-int vmw_bo_map_dma(struct ttm_buffer_object *bo)
-{
-       struct vmw_ttm_tt *vmw_tt =
-               container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
-
-       return vmw_ttm_map_dma(vmw_tt);
-}
-
-
-/**
- * vmw_bo_unmap_dma - Make sure buffer object pages are visible to the device
- *
- * @bo: Pointer to a struct ttm_buffer_object
- *
- * Wrapper around vmw_ttm_unmap_dma, that takes a TTM buffer object pointer
- * instead of a pointer to a struct vmw_ttm_backend as argument.
- */
-void vmw_bo_unmap_dma(struct ttm_buffer_object *bo)
-{
-       struct vmw_ttm_tt *vmw_tt =
-               container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
-
-       vmw_ttm_unmap_dma(vmw_tt);
-}
-
-
 /**
  * vmw_bo_sg_table - Return a struct vmw_sg_table object for a
  * TTM buffer object
@@ -576,7 +539,7 @@ const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo)
 }
 
 
-static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
+static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem)
 {
        struct vmw_ttm_tt *vmw_be =
                container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
@@ -734,40 +697,6 @@ out_no_init:
        return NULL;
 }
 
-static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
-                     struct ttm_mem_type_manager *man)
-{
-       switch (type) {
-       case TTM_PL_SYSTEM:
-               /* System memory */
-               man->available_caching = TTM_PL_FLAG_CACHED;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case TTM_PL_VRAM:
-               /* "On-card" video ram */
-               man->func = &vmw_thp_func;
-               man->flags = TTM_MEMTYPE_FLAG_FIXED;
-               man->available_caching = TTM_PL_FLAG_CACHED;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       case VMW_PL_GMR:
-       case VMW_PL_MOB:
-               /*
-                * "Guest Memory Regions" is an aperture like feature with
-                *  one slot per bo. There is an upper limit of the number of
-                *  slots as well as the bo size.
-                */
-               man->func = &vmw_gmrid_manager_func;
-               man->available_caching = TTM_PL_FLAG_CACHED;
-               man->default_caching = TTM_PL_FLAG_CACHED;
-               break;
-       default:
-               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static void vmw_evict_flags(struct ttm_buffer_object *bo,
                     struct ttm_placement *placement)
 {
@@ -782,7 +711,7 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp)
        return vmw_user_bo_verify_access(bo, tfile);
 }
 
-static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
 {
        struct vmw_private *dev_priv = container_of(bdev, struct vmw_private, bdev);
 
@@ -812,7 +741,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
  * vmw_move_notify - TTM move_notify_callback
  *
  * @bo: The TTM buffer object about to move.
- * @mem: The struct ttm_mem_reg indicating to what memory
+ * @mem: The struct ttm_resource indicating to what memory
  *       region the move is taking place.
  *
  * Calls move_notify for all subsystems needing it.
@@ -820,7 +749,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
  */
 static void vmw_move_notify(struct ttm_buffer_object *bo,
                            bool evict,
-                           struct ttm_mem_reg *mem)
+                           struct ttm_resource *mem)
 {
        vmw_bo_move_notify(bo, mem);
        vmw_query_move_notify(bo, mem);
@@ -843,7 +772,6 @@ struct ttm_bo_driver vmw_bo_driver = {
        .ttm_tt_create = &vmw_ttm_tt_create,
        .ttm_tt_populate = &vmw_ttm_populate,
        .ttm_tt_unpopulate = &vmw_ttm_unpopulate,
-       .init_mem_type = vmw_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = vmw_evict_flags,
        .move = NULL,
@@ -852,3 +780,38 @@ struct ttm_bo_driver vmw_bo_driver = {
        .swap_notify = vmw_swap_notify,
        .io_mem_reserve = &vmw_ttm_io_mem_reserve,
 };
+
+int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
+                              unsigned long bo_size,
+                              struct ttm_buffer_object **bo_p)
+{
+       struct ttm_operation_ctx ctx = {
+               .interruptible = false,
+               .no_wait_gpu = false
+       };
+       struct ttm_buffer_object *bo;
+       int ret;
+
+       ret = ttm_bo_create(&dev_priv->bdev, bo_size,
+                           ttm_bo_type_device,
+                           &vmw_sys_ne_placement,
+                           0, false, &bo);
+
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_bo_reserve(bo, false, true, NULL);
+       BUG_ON(ret != 0);
+       ret = vmw_ttm_populate(bo->ttm, &ctx);
+       if (likely(ret == 0)) {
+               struct vmw_ttm_tt *vmw_tt =
+                       container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+               ret = vmw_ttm_map_dma(vmw_tt);
+       }
+
+       ttm_bo_unreserve(bo);
+
+       if (likely(ret == 0))
+               *bo_p = bo;
+       return ret;
+}
index 09a9ad9..bcc92ae 100644 (file)
@@ -857,7 +857,7 @@ static void acornfb_parse_dram(char *opt)
                case 'M':
                case 'm':
                        size *= 1024;
-                       /* Fall through */
+                       fallthrough;
                case 'K':
                case 'k':
                        size *= 1024;
index 6f78389..1447324 100644 (file)
@@ -419,7 +419,7 @@ static int arcfb_ioctl(struct fb_info *info,
                        schedule();
                        finish_wait(&arcfb_waitq, &wait);
                }
-               /* fall through */
+               fallthrough;
 
                case FBIO_GETCONTROL2:
                {
index 1e25219..8c1d47e 100644 (file)
@@ -508,7 +508,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        case 32:
                var->transp.offset = 24;
                var->transp.length = 8;
-               /* fall through */
+               fallthrough;
        case 24:
                if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
                        /* RGB:888 mode */
@@ -633,7 +633,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
                case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
                case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
                case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
-               case 15: /* fall through */
+               case 15: fallthrough;
                case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
                case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
                case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
index 7c4483c..f3d8123 100644 (file)
@@ -1208,11 +1208,11 @@ static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
        case 1:
                if (mc & 0x4)
                        break;
-               /* fall through */
+               fallthrough;
        case 2:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKB_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKB_RESET;
-               /* fall through */
+               fallthrough;
        case 0:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKA_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKA_RESET;
@@ -1221,7 +1221,7 @@ static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
        case 1:
                if (!(mc & 0x4))
                        break;
-               /* fall through */
+               fallthrough;
        case 2:
                dll_sleep_mask |= MDLL_R300_RDCK__MRDCKD_SLEEP;
                dll_reset_mask |= MDLL_R300_RDCK__MRDCKD_RESET;
index 3df64a9..15a9ee7 100644 (file)
@@ -1476,11 +1476,11 @@ static void init_vgachip(struct fb_info *info)
                mdelay(100);
                /* mode */
                vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
-               /* fall through */
+               fallthrough;
        case BT_GD5480:
                /* from Klaus' NetBSD driver: */
                vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
-               /* fall through */
+               fallthrough;
        case BT_ALPINE:
                /* put blitter into 542x compat */
                vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
index 9c4f1be..a88dcb6 100644 (file)
@@ -713,7 +713,7 @@ static int controlfb_blank(int blank_mode, struct fb_info *info)
                        break;
                case FB_BLANK_POWERDOWN:
                        ctrl &= ~0x33;
-                       /* fall through */
+                       fallthrough;
                case FB_BLANK_NORMAL:
                        ctrl |= 0x400;
                        break;
index da7c88f..cc69649 100644 (file)
@@ -777,7 +777,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 
        if (info->fbops->fb_read)
                return info->fbops->fb_read(info, buf, count, ppos);
-       
+
        total_size = info->screen_size;
 
        if (total_size == 0)
@@ -842,7 +842,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 
        if (info->fbops->fb_write)
                return info->fbops->fb_write(info, buf, count, ppos);
-       
+
        total_size = info->screen_size;
 
        if (total_size == 0)
@@ -1057,7 +1057,7 @@ EXPORT_SYMBOL(fb_set_var);
 
 int
 fb_blank(struct fb_info *info, int blank)
-{      
+{
        struct fb_event event;
        int ret = -EINVAL;
 
@@ -1306,7 +1306,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
        case FBIOGET_CON2FBMAP:
        case FBIOPUT_CON2FBMAP:
                arg = (unsigned long) compat_ptr(arg);
-               /* fall through */
+               fallthrough;
        case FBIOBLANK:
                ret = do_fb_ioctl(info, cmd, arg);
                break;
@@ -1433,7 +1433,7 @@ out:
        return res;
 }
 
-static int 
+static int
 fb_release(struct inode *inode, struct file *file)
 __acquires(&info->lock)
 __releases(&info->lock)
@@ -1623,7 +1623,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
                        fb_info->pixmap.access_align = 32;
                        fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
                }
-       }       
+       }
        fb_info->pixmap.offset = 0;
 
        if (!fb_info->pixmap.blit_x)
index 67ebfe5..a547c21 100644 (file)
@@ -1287,7 +1287,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                dev_warn(info->dev,
                         "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
                         MFB_SET_PIXFMT_OLD);
-               /* fall through */
+               fallthrough;
        case MFB_SET_PIXFMT:
                if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
                        return -EFAULT;
@@ -1297,7 +1297,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
                dev_warn(info->dev,
                         "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
                         MFB_GET_PIXFMT_OLD);
-               /* fall through */
+               fallthrough;
        case MFB_GET_PIXFMT:
                pix_fmt = ad->pix_fmt;
                if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
index 13ded3a..e5475ae 100644 (file)
@@ -534,7 +534,7 @@ static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
                        break;
                case DFA_PIX_32BIT:
                        val |= (reg << 24);
-                       /* fall through */
+                       fallthrough;
                case DFA_PIX_24BIT:
                        val |= (reg << 16) | (reg << 8);
                        break;
index c65ec73..e6f35f8 100644 (file)
@@ -430,7 +430,7 @@ static int i740fb_decode_var(const struct fb_var_screeninfo *var,
                break;
        case 9 ... 15:
                bpp = 15;
-               /* fall through */
+               fallthrough;
        case 16:
                if ((1000000 / var->pixclock) > DACSPEED16) {
                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
index 5cd0f5f..4501e84 100644 (file)
@@ -141,7 +141,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
                out_le32(par->cmap_adr + 0x58,
                         in_le32(par->cmap_adr + 0x58) & ~0x20);
-               /* fall through */
+               fallthrough;
        case cmap_r128:
                /* Set palette index & data */
                out_8(par->cmap_adr + 0xb0, regno);
@@ -211,7 +211,7 @@ static int offb_blank(int blank, struct fb_info *info)
                                /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
                                out_le32(par->cmap_adr + 0x58,
                                         in_le32(par->cmap_adr + 0x58) & ~0x20);
-                               /* fall through */
+                               fallthrough;
                        case cmap_r128:
                                /* Set palette index & data */
                                out_8(par->cmap_adr + 0xb0, i);
index fa73acf..7317c9a 100644 (file)
@@ -328,13 +328,13 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
                        lcdc.bpp = 12;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        case OMAPFB_COLOR_YUV422:
                if (lcdc.ext_mode) {
                        lcdc.bpp = 16;
                        break;
                }
-               /* fallthrough */
+               fallthrough;
        default:
                /* FIXME: other BPPs.
                 * bpp1: code  0,     size 256
index 0cbcc74..3d090d2 100644 (file)
@@ -253,7 +253,7 @@ static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
                if (fbdev->ctrl->setcolreg)
                        r = fbdev->ctrl->setcolreg(regno, red, green, blue,
                                                        transp, update_hw_pal);
-               /* Fallthrough */
+               fallthrough;
        case OMAPFB_COLOR_RGB565:
        case OMAPFB_COLOR_RGB444:
                if (r != 0)
@@ -443,7 +443,7 @@ static int set_color_mode(struct omapfb_plane_struct *plane,
                return 0;
        case 12:
                var->bits_per_pixel = 16;
-               /* fall through */
+               fallthrough;
        case 16:
                if (plane->fbdev->panel->bpp == 12)
                        plane->color_mode = OMAPFB_COLOR_RGB444;
@@ -1531,27 +1531,27 @@ static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
        case OMAPFB_ACTIVE:
                for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
                        unregister_framebuffer(fbdev->fb_info[i]);
-               /* fall through */
+               fallthrough;
        case 7:
                omapfb_unregister_sysfs(fbdev);
-               /* fall through */
+               fallthrough;
        case 6:
                if (fbdev->panel->disable)
                        fbdev->panel->disable(fbdev->panel);
-               /* fall through */
+               fallthrough;
        case 5:
                omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
-               /* fall through */
+               fallthrough;
        case 4:
                planes_cleanup(fbdev);
-               /* fall through */
+               fallthrough;
        case 3:
                ctrl_cleanup(fbdev);
-               /* fall through */
+               fallthrough;
        case 2:
                if (fbdev->panel->cleanup)
                        fbdev->panel->cleanup(fbdev->panel);
-               /* fall through */
+               fallthrough;
        case 1:
                dev_set_drvdata(fbdev->dev, NULL);
                kfree(fbdev);
@@ -1854,7 +1854,7 @@ static int __init omapfb_setup(char *options)
                        case 'm':
                        case 'M':
                                vram *= 1024;
-                               /* Fall through */
+                               fallthrough;
                        case 'k':
                        case 'K':
                                vram *= 1024;
index 3920a0d..b2d6e6d 100644 (file)
@@ -1861,7 +1861,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY)
                        width = width >> 1;
-               /* fall through */
+               fallthrough;
        case OMAP_DSS_ROT_90:
        case OMAP_DSS_ROT_270:
                *offset1 = 0;
@@ -1884,7 +1884,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY)
                        width = width >> 1;
-               /* fall through */
+               fallthrough;
        case OMAP_DSS_ROT_90 + 4:
        case OMAP_DSS_ROT_270 + 4:
                *offset1 = 0;
index 22f1d37..496b43b 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/component.h>
 #include <video/omapfb_dss.h>
index a06b6f1..e3d441a 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/component.h>
 #include <video/omapfb_dss.h>
index f40be68..ea8c88a 100644 (file)
@@ -760,7 +760,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
                        r = -ENODEV;
                        break;
                }
-               /* FALLTHROUGH */
+               fallthrough;
 
        case OMAPFB_WAITFORVSYNC:
                DBG("ioctl WAITFORVSYNC\n");
index 836e7b1..a3decc7 100644 (file)
@@ -882,7 +882,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
                                / (var->bits_per_pixel >> 2);
                        break;
                }
-               /* fall through */
+               fallthrough;
        default:
                screen_width = fix->line_length / (var->bits_per_pixel >> 3);
                break;
index c7c98d8..0642555 100644 (file)
@@ -233,10 +233,10 @@ static u32 to3264(u32 timing, int bpp, int is64)
        switch (bpp) {
        case 24:
                timing *= 3;
-               /* fall through */
+               fallthrough;
        case 8:
                timing >>= 1;
-               /* fall through */
+               fallthrough;
        case 16:
                timing >>= 1;
        case 32:
index 2d9f69b..f4add36 100644 (file)
@@ -1028,6 +1028,8 @@ static int __init pvr2fb_setup(char *options)
        if (!options || !*options)
                return 0;
 
+       cable_arg[0] = output_arg[0] = 0;
+
        while ((this_opt = strsep(&options, ","))) {
                if (!*this_opt)
                        continue;
index a53d24f..f1551e0 100644 (file)
@@ -1614,7 +1614,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
                 */
                if (old_state != C_DISABLE_PM)
                        break;
-               /* fall through */
+               fallthrough;
 
        case C_ENABLE:
                /*
index 9dc9250..ba316bd 100644 (file)
@@ -284,7 +284,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
                /* 666 with one bit alpha/transparency */
                var->transp.offset      = 18;
                var->transp.length      = 1;
-               /* fall through */
+               fallthrough;
        case 18:
                var->bits_per_pixel     = 32;
 
@@ -312,7 +312,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
        case 25:
                var->transp.length      = var->bits_per_pixel - 24;
                var->transp.offset      = 24;
-               /* fall through */
+               fallthrough;
        case 24:
                /* our 24bpp is unpacked, so 32bpp */
                var->bits_per_pixel     = 32;
@@ -809,7 +809,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
        case FB_BLANK_POWERDOWN:
                wincon &= ~WINCONx_ENWIN;
                sfb->enabled &= ~(1 << index);
-               /* fall through - to FB_BLANK_NORMAL */
+               fallthrough;    /* to FB_BLANK_NORMAL */
 
        case FB_BLANK_NORMAL:
                /* disable the DMA and display 0x0 (black) */
index bda6cc3..e31cf63 100644 (file)
@@ -935,7 +935,7 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
                 */
                if (old_state != C_DISABLE_PM)
                        break;
-               /* fall through */
+               fallthrough;
 
        case C_ENABLE:
                /*
index 3fd87ae..661398e 100644 (file)
@@ -1859,8 +1859,7 @@ static int savage_init_hw(struct savagefb_par *par)
                vga_out8(0x3d4, 0x68, par);     /* memory control 1 */
                if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6))
                        RamSavage4[1] = 8;
-
-               /*FALLTHROUGH*/
+               fallthrough;
 
        case S3_SAVAGE2000:
                videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024;
index 8a27d12..c104342 100644 (file)
@@ -1594,7 +1594,7 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_NV21:
                info->fix.ypanstep = 2;
-               /* Fall through */
+               fallthrough;
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
                info->fix.xpanstep = 2;
@@ -2085,7 +2085,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_NV21:
                info->fix.ypanstep = 2;
-               /* Fall through */
+               fallthrough;
        case V4L2_PIX_FMT_NV16:
        case V4L2_PIX_FMT_NV61:
                info->fix.xpanstep = 2;
index 3dd1b1d..6a52eba 100644 (file)
@@ -1005,7 +1005,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
        case FB_BLANK_POWERDOWN:
                ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
                sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
-               /* fall through */
+               fallthrough;
 
        case FB_BLANK_NORMAL:
                ctrl |= SM501_DC_CRT_CONTROL_BLANK;
index f73e26c..f056d80 100644 (file)
@@ -523,7 +523,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        case 32:
                var->transp.offset = 24;
                var->transp.length = 8;
-               /* fall through */
+               fallthrough;
        case 24:
                var->red.offset = 16;
                var->green.offset = 8;
index 00307b8..5ec5144 100644 (file)
@@ -677,7 +677,7 @@ static void xenfb_backend_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* fall through - Missed the backend's CLOSING state. */
+               fallthrough;    /* Missed the backend's CLOSING state */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index af14560..9281365 100644 (file)
@@ -1604,10 +1604,13 @@ const char *drm_get_dvi_i_subconnector_name(int val);
 const char *drm_get_dvi_i_select_name(int val);
 const char *drm_get_tv_subconnector_name(int val);
 const char *drm_get_tv_select_name(int val);
+const char *drm_get_dp_subconnector_name(int val);
 const char *drm_get_content_protection_name(int val);
 const char *drm_get_hdcp_content_type_name(int val);
 
 int drm_mode_create_dvi_i_properties(struct drm_device *dev);
+void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector);
+
 int drm_mode_create_tv_margin_properties(struct drm_device *dev);
 int drm_mode_create_tv_properties(struct drm_device *dev,
                                  unsigned int num_modes,
index e47dc22..5c28199 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/types.h>
+#include <drm/drm_connector.h>
 
 /*
  * Unless otherwise noted, all values are from the DP 1.1a spec.  Note that
@@ -1619,6 +1620,13 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
 int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
 void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
                             const u8 port_cap[4], struct drm_dp_aux *aux);
+enum drm_mode_subconnector
+drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                        const u8 port_cap[4]);
+void drm_dp_set_subconnector_property(struct drm_connector *connector,
+                                     enum drm_connector_status status,
+                                     const u8 *dpcd,
+                                     const u8 port_cap[4]);
 
 void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
 void drm_dp_aux_init(struct drm_dp_aux *aux);
index c2d3d71..a18f73e 100644 (file)
@@ -680,6 +680,12 @@ struct drm_mode_config {
         */
        struct drm_property *dvi_i_select_subconnector_property;
 
+       /**
+        * @dp_subconnector_property: Optional DP property to differentiate
+        * between different DP downstream port types.
+        */
+       struct drm_property *dp_subconnector_property;
+
        /**
         * @tv_subconnector_property: Optional TV property to differentiate
         * between different TV connector types.
index 6193cb5..45a1b5a 100644 (file)
@@ -175,12 +175,9 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev,
                    const struct drm_panel_funcs *funcs,
                    int connector_type);
 
-int drm_panel_add(struct drm_panel *panel);
+void drm_panel_add(struct drm_panel *panel);
 void drm_panel_remove(struct drm_panel *panel);
 
-int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector);
-void drm_panel_detach(struct drm_panel *panel);
-
 int drm_panel_prepare(struct drm_panel *panel);
 int drm_panel_unprepare(struct drm_panel *panel);
 
index a9e13b2..6c58098 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/bitmap.h>
 #include <linux/dma-resv.h>
 
+#include "ttm_resource.h"
+
 struct ttm_bo_global;
 
 struct ttm_bo_device;
@@ -54,55 +56,6 @@ struct ttm_place;
 
 struct ttm_lru_bulk_move;
 
-/**
- * struct ttm_bus_placement
- *
- * @addr:              mapped virtual address
- * @base:              bus base address
- * @is_iomem:          is this io memory ?
- * @size:              size in byte
- * @offset:            offset from the base address
- * @io_reserved_vm:     The VM system has a refcount in @io_reserved_count
- * @io_reserved_count:  Refcounting the numbers of callers to ttm_mem_io_reserve
- *
- * Structure indicating the bus placement of an object.
- */
-struct ttm_bus_placement {
-       void            *addr;
-       phys_addr_t     base;
-       unsigned long   size;
-       unsigned long   offset;
-       bool            is_iomem;
-       bool            io_reserved_vm;
-       uint64_t        io_reserved_count;
-};
-
-
-/**
- * struct ttm_mem_reg
- *
- * @mm_node: Memory manager node.
- * @size: Requested size of memory region.
- * @num_pages: Actual size of memory region in pages.
- * @page_alignment: Page alignment.
- * @placement: Placement flags.
- * @bus: Placement on io bus accessible to the CPU
- *
- * Structure indicating the placement and space resources used by a
- * buffer object.
- */
-
-struct ttm_mem_reg {
-       void *mm_node;
-       unsigned long start;
-       unsigned long size;
-       unsigned long num_pages;
-       uint32_t page_alignment;
-       uint32_t mem_type;
-       uint32_t placement;
-       struct ttm_bus_placement bus;
-};
-
 /**
  * enum ttm_bo_type
  *
@@ -185,7 +138,7 @@ struct ttm_buffer_object {
         * Members protected by the bo::resv::reserved lock.
         */
 
-       struct ttm_mem_reg mem;
+       struct ttm_resource mem;
        struct file *persistent_swap_storage;
        struct ttm_tt *ttm;
        bool evicted;
@@ -314,12 +267,12 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, bool interruptible, bool no_wait);
  * ttm_bo_mem_compat - Check if proposed placement is compatible with a bo
  *
  * @placement:  Return immediately if buffer is busy.
- * @mem:  The struct ttm_mem_reg indicating the region where the bo resides
+ * @mem:  The struct ttm_resource indicating the region where the bo resides
  * @new_flags: Describes compatible placement found
  *
  * Returns true if the placement is compatible
  */
-bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_mem_reg *mem,
+bool ttm_bo_mem_compat(struct ttm_placement *placement, struct ttm_resource *mem,
                       uint32_t *new_flags);
 
 /**
@@ -531,52 +484,6 @@ int ttm_bo_create(struct ttm_bo_device *bdev, unsigned long size,
                  uint32_t page_alignment, bool interruptible,
                  struct ttm_buffer_object **p_bo);
 
-/**
- * ttm_bo_init_mm
- *
- * @bdev: Pointer to a ttm_bo_device struct.
- * @mem_type: The memory type.
- * @p_size: size managed area in pages.
- *
- * Initialize a manager for a given memory type.
- * Note: if part of driver firstopen, it must be protected from a
- * potentially racing lastclose.
- * Returns:
- * -EINVAL: invalid size or memory type.
- * -ENOMEM: Not enough memory.
- * May also return driver-specified errors.
- */
-int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
-                  unsigned long p_size);
-
-/**
- * ttm_bo_clean_mm
- *
- * @bdev: Pointer to a ttm_bo_device struct.
- * @mem_type: The memory type.
- *
- * Take down a manager for a given memory type after first walking
- * the LRU list to evict any buffers left alive.
- *
- * Normally, this function is part of lastclose() or unload(), and at that
- * point there shouldn't be any buffers left created by user-space, since
- * there should've been removed by the file descriptor release() method.
- * However, before this function is run, make sure to signal all sync objects,
- * and verify that the delayed delete queue is empty. The driver must also
- * make sure that there are no NO_EVICT buffers present in this memory type
- * when the call is made.
- *
- * If this function is part of a VT switch, the caller must make sure that
- * there are no appications currently validating buffers before this
- * function is called. The caller can do that by first taking the
- * struct ttm_bo_device::ttm_lock in write mode.
- *
- * Returns:
- * -EINVAL: invalid or uninitialized memory type.
- * -EBUSY: There are still buffers left in this memory type.
- */
-int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type);
-
 /**
  * ttm_bo_evict_mm
  *
@@ -713,6 +620,12 @@ static inline bool ttm_bo_uses_embedded_gem_object(struct ttm_buffer_object *bo)
        return bo->base.dev != NULL;
 }
 
+int ttm_mem_evict_first(struct ttm_bo_device *bdev,
+                       struct ttm_resource_manager *man,
+                       const struct ttm_place *place,
+                       struct ttm_operation_ctx *ctx,
+                       struct ww_acquire_ctx *ticket);
+
 /* Default number of pre-faulted pages in the TTM fault handler */
 #define TTM_BO_VM_NUM_PREFAULT 16
 
index 5a37f1c..bc8d0eb 100644 (file)
 #include "ttm_placement.h"
 #include "ttm_tt.h"
 
-#define TTM_MAX_BO_PRIORITY    4U
-
-#define TTM_MEMTYPE_FLAG_FIXED         (1 << 0)        /* Fixed (on-card) PCI memory */
-#define TTM_MEMTYPE_FLAG_MAPPABLE      (1 << 1)        /* Memory mappable */
-
-struct ttm_mem_type_manager;
-
-struct ttm_mem_type_manager_func {
-       /**
-        * struct ttm_mem_type_manager member init
-        *
-        * @man: Pointer to a memory type manager.
-        * @p_size: Implementation dependent, but typically the size of the
-        * range to be managed in pages.
-        *
-        * Called to initialize a private range manager. The function is
-        * expected to initialize the man::priv member.
-        * Returns 0 on success, negative error code on failure.
-        */
-       int  (*init)(struct ttm_mem_type_manager *man, unsigned long p_size);
-
-       /**
-        * struct ttm_mem_type_manager member takedown
-        *
-        * @man: Pointer to a memory type manager.
-        *
-        * Called to undo the setup done in init. All allocated resources
-        * should be freed.
-        */
-       int  (*takedown)(struct ttm_mem_type_manager *man);
-
-       /**
-        * struct ttm_mem_type_manager member get_node
-        *
-        * @man: Pointer to a memory type manager.
-        * @bo: Pointer to the buffer object we're allocating space for.
-        * @placement: Placement details.
-        * @flags: Additional placement flags.
-        * @mem: Pointer to a struct ttm_mem_reg to be filled in.
-        *
-        * This function should allocate space in the memory type managed
-        * by @man. Placement details if
-        * applicable are given by @placement. If successful,
-        * @mem::mm_node should be set to a non-null value, and
-        * @mem::start should be set to a value identifying the beginning
-        * of the range allocated, and the function should return zero.
-        * If the memory region accommodate the buffer object, @mem::mm_node
-        * should be set to NULL, and the function should return 0.
-        * If a system error occurred, preventing the request to be fulfilled,
-        * the function should return a negative error code.
-        *
-        * Note that @mem::mm_node will only be dereferenced by
-        * struct ttm_mem_type_manager functions and optionally by the driver,
-        * which has knowledge of the underlying type.
-        *
-        * This function may not be called from within atomic context, so
-        * an implementation can and must use either a mutex or a spinlock to
-        * protect any data structures managing the space.
-        */
-       int  (*get_node)(struct ttm_mem_type_manager *man,
-                        struct ttm_buffer_object *bo,
-                        const struct ttm_place *place,
-                        struct ttm_mem_reg *mem);
-
-       /**
-        * struct ttm_mem_type_manager member put_node
-        *
-        * @man: Pointer to a memory type manager.
-        * @mem: Pointer to a struct ttm_mem_reg to be filled in.
-        *
-        * This function frees memory type resources previously allocated
-        * and that are identified by @mem::mm_node and @mem::start. May not
-        * be called from within atomic context.
-        */
-       void (*put_node)(struct ttm_mem_type_manager *man,
-                        struct ttm_mem_reg *mem);
-
-       /**
-        * struct ttm_mem_type_manager member debug
-        *
-        * @man: Pointer to a memory type manager.
-        * @printer: Prefix to be used in printout to identify the caller.
-        *
-        * This function is called to print out the state of the memory
-        * type manager to aid debugging of out-of-memory conditions.
-        * It may not be called from within atomic context.
-        */
-       void (*debug)(struct ttm_mem_type_manager *man,
-                     struct drm_printer *printer);
-};
-
-/**
- * struct ttm_mem_type_manager
- *
- * @has_type: The memory type has been initialized.
- * @use_type: The memory type is enabled.
- * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory
- * managed by this memory type.
- * @gpu_offset: If used, the GPU offset of the first managed page of
- * fixed memory or the first managed location in an aperture.
- * @size: Size of the managed region.
- * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX,
- * as defined in ttm_placement_common.h
- * @default_caching: The default caching policy used for a buffer object
- * placed in this memory type if the user doesn't provide one.
- * @func: structure pointer implementing the range manager. See above
- * @priv: Driver private closure for @func.
- * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures
- * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions
- * reserved by the TTM vm system.
- * @io_reserve_lru: Optional lru list for unreserving io mem regions.
- * @move_lock: lock for move fence
- * static information. bdev::driver::io_mem_free is never used.
- * @lru: The lru list for this memory type.
- * @move: The fence of the last pipelined move operation.
- *
- * This structure is used to identify and manage memory types for a device.
- * It's set up by the ttm_bo_driver::init_mem_type method.
- */
-
-
-
-struct ttm_mem_type_manager {
-       struct ttm_bo_device *bdev;
-
-       /*
-        * No protection. Constant from start.
-        */
-
-       bool has_type;
-       bool use_type;
-       uint32_t flags;
-       uint64_t size;
-       uint32_t available_caching;
-       uint32_t default_caching;
-       const struct ttm_mem_type_manager_func *func;
-       void *priv;
-       struct mutex io_reserve_mutex;
-       bool use_io_reserve_lru;
-       spinlock_t move_lock;
-
-       /*
-        * Protected by @io_reserve_mutex:
-        */
-
-       struct list_head io_reserve_lru;
-
-       /*
-        * Protected by the global->lru_lock.
-        */
-
-       struct list_head lru[TTM_MAX_BO_PRIORITY];
-
-       /*
-        * Protected by @move_lock.
-        */
-       struct dma_fence *move;
-};
-
 /**
  * struct ttm_bo_driver
  *
  * @create_ttm_backend_entry: Callback to create a struct ttm_backend.
- * @init_mem_type: Callback to initialize a struct ttm_mem_type_manager
- * structure.
  * @evict_flags: Callback to obtain placement flags when a buffer is evicted.
  * @move: Callback for a driver to hook in accelerated functions to
  * move a buffer.
@@ -250,9 +89,6 @@ struct ttm_bo_driver {
         */
        void (*ttm_tt_unpopulate)(struct ttm_tt *ttm);
 
-       int (*init_mem_type)(struct ttm_bo_device *bdev, uint32_t type,
-                            struct ttm_mem_type_manager *man);
-
        /**
         * struct ttm_bo_driver member eviction_valuable
         *
@@ -290,7 +126,7 @@ struct ttm_bo_driver {
         */
        int (*move)(struct ttm_buffer_object *bo, bool evict,
                    struct ttm_operation_ctx *ctx,
-                   struct ttm_mem_reg *new_mem);
+                   struct ttm_resource *new_mem);
 
        /**
         * struct ttm_bo_driver_member verify_access
@@ -316,7 +152,7 @@ struct ttm_bo_driver {
         */
        void (*move_notify)(struct ttm_buffer_object *bo,
                            bool evict,
-                           struct ttm_mem_reg *new_mem);
+                           struct ttm_resource *new_mem);
        /* notify the driver we are taking a fault on this BO
         * and have reserved it */
        int (*fault_reserve_notify)(struct ttm_buffer_object *bo);
@@ -333,9 +169,9 @@ struct ttm_bo_driver {
         * are balanced.
         */
        int (*io_mem_reserve)(struct ttm_bo_device *bdev,
-                             struct ttm_mem_reg *mem);
+                             struct ttm_resource *mem);
        void (*io_mem_free)(struct ttm_bo_device *bdev,
-                           struct ttm_mem_reg *mem);
+                           struct ttm_resource *mem);
 
        /**
         * Return the pfn for a given page_offset inside the BO.
@@ -429,7 +265,7 @@ extern struct ttm_bo_global {
  * struct ttm_bo_device - Buffer object driver device-specific data.
  *
  * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver.
- * @man: An array of mem_type_managers.
+ * @man: An array of resource_managers.
  * @vma_manager: Address space manager (pointer)
  * lru_lock: Spinlock that protects the buffer+device lru lists and
  * ddestroy lists.
@@ -447,8 +283,11 @@ struct ttm_bo_device {
         */
        struct list_head device_list;
        struct ttm_bo_driver *driver;
-       struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
-
+       /*
+        * access via ttm_manager_type.
+        */
+       struct ttm_resource_manager sysman;
+       struct ttm_resource_manager *man_drv[TTM_NUM_MEM_TYPES];
        /*
         * Protected by internal locks.
         */
@@ -476,6 +315,19 @@ struct ttm_bo_device {
        bool no_retry;
 };
 
+static inline struct ttm_resource_manager *ttm_manager_type(struct ttm_bo_device *bdev,
+                                                           int mem_type)
+{
+       return bdev->man_drv[mem_type];
+}
+
+static inline void ttm_set_driver_manager(struct ttm_bo_device *bdev,
+                                         int type,
+                                         struct ttm_resource_manager *manager)
+{
+       bdev->man_drv[type] = manager;
+}
+
 /**
  * struct ttm_lru_bulk_move_pos
  *
@@ -531,7 +383,7 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)
  * @bo: Pointer to a struct ttm_buffer_object. the data of which
  * we want to allocate space for.
  * @proposed_placement: Proposed new placement for the buffer object.
- * @mem: A struct ttm_mem_reg.
+ * @mem: A struct ttm_resource.
  * @interruptible: Sleep interruptible when sliping.
  * @no_wait_gpu: Return immediately if the GPU is busy.
  *
@@ -546,11 +398,9 @@ ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)
  */
 int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                     struct ttm_placement *placement,
-                    struct ttm_mem_reg *mem,
+                    struct ttm_resource *mem,
                     struct ttm_operation_ctx *ctx);
 
-void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem);
-
 int ttm_bo_device_release(struct ttm_bo_device *bdev);
 
 /**
@@ -593,33 +443,34 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo);
 
 int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo);
 void ttm_mem_io_free_vm(struct ttm_buffer_object *bo);
-int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible);
-void ttm_mem_io_unlock(struct ttm_mem_type_manager *man);
+int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible);
+void ttm_mem_io_unlock(struct ttm_resource_manager *man);
 
 /**
- * __ttm_bo_reserve:
+ * ttm_bo_reserve:
  *
  * @bo: A pointer to a struct ttm_buffer_object.
  * @interruptible: Sleep interruptible if waiting.
  * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY.
  * @ticket: ticket used to acquire the ww_mutex.
  *
- * Will not remove reserved buffers from the lru lists.
- * Otherwise identical to ttm_bo_reserve.
+ * Locks a buffer object for validation. (Or prevents other processes from
+ * locking it for validation), while taking a number of measures to prevent
+ * deadlocks.
  *
  * Returns:
  * -EDEADLK: The reservation may cause a deadlock.
  * Release all buffer reservations, wait for @bo to become unreserved and
- * try again. (only if use_sequence == 1).
+ * try again.
  * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
  * a signal. Release all buffer reservations and return to user-space.
  * -EBUSY: The function needed to sleep, but @no_wait was true
  * -EALREADY: Bo already reserved using @ticket. This error code will only
  * be returned if @use_ticket is set to true.
  */
-static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo,
-                                  bool interruptible, bool no_wait,
-                                  struct ww_acquire_ctx *ticket)
+static inline int ttm_bo_reserve(struct ttm_buffer_object *bo,
+                                bool interruptible, bool no_wait,
+                                struct ww_acquire_ctx *ticket)
 {
        int ret = 0;
 
@@ -641,59 +492,6 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo,
        return ret;
 }
 
-/**
- * ttm_bo_reserve:
- *
- * @bo: A pointer to a struct ttm_buffer_object.
- * @interruptible: Sleep interruptible if waiting.
- * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY.
- * @ticket: ticket used to acquire the ww_mutex.
- *
- * Locks a buffer object for validation. (Or prevents other processes from
- * locking it for validation) and removes it from lru lists, while taking
- * a number of measures to prevent deadlocks.
- *
- * Deadlocks may occur when two processes try to reserve multiple buffers in
- * different order, either by will or as a result of a buffer being evicted
- * to make room for a buffer already reserved. (Buffers are reserved before
- * they are evicted). The following algorithm prevents such deadlocks from
- * occurring:
- * Processes attempting to reserve multiple buffers other than for eviction,
- * (typically execbuf), should first obtain a unique 32-bit
- * validation sequence number,
- * and call this function with @use_ticket == 1 and @ticket->stamp == the unique
- * sequence number. If upon call of this function, the buffer object is already
- * reserved, the validation sequence is checked against the validation
- * sequence of the process currently reserving the buffer,
- * and if the current validation sequence is greater than that of the process
- * holding the reservation, the function returns -EDEADLK. Otherwise it sleeps
- * waiting for the buffer to become unreserved, after which it retries
- * reserving.
- * The caller should, when receiving an -EDEADLK error
- * release all its buffer reservations, wait for @bo to become unreserved, and
- * then rerun the validation with the same validation sequence. This procedure
- * will always guarantee that the process with the lowest validation sequence
- * will eventually succeed, preventing both deadlocks and starvation.
- *
- * Returns:
- * -EDEADLK: The reservation may cause a deadlock.
- * Release all buffer reservations, wait for @bo to become unreserved and
- * try again. (only if use_sequence == 1).
- * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
- * a signal. Release all buffer reservations and return to user-space.
- * -EBUSY: The function needed to sleep, but @no_wait was true
- * -EALREADY: Bo already reserved using @ticket. This error code will only
- * be returned if @use_ticket is set to true.
- */
-static inline int ttm_bo_reserve(struct ttm_buffer_object *bo,
-                                bool interruptible, bool no_wait,
-                                struct ww_acquire_ctx *ticket)
-{
-       WARN_ON(!kref_read(&bo->kref));
-
-       return __ttm_bo_reserve(bo, interruptible, no_wait, ticket);
-}
-
 /**
  * ttm_bo_reserve_slowpath:
  * @bo: A pointer to a struct ttm_buffer_object.
@@ -708,20 +506,22 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
                                          bool interruptible,
                                          struct ww_acquire_ctx *ticket)
 {
-       int ret = 0;
-
-       WARN_ON(!kref_read(&bo->kref));
-
-       if (interruptible)
-               ret = dma_resv_lock_slow_interruptible(bo->base.resv,
-                                                                ticket);
-       else
-               dma_resv_lock_slow(bo->base.resv, ticket);
-
-       if (ret == -EINTR)
-               ret = -ERESTARTSYS;
+       if (interruptible) {
+               int ret = dma_resv_lock_slow_interruptible(bo->base.resv,
+                                                          ticket);
+               if (ret == -EINTR)
+                       ret = -ERESTARTSYS;
+               return ret;
+       }
+       dma_resv_lock_slow(bo->base.resv, ticket);
+       return 0;
+}
 
-       return ret;
+static inline void ttm_bo_move_to_lru_tail_unlocked(struct ttm_buffer_object *bo)
+{
+       spin_lock(&ttm_bo_glob.lru_lock);
+       ttm_bo_move_to_lru_tail(bo, NULL);
+       spin_unlock(&ttm_bo_glob.lru_lock);
 }
 
 /**
@@ -733,9 +533,7 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
  */
 static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo)
 {
-       spin_lock(&ttm_bo_glob.lru_lock);
-       ttm_bo_move_to_lru_tail(bo, NULL);
-       spin_unlock(&ttm_bo_glob.lru_lock);
+       ttm_bo_move_to_lru_tail_unlocked(bo);
        dma_resv_unlock(bo->base.resv);
 }
 
@@ -744,16 +542,16 @@ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo)
  */
 
 int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
-                      struct ttm_mem_reg *mem);
+                      struct ttm_resource *mem);
 void ttm_mem_io_free(struct ttm_bo_device *bdev,
-                    struct ttm_mem_reg *mem);
+                    struct ttm_resource *mem);
 /**
  * ttm_bo_move_ttm
  *
  * @bo: A pointer to a struct ttm_buffer_object.
  * @interruptible: Sleep interruptible if waiting.
  * @no_wait_gpu: Return immediately if the GPU is busy.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
  *
  * Optimized move function for a buffer object with both old and
  * new placement backed by a TTM. The function will, if successful,
@@ -767,7 +565,7 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
 
 int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
                    struct ttm_operation_ctx *ctx,
-                   struct ttm_mem_reg *new_mem);
+                   struct ttm_resource *new_mem);
 
 /**
  * ttm_bo_move_memcpy
@@ -775,7 +573,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
  * @bo: A pointer to a struct ttm_buffer_object.
  * @interruptible: Sleep interruptible if waiting.
  * @no_wait_gpu: Return immediately if the GPU is busy.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
  *
  * Fallback move function for a mappable buffer object in mappable memory.
  * The function will, if successful,
@@ -789,7 +587,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
 
 int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
                       struct ttm_operation_ctx *ctx,
-                      struct ttm_mem_reg *new_mem);
+                      struct ttm_resource *new_mem);
 
 /**
  * ttm_bo_free_old_node
@@ -806,7 +604,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
  * @bo: A pointer to a struct ttm_buffer_object.
  * @fence: A fence object that signals when moving is complete.
  * @evict: This is an evict move. Don't return until the buffer is idle.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
  *
  * Accelerated move function to be called when an accelerated move
  * has been scheduled. The function will create a new temporary buffer object
@@ -817,7 +615,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
  */
 int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                              struct dma_fence *fence, bool evict,
-                             struct ttm_mem_reg *new_mem);
+                             struct ttm_resource *new_mem);
 
 /**
  * ttm_bo_pipeline_move.
@@ -825,14 +623,14 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
  * @bo: A pointer to a struct ttm_buffer_object.
  * @fence: A fence object that signals when moving is complete.
  * @evict: This is an evict move. Don't return until the buffer is idle.
- * @new_mem: struct ttm_mem_reg indicating where to move.
+ * @new_mem: struct ttm_resource indicating where to move.
  *
  * Function for pipelining accelerated moves. Either free the memory
  * immediately or hang it on a temporary buffer object.
  */
 int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
                         struct dma_fence *fence, bool evict,
-                        struct ttm_mem_reg *new_mem);
+                        struct ttm_resource *new_mem);
 
 /**
  * ttm_bo_pipeline_gutting.
@@ -854,6 +652,35 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo);
  */
 pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp);
 
-extern const struct ttm_mem_type_manager_func ttm_bo_manager_func;
+/**
+ * ttm_range_man_init
+ *
+ * @bdev: ttm device
+ * @type: memory manager type
+ * @available_caching: TTM_PL_FLAG_* for allowed caching modes
+ * @default_caching: default caching mode
+ * @use_tt: if the memory manager uses tt
+ * @p_size: size of area to be managed in pages.
+ *
+ * Initialise a generic range manager for the selected memory type.
+ * The range manager is installed for this device in the type slot.
+ */
+int ttm_range_man_init(struct ttm_bo_device *bdev,
+                      unsigned type,
+                      uint32_t available_caching,
+                      uint32_t default_caching,
+                      bool use_tt,
+                      unsigned long p_size);
+
+/**
+ * ttm_range_man_fini
+ *
+ * @bdev: ttm device
+ * @type: memory manager type
+ *
+ * Remove the generic range manager from a slot and tear it down.
+ */
+int ttm_range_man_fini(struct ttm_bo_device *bdev,
+                      unsigned type);
 
 #endif
diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
new file mode 100644 (file)
index 0000000..bac22a5
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Christian König
+ */
+
+#ifndef _TTM_RESOURCE_H_
+#define _TTM_RESOURCE_H_
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/dma-fence.h>
+#include <drm/drm_print.h>
+
+#define TTM_MAX_BO_PRIORITY    4U
+
+struct ttm_bo_device;
+struct ttm_resource_manager;
+struct ttm_resource;
+struct ttm_place;
+struct ttm_buffer_object;
+
+struct ttm_resource_manager_func {
+       /**
+        * struct ttm_resource_manager_func member alloc
+        *
+        * @man: Pointer to a memory type manager.
+        * @bo: Pointer to the buffer object we're allocating space for.
+        * @placement: Placement details.
+        * @flags: Additional placement flags.
+        * @mem: Pointer to a struct ttm_resource to be filled in.
+        *
+        * This function should allocate space in the memory type managed
+        * by @man. Placement details if
+        * applicable are given by @placement. If successful,
+        * @mem::mm_node should be set to a non-null value, and
+        * @mem::start should be set to a value identifying the beginning
+        * of the range allocated, and the function should return zero.
+        * If the memory region accommodate the buffer object, @mem::mm_node
+        * should be set to NULL, and the function should return 0.
+        * If a system error occurred, preventing the request to be fulfilled,
+        * the function should return a negative error code.
+        *
+        * Note that @mem::mm_node will only be dereferenced by
+        * struct ttm_resource_manager functions and optionally by the driver,
+        * which has knowledge of the underlying type.
+        *
+        * This function may not be called from within atomic context, so
+        * an implementation can and must use either a mutex or a spinlock to
+        * protect any data structures managing the space.
+        */
+       int  (*alloc)(struct ttm_resource_manager *man,
+                     struct ttm_buffer_object *bo,
+                     const struct ttm_place *place,
+                     struct ttm_resource *mem);
+
+       /**
+        * struct ttm_resource_manager_func member free
+        *
+        * @man: Pointer to a memory type manager.
+        * @mem: Pointer to a struct ttm_resource to be filled in.
+        *
+        * This function frees memory type resources previously allocated
+        * and that are identified by @mem::mm_node and @mem::start. May not
+        * be called from within atomic context.
+        */
+       void (*free)(struct ttm_resource_manager *man,
+                    struct ttm_resource *mem);
+
+       /**
+        * struct ttm_resource_manager_func member debug
+        *
+        * @man: Pointer to a memory type manager.
+        * @printer: Prefix to be used in printout to identify the caller.
+        *
+        * This function is called to print out the state of the memory
+        * type manager to aid debugging of out-of-memory conditions.
+        * It may not be called from within atomic context.
+        */
+       void (*debug)(struct ttm_resource_manager *man,
+                     struct drm_printer *printer);
+};
+
+/**
+ * struct ttm_resource_manager
+ *
+ * @use_type: The memory type is enabled.
+ * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory
+ * managed by this memory type.
+ * @gpu_offset: If used, the GPU offset of the first managed page of
+ * fixed memory or the first managed location in an aperture.
+ * @size: Size of the managed region.
+ * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX,
+ * as defined in ttm_placement_common.h
+ * @default_caching: The default caching policy used for a buffer object
+ * placed in this memory type if the user doesn't provide one.
+ * @func: structure pointer implementing the range manager. See above
+ * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures
+ * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions
+ * reserved by the TTM vm system.
+ * @io_reserve_lru: Optional lru list for unreserving io mem regions.
+ * @move_lock: lock for move fence
+ * static information. bdev::driver::io_mem_free is never used.
+ * @lru: The lru list for this memory type.
+ * @move: The fence of the last pipelined move operation.
+ *
+ * This structure is used to identify and manage memory types for a device.
+ */
+struct ttm_resource_manager {
+       /*
+        * No protection. Constant from start.
+        */
+       bool use_type;
+       bool use_tt;
+       uint64_t size;
+       uint32_t available_caching;
+       uint32_t default_caching;
+       const struct ttm_resource_manager_func *func;
+       struct mutex io_reserve_mutex;
+       bool use_io_reserve_lru;
+       spinlock_t move_lock;
+
+       /*
+        * Protected by @io_reserve_mutex:
+        */
+
+       struct list_head io_reserve_lru;
+
+       /*
+        * Protected by the global->lru_lock.
+        */
+
+       struct list_head lru[TTM_MAX_BO_PRIORITY];
+
+       /*
+        * Protected by @move_lock.
+        */
+       struct dma_fence *move;
+};
+
+/**
+ * struct ttm_bus_placement
+ *
+ * @addr:              mapped virtual address
+ * @base:              bus base address
+ * @is_iomem:          is this io memory ?
+ * @size:              size in byte
+ * @offset:            offset from the base address
+ * @io_reserved_vm:     The VM system has a refcount in @io_reserved_count
+ * @io_reserved_count:  Refcounting the numbers of callers to ttm_mem_io_reserve
+ *
+ * Structure indicating the bus placement of an object.
+ */
+struct ttm_bus_placement {
+       void            *addr;
+       phys_addr_t     base;
+       unsigned long   size;
+       unsigned long   offset;
+       bool            is_iomem;
+       bool            io_reserved_vm;
+       uint64_t        io_reserved_count;
+};
+
+/**
+ * struct ttm_resource
+ *
+ * @mm_node: Memory manager node.
+ * @size: Requested size of memory region.
+ * @num_pages: Actual size of memory region in pages.
+ * @page_alignment: Page alignment.
+ * @placement: Placement flags.
+ * @bus: Placement on io bus accessible to the CPU
+ *
+ * Structure indicating the placement and space resources used by a
+ * buffer object.
+ */
+struct ttm_resource {
+       void *mm_node;
+       unsigned long start;
+       unsigned long size;
+       unsigned long num_pages;
+       uint32_t page_alignment;
+       uint32_t mem_type;
+       uint32_t placement;
+       struct ttm_bus_placement bus;
+};
+
+/**
+ * ttm_resource_manager_set_used
+ *
+ * @man: A memory manager object.
+ * @used: usage state to set.
+ *
+ * Set the manager in use flag. If disabled the manager is no longer
+ * used for object placement.
+ */
+static inline void
+ttm_resource_manager_set_used(struct ttm_resource_manager *man, bool used)
+{
+       man->use_type = used;
+}
+
+/**
+ * ttm_resource_manager_used
+ *
+ * @man: Manager to get used state for
+ *
+ * Get the in use flag for a manager.
+ * Returns:
+ * true is used, false if not.
+ */
+static inline bool ttm_resource_manager_used(struct ttm_resource_manager *man)
+{
+       return man->use_type;
+}
+
+/**
+ * ttm_resource_manager_cleanup
+ *
+ * @man: A memory manager object.
+ *
+ * Cleanup the move fences from the memory manager object.
+ */
+static inline void
+ttm_resource_manager_cleanup(struct ttm_resource_manager *man)
+{
+       dma_fence_put(man->move);
+       man->move = NULL;
+}
+
+int ttm_resource_alloc(struct ttm_buffer_object *bo,
+                      const struct ttm_place *place,
+                      struct ttm_resource *res);
+void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res);
+
+void ttm_resource_manager_init(struct ttm_resource_manager *man,
+                              unsigned long p_size);
+
+int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev,
+                                         struct ttm_resource_manager *man);
+
+void ttm_resource_manager_debug(struct ttm_resource_manager *man,
+                               struct drm_printer *p);
+
+#endif
index 5e2393f..241cc40 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/types.h>
 
 struct ttm_tt;
-struct ttm_mem_reg;
+struct ttm_resource;
 struct ttm_buffer_object;
 struct ttm_operation_ctx;
 
@@ -53,14 +53,14 @@ struct ttm_backend_func {
         * struct ttm_backend_func member bind
         *
         * @ttm: Pointer to a struct ttm_tt.
-        * @bo_mem: Pointer to a struct ttm_mem_reg describing the
+        * @bo_mem: Pointer to a struct ttm_resource describing the
         * memory type and location for binding.
         *
         * Bind the backend pages into the aperture in the location
         * indicated by @bo_mem. This function should be able to handle
         * differences between aperture and system page sizes.
         */
-       int (*bind) (struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem);
+       int (*bind) (struct ttm_tt *ttm, struct ttm_resource *bo_mem);
 
        /**
         * struct ttm_backend_func member unbind
@@ -179,11 +179,11 @@ void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma);
  * ttm_ttm_bind:
  *
  * @ttm: The struct ttm_tt containing backing pages.
- * @bo_mem: The struct ttm_mem_reg identifying the binding location.
+ * @bo_mem: The struct ttm_resource identifying the binding location.
  *
  * Bind the pages of @ttm to an aperture location identified by @bo_mem
  */
-int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem,
+int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
                struct ttm_operation_ctx *ctx);
 
 /**
index 850f79e..ecfbcc0 100644 (file)
@@ -124,7 +124,7 @@ struct fb_cursor_user {
  * Register/unregister for framebuffer events
  */
 
-/*     The resolution of the passed in fb_info about to change */ 
+/*     The resolution of the passed in fb_info about to change */
 #define FB_EVENT_MODE_CHANGE           0x01
 
 #ifdef CONFIG_GUMSTIX_AM200EPD
@@ -457,12 +457,12 @@ struct fb_info {
 
 #if IS_ENABLED(CONFIG_FB_BACKLIGHT)
        /* assigned backlight device */
-       /* set before framebuffer registration, 
+       /* set before framebuffer registration,
           remove after unregister */
        struct backlight_device *bl_dev;
 
        /* Backlight level curve */
-       struct mutex bl_curve_mutex;    
+       struct mutex bl_curve_mutex;
        u8 bl_curve[FB_BACKLIGHT_LEVELS];
 #endif
 #ifdef CONFIG_FB_DEFERRED_IO
@@ -481,8 +481,8 @@ struct fb_info {
                char __iomem *screen_base;      /* Virtual address */
                char *screen_buffer;
        };
-       unsigned long screen_size;      /* Amount of ioremapped VRAM or 0 */ 
-       void *pseudo_palette;           /* Fake palette of 16 colors */ 
+       unsigned long screen_size;      /* Amount of ioremapped VRAM or 0 */
+       void *pseudo_palette;           /* Fake palette of 16 colors */
 #define FBINFO_STATE_RUNNING   0
 #define FBINFO_STATE_SUSPENDED 1
        u32 state;                      /* Hardware state i.e suspend */
@@ -585,11 +585,11 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
      *  `Generic' versions of the frame buffer device operations
      */
 
-extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var); 
-extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var); 
+extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var);
+extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var);
 extern int fb_blank(struct fb_info *info, int blank);
-extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 
-extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); 
+extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
 /*
  * Drawing operations where framebuffer is in system RAM
index 3ef917f..cff7261 100644 (file)
@@ -118,7 +118,7 @@ struct kparam_array
  * you can create your own by defining those variables.
  *
  * Standard types are:
- *     byte, short, ushort, int, uint, long, ulong
+ *     byte, hexint, short, ushort, int, uint, long, ulong
  *     charp: a character pointer
  *     bool: a bool, values 0/1, y/n, Y/N.
  *     invbool: the above, only sense-reversed (N = true).
@@ -448,6 +448,11 @@ extern int param_set_ullong(const char *val, const struct kernel_param *kp);
 extern int param_get_ullong(char *buffer, const struct kernel_param *kp);
 #define param_check_ullong(name, p) __param_check(name, p, unsigned long long)
 
+extern const struct kernel_param_ops param_ops_hexint;
+extern int param_set_hexint(const char *val, const struct kernel_param *kp);
+extern int param_get_hexint(char *buffer, const struct kernel_param *kp);
+#define param_check_hexint(name, p) param_check_uint(name, p)
+
 extern const struct kernel_param_ops param_ops_charp;
 extern int param_set_charp(const char *val, const struct kernel_param *kp);
 extern int param_get_charp(char *buffer, const struct kernel_param *kp);
index deea447..863eda0 100644 (file)
@@ -332,14 +332,19 @@ struct drm_mode_get_encoder {
 /* This is for connectors with multiple signal types. */
 /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
 enum drm_mode_subconnector {
-       DRM_MODE_SUBCONNECTOR_Automatic = 0,
-       DRM_MODE_SUBCONNECTOR_Unknown = 0,
-       DRM_MODE_SUBCONNECTOR_DVID = 3,
-       DRM_MODE_SUBCONNECTOR_DVIA = 4,
-       DRM_MODE_SUBCONNECTOR_Composite = 5,
-       DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
-       DRM_MODE_SUBCONNECTOR_Component = 8,
-       DRM_MODE_SUBCONNECTOR_SCART = 9,
+       DRM_MODE_SUBCONNECTOR_Automatic   = 0,  /* DVI-I, TV     */
+       DRM_MODE_SUBCONNECTOR_Unknown     = 0,  /* DVI-I, TV, DP */
+       DRM_MODE_SUBCONNECTOR_VGA         = 1,  /*            DP */
+       DRM_MODE_SUBCONNECTOR_DVID        = 3,  /* DVI-I      DP */
+       DRM_MODE_SUBCONNECTOR_DVIA        = 4,  /* DVI-I         */
+       DRM_MODE_SUBCONNECTOR_Composite   = 5,  /*        TV     */
+       DRM_MODE_SUBCONNECTOR_SVIDEO      = 6,  /*        TV     */
+       DRM_MODE_SUBCONNECTOR_Component   = 8,  /*        TV     */
+       DRM_MODE_SUBCONNECTOR_SCART       = 9,  /*        TV     */
+       DRM_MODE_SUBCONNECTOR_DisplayPort = 10, /*            DP */
+       DRM_MODE_SUBCONNECTOR_HDMIA       = 11, /*            DP */
+       DRM_MODE_SUBCONNECTOR_Native      = 15, /*            DP */
+       DRM_MODE_SUBCONNECTOR_Wireless    = 18, /*            DP */
 };
 
 #define DRM_MODE_CONNECTOR_Unknown     0
index 8e56f8b..3835fb8 100644 (file)
@@ -233,14 +233,15 @@ char *parse_args(const char *doing,
        EXPORT_SYMBOL(param_ops_##name)
 
 
-STANDARD_PARAM_DEF(byte,       unsigned char,          "%hhu", kstrtou8);
-STANDARD_PARAM_DEF(short,      short,                  "%hi",  kstrtos16);
-STANDARD_PARAM_DEF(ushort,     unsigned short,         "%hu",  kstrtou16);
-STANDARD_PARAM_DEF(int,                int,                    "%i",   kstrtoint);
-STANDARD_PARAM_DEF(uint,       unsigned int,           "%u",   kstrtouint);
-STANDARD_PARAM_DEF(long,       long,                   "%li",  kstrtol);
-STANDARD_PARAM_DEF(ulong,      unsigned long,          "%lu",  kstrtoul);
-STANDARD_PARAM_DEF(ullong,     unsigned long long,     "%llu", kstrtoull);
+STANDARD_PARAM_DEF(byte,       unsigned char,          "%hhu",         kstrtou8);
+STANDARD_PARAM_DEF(short,      short,                  "%hi",          kstrtos16);
+STANDARD_PARAM_DEF(ushort,     unsigned short,         "%hu",          kstrtou16);
+STANDARD_PARAM_DEF(int,                int,                    "%i",           kstrtoint);
+STANDARD_PARAM_DEF(uint,       unsigned int,           "%u",           kstrtouint);
+STANDARD_PARAM_DEF(long,       long,                   "%li",          kstrtol);
+STANDARD_PARAM_DEF(ulong,      unsigned long,          "%lu",          kstrtoul);
+STANDARD_PARAM_DEF(ullong,     unsigned long long,     "%llu",         kstrtoull);
+STANDARD_PARAM_DEF(hexint,     unsigned int,           "%#08x",        kstrtouint);
 
 int param_set_charp(const char *val, const struct kernel_param *kp)
 {