]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge drm/drm-next into drm-misc-next
authorMaxime Ripard <maxime@cerno.tech>
Mon, 14 Sep 2020 16:11:40 +0000 (18:11 +0200)
committerMaxime Ripard <maxime@cerno.tech>
Mon, 14 Sep 2020 16:11:40 +0000 (18:11 +0200)
Paul Cercueil needs some patches in -rc5 to apply new patches for ingenic
properly.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
190 files changed:
Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml
Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml
Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml
Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/ssd1307fb.txt
Documentation/driver-api/driver-model/devres.rst
Documentation/fb/fbcon.rst
Documentation/userspace-api/ioctl/ioctl-number.rst
MAINTAINERS
drivers/dma-buf/dma-fence.c
drivers/dma-buf/udmabuf.c
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
drivers/gpu/drm/armada/armada_crtc.c
drivers/gpu/drm/armada/armada_debugfs.c
drivers/gpu/drm/armada/armada_drm.h
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/armada/armada_fbdev.c
drivers/gpu/drm/armada/armada_gem.c
drivers/gpu/drm/armada/armada_overlay.c
drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
drivers/gpu/drm/bridge/tc358775.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_debugfs_crc.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/drm_gem_ttm_helper.c
drivers/gpu/drm/drm_gem_vram_helper.c
drivers/gpu/drm/drm_managed.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/etnaviv/etnaviv_gem.c
drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/i810/i810_dma.c
drivers/gpu/drm/imx/Kconfig
drivers/gpu/drm/imx/Makefile
drivers/gpu/drm/imx/dcss/Kconfig [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/Makefile [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-blkctl.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-crtc.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-ctxld.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-dev.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-dev.h [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-dpr.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-drv.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-dtg.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-kms.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-kms.h [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-plane.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-scaler.c [new file with mode: 0644]
drivers/gpu/drm/imx/dcss/dcss-ss.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_prime.c
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv04/overlay.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/dispnv50/wndw.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_dmem.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_prime.c
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/nouveau/nv84_fence.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-samsung-s6e63m0.c
drivers/gpu/drm/panel/panel-samsung-s6e63m0.h [new file with mode: 0644]
drivers/gpu/drm/panfrost/panfrost_gpu.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_prime.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/ttm/ttm_agp_backend.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_resource.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/vboxvideo/vbox_mode.c
drivers/gpu/drm/vc4/Makefile
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_drv.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.h [new file with mode: 0644]
drivers/gpu/drm/vc4/vc4_hdmi_phy.c [new file with mode: 0644]
drivers/gpu/drm/vc4/vc4_hdmi_regs.h [new file with mode: 0644]
drivers/gpu/drm/vc4/vc4_hvs.c
drivers/gpu/drm/vc4/vc4_kms.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/vc4/vc4_regs.h
drivers/gpu/drm/vc4/vc4_txp.c
drivers/gpu/drm/vgem/vgem_drv.c
drivers/gpu/drm/virtio/virtgpu_debugfs.c
drivers/gpu/drm/virtio/virtgpu_kms.c
drivers/gpu/drm/virtio/virtgpu_vq.c
drivers/gpu/drm/vkms/Makefile
drivers/gpu/drm/vkms/vkms_composer.c
drivers/gpu/drm/vkms/vkms_drv.c
drivers/gpu/drm/vkms/vkms_drv.h
drivers/gpu/drm/vkms/vkms_output.c
drivers/gpu/drm/vkms/vkms_writeback.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_blit.c
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
drivers/gpu/drm/xen/xen_drm_front_gem.c
drivers/gpu/drm/xlnx/zynqmp_disp.c
drivers/gpu/drm/xlnx/zynqmp_dpsub.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/arkfb.c
drivers/video/fbdev/aty/aty128fb.c
drivers/video/fbdev/aty/atyfb_base.c
drivers/video/fbdev/aty/radeon_base.c
drivers/video/fbdev/aty/radeon_pm.c
drivers/video/fbdev/aty/radeonfb.h
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/cyber2000fb.c
drivers/video/fbdev/geode/gxfb.h
drivers/video/fbdev/geode/gxfb_core.c
drivers/video/fbdev/geode/lxfb.h
drivers/video/fbdev/geode/lxfb_core.c
drivers/video/fbdev/geode/lxfb_ops.c
drivers/video/fbdev/geode/suspend_gx.c
drivers/video/fbdev/i740fb.c
drivers/video/fbdev/kyro/STG4000InitDevice.c
drivers/video/fbdev/mbx/Makefile [deleted file]
drivers/video/fbdev/mbx/mbxdebugfs.c [deleted file]
drivers/video/fbdev/mbx/mbxfb.c [deleted file]
drivers/video/fbdev/mbx/reg_bits.h [deleted file]
drivers/video/fbdev/mbx/regs.h [deleted file]
drivers/video/fbdev/nvidia/nvidia.c
drivers/video/fbdev/omap2/omapfb/dss/venc.c
drivers/video/fbdev/s3fb.c
drivers/video/fbdev/savage/savagefb_driver.c
drivers/video/fbdev/sis/init.c
drivers/video/fbdev/sm712fb.c
drivers/video/fbdev/ssd1307fb.c
drivers/video/fbdev/sstfb.c
drivers/video/fbdev/tgafb.c
drivers/video/fbdev/udlfb.c
drivers/video/fbdev/vga16fb.c
drivers/video/fbdev/via/via-core.c
drivers/video/fbdev/vt8623fb.c
include/drm/bridge/dw_mipi_dsi.h
include/drm/drm_device.h
include/drm/drm_drv.h
include/drm/drm_gem_vram_helper.h
include/drm/drm_modes.h
include/drm/drm_prime.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_placement.h
include/drm/ttm/ttm_resource.h
include/drm/ttm/ttm_tt.h
include/linux/dma-buf.h
include/linux/font.h
include/linux/via-core.h
include/video/mbxfb.h [deleted file]
lib/fonts/Kconfig
lib/fonts/Makefile
lib/fonts/font_6x8.c [new file with mode: 0644]
lib/fonts/fonts.c

diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2711-hdmi.yaml
new file mode 100644 (file)
index 0000000..03a7672
--- /dev/null
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/brcm,bcm2711-hdmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM2711 HDMI Controller Device Tree Bindings
+
+maintainers:
+  - Eric Anholt <eric@anholt.net>
+
+properties:
+  compatible:
+    enum:
+      - brcm,bcm2711-hdmi0
+      - brcm,bcm2711-hdmi1
+
+  reg:
+    items:
+      - description: HDMI controller register range
+      - description: DVP register range
+      - description: HDMI PHY register range
+      - description: Rate Manager register range
+      - description: Packet RAM register range
+      - description: Metadata RAM register range
+      - description: CSC register range
+      - description: CEC register range
+      - description: HD register range
+
+  reg-names:
+    items:
+      - const: hdmi
+      - const: dvp
+      - const: phy
+      - const: rm
+      - const: packet
+      - const: metadata
+      - const: csc
+      - const: cec
+      - const: hd
+
+  clocks:
+    items:
+      - description: The HDMI state machine clock
+      - description: The Pixel BVB clock
+      - description: The HDMI Audio parent clock
+      - description: The HDMI CEC parent clock
+
+  clock-names:
+    items:
+      - const: hdmi
+      - const: bvb
+      - const: audio
+      - const: cec
+
+  ddc:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+    description: >
+      Phandle of the I2C controller used for DDC EDID probing
+
+  hpd-gpios:
+    description: >
+      The GPIO pin for the HDMI hotplug detect (if it doesn't appear
+      as an interrupt/status bit in the HDMI controller itself)
+
+  dmas:
+    maxItems: 1
+    description: >
+      Should contain one entry pointing to the DMA channel used to
+      transfer audio data.
+
+  dma-names:
+    const: audio-rx
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - resets
+  - ddc
+
+additionalProperties: false
+
+examples:
+  - |
+    hdmi0: hdmi@7ef00700 {
+        compatible = "brcm,bcm2711-hdmi0";
+        reg = <0x7ef00700 0x300>,
+              <0x7ef00300 0x200>,
+              <0x7ef00f00 0x80>,
+              <0x7ef00f80 0x80>,
+              <0x7ef01b00 0x200>,
+              <0x7ef01f00 0x400>,
+              <0x7ef00200 0x80>,
+              <0x7ef04300 0x100>,
+              <0x7ef20000 0x100>;
+        reg-names = "hdmi",
+                    "dvp",
+                    "phy",
+                    "rm",
+                    "packet",
+                    "metadata",
+                    "csc",
+                    "cec",
+                    "hd";
+        clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>;
+        clock-names = "hdmi", "bvb", "audio", "cec";
+        resets = <&dvp 0>;
+        ddc = <&ddc0>;
+    };
+
+...
index 02410f8d6d4985f0a3dc8d4b9515da2ef5914c16..e826ab0adb75dc87665a9550c67439449420adfc 100644 (file)
@@ -11,7 +11,9 @@ maintainers:
 
 properties:
   compatible:
-    const: brcm,bcm2835-hvs
+    enum:
+      - brcm,bcm2711-hvs
+      - brcm,bcm2835-hvs
 
   reg:
     maxItems: 1
@@ -19,6 +21,10 @@ properties:
   interrupts:
     maxItems: 1
 
+  clocks:
+    maxItems: 1
+    description: Core Clock
+
 required:
   - compatible
   - reg
@@ -26,6 +32,16 @@ required:
 
 additionalProperties: false
 
+if:
+  properties:
+    compatible:
+      contains:
+        const: brcm,bcm2711-hvs"
+
+then:
+  required:
+    - clocks
+
 examples:
   - |
     hvs@7e400000 {
index e60791db1fa12dbe992812244ede905208607033..4e1ba03f6477f450868f2c73673295ada5e4c160 100644 (file)
@@ -15,6 +15,11 @@ properties:
       - brcm,bcm2835-pixelvalve0
       - brcm,bcm2835-pixelvalve1
       - brcm,bcm2835-pixelvalve2
+      - brcm,bcm2711-pixelvalve0
+      - brcm,bcm2711-pixelvalve1
+      - brcm,bcm2711-pixelvalve2
+      - brcm,bcm2711-pixelvalve3
+      - brcm,bcm2711-pixelvalve4
 
   reg:
     maxItems: 1
index 0dcf0c3973759b5bb571dcfa876772e20f388137..49a5e041aa49369a70ee716d02d5dc2a868aff28 100644 (file)
@@ -17,6 +17,7 @@ description: >
 properties:
   compatible:
     enum:
+      - brcm,bcm2711-vc5
       - brcm,bcm2835-vc4
       - brcm,cygnus-vc4
 
diff --git a/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml b/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
new file mode 100644 (file)
index 0000000..f1f25aa
--- /dev/null
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 NXP
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/imx/nxp,imx8mq-dcss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: iMX8MQ Display Controller Subsystem (DCSS)
+
+maintainers:
+  - Laurentiu Palcu <laurentiu.palcu@nxp.com>
+
+description:
+
+  The DCSS (display controller sub system) is used to source up to three
+  display buffers, compose them, and drive a display using HDMI 2.0a(with HDCP
+  2.2) or MIPI-DSI. The DCSS is intended to support up to 4kp60 displays. HDR10
+  image processing capabilities are included to provide a solution capable of
+  driving next generation high dynamic range displays.
+
+properties:
+  compatible:
+    const: nxp,imx8mq-dcss
+
+  reg:
+    items:
+      - description: DCSS base address and size, up to IRQ steer start
+      - description: DCSS BLKCTL base address and size
+
+  interrupts:
+    items:
+      - description: Context loader completion and error interrupt
+      - description: DTG interrupt used to signal context loader trigger time
+      - description: DTG interrupt for Vblank
+
+  interrupt-names:
+    items:
+      - const: ctxld
+      - const: ctxld_kick
+      - const: vblank
+
+  clocks:
+    items:
+      - description: Display APB clock for all peripheral PIO access interfaces
+      - description: Display AXI clock needed by DPR, Scaler, RTRAM_CTRL
+      - description: RTRAM clock
+      - description: Pixel clock, can be driven either by HDMI phy clock or MIPI
+      - description: DTRC clock, needed by video decompressor
+
+  clock-names:
+    items:
+      - const: apb
+      - const: axi
+      - const: rtrm
+      - const: pix
+      - const: dtrc
+
+  assigned-clocks:
+    items:
+      - description: Phandle and clock specifier of IMX8MQ_CLK_DISP_AXI_ROOT
+      - description: Phandle and clock specifier of IMX8MQ_CLK_DISP_RTRM
+      - description: Phandle and clock specifier of either IMX8MQ_VIDEO2_PLL1_REF_SEL or
+                     IMX8MQ_VIDEO_PLL1_REF_SEL
+
+  assigned-clock-parents:
+    items:
+      - description: Phandle and clock specifier of IMX8MQ_SYS1_PLL_800M
+      - description: Phandle and clock specifier of IMX8MQ_SYS1_PLL_800M
+      - description: Phandle and clock specifier of IMX8MQ_CLK_27M
+
+  assigned-clock-rates:
+    items:
+      - description: Must be 800 MHz
+      - description: Must be 400 MHz
+
+  port:
+    type: object
+    description:
+      A port node pointing to the input port of a HDMI/DP or MIPI display bridge.
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mq-clock.h>
+    dcss: display-controller@32e00000 {
+        compatible = "nxp,imx8mq-dcss";
+        reg = <0x32e00000 0x2d000>, <0x32e2f000 0x1000>;
+        interrupts = <6>, <8>, <9>;
+        interrupt-names = "ctxld", "ctxld_kick", "vblank";
+        interrupt-parent = <&irqsteer>;
+        clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>, <&clk IMX8MQ_CLK_DISP_AXI_ROOT>,
+                 <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>, <&clk IMX8MQ_VIDEO2_PLL_OUT>,
+                 <&clk IMX8MQ_CLK_DISP_DTRC>;
+        clock-names = "apb", "axi", "rtrm", "pix", "dtrc";
+        assigned-clocks = <&clk IMX8MQ_CLK_DISP_AXI>, <&clk IMX8MQ_CLK_DISP_RTRM>,
+                          <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>;
+        assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>, <&clk IMX8MQ_SYS1_PLL_800M>,
+                                 <&clk IMX8MQ_CLK_27M>;
+        assigned-clock-rates = <800000000>,
+                               <400000000>;
+        port {
+            dcss_out: endpoint {
+                remote-endpoint = <&hdmi_in>;
+            };
+        };
+    };
+
index 27333b9551b33d302a31a908e389d05176a171da..2dcb6d12d137153664bc4aa7b04983a409658a59 100644 (file)
@@ -19,6 +19,7 @@ Optional properties:
   - vbat-supply: The supply for VBAT
   - solomon,segment-no-remap: Display needs normal (non-inverted) data column
                               to segment mapping
+  - solomon,col-offset: Offset of columns (COL/SEG) that the screen is mapped to.
   - solomon,com-seq: Display uses sequential COM pin configuration
   - solomon,com-lrremap: Display uses left-right COM pin remap
   - solomon,com-invdir: Display uses inverted COM pin scan direction
index eaaaafc21134f1bbff9c8d10f6750943bd08e47f..aa4d2420f79e81e8fba3e5a36e84869c14b8122c 100644 (file)
@@ -263,7 +263,7 @@ DMA
   dmam_pool_destroy()
 
 DRM
-  devm_drm_dev_init()
+  devm_drm_dev_alloc()
 
 GPIO
   devm_gpiod_get()
index e57a3d1d085ad6e5dc0c43cc582456e2eec56c36..a7b487cba307ec776b1996d1328e7006f2d573ff 100644 (file)
@@ -20,8 +20,8 @@ A. Configuration
 ================
 
 The framebuffer console can be enabled by using your favorite kernel
-configuration tool.  It is under Device Drivers->Graphics Support->Frame
-buffer Devices->Console display driver support->Framebuffer Console Support.
+configuration tool.  It is under Device Drivers->Graphics Support->
+Console display driver support->Framebuffer Console Support.
 Select 'y' to compile support statically or 'm' for module support.  The
 module will be fbcon.
 
index 2a198838fca913fba9bba55169c41e668c471c4c..a20102f7db69afe49d90f30cb349e8e9bbfd2c83 100644 (file)
@@ -356,8 +356,6 @@ Code  Seq#    Include File                                           Comments
 0xEC  00-01  drivers/platform/chrome/cros_ec_dev.h                   ChromeOS EC driver
 0xF3  00-3F  drivers/usb/misc/sisusbvga/sisusb.h                     sisfb (in development)
                                                                      <mailto:thomas@winischhofer.net>
-0xF4  00-1F  video/mbxfb.h                                           mbxfb
-                                                                     <mailto:raph@8d.com>
 0xF6  all                                                            LTTng Linux Trace Toolkit Next Generation
                                                                      <mailto:mathieu.desnoyers@efficios.com>
 0xFD  all    linux/dm-ioctl.h
index 2611c18dec98c83fc8e72dccb6118d9dc2e3f44c..c4e8bd1ab7616868959983435148a93e6bd33026 100644 (file)
@@ -5659,6 +5659,7 @@ F:        drivers/gpu/drm/udl/
 
 DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
 M:     Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
+M:     Melissa Wen <melissa.srw@gmail.com>
 R:     Haneen Mohammed <hamohammed.sa@gmail.com>
 R:     Daniel Vetter <daniel@ffwll.ch>
 L:     dri-devel@lists.freedesktop.org
@@ -12462,6 +12463,14 @@ F:     drivers/iio/gyro/fxas21002c_core.c
 F:     drivers/iio/gyro/fxas21002c_i2c.c
 F:     drivers/iio/gyro/fxas21002c_spi.c
 
+NXP i.MX 8MQ DCSS DRIVER
+M:     Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
+R:     Lucas Stach <l.stach@pengutronix.de>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
+F:     drivers/gpu/drm/imx/dcss/
+
 NXP SGTL5000 DRIVER
 M:     Fabio Estevam <festevam@gmail.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
index 43624b4ee13d2fc1fd6a5e6971416430f264fd25..7475e09b0680835e0606b5acbb3a16133d71e658 100644 (file)
@@ -283,6 +283,7 @@ EXPORT_SYMBOL(dma_fence_begin_signalling);
 
 /**
  * dma_fence_end_signalling - end a critical DMA fence signalling section
+ * @cookie: opaque cookie from dma_fence_begin_signalling()
  *
  * Closes a critical section annotation opened by dma_fence_begin_signalling().
  */
index acb26c627d27bbc43f766802205866e168ab0c8b..5ee1e939971056655d8294cab59c46811022a839 100644 (file)
@@ -308,6 +308,9 @@ static long udmabuf_ioctl(struct file *filp, unsigned int ioctl,
 static const struct file_operations udmabuf_fops = {
        .owner          = THIS_MODULE,
        .unlocked_ioctl = udmabuf_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = udmabuf_ioctl,
+#endif
 };
 
 static struct miscdevice udmabuf_misc = {
index 2f31579f91d424dd3b6579bfefb7843b20fa09ab..81569009f884817ef0ff73e9c3d3dd58cdbd25a4 100644 (file)
@@ -100,7 +100,7 @@ obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STM) += stm/
 obj-$(CONFIG_DRM_STI) += sti/
-obj-$(CONFIG_DRM_IMX) += imx/
+obj-y                  += imx/
 obj-$(CONFIG_DRM_INGENIC) += ingenic/
 obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
 obj-$(CONFIG_DRM_MESON)        += meson/
index 427a7c5ba93de4c29498262cf02b08dcf1d13b63..957934926b24529341b3b0a4c13468d7e012afee 100644 (file)
@@ -303,7 +303,8 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
 
        switch (bo->tbo.mem.mem_type) {
        case TTM_PL_TT:
-               sgt = drm_prime_pages_to_sg(bo->tbo.ttm->pages,
+               sgt = drm_prime_pages_to_sg(obj->dev,
+                                           bo->tbo.ttm->pages,
                                            bo->tbo.num_pages);
                if (IS_ERR(sgt))
                        return sgt;
index 887a4da5eefc6175ef72059ce729478871374f2d..ac043baac05d6d234ee726794176cf624ccccb5e 100644 (file)
@@ -136,8 +136,8 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
 
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
-                       TTM_PL_FLAG_VRAM;
+               places[c].mem_type = TTM_PL_VRAM;
+               places[c].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED;
 
                if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
                        places[c].lpfn = visible_pfn;
@@ -152,7 +152,8 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
        if (domain & AMDGPU_GEM_DOMAIN_GTT) {
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_FLAG_TT;
+               places[c].mem_type = TTM_PL_TT;
+               places[c].flags = 0;
                if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
                        places[c].flags |= TTM_PL_FLAG_WC |
                                TTM_PL_FLAG_UNCACHED;
@@ -164,7 +165,8 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
        if (domain & AMDGPU_GEM_DOMAIN_CPU) {
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_FLAG_SYSTEM;
+               places[c].mem_type = TTM_PL_SYSTEM;
+               places[c].flags = 0;
                if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
                        places[c].flags |= TTM_PL_FLAG_WC |
                                TTM_PL_FLAG_UNCACHED;
@@ -176,28 +178,32 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
        if (domain & AMDGPU_GEM_DOMAIN_GDS) {
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GDS;
+               places[c].mem_type = AMDGPU_PL_GDS;
+               places[c].flags = TTM_PL_FLAG_UNCACHED;
                c++;
        }
 
        if (domain & AMDGPU_GEM_DOMAIN_GWS) {
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GWS;
+               places[c].mem_type = AMDGPU_PL_GWS;
+               places[c].flags = TTM_PL_FLAG_UNCACHED;
                c++;
        }
 
        if (domain & AMDGPU_GEM_DOMAIN_OA) {
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_OA;
+               places[c].mem_type = AMDGPU_PL_OA;
+               places[c].flags = TTM_PL_FLAG_UNCACHED;
                c++;
        }
 
        if (!c) {
                places[c].fpfn = 0;
                places[c].lpfn = 0;
-               places[c].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+               places[c].mem_type = TTM_PL_SYSTEM;
+               places[c].flags = TTM_PL_MASK_CACHING;
                c++;
        }
 
@@ -594,7 +600,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
                amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0);
 
        if (bp->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED &&
-           bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) {
+           bo->tbo.mem.mem_type == TTM_PL_VRAM) {
                struct dma_fence *fence;
 
                r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence);
index a18dc878339ab033391550f466d99a88bf76cd88..6fc3af082f6fdd2e4fd3b0c8e2b1d1ec27ceb12d 100644 (file)
@@ -88,7 +88,8 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
        static const struct ttm_place placements = {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
+               .mem_type = TTM_PL_SYSTEM,
+               .flags = TTM_PL_MASK_CACHING
        };
 
        /* Don't handle scatter gather BOs */
@@ -174,24 +175,6 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp)
                                          filp->private_data);
 }
 
-/**
- * amdgpu_move_null - Register memory for a buffer object
- *
- * @bo: The bo to assign the memory to
- * @new_mem: The memory to be assigned.
- *
- * 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_resource *new_mem)
-{
-       struct ttm_resource *old_mem = &bo->mem;
-
-       BUG_ON(old_mem->mm_node != NULL);
-       *old_mem = *new_mem;
-       new_mem->mm_node = NULL;
-}
-
 /**
  * amdgpu_mm_node_addr - Compute the GPU relative offset of a GTT buffer.
  *
@@ -551,7 +534,8 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
        placement.busy_placement = &placements;
        placements.fpfn = 0;
        placements.lpfn = 0;
-       placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+       placements.mem_type = TTM_PL_TT;
+       placements.flags = TTM_PL_MASK_CACHING;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem, ctx);
        if (unlikely(r)) {
                pr_err("Failed to find GTT space for blit from VRAM\n");
@@ -565,7 +549,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
        }
 
        /* Bind the memory to the GTT space */
-       r = ttm_tt_bind(bo->ttm, &tmp_mem, ctx);
+       r = ttm_tt_bind(bo->bdev, bo->ttm, &tmp_mem, ctx);
        if (unlikely(r)) {
                goto out_cleanup;
        }
@@ -607,7 +591,8 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
        placement.busy_placement = &placements;
        placements.fpfn = 0;
        placements.lpfn = 0;
-       placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+       placements.mem_type = TTM_PL_TT;
+       placements.flags = TTM_PL_MASK_CACHING;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem, ctx);
        if (unlikely(r)) {
                pr_err("Failed to find GTT space for blit to VRAM\n");
@@ -676,7 +661,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
        adev = amdgpu_ttm_adev(bo->bdev);
 
        if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
-               amdgpu_move_null(bo, new_mem);
+               ttm_bo_move_null(bo, new_mem);
                return 0;
        }
        if ((old_mem->mem_type == TTM_PL_TT &&
@@ -684,7 +669,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
            (old_mem->mem_type == TTM_PL_SYSTEM &&
             new_mem->mem_type == TTM_PL_TT)) {
                /* bind is enough */
-               amdgpu_move_null(bo, new_mem);
+               ttm_bo_move_null(bo, new_mem);
                return 0;
        }
        if (old_mem->mem_type == AMDGPU_PL_GDS ||
@@ -694,7 +679,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
            new_mem->mem_type == AMDGPU_PL_GWS ||
            new_mem->mem_type == AMDGPU_PL_OA) {
                /* Nothing to save here */
-               amdgpu_move_null(bo, new_mem);
+               ttm_bo_move_null(bo, new_mem);
                return 0;
        }
 
@@ -773,7 +758,7 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
                        mem->bus.addr = (u8 *)adev->mman.aper_base_kaddr +
                                        mem->bus.offset;
 
-               mem->bus.base = adev->gmc.aper_base;
+               mem->bus.offset += adev->gmc.aper_base;
                mem->bus.is_iomem = true;
                break;
        default:
@@ -785,12 +770,13 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
 static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
                                           unsigned long page_offset)
 {
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
        uint64_t offset = (page_offset << PAGE_SHIFT);
        struct drm_mm_node *mm;
 
        mm = amdgpu_find_mm_node(&bo->mem, &offset);
-       return (bo->mem.bus.base >> PAGE_SHIFT) + mm->start +
-               (offset >> PAGE_SHIFT);
+       offset += adev->gmc.aper_base;
+       return mm->start + (offset >> PAGE_SHIFT);
 }
 
 /**
@@ -991,9 +977,10 @@ void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages)
  *
  * Called by amdgpu_ttm_backend_bind()
  **/
-static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
+static int amdgpu_ttm_tt_pin_userptr(struct ttm_bo_device *bdev,
+                                    struct ttm_tt *ttm)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
        int r;
 
@@ -1027,9 +1014,10 @@ release_sg:
 /**
  * amdgpu_ttm_tt_unpin_userptr - Unpin and unmap userptr pages
  */
-static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
+static void amdgpu_ttm_tt_unpin_userptr(struct ttm_bo_device *bdev,
+                                       struct ttm_tt *ttm)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
 
        int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
@@ -1110,16 +1098,17 @@ gart_bind_fail:
  * Called by ttm_tt_bind() on behalf of ttm_bo_handle_move_mem().
  * This handles binding GTT memory to the device address space.
  */
-static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
+static int amdgpu_ttm_backend_bind(struct ttm_bo_device *bdev,
+                                  struct ttm_tt *ttm,
                                   struct ttm_resource *bo_mem)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
        struct amdgpu_ttm_tt *gtt = (void*)ttm;
        uint64_t flags;
        int r = 0;
 
        if (gtt->userptr) {
-               r = amdgpu_ttm_tt_pin_userptr(ttm);
+               r = amdgpu_ttm_tt_pin_userptr(bdev, ttm);
                if (r) {
                        DRM_ERROR("failed to pin userptr\n");
                        return r;
@@ -1185,8 +1174,8 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
                placement.busy_placement = &placements;
                placements.fpfn = 0;
                placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT;
-               placements.flags = (bo->mem.placement & ~TTM_PL_MASK_MEM) |
-                       TTM_PL_FLAG_TT;
+               placements.mem_type = TTM_PL_TT;
+               placements.flags = bo->mem.placement;
 
                r = ttm_bo_mem_space(bo, &placement, &tmp, &ctx);
                if (unlikely(r))
@@ -1237,15 +1226,16 @@ int amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo)
  * Called by ttm_tt_unbind() on behalf of ttm_bo_move_ttm() and
  * ttm_tt_destroy().
  */
-static void amdgpu_ttm_backend_unbind(struct ttm_tt *ttm)
+static void amdgpu_ttm_backend_unbind(struct ttm_bo_device *bdev,
+                                     struct ttm_tt *ttm)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
        int r;
 
        /* if the pages have userptr pinning then clear that first */
        if (gtt->userptr)
-               amdgpu_ttm_tt_unpin_userptr(ttm);
+               amdgpu_ttm_tt_unpin_userptr(bdev, ttm);
 
        if (gtt->offset == AMDGPU_BO_INVALID_OFFSET)
                return;
@@ -1257,7 +1247,8 @@ static void amdgpu_ttm_backend_unbind(struct ttm_tt *ttm)
                          gtt->ttm.ttm.num_pages, gtt->offset);
 }
 
-static void amdgpu_ttm_backend_destroy(struct ttm_tt *ttm)
+static void amdgpu_ttm_backend_destroy(struct ttm_bo_device *bdev,
+                                      struct ttm_tt *ttm)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
 
@@ -1268,12 +1259,6 @@ static void amdgpu_ttm_backend_destroy(struct ttm_tt *ttm)
        kfree(gtt);
 }
 
-static struct ttm_backend_func amdgpu_backend_func = {
-       .bind = &amdgpu_ttm_backend_bind,
-       .unbind = &amdgpu_ttm_backend_unbind,
-       .destroy = &amdgpu_ttm_backend_destroy,
-};
-
 /**
  * amdgpu_ttm_tt_create - Create a ttm_tt object for a given BO
  *
@@ -1290,7 +1275,6 @@ static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_buffer_object *bo,
        if (gtt == NULL) {
                return NULL;
        }
-       gtt->ttm.ttm.func = &amdgpu_backend_func;
        gtt->gobj = &bo->base;
 
        /* allocate space for the uninitialized page entries */
@@ -1307,10 +1291,11 @@ static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_buffer_object *bo,
  * Map the pages of a ttm_tt object to an address space visible
  * to the underlying device.
  */
-static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm,
-                       struct ttm_operation_ctx *ctx)
+static int amdgpu_ttm_tt_populate(struct ttm_bo_device *bdev,
+                                 struct ttm_tt *ttm,
+                                 struct ttm_operation_ctx *ctx)
 {
-       struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev);
+       struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
 
        /* user pages are bound by amdgpu_ttm_tt_pin_userptr() */
@@ -1361,7 +1346,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm,
  * Unmaps pages of a ttm_tt object from the device address space and
  * unpopulates the page array backing it.
  */
-static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm)
+static void amdgpu_ttm_tt_unpopulate(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
        struct amdgpu_device *adev;
@@ -1385,7 +1370,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm)
        if (ttm->page_flags & TTM_PAGE_FLAG_SG)
                return;
 
-       adev = amdgpu_ttm_adev(ttm->bdev);
+       adev = amdgpu_ttm_adev(bdev);
 
 #ifdef CONFIG_SWIOTLB
        if (adev->need_swiotlb && swiotlb_nr_tbl()) {
@@ -1691,6 +1676,9 @@ 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,
+       .ttm_tt_bind = &amdgpu_ttm_backend_bind,
+       .ttm_tt_unbind = &amdgpu_ttm_backend_unbind,
+       .ttm_tt_destroy = &amdgpu_ttm_backend_destroy,
        .eviction_valuable = amdgpu_ttm_bo_eviction_valuable,
        .evict_flags = &amdgpu_evict_flags,
        .move = &amdgpu_bo_move,
index 68c5e3662b871065489ea9854088492c6432d8db..a87951b2f06dd159ecb5e2b860e925d6e1c2a21a 100644 (file)
 #define AMDGPU_PL_GWS          (TTM_PL_PRIV + 1)
 #define AMDGPU_PL_OA           (TTM_PL_PRIV + 2)
 
-#define AMDGPU_PL_FLAG_GDS             (TTM_PL_FLAG_PRIV << 0)
-#define AMDGPU_PL_FLAG_GWS             (TTM_PL_FLAG_PRIV << 1)
-#define AMDGPU_PL_FLAG_OA              (TTM_PL_FLAG_PRIV << 2)
-
 #define AMDGPU_GTT_MAX_TRANSFER_SIZE   512
 #define AMDGPU_GTT_NUM_TRANSFER_WINDOWS        2
 
index 38dfaa46d30699552f80668cc4c6c01f5f2cc66a..a887b6a5f8bd7497953656795988fe71a40602d3 100644 (file)
@@ -757,7 +757,7 @@ static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
 {
        struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
-       struct armada_private *priv = crtc->dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(crtc->dev);
 
        if (dcrtc->cursor_obj)
                drm_gem_object_put(&dcrtc->cursor_obj->obj);
@@ -901,7 +901,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
        struct resource *res, int irq, const struct armada_variant *variant,
        struct device_node *port)
 {
-       struct armada_private *priv = drm->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(drm);
        struct armada_crtc *dcrtc;
        struct drm_plane *primary;
        void __iomem *base;
index c6fc2f1d58e99f6b51a7a336ce7b2144952241f7..29f4b52e3c8d38bd3befa73882fa1ec7efccd8b5 100644 (file)
@@ -19,7 +19,7 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = m->private;
        struct drm_device *dev = node->minor->dev;
-       struct armada_private *priv = dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(dev);
        struct drm_printer p = drm_seq_file_printer(m);
 
        mutex_lock(&priv->linear_lock);
index a11bdaccbb33690f24821b4df9591f43db18b388..6a5a87932576601d6c75ba3cef11bb0362535aba 100644 (file)
@@ -73,6 +73,8 @@ struct armada_private {
 #endif
 };
 
+#define drm_to_armada_dev(dev) container_of(dev, struct armada_private, drm)
+
 int armada_fbdev_init(struct drm_device *);
 void armada_fbdev_fini(struct drm_device *);
 
index 5fc25c3f445c22be12ac4a53df43248584366d6f..980d3f1f8f16e965b224135ebfe6fcaaa3cfdd49 100644 (file)
@@ -87,24 +87,13 @@ static int armada_drm_bind(struct device *dev)
                                     "armada-drm"))
                return -EBUSY;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       /*
-        * The drm_device structure must be at the start of
-        * armada_private for drm_dev_put() to work correctly.
-        */
-       BUILD_BUG_ON(offsetof(struct armada_private, drm) != 0);
-
-       ret = drm_dev_init(&priv->drm, &armada_drm_driver, dev);
-       if (ret) {
-               dev_err(dev, "[" DRM_NAME ":%s] drm_dev_init failed: %d\n",
-                       __func__, ret);
-               kfree(priv);
-               return ret;
+       priv = devm_drm_dev_alloc(dev, &armada_drm_driver,
+                                 struct armada_private, drm);
+       if (IS_ERR(priv)) {
+               dev_err(dev, "[" DRM_NAME ":%s] devm_drm_dev_alloc failed: %li\n",
+                       __func__, PTR_ERR(priv));
+               return PTR_ERR(priv);
        }
-       drmm_add_final_kfree(&priv->drm, priv);
 
        /* Remove early framebuffers */
        ret = drm_fb_helper_remove_conflicting_framebuffers(NULL,
@@ -117,8 +106,6 @@ static int armada_drm_bind(struct device *dev)
                return ret;
        }
 
-       priv->drm.dev_private = priv;
-
        dev_set_drvdata(dev, &priv->drm);
 
        /* Mode setting support */
@@ -174,14 +161,13 @@ static int armada_drm_bind(struct device *dev)
  err_kms:
        drm_mode_config_cleanup(&priv->drm);
        drm_mm_takedown(&priv->linear);
-       drm_dev_put(&priv->drm);
        return ret;
 }
 
 static void armada_drm_unbind(struct device *dev)
 {
        struct drm_device *drm = dev_get_drvdata(dev);
-       struct armada_private *priv = drm->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(drm);
 
        drm_kms_helper_poll_fini(&priv->drm);
        armada_fbdev_fini(&priv->drm);
@@ -194,8 +180,6 @@ static void armada_drm_unbind(struct device *dev)
 
        drm_mode_config_cleanup(&priv->drm);
        drm_mm_takedown(&priv->linear);
-
-       drm_dev_put(&priv->drm);
 }
 
 static int compare_of(struct device *dev, void *data)
index 0c46012755078eb41c288772de846161421d0390..38f5170c0fea66175eb40edafa8c9c9a1fd11130 100644 (file)
@@ -117,7 +117,7 @@ static const struct drm_fb_helper_funcs armada_fb_helper_funcs = {
 
 int armada_fbdev_init(struct drm_device *dev)
 {
-       struct armada_private *priv = dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(dev);
        struct drm_fb_helper *fbh;
        int ret;
 
@@ -151,7 +151,7 @@ int armada_fbdev_init(struct drm_device *dev)
 
 void armada_fbdev_fini(struct drm_device *dev)
 {
-       struct armada_private *priv = dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(dev);
        struct drm_fb_helper *fbh = priv->fbdev;
 
        if (fbh) {
index 8005614d2e6ba006f9c0bed2eba263cf2cf5d7cd..ecf8a55e93d9338fd6b4eb11d1b774ab8512bb11 100644 (file)
@@ -39,7 +39,7 @@ static size_t roundup_gem_size(size_t size)
 void armada_gem_free_object(struct drm_gem_object *obj)
 {
        struct armada_gem_object *dobj = drm_to_armada_gem(obj);
-       struct armada_private *priv = obj->dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(obj->dev);
 
        DRM_DEBUG_DRIVER("release obj %p\n", dobj);
 
@@ -77,7 +77,7 @@ void armada_gem_free_object(struct drm_gem_object *obj)
 int
 armada_gem_linear_back(struct drm_device *dev, struct armada_gem_object *obj)
 {
-       struct armada_private *priv = dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(dev);
        size_t size = obj->obj.size;
 
        if (obj->page || obj->linear)
index 07f0da4d9ba19643da6077278c5fd179dce54270..30e01101f59ed495480826d91d132cc6ff1837b0 100644 (file)
@@ -344,7 +344,7 @@ static int armada_overlay_set_property(struct drm_plane *plane,
        struct drm_plane_state *state, struct drm_property *property,
        uint64_t val)
 {
-       struct armada_private *priv = plane->dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(plane->dev);
 
 #define K2R(val) (((val) >> 0) & 0xff)
 #define K2G(val) (((val) >> 8) & 0xff)
@@ -412,7 +412,7 @@ static int armada_overlay_get_property(struct drm_plane *plane,
        const struct drm_plane_state *state, struct drm_property *property,
        uint64_t *val)
 {
-       struct armada_private *priv = plane->dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(plane->dev);
 
 #define C2K(c,s)       (((c) >> (s)) & 0xff)
 #define R2BGR(r,g,b,s) (C2K(r,s) << 0 | C2K(g,s) << 8 | C2K(b,s) << 16)
@@ -505,7 +505,7 @@ static const struct drm_prop_enum_list armada_drm_colorkey_enum_list[] = {
 
 static int armada_overlay_create_properties(struct drm_device *dev)
 {
-       struct armada_private *priv = dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(dev);
 
        if (priv->colorkey_prop)
                return 0;
@@ -539,7 +539,7 @@ static int armada_overlay_create_properties(struct drm_device *dev)
 
 int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
 {
-       struct armada_private *priv = dev->dev_private;
+       struct armada_private *priv = drm_to_armada_dev(dev);
        struct drm_mode_object *mobj;
        struct drm_plane *overlay;
        int ret;
index 903f4f3046472529c594ca95cb4929273b6c7102..2b424b2b85cc8174480843756914e7042fa6b6b0 100644 (file)
@@ -63,15 +63,21 @@ static const struct drm_mode_config_funcs aspeed_gfx_mode_config_funcs = {
        .atomic_commit          = drm_atomic_helper_commit,
 };
 
-static void aspeed_gfx_setup_mode_config(struct drm_device *drm)
+static int aspeed_gfx_setup_mode_config(struct drm_device *drm)
 {
-       drm_mode_config_init(drm);
+       int ret;
+
+       ret = drmm_mode_config_init(drm);
+       if (ret)
+               return ret;
 
        drm->mode_config.min_width = 0;
        drm->mode_config.min_height = 0;
        drm->mode_config.max_width = 800;
        drm->mode_config.max_height = 600;
        drm->mode_config.funcs = &aspeed_gfx_mode_config_funcs;
+
+       return ret;
 }
 
 static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
@@ -144,7 +150,9 @@ static int aspeed_gfx_load(struct drm_device *drm)
        writel(0, priv->base + CRT_CTRL1);
        writel(0, priv->base + CRT_CTRL2);
 
-       aspeed_gfx_setup_mode_config(drm);
+       ret = aspeed_gfx_setup_mode_config(drm);
+       if (ret < 0)
+               return ret;
 
        ret = drm_vblank_init(drm, 1);
        if (ret < 0) {
@@ -179,7 +187,6 @@ static int aspeed_gfx_load(struct drm_device *drm)
 static void aspeed_gfx_unload(struct drm_device *drm)
 {
        drm_kms_helper_poll_fini(drm);
-       drm_mode_config_cleanup(drm);
 }
 
 DEFINE_DRM_GEM_CMA_FOPS(fops);
index d580b2aa4ce9859a000268ef33a90c69938b088e..6b268f9445b36aea903d13fdd8c76822d50c66dc 100644 (file)
@@ -89,7 +89,9 @@
 #define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS    0x1
 #define VID_MODE_TYPE_BURST                    0x2
 #define VID_MODE_TYPE_MASK                     0x3
+#define ENABLE_LOW_POWER_CMD           BIT(15)
 #define VID_MODE_VPG_ENABLE            BIT(16)
+#define VID_MODE_VPG_MODE              BIT(20)
 #define VID_MODE_VPG_HORIZONTAL                BIT(24)
 
 #define DSI_VID_PKT_SIZE               0x3c
 #define PHY_STATUS_TIMEOUT_US          10000
 #define CMD_PKT_STATUS_TIMEOUT_US      20000
 
+#ifdef CONFIG_DEBUG_FS
+#define VPG_DEFS(name, dsi) \
+       ((void __force *)&((*dsi).vpg_defs.name))
+
+#define REGISTER(name, mask, dsi) \
+       { #name, VPG_DEFS(name, dsi), mask, dsi }
+
+struct debugfs_entries {
+       const char                              *name;
+       bool                                    *reg;
+       u32                                     mask;
+       struct dw_mipi_dsi                      *dsi;
+};
+#endif /* CONFIG_DEBUG_FS */
+
 struct dw_mipi_dsi {
        struct drm_bridge bridge;
        struct mipi_dsi_host dsi_host;
@@ -237,9 +254,12 @@ struct dw_mipi_dsi {
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs;
-
-       bool vpg;
-       bool vpg_horizontal;
+       struct debugfs_entries *debugfs_vpg;
+       struct {
+               bool vpg;
+               bool vpg_horizontal;
+               bool vpg_ber_pattern;
+       } vpg_defs;
 #endif /* CONFIG_DEBUG_FS */
 
        struct dw_mipi_dsi *master; /* dual-dsi master ptr */
@@ -360,13 +380,28 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
        bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;
        u32 val = 0;
 
+       /*
+        * TODO dw drv improvements
+        * largest packet sizes during hfp or during vsa/vpb/vfp
+        * should be computed according to byte lane, lane number and only
+        * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS)
+        */
+       dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(16)
+                 | INVACT_LPCMD_TIME(4));
+
        if (msg->flags & MIPI_DSI_MSG_REQ_ACK)
                val |= ACK_RQST_EN;
        if (lpm)
                val |= CMD_MODE_ALL_LP;
 
-       dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS);
        dsi_write(dsi, DSI_CMD_MODE_CFG, val);
+
+       val = dsi_read(dsi, DSI_VID_MODE_CFG);
+       if (lpm)
+               val |= ENABLE_LOW_POWER_CMD;
+       else
+               val &= ~ENABLE_LOW_POWER_CMD;
+       dsi_write(dsi, DSI_VID_MODE_CFG, val);
 }
 
 static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
@@ -529,9 +564,11 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
                val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
 
 #ifdef CONFIG_DEBUG_FS
-       if (dsi->vpg) {
+       if (dsi->vpg_defs.vpg) {
                val |= VID_MODE_VPG_ENABLE;
-               val |= dsi->vpg_horizontal ? VID_MODE_VPG_HORIZONTAL : 0;
+               val |= dsi->vpg_defs.vpg_horizontal ?
+                      VID_MODE_VPG_HORIZONTAL : 0;
+               val |= dsi->vpg_defs.vpg_ber_pattern ? VID_MODE_VPG_MODE : 0;
        }
 #endif /* CONFIG_DEBUG_FS */
 
@@ -541,16 +578,22 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
 static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
                                 unsigned long mode_flags)
 {
+       u32 val;
+
        dsi_write(dsi, DSI_PWR_UP, RESET);
 
        if (mode_flags & MIPI_DSI_MODE_VIDEO) {
                dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE);
                dw_mipi_dsi_video_mode_config(dsi);
-               dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
        } else {
                dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
        }
 
+       val = PHY_TXREQUESTCLKHS;
+       if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+               val |= AUTO_CLKLANE_CTRL;
+       dsi_write(dsi, DSI_LPCLK_CTRL, val);
+
        dsi_write(dsi, DSI_PWR_UP, POWERUP);
 }
 
@@ -562,15 +605,30 @@ static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
 
 static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
 {
+       const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
+       unsigned int esc_rate; /* in MHz */
+       u32 esc_clk_division;
+       int ret;
+
        /*
         * The maximum permitted escape clock is 20MHz and it is derived from
-        * lanebyteclk, which is running at "lane_mbps / 8".  Thus we want:
-        *
-        *     (lane_mbps >> 3) / esc_clk_division < 20
+        * lanebyteclk, which is running at "lane_mbps / 8".
+        */
+       if (phy_ops->get_esc_clk_rate) {
+               ret = phy_ops->get_esc_clk_rate(dsi->plat_data->priv_data,
+                                               &esc_rate);
+               if (ret)
+                       DRM_DEBUG_DRIVER("Phy get_esc_clk_rate() failed\n");
+       } else
+               esc_rate = 20; /* Default to 20MHz */
+
+       /*
+        * We want :
+        *     (lane_mbps >> 3) / esc_clk_division < X
         * which is:
-        *     (lane_mbps >> 3) / 20 > esc_clk_division
+        *     (lane_mbps >> 3) / X > esc_clk_division
         */
-       u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1;
+       esc_clk_division = (dsi->lane_mbps >> 3) / esc_rate + 1;
 
        dsi_write(dsi, DSI_PWR_UP, RESET);
 
@@ -611,14 +669,6 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
        dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel));
        dsi_write(dsi, DSI_DPI_COLOR_CODING, color);
        dsi_write(dsi, DSI_DPI_CFG_POL, val);
-       /*
-        * TODO dw drv improvements
-        * largest packet sizes during hfp or during vsa/vpb/vfp
-        * should be computed according to byte lane, lane number and only
-        * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS)
-        */
-       dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4)
-                 | INVACT_LPCMD_TIME(4));
 }
 
 static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
@@ -964,6 +1014,66 @@ static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
 
 #ifdef CONFIG_DEBUG_FS
 
+static int dw_mipi_dsi_debugfs_write(void *data, u64 val)
+{
+       struct debugfs_entries *vpg = data;
+       struct dw_mipi_dsi *dsi;
+       u32 mode_cfg;
+
+       if (!vpg)
+               return -ENODEV;
+
+       dsi = vpg->dsi;
+
+       *vpg->reg = (bool)val;
+
+       mode_cfg = dsi_read(dsi, DSI_VID_MODE_CFG);
+
+       if (*vpg->reg)
+               mode_cfg |= vpg->mask;
+       else
+               mode_cfg &= ~vpg->mask;
+
+       dsi_write(dsi, DSI_VID_MODE_CFG, mode_cfg);
+
+       return 0;
+}
+
+static int dw_mipi_dsi_debugfs_show(void *data, u64 *val)
+{
+       struct debugfs_entries *vpg = data;
+
+       if (!vpg)
+               return -ENODEV;
+
+       *val = *vpg->reg;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_mipi_dsi_debugfs_show,
+                        dw_mipi_dsi_debugfs_write, "%llu\n");
+
+static void debugfs_create_files(void *data)
+{
+       struct dw_mipi_dsi *dsi = data;
+       struct debugfs_entries debugfs[] = {
+               REGISTER(vpg, VID_MODE_VPG_ENABLE, dsi),
+               REGISTER(vpg_horizontal, VID_MODE_VPG_HORIZONTAL, dsi),
+               REGISTER(vpg_ber_pattern, VID_MODE_VPG_MODE, dsi),
+       };
+       int i;
+
+       dsi->debugfs_vpg = kmemdup(debugfs, sizeof(debugfs), GFP_KERNEL);
+       if (!dsi->debugfs_vpg)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(debugfs); i++)
+               debugfs_create_file(dsi->debugfs_vpg[i].name, 0644,
+                                   dsi->debugfs, &dsi->debugfs_vpg[i],
+                                   &fops_x32);
+}
+
 static void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi)
 {
        dsi->debugfs = debugfs_create_dir(dev_name(dsi->dev), NULL);
@@ -972,14 +1082,13 @@ static void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi)
                return;
        }
 
-       debugfs_create_bool("vpg", 0660, dsi->debugfs, &dsi->vpg);
-       debugfs_create_bool("vpg_horizontal", 0660, dsi->debugfs,
-                           &dsi->vpg_horizontal);
+       debugfs_create_files(dsi);
 }
 
 static void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi)
 {
        debugfs_remove_recursive(dsi->debugfs);
+       kfree(dsi->debugfs_vpg);
 }
 
 #else
index d951cdc58297111d2dde6f04f068f9fa41af3f87..2272adcc5b4adbd0c855e82ad8df1ca24f5bf36a 100644 (file)
@@ -485,7 +485,7 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
                val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_6);
        } else {
                val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_3);
-       };
+       }
        d2l_write(tc->i2c, LVCFG, val);
 }
 
index 3d48ad1c36823e33132127263e81c9960ee46698..717c4e7271b0422692c485d8c8cb426de0bc006f 100644 (file)
@@ -2289,7 +2289,7 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne
 
 static bool
 drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
-                            const struct list_head *export_list,
+                            const struct list_head *modes,
                             const struct drm_file *file_priv)
 {
        /*
@@ -2305,15 +2305,17 @@ drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
         * while preparing the list of user-modes.
         */
        if (!file_priv->aspect_ratio_allowed) {
-               struct drm_display_mode *mode_itr;
+               const struct drm_display_mode *mode_itr;
 
-               list_for_each_entry(mode_itr, export_list, export_head)
-                       if (drm_mode_match(mode_itr, mode,
+               list_for_each_entry(mode_itr, modes, head) {
+                       if (mode_itr->expose_to_userspace &&
+                           drm_mode_match(mode_itr, mode,
                                           DRM_MODE_MATCH_TIMINGS |
                                           DRM_MODE_MATCH_CLOCK |
                                           DRM_MODE_MATCH_FLAGS |
                                           DRM_MODE_MATCH_3D_FLAGS))
                                return false;
+               }
        }
 
        return true;
@@ -2333,7 +2335,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        struct drm_mode_modeinfo u_mode;
        struct drm_mode_modeinfo __user *mode_ptr;
        uint32_t __user *encoder_ptr;
-       LIST_HEAD(export_list);
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EOPNOTSUPP;
@@ -2377,25 +2378,30 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        out_resp->connection = connector->status;
 
        /* delayed so we get modes regardless of pre-fill_modes state */
-       list_for_each_entry(mode, &connector->modes, head)
-               if (drm_mode_expose_to_userspace(mode, &export_list,
+       list_for_each_entry(mode, &connector->modes, head) {
+               WARN_ON(mode->expose_to_userspace);
+
+               if (drm_mode_expose_to_userspace(mode, &connector->modes,
                                                 file_priv)) {
-                       list_add_tail(&mode->export_head, &export_list);
+                       mode->expose_to_userspace = true;
                        mode_count++;
                }
+       }
 
        /*
         * This ioctl is called twice, once to determine how much space is
         * needed, and the 2nd time to fill it.
-        * The modes that need to be exposed to the user are maintained in the
-        * 'export_list'. When the ioctl is called first time to determine the,
-        * space, the export_list gets filled, to find the no.of modes. In the
-        * 2nd time, the user modes are filled, one by one from the export_list.
         */
        if ((out_resp->count_modes >= mode_count) && mode_count) {
                copied = 0;
                mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
-               list_for_each_entry(mode, &export_list, export_head) {
+               list_for_each_entry(mode, &connector->modes, head) {
+                       if (!mode->expose_to_userspace)
+                               continue;
+
+                       /* Clear the tag for the next time around */
+                       mode->expose_to_userspace = false;
+
                        drm_mode_convert_to_umode(&u_mode, mode);
                        /*
                         * Reset aspect ratio flags of user-mode, if modes with
@@ -2406,13 +2412,26 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
                        if (copy_to_user(mode_ptr + copied,
                                         &u_mode, sizeof(u_mode))) {
                                ret = -EFAULT;
+
+                               /*
+                                * Clear the tag for the rest of
+                                * the modes for the next time around.
+                                */
+                               list_for_each_entry_continue(mode, &connector->modes, head)
+                                       mode->expose_to_userspace = false;
+
                                mutex_unlock(&dev->mode_config.mutex);
 
                                goto out;
                        }
                        copied++;
                }
+       } else {
+               /* Clear the tag for the next time around */
+               list_for_each_entry(mode, &connector->modes, head)
+                       mode->expose_to_userspace = false;
        }
+
        out_resp->count_modes = mode_count;
        mutex_unlock(&dev->mode_config.mutex);
 
index 5d67a41f7c3a8f208e2aee802c8bffa16e13cac6..3dd70d813f69427323b658d311e76b6a0edd6bf5 100644 (file)
@@ -144,8 +144,10 @@ static ssize_t crc_control_write(struct file *file, const char __user *ubuf,
                source[len - 1] = '\0';
 
        ret = crtc->funcs->verify_crc_source(crtc, source, &values_cnt);
-       if (ret)
+       if (ret) {
+               kfree(source);
                return ret;
+       }
 
        spin_lock_irq(&crc->lock);
 
index 17dbed0a9800dcff491a570af9142160d504c522..b9c5a98c5c9ce38e43d098067df50c379e705ab2 100644 (file)
@@ -961,6 +961,8 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
                return drm_dp_sideband_parse_remote_dpcd_write(raw, msg);
        case DP_REMOTE_I2C_READ:
                return drm_dp_sideband_parse_remote_i2c_read_ack(raw, msg);
+       case DP_REMOTE_I2C_WRITE:
+               return true; /* since there's nothing to parse */
        case DP_ENUM_PATH_RESOURCES:
                return drm_dp_sideband_parse_enum_path_resources_ack(raw, msg);
        case DP_ALLOCATE_PAYLOAD:
@@ -5349,29 +5351,29 @@ static bool remote_i2c_read_ok(const struct i2c_msg msgs[], int num)
                msgs[num - 1].len <= 0xff;
 }
 
-/* I2C device */
-static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
-                              int num)
+static bool remote_i2c_write_ok(const struct i2c_msg msgs[], int num)
+{
+       int i;
+
+       for (i = 0; i < num - 1; i++) {
+               if (msgs[i].flags & I2C_M_RD || !(msgs[i].flags & I2C_M_STOP) ||
+                   msgs[i].len > 0xff)
+                       return false;
+       }
+
+       return !(msgs[num - 1].flags & I2C_M_RD) && msgs[num - 1].len <= 0xff;
+}
+
+static int drm_dp_mst_i2c_read(struct drm_dp_mst_branch *mstb,
+                              struct drm_dp_mst_port *port,
+                              struct i2c_msg *msgs, int num)
 {
-       struct drm_dp_aux *aux = adapter->algo_data;
-       struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port, aux);
-       struct drm_dp_mst_branch *mstb;
        struct drm_dp_mst_topology_mgr *mgr = port->mgr;
        unsigned int i;
        struct drm_dp_sideband_msg_req_body msg;
        struct drm_dp_sideband_msg_tx *txmsg = NULL;
        int ret;
 
-       mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent);
-       if (!mstb)
-               return -EREMOTEIO;
-
-       if (!remote_i2c_read_ok(msgs, num)) {
-               DRM_DEBUG_KMS("Unsupported I2C transaction for MST device\n");
-               ret = -EIO;
-               goto out;
-       }
-
        memset(&msg, 0, sizeof(msg));
        msg.req_type = DP_REMOTE_I2C_READ;
        msg.u.i2c_read.num_transactions = num - 1;
@@ -5412,6 +5414,78 @@ static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs
        }
 out:
        kfree(txmsg);
+       return ret;
+}
+
+static int drm_dp_mst_i2c_write(struct drm_dp_mst_branch *mstb,
+                               struct drm_dp_mst_port *port,
+                               struct i2c_msg *msgs, int num)
+{
+       struct drm_dp_mst_topology_mgr *mgr = port->mgr;
+       unsigned int i;
+       struct drm_dp_sideband_msg_req_body msg;
+       struct drm_dp_sideband_msg_tx *txmsg = NULL;
+       int ret;
+
+       txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
+       if (!txmsg) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       for (i = 0; i < num; i++) {
+               memset(&msg, 0, sizeof(msg));
+               msg.req_type = DP_REMOTE_I2C_WRITE;
+               msg.u.i2c_write.port_number = port->port_num;
+               msg.u.i2c_write.write_i2c_device_id = msgs[i].addr;
+               msg.u.i2c_write.num_bytes = msgs[i].len;
+               msg.u.i2c_write.bytes = msgs[i].buf;
+
+               memset(txmsg, 0, sizeof(*txmsg));
+               txmsg->dst = mstb;
+
+               drm_dp_encode_sideband_req(&msg, txmsg);
+               drm_dp_queue_down_tx(mgr, txmsg);
+
+               ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
+               if (ret > 0) {
+                       if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
+                               ret = -EREMOTEIO;
+                               goto out;
+                       }
+               } else {
+                       goto out;
+               }
+       }
+       ret = num;
+out:
+       kfree(txmsg);
+       return ret;
+}
+
+/* I2C device */
+static int drm_dp_mst_i2c_xfer(struct i2c_adapter *adapter,
+                              struct i2c_msg *msgs, int num)
+{
+       struct drm_dp_aux *aux = adapter->algo_data;
+       struct drm_dp_mst_port *port =
+               container_of(aux, struct drm_dp_mst_port, aux);
+       struct drm_dp_mst_branch *mstb;
+       struct drm_dp_mst_topology_mgr *mgr = port->mgr;
+       int ret;
+
+       mstb = drm_dp_mst_topology_get_mstb_validated(mgr, port->parent);
+       if (!mstb)
+               return -EREMOTEIO;
+
+       if (remote_i2c_read_ok(msgs, num)) {
+               ret = drm_dp_mst_i2c_read(mstb, port, msgs, num);
+       } else if (remote_i2c_write_ok(msgs, num)) {
+               ret = drm_dp_mst_i2c_write(mstb, port, msgs, num);
+       } else {
+               DRM_DEBUG_KMS("Unsupported I2C transaction for MST device\n");
+               ret = -EIO;
+       }
+
        drm_dp_mst_topology_put_mstb(mstb);
        return ret;
 }
index 13068fdf4331a2c814400364b94e1b179d15c1e7..3b70f91e4316a2661e513a5622f5e44083c14bb6 100644 (file)
@@ -240,13 +240,13 @@ void drm_minor_release(struct drm_minor *minor)
  * DOC: driver instance overview
  *
  * A device instance for a drm driver is represented by &struct drm_device. This
- * is initialized with drm_dev_init(), usually from bus-specific ->probe()
- * callbacks implemented by the driver. The driver then needs to initialize all
- * the various subsystems for the drm device like memory management, vblank
- * handling, modesetting support and intial output configuration plus obviously
- * initialize all the corresponding hardware bits. Finally when everything is up
- * and running and ready for userspace the device instance can be published
- * using drm_dev_register().
+ * is allocated and initialized with devm_drm_dev_alloc(), usually from
+ * bus-specific ->probe() callbacks implemented by the driver. The driver then
+ * needs to initialize all the various subsystems for the drm device like memory
+ * management, vblank handling, modesetting support and initial output
+ * configuration plus obviously initialize all the corresponding hardware bits.
+ * Finally when everything is up and running and ready for userspace the device
+ * instance can be published using drm_dev_register().
  *
  * There is also deprecated support for initalizing device instances using
  * bus-specific helpers and the &drm_driver.load callback. But due to
@@ -274,7 +274,7 @@ void drm_minor_release(struct drm_minor *minor)
  *
  * The following example shows a typical structure of a DRM display driver.
  * The example focus on the probe() function and the other functions that is
- * almost always present and serves as a demonstration of devm_drm_dev_init().
+ * almost always present and serves as a demonstration of devm_drm_dev_alloc().
  *
  * .. code-block:: c
  *
@@ -294,22 +294,12 @@ void drm_minor_release(struct drm_minor *minor)
  *             struct drm_device *drm;
  *             int ret;
  *
- *             // devm_kzalloc() can't be used here because the drm_device '
- *             // lifetime can exceed the device lifetime if driver unbind
- *             // happens when userspace still has open file descriptors.
- *             priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- *             if (!priv)
- *                     return -ENOMEM;
- *
+ *             priv = devm_drm_dev_alloc(&pdev->dev, &driver_drm_driver,
+ *                                       struct driver_device, drm);
+ *             if (IS_ERR(priv))
+ *                     return PTR_ERR(priv);
  *             drm = &priv->drm;
  *
- *             ret = devm_drm_dev_init(&pdev->dev, drm, &driver_drm_driver);
- *             if (ret) {
- *                     kfree(priv);
- *                     return ret;
- *             }
- *             drmm_add_final_kfree(drm, priv);
- *
  *             ret = drmm_mode_config_init(drm);
  *             if (ret)
  *                     return ret;
@@ -550,9 +540,9 @@ static void drm_fs_inode_free(struct inode *inode)
  * following guidelines apply:
  *
  *  - The entire device initialization procedure should be run from the
- *    &component_master_ops.master_bind callback, starting with drm_dev_init(),
- *    then binding all components with component_bind_all() and finishing with
- *    drm_dev_register().
+ *    &component_master_ops.master_bind callback, starting with
+ *    devm_drm_dev_alloc(), then binding all components with
+ *    component_bind_all() and finishing with drm_dev_register().
  *
  *  - The opaque pointer passed to all components through component_bind_all()
  *    should point at &struct drm_device of the device instance, not some driver
@@ -706,24 +696,9 @@ static void devm_drm_dev_init_release(void *data)
        drm_dev_put(data);
 }
 
-/**
- * devm_drm_dev_init - Resource managed drm_dev_init()
- * @parent: Parent device object
- * @dev: DRM device
- * @driver: DRM driver
- *
- * Managed drm_dev_init(). The DRM device initialized with this function is
- * automatically put on driver detach using drm_dev_put().
- *
- * Note that drivers must call drmm_add_final_kfree() after this function has
- * completed successfully.
- *
- * RETURNS:
- * 0 on success, or error code on failure.
- */
-int devm_drm_dev_init(struct device *parent,
-                     struct drm_device *dev,
-                     struct drm_driver *driver)
+static int devm_drm_dev_init(struct device *parent,
+                            struct drm_device *dev,
+                            struct drm_driver *driver)
 {
        int ret;
 
@@ -737,7 +712,6 @@ int devm_drm_dev_init(struct device *parent,
 
        return ret;
 }
-EXPORT_SYMBOL(devm_drm_dev_init);
 
 void *__devm_drm_dev_alloc(struct device *parent, struct drm_driver *driver,
                           size_t size, size_t offset)
@@ -767,19 +741,9 @@ EXPORT_SYMBOL(__devm_drm_dev_alloc);
  * @driver: DRM driver to allocate device for
  * @parent: Parent device object
  *
- * Allocate and initialize a new DRM device. No device registration is done.
- * Call drm_dev_register() to advertice the device to user space and register it
- * with other core subsystems. This should be done last in the device
- * initialization sequence to make sure userspace can't access an inconsistent
- * state.
- *
- * The initial ref-count of the object is 1. Use drm_dev_get() and
- * drm_dev_put() to take and drop further ref-counts.
- *
- * Note that for purely virtual devices @parent can be NULL.
- *
- * Drivers that wish to subclass or embed &struct drm_device into their
- * own struct should look at using drm_dev_init() instead.
+ * This is the deprecated version of devm_drm_dev_alloc(), which does not support
+ * subclassing through embedding the struct &drm_device in a driver private
+ * structure, and which does not support automatic cleanup through devres.
  *
  * RETURNS:
  * Pointer to new DRM device, or ERR_PTR on failure.
index df656366a530208bd26a5f15738e09a762f9a4de..2f5b0c2bb0fe3ff885becc9c6b2cca2e34a255b6 100644 (file)
@@ -176,8 +176,7 @@ static int framebuffer_check(struct drm_device *dev,
        int i;
 
        /* check if the format is supported at all */
-       info = __drm_format_info(r->pixel_format);
-       if (!info) {
+       if (!__drm_format_info(r->pixel_format)) {
                struct drm_format_name_buf format_name;
 
                DRM_DEBUG_KMS("bad framebuffer format %s\n",
@@ -186,9 +185,6 @@ static int framebuffer_check(struct drm_device *dev,
                return -EINVAL;
        }
 
-       /* now let the driver pick its own format info */
-       info = drm_get_format_info(dev, r);
-
        if (r->width == 0) {
                DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
                return -EINVAL;
@@ -199,6 +195,9 @@ static int framebuffer_check(struct drm_device *dev,
                return -EINVAL;
        }
 
+       /* now let the driver pick its own format info */
+       info = drm_get_format_info(dev, r);
+
        for (i = 0; i < info->num_planes; i++) {
                unsigned int width = fb_plane_width(r->width, info, i);
                unsigned int height = fb_plane_height(r->height, info, i);
index 4b7cfbac4daae3917e809dca4da3cd0ba88b1321..0a952f27c184670c2736b18d75c50d78b5b354d7 100644 (file)
@@ -656,7 +656,7 @@ struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj)
 
        WARN_ON(shmem->base.import_attach);
 
-       return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT);
+       return drm_prime_pages_to_sg(obj->dev, shmem->pages, obj->size >> PAGE_SHIFT);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
 
index 892b2288a104b52beba131e04df09fbc532ed04d..0e4fb9ba43adb6b306801ff0bef1b95650496fcc 100644 (file)
@@ -43,12 +43,9 @@ void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent,
        drm_print_bits(p, bo->mem.placement, plname, ARRAY_SIZE(plname));
        drm_printf(p, "\n");
 
-       if (bo->mem.bus.is_iomem) {
-               drm_printf_indent(p, indent, "bus.base=%lx\n",
-                                 (unsigned long)bo->mem.bus.base);
+       if (bo->mem.bus.is_iomem)
                drm_printf_indent(p, indent, "bus.offset=%lx\n",
                                  (unsigned long)bo->mem.bus.offset);
-       }
 }
 EXPORT_SYMBOL(drm_gem_ttm_print_info);
 
index 545a877406f45f19405f0261bf76bb83b188940e..4291f0b71021b0d1203e81f211b1f0e962495286 100644 (file)
@@ -97,8 +97,8 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
  * hardware's draing engine.
  *
  * To access a buffer object's memory from the DRM driver, call
- * drm_gem_vram_kmap(). It (optionally) maps the buffer into kernel address
- * space and returns the memory address. Use drm_gem_vram_kunmap() to
+ * drm_gem_vram_vmap(). It maps the buffer into kernel address
+ * space and returns the memory address. Use drm_gem_vram_vunmap() to
  * release the mapping.
  */
 
@@ -135,28 +135,28 @@ static void ttm_buffer_object_destroy(struct ttm_buffer_object *bo)
 static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo,
                                   unsigned long pl_flag)
 {
+       u32 invariant_flags = 0;
        unsigned int i;
        unsigned int c = 0;
-       u32 invariant_flags = pl_flag & TTM_PL_FLAG_TOPDOWN;
+
+       if (pl_flag & DRM_GEM_VRAM_PL_FLAG_TOPDOWN)
+               pl_flag = TTM_PL_FLAG_TOPDOWN;
 
        gbo->placement.placement = gbo->placements;
        gbo->placement.busy_placement = gbo->placements;
 
-       if (pl_flag & TTM_PL_FLAG_VRAM)
+       if (pl_flag & DRM_GEM_VRAM_PL_FLAG_VRAM) {
+               gbo->placements[c].mem_type = TTM_PL_VRAM;
                gbo->placements[c++].flags = TTM_PL_FLAG_WC |
                                             TTM_PL_FLAG_UNCACHED |
-                                            TTM_PL_FLAG_VRAM |
-                                            invariant_flags;
-
-       if (pl_flag & TTM_PL_FLAG_SYSTEM)
-               gbo->placements[c++].flags = TTM_PL_MASK_CACHING |
-                                            TTM_PL_FLAG_SYSTEM |
                                             invariant_flags;
+       }
 
-       if (!c)
+       if (pl_flag & DRM_GEM_VRAM_PL_FLAG_SYSTEM || !c) {
+               gbo->placements[c].mem_type = TTM_PL_SYSTEM;
                gbo->placements[c++].flags = TTM_PL_MASK_CACHING |
-                                            TTM_PL_FLAG_SYSTEM |
                                             invariant_flags;
+       }
 
        gbo->placement.num_placement = c;
        gbo->placement.num_busy_placement = c;
@@ -167,6 +167,10 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo,
        }
 }
 
+/*
+ * Note that on error, drm_gem_vram_init will free the buffer object.
+ */
+
 static int drm_gem_vram_init(struct drm_device *dev,
                             struct drm_gem_vram_object *gbo,
                             size_t size, unsigned long pg_align)
@@ -176,32 +180,37 @@ static int drm_gem_vram_init(struct drm_device *dev,
        int ret;
        size_t acc_size;
 
-       if (WARN_ONCE(!vmm, "VRAM MM not initialized"))
+       if (WARN_ONCE(!vmm, "VRAM MM not initialized")) {
+               kfree(gbo);
                return -EINVAL;
+       }
        bdev = &vmm->bdev;
 
        gbo->bo.base.funcs = &drm_gem_vram_object_funcs;
 
        ret = drm_gem_object_init(dev, &gbo->bo.base, size);
-       if (ret)
+       if (ret) {
+               kfree(gbo);
                return ret;
+       }
 
        acc_size = ttm_bo_dma_acc_size(bdev, size, sizeof(*gbo));
 
        gbo->bo.bdev = bdev;
-       drm_gem_vram_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+       drm_gem_vram_placement(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM |
+                              DRM_GEM_VRAM_PL_FLAG_SYSTEM);
 
        ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device,
                          &gbo->placement, pg_align, false, acc_size,
                          NULL, NULL, ttm_buffer_object_destroy);
        if (ret)
-               goto err_drm_gem_object_release;
+               /*
+                * A failing ttm_bo_init will call ttm_buffer_object_destroy
+                * to release gbo->bo.base and kfree gbo.
+                */
+               return ret;
 
        return 0;
-
-err_drm_gem_object_release:
-       drm_gem_object_release(&gbo->bo.base);
-       return ret;
 }
 
 /**
@@ -235,13 +244,9 @@ struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev,
 
        ret = drm_gem_vram_init(dev, gbo, size, pg_align);
        if (ret < 0)
-               goto err_kfree;
+               return ERR_PTR(ret);
 
        return gbo;
-
-err_kfree:
-       kfree(gbo);
-       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(drm_gem_vram_create);
 
@@ -436,39 +441,6 @@ out:
        return kmap->virtual;
 }
 
-/**
- * drm_gem_vram_kmap() - Maps a GEM VRAM object into kernel address space
- * @gbo:       the GEM VRAM object
- * @map:       establish a mapping if necessary
- * @is_iomem:  returns true if the mapped memory is I/O memory, or false \
-       otherwise; can be NULL
- *
- * This function maps the buffer object into the kernel's address space
- * or returns the current mapping. If the parameter map is false, the
- * function only queries the current mapping, but does not establish a
- * new one.
- *
- * Returns:
- * The buffers virtual address if mapped, or
- * NULL if not mapped, or
- * an ERR_PTR()-encoded error code otherwise.
- */
-void *drm_gem_vram_kmap(struct drm_gem_vram_object *gbo, bool map,
-                       bool *is_iomem)
-{
-       int ret;
-       void *virtual;
-
-       ret = ttm_bo_reserve(&gbo->bo, true, false, NULL);
-       if (ret)
-               return ERR_PTR(ret);
-       virtual = drm_gem_vram_kmap_locked(gbo, map, is_iomem);
-       ttm_bo_unreserve(&gbo->bo);
-
-       return virtual;
-}
-EXPORT_SYMBOL(drm_gem_vram_kmap);
-
 static void drm_gem_vram_kunmap_locked(struct drm_gem_vram_object *gbo)
 {
        if (WARN_ON_ONCE(!gbo->kmap_use_count))
@@ -484,22 +456,6 @@ static void drm_gem_vram_kunmap_locked(struct drm_gem_vram_object *gbo)
         */
 }
 
-/**
- * drm_gem_vram_kunmap() - Unmaps a GEM VRAM object
- * @gbo:       the GEM VRAM object
- */
-void drm_gem_vram_kunmap(struct drm_gem_vram_object *gbo)
-{
-       int ret;
-
-       ret = ttm_bo_reserve(&gbo->bo, false, false, NULL);
-       if (WARN_ONCE(ret, "ttm_bo_reserve_failed(): ret=%d\n", ret))
-               return;
-       drm_gem_vram_kunmap_locked(gbo);
-       ttm_bo_unreserve(&gbo->bo);
-}
-EXPORT_SYMBOL(drm_gem_vram_kunmap);
-
 /**
  * drm_gem_vram_vmap() - Pins and maps a GEM VRAM object into kernel address
  *                       space
@@ -511,9 +467,6 @@ EXPORT_SYMBOL(drm_gem_vram_kunmap);
  * permanently. Call drm_gem_vram_vunmap() with the returned address to
  * unmap and unpin the GEM VRAM object.
  *
- * If you have special requirements for the pinning or mapping operations,
- * call drm_gem_vram_pin() and drm_gem_vram_kmap() directly.
- *
  * Returns:
  * The buffer's virtual address on success, or
  * an ERR_PTR()-encoded error code otherwise.
@@ -647,7 +600,7 @@ static bool drm_is_gem_vram(struct ttm_buffer_object *bo)
 static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo,
                                               struct ttm_placement *pl)
 {
-       drm_gem_vram_placement(gbo, TTM_PL_FLAG_SYSTEM);
+       drm_gem_vram_placement(gbo, DRM_GEM_VRAM_PL_FLAG_SYSTEM);
        *pl = gbo->placement;
 }
 
@@ -967,16 +920,12 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs = {
  * TTM TT
  */
 
-static void backend_func_destroy(struct ttm_tt *tt)
+static void bo_driver_ttm_tt_destroy(struct ttm_bo_device *bdev, struct ttm_tt *tt)
 {
        ttm_tt_fini(tt);
        kfree(tt);
 }
 
-static struct ttm_backend_func backend_func = {
-       .destroy = backend_func_destroy
-};
-
 /*
  * TTM BO device
  */
@@ -991,8 +940,6 @@ static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo,
        if (!tt)
                return NULL;
 
-       tt->func = &backend_func;
-
        ret = ttm_tt_init(tt, bo, page_flags);
        if (ret < 0)
                goto err_ttm_tt_init;
@@ -1042,8 +989,7 @@ static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
        case TTM_PL_SYSTEM:     /* nothing to do */
                break;
        case TTM_PL_VRAM:
-               mem->bus.offset = mem->start << PAGE_SHIFT;
-               mem->bus.base = vmm->vram_base;
+               mem->bus.offset = (mem->start << PAGE_SHIFT) + vmm->vram_base;
                mem->bus.is_iomem = true;
                break;
        default:
@@ -1055,6 +1001,7 @@ 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_destroy = bo_driver_ttm_tt_destroy,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = bo_driver_evict_flags,
        .move_notify = bo_driver_move_notify,
index 1e1356560c2ef9d10594741aa3022cb919d3a614..c36e3d98fd7131e25084020bd2031108a9d05bc5 100644 (file)
@@ -27,7 +27,7 @@
  * be done directly with drmm_kmalloc() and the related functions. Everything
  * will be released on the final drm_dev_put() in reverse order of how the
  * release actions have been added and memory has been allocated since driver
- * loading started with drm_dev_init().
+ * loading started with devm_drm_dev_alloc().
  *
  * Note that release actions and managed memory can also be added and removed
  * during the lifetime of the driver, all the functions are fully concurrent
index 1693aa7c14b5faccc177f996907efdae9298b2f8..8a6a3c99b7d8a759c3168ae329ac1b37ac6640e5 100644 (file)
@@ -802,9 +802,11 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
  *
  * This is useful for implementing &drm_gem_object_funcs.get_sg_table.
  */
-struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages)
+struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
+                                      struct page **pages, unsigned int nr_pages)
 {
        struct sg_table *sg = NULL;
+       size_t max_segment = 0;
        int ret;
 
        sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
@@ -813,8 +815,13 @@ struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_page
                goto out;
        }
 
-       ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
-                               nr_pages << PAGE_SHIFT, GFP_KERNEL);
+       if (dev)
+               max_segment = dma_max_mapping_size(dev->dev);
+       if (max_segment == 0 || max_segment > SCATTERLIST_MAX_SEGMENT)
+               max_segment = SCATTERLIST_MAX_SEGMENT;
+       ret = __sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
+                                         nr_pages << PAGE_SHIFT,
+                                         max_segment, GFP_KERNEL);
        if (ret)
                goto out;
 
index f06e19e7be04a5cd315369468492a488bd89e7d6..ea19f1d27275683ab0fe507309e3a69135acb6c1 100644 (file)
@@ -103,7 +103,8 @@ struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj)
                int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
                struct sg_table *sgt;
 
-               sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
+               sgt = drm_prime_pages_to_sg(etnaviv_obj->base.dev,
+                                           etnaviv_obj->pages, npages);
                if (IS_ERR(sgt)) {
                        dev_err(dev->dev, "failed to allocate sgt: %ld\n",
                                PTR_ERR(sgt));
index 6d9e5c3c4dd5738a90617f74d59d73d26ec9c364..4aa3426a9ba4beea8863d7ed07bb24da388e7d0f 100644 (file)
@@ -19,7 +19,7 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
        if (WARN_ON(!etnaviv_obj->pages))  /* should have already pinned! */
                return ERR_PTR(-EINVAL);
 
-       return drm_prime_pages_to_sg(etnaviv_obj->pages, npages);
+       return drm_prime_pages_to_sg(obj->dev, etnaviv_obj->pages, npages);
 }
 
 void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj)
index da02d7e8a8f5568ed532c1e12c6372119487be7f..54d9876b5305a475de62e4b219c77437787809b1 100644 (file)
@@ -164,7 +164,7 @@ static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
        return 0;
 }
 
-static struct fb_ops psbfb_ops = {
+static const struct fb_ops psbfb_ops = {
        .owner = THIS_MODULE,
        DRM_FB_HELPER_DEFAULT_OPS,
        .fb_setcolreg = psbfb_setcolreg,
@@ -175,7 +175,7 @@ static struct fb_ops psbfb_ops = {
        .fb_sync = psbfb_sync,
 };
 
-static struct fb_ops psbfb_roll_ops = {
+static const struct fb_ops psbfb_roll_ops = {
        .owner = THIS_MODULE,
        DRM_FB_HELPER_DEFAULT_OPS,
        .fb_setcolreg = psbfb_setcolreg,
@@ -186,7 +186,7 @@ static struct fb_ops psbfb_roll_ops = {
        .fb_mmap = psbfb_mmap,
 };
 
-static struct fb_ops psbfb_unaccel_ops = {
+static const struct fb_ops psbfb_unaccel_ops = {
        .owner = THIS_MODULE,
        DRM_FB_HELPER_DEFAULT_OPS,
        .fb_setcolreg = psbfb_setcolreg,
index 303c2d483c6ea2e052527b73c313caa602ec455d..88250860f8e4541f9a8a51873bedc48fd7799547 100644 (file)
@@ -853,11 +853,11 @@ static void i810_dma_quiescent(struct drm_device *dev)
        i810_wait_ring(dev, dev_priv->ring.Size - 8);
 }
 
-static int i810_flush_queue(struct drm_device *dev)
+static void i810_flush_queue(struct drm_device *dev)
 {
        drm_i810_private_t *dev_priv = dev->dev_private;
        struct drm_device_dma *dma = dev->dma;
-       int i, ret = 0;
+       int i;
        RING_LOCALS;
 
        i810_kernel_lost_context(dev);
@@ -882,7 +882,7 @@ static int i810_flush_queue(struct drm_device *dev)
                        DRM_DEBUG("still on client\n");
        }
 
-       return ret;
+       return;
 }
 
 /* Must be called with the lock held */
index 207bf7409dfba5fb3f243fb74410f4f152ad5731..6231048aa5aaa05faf1e10697a63753999fae798 100644 (file)
@@ -39,3 +39,5 @@ config DRM_IMX_HDMI
        depends on DRM_IMX
        help
          Choose this if you want to use HDMI on i.MX6.
+
+source "drivers/gpu/drm/imx/dcss/Kconfig"
index 21cdcc2faabc8fb9d6e4a5f168692f3109fd9acd..b644deffe948beaa2a426c9075e24218cd5d5252 100644 (file)
@@ -9,3 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
 
 obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
diff --git a/drivers/gpu/drm/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig
new file mode 100644 (file)
index 0000000..2b17a96
--- /dev/null
@@ -0,0 +1,9 @@
+config DRM_IMX_DCSS
+       tristate "i.MX8MQ DCSS"
+       select IMX_IRQSTEER
+       select DRM_KMS_CMA_HELPER
+       select VIDEOMODE_HELPERS
+       depends on DRM && ARCH_MXC && ARM64
+       help
+         Choose this if you have a NXP i.MX8MQ based system and want to use the
+         Display Controller Subsystem. This option enables DCSS support.
diff --git a/drivers/gpu/drm/imx/dcss/Makefile b/drivers/gpu/drm/imx/dcss/Makefile
new file mode 100644 (file)
index 0000000..8c7c8da
--- /dev/null
@@ -0,0 +1,6 @@
+imx-dcss-objs := dcss-drv.o dcss-dev.o dcss-blkctl.o dcss-ctxld.o dcss-dtg.o \
+                                dcss-ss.o dcss-dpr.o dcss-scaler.o dcss-kms.o dcss-crtc.o \
+                                dcss-plane.o
+
+obj-$(CONFIG_DRM_IMX_DCSS) += imx-dcss.o
+
diff --git a/drivers/gpu/drm/imx/dcss/dcss-blkctl.c b/drivers/gpu/drm/imx/dcss/dcss-blkctl.c
new file mode 100644 (file)
index 0000000..c9b54bb
--- /dev/null
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_BLKCTL_RESET_CTRL         0x00
+#define   B_CLK_RESETN                 BIT(0)
+#define   APB_CLK_RESETN               BIT(1)
+#define   P_CLK_RESETN                 BIT(2)
+#define   RTR_CLK_RESETN               BIT(4)
+#define DCSS_BLKCTL_CONTROL0           0x10
+#define   HDMI_MIPI_CLK_SEL            BIT(0)
+#define   DISPMIX_REFCLK_SEL_POS       4
+#define   DISPMIX_REFCLK_SEL_MASK      GENMASK(5, 4)
+#define   DISPMIX_PIXCLK_SEL           BIT(8)
+#define   HDMI_SRC_SECURE_EN           BIT(16)
+
+struct dcss_blkctl {
+       struct dcss_dev *dcss;
+       void __iomem *base_reg;
+};
+
+void dcss_blkctl_cfg(struct dcss_blkctl *blkctl)
+{
+       if (blkctl->dcss->hdmi_output)
+               dcss_writel(0, blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+       else
+               dcss_writel(DISPMIX_PIXCLK_SEL,
+                           blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+
+       dcss_set(B_CLK_RESETN | APB_CLK_RESETN | P_CLK_RESETN | RTR_CLK_RESETN,
+                blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+}
+
+int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base)
+{
+       struct dcss_blkctl *blkctl;
+
+       blkctl = kzalloc(sizeof(*blkctl), GFP_KERNEL);
+       if (!blkctl)
+               return -ENOMEM;
+
+       blkctl->base_reg = ioremap(blkctl_base, SZ_4K);
+       if (!blkctl->base_reg) {
+               dev_err(dcss->dev, "unable to remap BLK CTRL base\n");
+               kfree(blkctl);
+               return -ENOMEM;
+       }
+
+       dcss->blkctl = blkctl;
+       blkctl->dcss = dcss;
+
+       dcss_blkctl_cfg(blkctl);
+
+       return 0;
+}
+
+void dcss_blkctl_exit(struct dcss_blkctl *blkctl)
+{
+       if (blkctl->base_reg)
+               iounmap(blkctl->base_reg);
+
+       kfree(blkctl);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-crtc.c b/drivers/gpu/drm/imx/dcss/dcss-crtc.c
new file mode 100644 (file)
index 0000000..36abff0
--- /dev/null
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_vblank.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static int dcss_enable_vblank(struct drm_crtc *crtc)
+{
+       struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+                                                  base);
+       struct dcss_dev *dcss = crtc->dev->dev_private;
+
+       dcss_dtg_vblank_irq_enable(dcss->dtg, true);
+
+       dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);
+
+       enable_irq(dcss_crtc->irq);
+
+       return 0;
+}
+
+static void dcss_disable_vblank(struct drm_crtc *crtc)
+{
+       struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+                                                  base);
+       struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+       disable_irq_nosync(dcss_crtc->irq);
+
+       dcss_dtg_vblank_irq_enable(dcss->dtg, false);
+
+       if (dcss_crtc->disable_ctxld_kick_irq)
+               dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, false);
+}
+
+static const struct drm_crtc_funcs dcss_crtc_funcs = {
+       .set_config = drm_atomic_helper_set_config,
+       .destroy = drm_crtc_cleanup,
+       .page_flip = drm_atomic_helper_page_flip,
+       .reset = drm_atomic_helper_crtc_reset,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+       .enable_vblank = dcss_enable_vblank,
+       .disable_vblank = dcss_disable_vblank,
+};
+
+static void dcss_crtc_atomic_begin(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
+{
+       drm_crtc_vblank_on(crtc);
+}
+
+static void dcss_crtc_atomic_flush(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *old_crtc_state)
+{
+       struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+                                                  base);
+       struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+       spin_lock_irq(&crtc->dev->event_lock);
+       if (crtc->state->event) {
+               WARN_ON(drm_crtc_vblank_get(crtc));
+               drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+               crtc->state->event = NULL;
+       }
+       spin_unlock_irq(&crtc->dev->event_lock);
+
+       if (dcss_dtg_is_enabled(dcss->dtg))
+               dcss_ctxld_enable(dcss->ctxld);
+}
+
+static void dcss_crtc_atomic_enable(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_crtc_state)
+{
+       struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+                                                  base);
+       struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+       struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       struct drm_display_mode *old_mode = &old_crtc_state->adjusted_mode;
+       struct videomode vm;
+
+       drm_display_mode_to_videomode(mode, &vm);
+
+       pm_runtime_get_sync(dcss->dev);
+
+       vm.pixelclock = mode->crtc_clock * 1000;
+
+       dcss_ss_subsam_set(dcss->ss);
+       dcss_dtg_css_set(dcss->dtg);
+
+       if (!drm_mode_equal(mode, old_mode) || !old_crtc_state->active) {
+               dcss_dtg_sync_set(dcss->dtg, &vm);
+               dcss_ss_sync_set(dcss->ss, &vm,
+                                mode->flags & DRM_MODE_FLAG_PHSYNC,
+                                mode->flags & DRM_MODE_FLAG_PVSYNC);
+       }
+
+       dcss_enable_dtg_and_ss(dcss);
+
+       dcss_ctxld_enable(dcss->ctxld);
+
+       /* Allow CTXLD kick interrupt to be disabled when VBLANK is disabled. */
+       dcss_crtc->disable_ctxld_kick_irq = true;
+}
+
+static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *old_crtc_state)
+{
+       struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+                                                  base);
+       struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+       struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       struct drm_display_mode *old_mode = &old_crtc_state->adjusted_mode;
+
+       drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
+
+       spin_lock_irq(&crtc->dev->event_lock);
+       if (crtc->state->event) {
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               crtc->state->event = NULL;
+       }
+       spin_unlock_irq(&crtc->dev->event_lock);
+
+       dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);
+
+       reinit_completion(&dcss->disable_completion);
+
+       dcss_disable_dtg_and_ss(dcss);
+
+       dcss_ctxld_enable(dcss->ctxld);
+
+       if (!drm_mode_equal(mode, old_mode) || !crtc->state->active)
+               if (!wait_for_completion_timeout(&dcss->disable_completion,
+                                                msecs_to_jiffies(100)))
+                       dev_err(dcss->dev, "Shutting off DTG timed out.\n");
+
+       /*
+        * Do not shut off CTXLD kick interrupt when shutting VBLANK off. It
+        * will be needed to commit the last changes, before going to suspend.
+        */
+       dcss_crtc->disable_ctxld_kick_irq = false;
+
+       drm_crtc_vblank_off(crtc);
+
+       pm_runtime_mark_last_busy(dcss->dev);
+       pm_runtime_put_autosuspend(dcss->dev);
+}
+
+static const struct drm_crtc_helper_funcs dcss_helper_funcs = {
+       .atomic_begin = dcss_crtc_atomic_begin,
+       .atomic_flush = dcss_crtc_atomic_flush,
+       .atomic_enable = dcss_crtc_atomic_enable,
+       .atomic_disable = dcss_crtc_atomic_disable,
+};
+
+static irqreturn_t dcss_crtc_irq_handler(int irq, void *dev_id)
+{
+       struct dcss_crtc *dcss_crtc = dev_id;
+       struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+       if (!dcss_dtg_vblank_irq_valid(dcss->dtg))
+               return IRQ_NONE;
+
+       if (dcss_ctxld_is_flushed(dcss->ctxld))
+               drm_crtc_handle_vblank(&dcss_crtc->base);
+
+       dcss_dtg_vblank_irq_clear(dcss->dtg);
+
+       return IRQ_HANDLED;
+}
+
+int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm)
+{
+       struct dcss_dev *dcss = drm->dev_private;
+       struct platform_device *pdev = to_platform_device(dcss->dev);
+       int ret;
+
+       crtc->plane[0] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+                                        DRM_PLANE_TYPE_PRIMARY, 0);
+       if (IS_ERR(crtc->plane[0]))
+               return PTR_ERR(crtc->plane[0]);
+
+       crtc->base.port = dcss->of_port;
+
+       drm_crtc_helper_add(&crtc->base, &dcss_helper_funcs);
+       ret = drm_crtc_init_with_planes(drm, &crtc->base, &crtc->plane[0]->base,
+                                       NULL, &dcss_crtc_funcs, NULL);
+       if (ret) {
+               dev_err(dcss->dev, "failed to init crtc\n");
+               return ret;
+       }
+
+       crtc->irq = platform_get_irq_byname(pdev, "vblank");
+       if (crtc->irq < 0)
+               return crtc->irq;
+
+       ret = request_irq(crtc->irq, dcss_crtc_irq_handler,
+                         0, "dcss_drm", crtc);
+       if (ret) {
+               dev_err(dcss->dev, "irq request failed with %d.\n", ret);
+               return ret;
+       }
+
+       disable_irq(crtc->irq);
+
+       return 0;
+}
+
+void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm)
+{
+       free_irq(crtc->irq, crtc);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-ctxld.c b/drivers/gpu/drm/imx/dcss/dcss-ctxld.c
new file mode 100644 (file)
index 0000000..3a84cb3
--- /dev/null
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_CTXLD_CONTROL_STATUS      0x0
+#define   CTXLD_ENABLE                 BIT(0)
+#define   ARB_SEL                      BIT(1)
+#define   RD_ERR_EN                    BIT(2)
+#define   DB_COMP_EN                   BIT(3)
+#define   SB_HP_COMP_EN                        BIT(4)
+#define   SB_LP_COMP_EN                        BIT(5)
+#define   DB_PEND_SB_REC_EN            BIT(6)
+#define   SB_PEND_DISP_ACTIVE_EN       BIT(7)
+#define   AHB_ERR_EN                   BIT(8)
+#define   RD_ERR                       BIT(16)
+#define   DB_COMP                      BIT(17)
+#define   SB_HP_COMP                   BIT(18)
+#define   SB_LP_COMP                   BIT(19)
+#define   DB_PEND_SB_REC               BIT(20)
+#define   SB_PEND_DISP_ACTIVE          BIT(21)
+#define   AHB_ERR                      BIT(22)
+#define DCSS_CTXLD_DB_BASE_ADDR                0x10
+#define DCSS_CTXLD_DB_COUNT            0x14
+#define DCSS_CTXLD_SB_BASE_ADDR                0x18
+#define DCSS_CTXLD_SB_COUNT            0x1C
+#define   SB_HP_COUNT_POS              0
+#define   SB_HP_COUNT_MASK             0xffff
+#define   SB_LP_COUNT_POS              16
+#define   SB_LP_COUNT_MASK             0xffff0000
+#define DCSS_AHB_ERR_ADDR              0x20
+
+#define CTXLD_IRQ_COMPLETION           (DB_COMP | SB_HP_COMP | SB_LP_COMP)
+#define CTXLD_IRQ_ERROR                        (RD_ERR | DB_PEND_SB_REC | AHB_ERR)
+
+/* The following sizes are in context loader entries, 8 bytes each. */
+#define CTXLD_DB_CTX_ENTRIES           1024    /* max 65536 */
+#define CTXLD_SB_LP_CTX_ENTRIES                10240   /* max 65536 */
+#define CTXLD_SB_HP_CTX_ENTRIES                20000   /* max 65536 */
+#define CTXLD_SB_CTX_ENTRIES           (CTXLD_SB_LP_CTX_ENTRIES + \
+                                        CTXLD_SB_HP_CTX_ENTRIES)
+
+/* Sizes, in entries, of the DB, SB_HP and SB_LP context regions. */
+static u16 dcss_ctxld_ctx_size[3] = {
+       CTXLD_DB_CTX_ENTRIES,
+       CTXLD_SB_HP_CTX_ENTRIES,
+       CTXLD_SB_LP_CTX_ENTRIES
+};
+
+/* this represents an entry in the context loader map */
+struct dcss_ctxld_item {
+       u32 val;
+       u32 ofs;
+};
+
+#define CTX_ITEM_SIZE                  sizeof(struct dcss_ctxld_item)
+
+struct dcss_ctxld {
+       struct device *dev;
+       void __iomem *ctxld_reg;
+       int irq;
+       bool irq_en;
+
+       struct dcss_ctxld_item *db[2];
+       struct dcss_ctxld_item *sb_hp[2];
+       struct dcss_ctxld_item *sb_lp[2];
+
+       dma_addr_t db_paddr[2];
+       dma_addr_t sb_paddr[2];
+
+       u16 ctx_size[2][3]; /* holds the sizes of DB, SB_HP and SB_LP ctx */
+       u8 current_ctx;
+
+       bool in_use;
+       bool armed;
+
+       spinlock_t lock; /* protects concurent access to private data */
+};
+
+static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data)
+{
+       struct dcss_ctxld *ctxld = data;
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(ctxld->dev);
+       u32 irq_status;
+
+       irq_status = dcss_readl(ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       if (irq_status & CTXLD_IRQ_COMPLETION &&
+           !(irq_status & CTXLD_ENABLE) && ctxld->in_use) {
+               ctxld->in_use = false;
+
+               if (dcss && dcss->disable_callback)
+                       dcss->disable_callback(dcss);
+       } else if (irq_status & CTXLD_IRQ_ERROR) {
+               /*
+                * Except for throwing an error message and clearing the status
+                * register, there's not much we can do here.
+                */
+               dev_err(ctxld->dev, "ctxld: error encountered: %08x\n",
+                       irq_status);
+               dev_err(ctxld->dev, "ctxld: db=%d, sb_hp=%d, sb_lp=%d\n",
+                       ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_DB],
+                       ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_HP],
+                       ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_LP]);
+       }
+
+       dcss_clr(irq_status & (CTXLD_IRQ_ERROR | CTXLD_IRQ_COMPLETION),
+                ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       return IRQ_HANDLED;
+}
+
+static int dcss_ctxld_irq_config(struct dcss_ctxld *ctxld,
+                                struct platform_device *pdev)
+{
+       int ret;
+
+       ctxld->irq = platform_get_irq_byname(pdev, "ctxld");
+       if (ctxld->irq < 0)
+               return ctxld->irq;
+
+       ret = request_irq(ctxld->irq, dcss_ctxld_irq_handler,
+                         0, "dcss_ctxld", ctxld);
+       if (ret) {
+               dev_err(ctxld->dev, "ctxld: irq request failed.\n");
+               return ret;
+       }
+
+       ctxld->irq_en = true;
+
+       return 0;
+}
+
+static void dcss_ctxld_hw_cfg(struct dcss_ctxld *ctxld)
+{
+       dcss_writel(RD_ERR_EN | SB_HP_COMP_EN |
+                   DB_PEND_SB_REC_EN | AHB_ERR_EN | RD_ERR | AHB_ERR,
+                   ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+}
+
+static void dcss_ctxld_free_ctx(struct dcss_ctxld *ctxld)
+{
+       struct dcss_ctxld_item *ctx;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               if (ctxld->db[i]) {
+                       dma_free_coherent(ctxld->dev,
+                                         CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+                                         ctxld->db[i], ctxld->db_paddr[i]);
+                       ctxld->db[i] = NULL;
+                       ctxld->db_paddr[i] = 0;
+               }
+
+               if (ctxld->sb_hp[i]) {
+                       dma_free_coherent(ctxld->dev,
+                                         CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+                                         ctxld->sb_hp[i], ctxld->sb_paddr[i]);
+                       ctxld->sb_hp[i] = NULL;
+                       ctxld->sb_paddr[i] = 0;
+               }
+       }
+}
+
+static int dcss_ctxld_alloc_ctx(struct dcss_ctxld *ctxld)
+{
+       struct dcss_ctxld_item *ctx;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               ctx = dma_alloc_coherent(ctxld->dev,
+                                        CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+                                        &ctxld->db_paddr[i], GFP_KERNEL);
+               if (!ctx)
+                       return -ENOMEM;
+
+               ctxld->db[i] = ctx;
+
+               ctx = dma_alloc_coherent(ctxld->dev,
+                                        CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+                                        &ctxld->sb_paddr[i], GFP_KERNEL);
+               if (!ctx)
+                       return -ENOMEM;
+
+               ctxld->sb_hp[i] = ctx;
+               ctxld->sb_lp[i] = ctx + CTXLD_SB_HP_CTX_ENTRIES;
+       }
+
+       return 0;
+}
+
+int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base)
+{
+       struct dcss_ctxld *ctxld;
+       int ret;
+
+       ctxld = kzalloc(sizeof(*ctxld), GFP_KERNEL);
+       if (!ctxld)
+               return -ENOMEM;
+
+       dcss->ctxld = ctxld;
+       ctxld->dev = dcss->dev;
+
+       spin_lock_init(&ctxld->lock);
+
+       ret = dcss_ctxld_alloc_ctx(ctxld);
+       if (ret) {
+               dev_err(dcss->dev, "ctxld: cannot allocate context memory.\n");
+               goto err;
+       }
+
+       ctxld->ctxld_reg = ioremap(ctxld_base, SZ_4K);
+       if (!ctxld->ctxld_reg) {
+               dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = dcss_ctxld_irq_config(ctxld, to_platform_device(dcss->dev));
+       if (ret)
+               goto err_irq;
+
+       dcss_ctxld_hw_cfg(ctxld);
+
+       return 0;
+
+err_irq:
+       iounmap(ctxld->ctxld_reg);
+
+err:
+       dcss_ctxld_free_ctx(ctxld);
+       kfree(ctxld);
+
+       return ret;
+}
+
+void dcss_ctxld_exit(struct dcss_ctxld *ctxld)
+{
+       free_irq(ctxld->irq, ctxld);
+
+       if (ctxld->ctxld_reg)
+               iounmap(ctxld->ctxld_reg);
+
+       dcss_ctxld_free_ctx(ctxld);
+       kfree(ctxld);
+}
+
+static int dcss_ctxld_enable_locked(struct dcss_ctxld *ctxld)
+{
+       int curr_ctx = ctxld->current_ctx;
+       u32 db_base, sb_base, sb_count;
+       u32 sb_hp_cnt, sb_lp_cnt, db_cnt;
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(ctxld->dev);
+
+       if (!dcss)
+               return 0;
+
+       dcss_dpr_write_sysctrl(dcss->dpr);
+
+       dcss_scaler_write_sclctrl(dcss->scaler);
+
+       sb_hp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_HP];
+       sb_lp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_LP];
+       db_cnt = ctxld->ctx_size[curr_ctx][CTX_DB];
+
+       /* make sure SB_LP context area comes after SB_HP */
+       if (sb_lp_cnt &&
+           ctxld->sb_lp[curr_ctx] != ctxld->sb_hp[curr_ctx] + sb_hp_cnt) {
+               struct dcss_ctxld_item *sb_lp_adjusted;
+
+               sb_lp_adjusted = ctxld->sb_hp[curr_ctx] + sb_hp_cnt;
+
+               memcpy(sb_lp_adjusted, ctxld->sb_lp[curr_ctx],
+                      sb_lp_cnt * CTX_ITEM_SIZE);
+       }
+
+       db_base = db_cnt ? ctxld->db_paddr[curr_ctx] : 0;
+
+       dcss_writel(db_base, ctxld->ctxld_reg + DCSS_CTXLD_DB_BASE_ADDR);
+       dcss_writel(db_cnt, ctxld->ctxld_reg + DCSS_CTXLD_DB_COUNT);
+
+       if (sb_hp_cnt)
+               sb_count = ((sb_hp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK) |
+                          ((sb_lp_cnt << SB_LP_COUNT_POS) & SB_LP_COUNT_MASK);
+       else
+               sb_count = (sb_lp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK;
+
+       sb_base = sb_count ? ctxld->sb_paddr[curr_ctx] : 0;
+
+       dcss_writel(sb_base, ctxld->ctxld_reg + DCSS_CTXLD_SB_BASE_ADDR);
+       dcss_writel(sb_count, ctxld->ctxld_reg + DCSS_CTXLD_SB_COUNT);
+
+       /* enable the context loader */
+       dcss_set(CTXLD_ENABLE, ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       ctxld->in_use = true;
+
+       /*
+        * Toggle the current context to the alternate one so that any updates
+        * in the modules' settings take place there.
+        */
+       ctxld->current_ctx ^= 1;
+
+       ctxld->ctx_size[ctxld->current_ctx][CTX_DB] = 0;
+       ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] = 0;
+       ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] = 0;
+
+       return 0;
+}
+
+int dcss_ctxld_enable(struct dcss_ctxld *ctxld)
+{
+       spin_lock_irq(&ctxld->lock);
+       ctxld->armed = true;
+       spin_unlock_irq(&ctxld->lock);
+
+       return 0;
+}
+
+void dcss_ctxld_kick(struct dcss_ctxld *ctxld)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctxld->lock, flags);
+       if (ctxld->armed && !ctxld->in_use) {
+               ctxld->armed = false;
+               dcss_ctxld_enable_locked(ctxld);
+       }
+       spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+
+void dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctxld, u32 ctx_id, u32 val,
+                             u32 reg_ofs)
+{
+       int curr_ctx = ctxld->current_ctx;
+       struct dcss_ctxld_item *ctx[] = {
+               [CTX_DB] = ctxld->db[curr_ctx],
+               [CTX_SB_HP] = ctxld->sb_hp[curr_ctx],
+               [CTX_SB_LP] = ctxld->sb_lp[curr_ctx]
+       };
+       int item_idx = ctxld->ctx_size[curr_ctx][ctx_id];
+
+       if (item_idx + 1 > dcss_ctxld_ctx_size[ctx_id]) {
+               WARN_ON(1);
+               return;
+       }
+
+       ctx[ctx_id][item_idx].val = val;
+       ctx[ctx_id][item_idx].ofs = reg_ofs;
+       ctxld->ctx_size[curr_ctx][ctx_id] += 1;
+}
+
+void dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id,
+                     u32 val, u32 reg_ofs)
+{
+       spin_lock_irq(&ctxld->lock);
+       dcss_ctxld_write_irqsafe(ctxld, ctx_id, val, reg_ofs);
+       spin_unlock_irq(&ctxld->lock);
+}
+
+bool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld)
+{
+       return ctxld->ctx_size[ctxld->current_ctx][CTX_DB] == 0 &&
+               ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] == 0 &&
+               ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] == 0;
+}
+
+int dcss_ctxld_resume(struct dcss_ctxld *ctxld)
+{
+       dcss_ctxld_hw_cfg(ctxld);
+
+       if (!ctxld->irq_en) {
+               enable_irq(ctxld->irq);
+               ctxld->irq_en = true;
+       }
+
+       return 0;
+}
+
+int dcss_ctxld_suspend(struct dcss_ctxld *ctxld)
+{
+       int ret = 0;
+       unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+       if (!dcss_ctxld_is_flushed(ctxld)) {
+               dcss_ctxld_kick(ctxld);
+
+               while (!time_after(jiffies, timeout) && ctxld->in_use)
+                       msleep(20);
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+       }
+
+       spin_lock_irq(&ctxld->lock);
+
+       if (ctxld->irq_en) {
+               disable_irq_nosync(ctxld->irq);
+               ctxld->irq_en = false;
+       }
+
+       /* reset context region and sizes */
+       ctxld->current_ctx = 0;
+       ctxld->ctx_size[0][CTX_DB] = 0;
+       ctxld->ctx_size[0][CTX_SB_HP] = 0;
+       ctxld->ctx_size[0][CTX_SB_LP] = 0;
+
+       spin_unlock_irq(&ctxld->lock);
+
+       return ret;
+}
+
+void dcss_ctxld_assert_locked(struct dcss_ctxld *ctxld)
+{
+       lockdep_assert_held(&ctxld->lock);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.c b/drivers/gpu/drm/imx/dcss/dcss-dev.c
new file mode 100644 (file)
index 0000000..c849533
--- /dev/null
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_device.h>
+#include <drm/drm_modeset_helper.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static void dcss_clocks_enable(struct dcss_dev *dcss)
+{
+       clk_prepare_enable(dcss->axi_clk);
+       clk_prepare_enable(dcss->apb_clk);
+       clk_prepare_enable(dcss->rtrm_clk);
+       clk_prepare_enable(dcss->dtrc_clk);
+       clk_prepare_enable(dcss->pix_clk);
+}
+
+static void dcss_clocks_disable(struct dcss_dev *dcss)
+{
+       clk_disable_unprepare(dcss->pix_clk);
+       clk_disable_unprepare(dcss->dtrc_clk);
+       clk_disable_unprepare(dcss->rtrm_clk);
+       clk_disable_unprepare(dcss->apb_clk);
+       clk_disable_unprepare(dcss->axi_clk);
+}
+
+static void dcss_disable_dtg_and_ss_cb(void *data)
+{
+       struct dcss_dev *dcss = data;
+
+       dcss->disable_callback = NULL;
+
+       dcss_ss_shutoff(dcss->ss);
+       dcss_dtg_shutoff(dcss->dtg);
+
+       complete(&dcss->disable_completion);
+}
+
+void dcss_disable_dtg_and_ss(struct dcss_dev *dcss)
+{
+       dcss->disable_callback = dcss_disable_dtg_and_ss_cb;
+}
+
+void dcss_enable_dtg_and_ss(struct dcss_dev *dcss)
+{
+       if (dcss->disable_callback)
+               dcss->disable_callback = NULL;
+
+       dcss_dtg_enable(dcss->dtg);
+       dcss_ss_enable(dcss->ss);
+}
+
+static int dcss_submodules_init(struct dcss_dev *dcss)
+{
+       int ret = 0;
+       u32 base_addr = dcss->start_addr;
+       const struct dcss_type_data *devtype = dcss->devtype;
+
+       dcss_clocks_enable(dcss);
+
+       ret = dcss_blkctl_init(dcss, base_addr + devtype->blkctl_ofs);
+       if (ret)
+               return ret;
+
+       ret = dcss_ctxld_init(dcss, base_addr + devtype->ctxld_ofs);
+       if (ret)
+               goto ctxld_err;
+
+       ret = dcss_dtg_init(dcss, base_addr + devtype->dtg_ofs);
+       if (ret)
+               goto dtg_err;
+
+       ret = dcss_ss_init(dcss, base_addr + devtype->ss_ofs);
+       if (ret)
+               goto ss_err;
+
+       ret = dcss_dpr_init(dcss, base_addr + devtype->dpr_ofs);
+       if (ret)
+               goto dpr_err;
+
+       ret = dcss_scaler_init(dcss, base_addr + devtype->scaler_ofs);
+       if (ret)
+               goto scaler_err;
+
+       dcss_clocks_disable(dcss);
+
+       return 0;
+
+scaler_err:
+       dcss_dpr_exit(dcss->dpr);
+
+dpr_err:
+       dcss_ss_exit(dcss->ss);
+
+ss_err:
+       dcss_dtg_exit(dcss->dtg);
+
+dtg_err:
+       dcss_ctxld_exit(dcss->ctxld);
+
+ctxld_err:
+       dcss_blkctl_exit(dcss->blkctl);
+
+       dcss_clocks_disable(dcss);
+
+       return ret;
+}
+
+static void dcss_submodules_stop(struct dcss_dev *dcss)
+{
+       dcss_clocks_enable(dcss);
+       dcss_scaler_exit(dcss->scaler);
+       dcss_dpr_exit(dcss->dpr);
+       dcss_ss_exit(dcss->ss);
+       dcss_dtg_exit(dcss->dtg);
+       dcss_ctxld_exit(dcss->ctxld);
+       dcss_blkctl_exit(dcss->blkctl);
+       dcss_clocks_disable(dcss);
+}
+
+static int dcss_clks_init(struct dcss_dev *dcss)
+{
+       int i;
+       struct {
+               const char *id;
+               struct clk **clk;
+       } clks[] = {
+               {"apb",   &dcss->apb_clk},
+               {"axi",   &dcss->axi_clk},
+               {"pix",   &dcss->pix_clk},
+               {"rtrm",  &dcss->rtrm_clk},
+               {"dtrc",  &dcss->dtrc_clk},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               *clks[i].clk = devm_clk_get(dcss->dev, clks[i].id);
+               if (IS_ERR(*clks[i].clk)) {
+                       dev_err(dcss->dev, "failed to get %s clock\n",
+                               clks[i].id);
+                       return PTR_ERR(*clks[i].clk);
+               }
+       }
+
+       return 0;
+}
+
+static void dcss_clks_release(struct dcss_dev *dcss)
+{
+       devm_clk_put(dcss->dev, dcss->dtrc_clk);
+       devm_clk_put(dcss->dev, dcss->rtrm_clk);
+       devm_clk_put(dcss->dev, dcss->pix_clk);
+       devm_clk_put(dcss->dev, dcss->axi_clk);
+       devm_clk_put(dcss->dev, dcss->apb_clk);
+}
+
+struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       int ret;
+       struct resource *res;
+       struct dcss_dev *dcss;
+       const struct dcss_type_data *devtype;
+
+       devtype = of_device_get_match_data(dev);
+       if (!devtype) {
+               dev_err(dev, "no device match found\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "cannot get memory resource\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       dcss = kzalloc(sizeof(*dcss), GFP_KERNEL);
+       if (!dcss)
+               return ERR_PTR(-ENOMEM);
+
+       dcss->dev = dev;
+       dcss->devtype = devtype;
+       dcss->hdmi_output = hdmi_output;
+
+       ret = dcss_clks_init(dcss);
+       if (ret) {
+               dev_err(dev, "clocks initialization failed\n");
+               goto err;
+       }
+
+       dcss->of_port = of_graph_get_port_by_id(dev->of_node, 0);
+       if (!dcss->of_port) {
+               dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
+               ret = -ENODEV;
+               goto clks_err;
+       }
+
+       dcss->start_addr = res->start;
+
+       ret = dcss_submodules_init(dcss);
+       if (ret) {
+               dev_err(dev, "submodules initialization failed\n");
+               goto clks_err;
+       }
+
+       init_completion(&dcss->disable_completion);
+
+       pm_runtime_set_autosuspend_delay(dev, 100);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_allow(dev);
+       pm_runtime_enable(dev);
+
+       return dcss;
+
+clks_err:
+       dcss_clks_release(dcss);
+
+err:
+       kfree(dcss);
+
+       return ERR_PTR(ret);
+}
+
+void dcss_dev_destroy(struct dcss_dev *dcss)
+{
+       if (!pm_runtime_suspended(dcss->dev)) {
+               dcss_ctxld_suspend(dcss->ctxld);
+               dcss_clocks_disable(dcss);
+       }
+
+       pm_runtime_disable(dcss->dev);
+
+       dcss_submodules_stop(dcss);
+
+       dcss_clks_release(dcss);
+
+       kfree(dcss);
+}
+
+#ifdef CONFIG_PM_SLEEP
+int dcss_dev_suspend(struct device *dev)
+{
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+       struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
+       struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
+       int ret;
+
+       drm_bridge_connector_disable_hpd(kms->connector);
+
+       drm_mode_config_helper_suspend(ddev);
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       ret = dcss_ctxld_suspend(dcss->ctxld);
+       if (ret)
+               return ret;
+
+       dcss_clocks_disable(dcss);
+
+       return 0;
+}
+
+int dcss_dev_resume(struct device *dev)
+{
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+       struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
+       struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
+
+       if (pm_runtime_suspended(dev)) {
+               drm_mode_config_helper_resume(ddev);
+               return 0;
+       }
+
+       dcss_clocks_enable(dcss);
+
+       dcss_blkctl_cfg(dcss->blkctl);
+
+       dcss_ctxld_resume(dcss->ctxld);
+
+       drm_mode_config_helper_resume(ddev);
+
+       drm_bridge_connector_enable_hpd(kms->connector);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+int dcss_dev_runtime_suspend(struct device *dev)
+{
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+       int ret;
+
+       ret = dcss_ctxld_suspend(dcss->ctxld);
+       if (ret)
+               return ret;
+
+       dcss_clocks_disable(dcss);
+
+       return 0;
+}
+
+int dcss_dev_runtime_resume(struct device *dev)
+{
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+
+       dcss_clocks_enable(dcss);
+
+       dcss_blkctl_cfg(dcss->blkctl);
+
+       dcss_ctxld_resume(dcss->ctxld);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.h b/drivers/gpu/drm/imx/dcss/dcss-dev.h
new file mode 100644 (file)
index 0000000..c642ae1
--- /dev/null
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP.
+ */
+
+#ifndef __DCSS_PRV_H__
+#define __DCSS_PRV_H__
+
+#include <drm/drm_fourcc.h>
+#include <linux/io.h>
+#include <video/videomode.h>
+
+#define SET                    0x04
+#define CLR                    0x08
+#define TGL                    0x0C
+
+#define dcss_writel(v, c)      writel((v), (c))
+#define dcss_readl(c)          readl(c)
+#define dcss_set(v, c)         writel((v), (c) + SET)
+#define dcss_clr(v, c)         writel((v), (c) + CLR)
+#define dcss_toggle(v, c)      writel((v), (c) + TGL)
+
+static inline void dcss_update(u32 v, u32 m, void __iomem *c)
+{
+       writel((readl(c) & ~(m)) | (v), (c));
+}
+
+#define DCSS_DBG_REG(reg)      {.name = #reg, .ofs = reg}
+
+enum {
+       DCSS_IMX8MQ = 0,
+};
+
+struct dcss_type_data {
+       const char *name;
+       u32 blkctl_ofs;
+       u32 ctxld_ofs;
+       u32 rdsrc_ofs;
+       u32 wrscl_ofs;
+       u32 dtg_ofs;
+       u32 scaler_ofs;
+       u32 ss_ofs;
+       u32 dpr_ofs;
+       u32 dtrc_ofs;
+       u32 dec400d_ofs;
+       u32 hdr10_ofs;
+};
+
+struct dcss_debug_reg {
+       char *name;
+       u32 ofs;
+};
+
+enum dcss_ctxld_ctx_type {
+       CTX_DB,
+       CTX_SB_HP, /* high-priority */
+       CTX_SB_LP, /* low-priority  */
+};
+
+struct dcss_dev {
+       struct device *dev;
+       const struct dcss_type_data *devtype;
+       struct device_node *of_port;
+
+       u32 start_addr;
+
+       struct dcss_blkctl *blkctl;
+       struct dcss_ctxld *ctxld;
+       struct dcss_dpr *dpr;
+       struct dcss_dtg *dtg;
+       struct dcss_ss *ss;
+       struct dcss_hdr10 *hdr10;
+       struct dcss_scaler *scaler;
+       struct dcss_dtrc *dtrc;
+       struct dcss_dec400d *dec400d;
+       struct dcss_wrscl *wrscl;
+       struct dcss_rdsrc *rdsrc;
+
+       struct clk *apb_clk;
+       struct clk *axi_clk;
+       struct clk *pix_clk;
+       struct clk *rtrm_clk;
+       struct clk *dtrc_clk;
+       struct clk *pll_src_clk;
+       struct clk *pll_phy_ref_clk;
+
+       bool hdmi_output;
+
+       void (*disable_callback)(void *data);
+       struct completion disable_completion;
+};
+
+struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev);
+struct drm_device *dcss_drv_dev_to_drm(struct device *dev);
+struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output);
+void dcss_dev_destroy(struct dcss_dev *dcss);
+int dcss_dev_runtime_suspend(struct device *dev);
+int dcss_dev_runtime_resume(struct device *dev);
+int dcss_dev_suspend(struct device *dev);
+int dcss_dev_resume(struct device *dev);
+void dcss_enable_dtg_and_ss(struct dcss_dev *dcss);
+void dcss_disable_dtg_and_ss(struct dcss_dev *dcss);
+
+/* BLKCTL */
+int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base);
+void dcss_blkctl_cfg(struct dcss_blkctl *blkctl);
+void dcss_blkctl_exit(struct dcss_blkctl *blkctl);
+
+/* CTXLD */
+int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base);
+void dcss_ctxld_exit(struct dcss_ctxld *ctxld);
+void dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id,
+                     u32 val, u32 reg_idx);
+int dcss_ctxld_resume(struct dcss_ctxld *dcss_ctxld);
+int dcss_ctxld_suspend(struct dcss_ctxld *dcss_ctxld);
+void dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctlxd, u32 ctx_id, u32 val,
+                             u32 reg_ofs);
+void dcss_ctxld_kick(struct dcss_ctxld *ctxld);
+bool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld);
+int dcss_ctxld_enable(struct dcss_ctxld *ctxld);
+void dcss_ctxld_register_completion(struct dcss_ctxld *ctxld,
+                                   struct completion *dis_completion);
+void dcss_ctxld_assert_locked(struct dcss_ctxld *ctxld);
+
+/* DPR */
+int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base);
+void dcss_dpr_exit(struct dcss_dpr *dpr);
+void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr);
+void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres);
+void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
+                      u32 chroma_base_addr, u16 pitch);
+void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en);
+void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
+                        const struct drm_format_info *format, u64 modifier);
+void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation);
+
+/* DTG */
+int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base);
+void dcss_dtg_exit(struct dcss_dtg *dtg);
+bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg);
+void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en);
+void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg);
+void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm);
+void dcss_dtg_css_set(struct dcss_dtg *dtg);
+void dcss_dtg_enable(struct dcss_dtg *dtg);
+void dcss_dtg_shutoff(struct dcss_dtg *dtg);
+bool dcss_dtg_is_enabled(struct dcss_dtg *dtg);
+void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en);
+bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha);
+void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
+                             const struct drm_format_info *format, int alpha);
+void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
+                           int px, int py, int pw, int ph);
+void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en);
+
+/* SUBSAM */
+int dcss_ss_init(struct dcss_dev *dcss, unsigned long subsam_base);
+void dcss_ss_exit(struct dcss_ss *ss);
+void dcss_ss_enable(struct dcss_ss *ss);
+void dcss_ss_shutoff(struct dcss_ss *ss);
+void dcss_ss_subsam_set(struct dcss_ss *ss);
+void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
+                     bool phsync, bool pvsync);
+
+/* SCALER */
+int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base);
+void dcss_scaler_exit(struct dcss_scaler *scl);
+void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
+                      const struct drm_format_info *format,
+                      int src_xres, int src_yres, int dst_xres, int dst_yres,
+                      u32 vrefresh_hz);
+void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en);
+int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
+                                  int *min, int *max);
+void dcss_scaler_write_sclctrl(struct dcss_scaler *scl);
+
+#endif /* __DCSS_PRV_H__ */
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dpr.c b/drivers/gpu/drm/imx/dcss/dcss-dpr.c
new file mode 100644 (file)
index 0000000..df9dab9
--- /dev/null
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_DPR_SYSTEM_CTRL0                  0x000
+#define   RUN_EN                               BIT(0)
+#define   SOFT_RESET                           BIT(1)
+#define   REPEAT_EN                            BIT(2)
+#define   SHADOW_LOAD_EN                       BIT(3)
+#define   SW_SHADOW_LOAD_SEL                   BIT(4)
+#define   BCMD2AXI_MSTR_ID_CTRL                        BIT(16)
+#define DCSS_DPR_IRQ_MASK                      0x020
+#define DCSS_DPR_IRQ_MASK_STATUS               0x030
+#define DCSS_DPR_IRQ_NONMASK_STATUS            0x040
+#define   IRQ_DPR_CTRL_DONE                    BIT(0)
+#define   IRQ_DPR_RUN                          BIT(1)
+#define   IRQ_DPR_SHADOW_LOADED                        BIT(2)
+#define   IRQ_AXI_READ_ERR                     BIT(3)
+#define   DPR2RTR_YRGB_FIFO_OVFL               BIT(4)
+#define   DPR2RTR_UV_FIFO_OVFL                 BIT(5)
+#define   DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR     BIT(6)
+#define   DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR       BIT(7)
+#define DCSS_DPR_MODE_CTRL0                    0x050
+#define   RTR_3BUF_EN                          BIT(0)
+#define   RTR_4LINE_BUF_EN                     BIT(1)
+#define   TILE_TYPE_POS                                2
+#define   TILE_TYPE_MASK                       GENMASK(4, 2)
+#define   YUV_EN                               BIT(6)
+#define   COMP_2PLANE_EN                       BIT(7)
+#define   PIX_SIZE_POS                         8
+#define   PIX_SIZE_MASK                                GENMASK(9, 8)
+#define   PIX_LUMA_UV_SWAP                     BIT(10)
+#define   PIX_UV_SWAP                          BIT(11)
+#define   B_COMP_SEL_POS                       12
+#define   B_COMP_SEL_MASK                      GENMASK(13, 12)
+#define   G_COMP_SEL_POS                       14
+#define   G_COMP_SEL_MASK                      GENMASK(15, 14)
+#define   R_COMP_SEL_POS                       16
+#define   R_COMP_SEL_MASK                      GENMASK(17, 16)
+#define   A_COMP_SEL_POS                       18
+#define   A_COMP_SEL_MASK                      GENMASK(19, 18)
+#define DCSS_DPR_FRAME_CTRL0                   0x070
+#define   HFLIP_EN                             BIT(0)
+#define   VFLIP_EN                             BIT(1)
+#define   ROT_ENC_POS                          2
+#define   ROT_ENC_MASK                         GENMASK(3, 2)
+#define   ROT_FLIP_ORDER_EN                    BIT(4)
+#define   PITCH_POS                            16
+#define   PITCH_MASK                           GENMASK(31, 16)
+#define DCSS_DPR_FRAME_1P_CTRL0                        0x090
+#define DCSS_DPR_FRAME_1P_PIX_X_CTRL           0x0A0
+#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL           0x0B0
+#define DCSS_DPR_FRAME_1P_BASE_ADDR            0x0C0
+#define DCSS_DPR_FRAME_2P_CTRL0                        0x0E0
+#define DCSS_DPR_FRAME_2P_PIX_X_CTRL           0x0F0
+#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL           0x100
+#define DCSS_DPR_FRAME_2P_BASE_ADDR            0x110
+#define DCSS_DPR_STATUS_CTRL0                  0x130
+#define   STATUS_MUX_SEL_MASK                  GENMASK(2, 0)
+#define   STATUS_SRC_SEL_POS                   16
+#define   STATUS_SRC_SEL_MASK                  GENMASK(18, 16)
+#define DCSS_DPR_STATUS_CTRL1                  0x140
+#define DCSS_DPR_RTRAM_CTRL0                   0x200
+#define   NUM_ROWS_ACTIVE                      BIT(0)
+#define   THRES_HIGH_POS                       1
+#define   THRES_HIGH_MASK                      GENMASK(3, 1)
+#define   THRES_LOW_POS                                4
+#define   THRES_LOW_MASK                       GENMASK(6, 4)
+#define   ABORT_SEL                            BIT(7)
+
+enum dcss_tile_type {
+       TILE_LINEAR = 0,
+       TILE_GPU_STANDARD,
+       TILE_GPU_SUPER,
+       TILE_VPU_YUV420,
+       TILE_VPU_VP9,
+};
+
+enum dcss_pix_size {
+       PIX_SIZE_8,
+       PIX_SIZE_16,
+       PIX_SIZE_32,
+};
+
+struct dcss_dpr_ch {
+       struct dcss_dpr *dpr;
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       struct drm_format_info format;
+       enum dcss_pix_size pix_size;
+       enum dcss_tile_type tile;
+       bool rtram_4line_en;
+       bool rtram_3buf_en;
+
+       u32 frame_ctrl;
+       u32 mode_ctrl;
+       u32 sys_ctrl;
+       u32 rtram_ctrl;
+
+       bool sys_ctrl_chgd;
+
+       int ch_num;
+       int irq;
+};
+
+struct dcss_dpr {
+       struct device *dev;
+       struct dcss_ctxld *ctxld;
+       u32  ctx_id;
+
+       struct dcss_dpr_ch ch[3];
+};
+
+static void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs)
+{
+       struct dcss_dpr *dpr = ch->dpr;
+
+       dcss_ctxld_write(dpr->ctxld, dpr->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base)
+{
+       struct dcss_dpr_ch *ch;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               ch = &dpr->ch[i];
+
+               ch->base_ofs = dpr_base + i * 0x1000;
+
+               ch->base_reg = ioremap(ch->base_ofs, SZ_4K);
+               if (!ch->base_reg) {
+                       dev_err(dpr->dev, "dpr: unable to remap ch %d base\n",
+                               i);
+                       return -ENOMEM;
+               }
+
+               ch->dpr = dpr;
+               ch->ch_num = i;
+
+               dcss_writel(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK);
+       }
+
+       return 0;
+}
+
+int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base)
+{
+       struct dcss_dpr *dpr;
+
+       dpr = kzalloc(sizeof(*dpr), GFP_KERNEL);
+       if (!dpr)
+               return -ENOMEM;
+
+       dcss->dpr = dpr;
+       dpr->dev = dcss->dev;
+       dpr->ctxld = dcss->ctxld;
+       dpr->ctx_id = CTX_SB_HP;
+
+       if (dcss_dpr_ch_init_all(dpr, dpr_base)) {
+               int i;
+
+               for (i = 0; i < 3; i++) {
+                       if (dpr->ch[i].base_reg)
+                               iounmap(dpr->ch[i].base_reg);
+               }
+
+               kfree(dpr);
+
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void dcss_dpr_exit(struct dcss_dpr *dpr)
+{
+       int ch_no;
+
+       /* stop DPR on all channels */
+       for (ch_no = 0; ch_no < 3; ch_no++) {
+               struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
+
+               dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
+
+               if (ch->base_reg)
+                       iounmap(ch->base_reg);
+       }
+
+       kfree(dpr);
+}
+
+static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
+                                     u32 pix_format)
+{
+       u8 pix_in_64byte_map[3][5] = {
+               /* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
+               {   64,       8,       8,          8,     16}, /* PIX_SIZE_8  */
+               {   32,       8,       8,          8,      8}, /* PIX_SIZE_16 */
+               {   16,       4,       4,          8,      8}, /* PIX_SIZE_32 */
+       };
+       u32 offset;
+       u32 div_64byte_mod, pix_in_64byte;
+
+       pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
+
+       div_64byte_mod = pix_wide % pix_in_64byte;
+       offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
+
+       return pix_wide + offset;
+}
+
+static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
+                                     u32 pix_format)
+{
+       u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
+       u32 offset, pix_y_mod;
+
+       pix_y_mod = pix_high % num_rows_buf;
+       offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
+
+       return pix_high + offset;
+}
+
+void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres)
+{
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+       u32 pix_format = ch->format.format;
+       u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
+       int plane, max_planes = 1;
+       u32 pix_x_wide, pix_y_high;
+
+       if (pix_format == DRM_FORMAT_NV12 ||
+           pix_format == DRM_FORMAT_NV21)
+               max_planes = 2;
+
+       for (plane = 0; plane < max_planes; plane++) {
+               yres = plane == 1 ? yres >> 1 : yres;
+
+               pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
+               pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
+
+               dcss_dpr_write(ch, pix_x_wide,
+                              DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
+               dcss_dpr_write(ch, pix_y_high,
+                              DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
+
+               dcss_dpr_write(ch, 2, DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
+       }
+}
+
+void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
+                      u32 chroma_base_addr, u16 pitch)
+{
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+       dcss_dpr_write(ch, luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR);
+
+       dcss_dpr_write(ch, chroma_base_addr, DCSS_DPR_FRAME_2P_BASE_ADDR);
+
+       ch->frame_ctrl &= ~PITCH_MASK;
+       ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK);
+}
+
+static void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel,
+                                  int g_sel, int b_sel)
+{
+       u32 sel;
+
+       sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
+             ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
+             ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
+             ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
+
+       ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
+                          G_COMP_SEL_MASK | B_COMP_SEL_MASK);
+       ch->mode_ctrl |= sel;
+}
+
+static void dcss_dpr_pix_size_set(struct dcss_dpr_ch *ch,
+                                 const struct drm_format_info *format)
+{
+       u32 val;
+
+       switch (format->format) {
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+               val = PIX_SIZE_8;
+               break;
+
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+               val = PIX_SIZE_16;
+               break;
+
+       default:
+               val = PIX_SIZE_32;
+               break;
+       }
+
+       ch->pix_size = val;
+
+       ch->mode_ctrl &= ~PIX_SIZE_MASK;
+       ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
+}
+
+static void dcss_dpr_uv_swap(struct dcss_dpr_ch *ch, bool swap)
+{
+       ch->mode_ctrl &= ~PIX_UV_SWAP;
+       ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
+}
+
+static void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap)
+{
+       ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
+       ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
+}
+
+static void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en)
+{
+       ch->mode_ctrl &= ~COMP_2PLANE_EN;
+       ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
+}
+
+static void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en)
+{
+       ch->mode_ctrl &= ~YUV_EN;
+       ch->mode_ctrl |= (en ? YUV_EN : 0);
+}
+
+void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en)
+{
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+       u32 sys_ctrl;
+
+       sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
+
+       if (en) {
+               dcss_dpr_write(ch, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
+               dcss_dpr_write(ch, ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0);
+               dcss_dpr_write(ch, ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0);
+       }
+
+       if (ch->sys_ctrl != sys_ctrl)
+               ch->sys_ctrl_chgd = true;
+
+       ch->sys_ctrl = sys_ctrl;
+}
+
+struct rgb_comp_sel {
+       u32 drm_format;
+       int a_sel;
+       int r_sel;
+       int g_sel;
+       int b_sel;
+};
+
+static struct rgb_comp_sel comp_sel_map[] = {
+       {DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
+       {DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
+       {DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
+       {DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
+       {DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
+       {DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
+       {DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
+       {DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
+};
+
+static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
+                      int *b_sel)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
+               if (comp_sel_map[i].drm_format == pix_fmt) {
+                       *a_sel = comp_sel_map[i].a_sel;
+                       *r_sel = comp_sel_map[i].r_sel;
+                       *g_sel = comp_sel_map[i].g_sel;
+                       *b_sel = comp_sel_map[i].b_sel;
+
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+static void dcss_dpr_rtram_set(struct dcss_dpr_ch *ch, u32 pix_format)
+{
+       u32 val, mask;
+
+       switch (pix_format) {
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV12:
+               ch->rtram_3buf_en = true;
+               ch->rtram_4line_en = false;
+               break;
+
+       default:
+               ch->rtram_3buf_en = true;
+               ch->rtram_4line_en = true;
+               break;
+       }
+
+       val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
+       val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
+       mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
+
+       ch->mode_ctrl &= ~mask;
+       ch->mode_ctrl |= (val & mask);
+
+       val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
+       val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
+       val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
+       mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
+
+       ch->rtram_ctrl &= ~mask;
+       ch->rtram_ctrl |= (val & mask);
+}
+
+static void dcss_dpr_setup_components(struct dcss_dpr_ch *ch,
+                                     const struct drm_format_info *format)
+{
+       int a_sel, r_sel, g_sel, b_sel;
+       bool uv_swap, y_uv_swap;
+
+       switch (format->format) {
+       case DRM_FORMAT_YVYU:
+               uv_swap = true;
+               y_uv_swap = true;
+               break;
+
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_NV21:
+               uv_swap = true;
+               y_uv_swap = false;
+               break;
+
+       case DRM_FORMAT_YUYV:
+               uv_swap = false;
+               y_uv_swap = true;
+               break;
+
+       default:
+               uv_swap = false;
+               y_uv_swap = false;
+               break;
+       }
+
+       dcss_dpr_uv_swap(ch, uv_swap);
+
+       dcss_dpr_y_uv_swap(ch, y_uv_swap);
+
+       if (!format->is_yuv) {
+               if (!to_comp_sel(format->format, &a_sel, &r_sel,
+                                &g_sel, &b_sel)) {
+                       dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel);
+               } else {
+                       dcss_dpr_argb_comp_sel(ch, 3, 2, 1, 0);
+               }
+       } else {
+               dcss_dpr_argb_comp_sel(ch, 0, 0, 0, 0);
+       }
+}
+
+static void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier)
+{
+       switch (ch->ch_num) {
+       case 0:
+               switch (modifier) {
+               case DRM_FORMAT_MOD_LINEAR:
+                       ch->tile = TILE_LINEAR;
+                       break;
+               case DRM_FORMAT_MOD_VIVANTE_TILED:
+                       ch->tile = TILE_GPU_STANDARD;
+                       break;
+               case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+                       ch->tile = TILE_GPU_SUPER;
+                       break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+               break;
+       case 1:
+       case 2:
+               ch->tile = TILE_LINEAR;
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+
+       ch->mode_ctrl &= ~TILE_TYPE_MASK;
+       ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
+}
+
+void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
+                        const struct drm_format_info *format, u64 modifier)
+{
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+       ch->format = *format;
+
+       dcss_dpr_yuv_en(ch, format->is_yuv);
+
+       dcss_dpr_pix_size_set(ch, format);
+
+       dcss_dpr_setup_components(ch, format);
+
+       dcss_dpr_2plane_en(ch, format->num_planes == 2);
+
+       dcss_dpr_rtram_set(ch, format->format);
+
+       dcss_dpr_tile_set(ch, modifier);
+}
+
+/* This function will be called from interrupt context. */
+void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr)
+{
+       int chnum;
+
+       dcss_ctxld_assert_locked(dpr->ctxld);
+
+       for (chnum = 0; chnum < 3; chnum++) {
+               struct dcss_dpr_ch *ch = &dpr->ch[chnum];
+
+               if (ch->sys_ctrl_chgd) {
+                       dcss_ctxld_write_irqsafe(dpr->ctxld, dpr->ctx_id,
+                                                ch->sys_ctrl,
+                                                ch->base_ofs +
+                                                DCSS_DPR_SYSTEM_CTRL0);
+                       ch->sys_ctrl_chgd = false;
+               }
+       }
+}
+
+void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation)
+{
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+       ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
+
+       ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
+       ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
+
+       if (rotation & DRM_MODE_ROTATE_90)
+               ch->frame_ctrl |= 1 << ROT_ENC_POS;
+       else if (rotation & DRM_MODE_ROTATE_180)
+               ch->frame_ctrl |= 2 << ROT_ENC_POS;
+       else if (rotation & DRM_MODE_ROTATE_270)
+               ch->frame_ctrl |= 3 << ROT_ENC_POS;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c
new file mode 100644 (file)
index 0000000..8dc2f85
--- /dev/null
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <drm/drm_of.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+struct dcss_drv {
+       struct dcss_dev *dcss;
+       struct dcss_kms_dev *kms;
+};
+
+struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev)
+{
+       struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+       return mdrv ? mdrv->dcss : NULL;
+}
+
+struct drm_device *dcss_drv_dev_to_drm(struct device *dev)
+{
+       struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+       return mdrv ? &mdrv->kms->base : NULL;
+}
+
+static int dcss_drv_platform_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *remote;
+       struct dcss_drv *mdrv;
+       int err = 0;
+       bool hdmi_output = true;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       remote = of_graph_get_remote_node(dev->of_node, 0, 0);
+       if (!remote)
+               return -ENODEV;
+
+       hdmi_output = !of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi");
+
+       of_node_put(remote);
+
+       mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
+       if (!mdrv)
+               return -ENOMEM;
+
+       mdrv->dcss = dcss_dev_create(dev, hdmi_output);
+       if (IS_ERR(mdrv->dcss)) {
+               err = PTR_ERR(mdrv->dcss);
+               goto err;
+       }
+
+       dev_set_drvdata(dev, mdrv);
+
+       mdrv->kms = dcss_kms_attach(mdrv->dcss);
+       if (IS_ERR(mdrv->kms)) {
+               err = PTR_ERR(mdrv->kms);
+               goto dcss_shutoff;
+       }
+
+       return 0;
+
+dcss_shutoff:
+       dcss_dev_destroy(mdrv->dcss);
+
+       dev_set_drvdata(dev, NULL);
+
+err:
+       kfree(mdrv);
+       return err;
+}
+
+static int dcss_drv_platform_remove(struct platform_device *pdev)
+{
+       struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
+
+       if (!mdrv)
+               return 0;
+
+       dcss_kms_detach(mdrv->kms);
+       dcss_dev_destroy(mdrv->dcss);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       kfree(mdrv);
+
+       return 0;
+}
+
+static struct dcss_type_data dcss_types[] = {
+       [DCSS_IMX8MQ] = {
+               .name = "DCSS_IMX8MQ",
+               .blkctl_ofs = 0x2F000,
+               .ctxld_ofs = 0x23000,
+               .dtg_ofs = 0x20000,
+               .scaler_ofs = 0x1C000,
+               .ss_ofs = 0x1B000,
+               .dpr_ofs = 0x18000,
+       },
+};
+
+static const struct of_device_id dcss_of_match[] = {
+       { .compatible = "nxp,imx8mq-dcss", .data = &dcss_types[DCSS_IMX8MQ], },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dcss_of_match);
+
+static const struct dev_pm_ops dcss_dev_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(dcss_dev_suspend, dcss_dev_resume)
+       SET_RUNTIME_PM_OPS(dcss_dev_runtime_suspend,
+                          dcss_dev_runtime_resume, NULL)
+};
+
+static struct platform_driver dcss_platform_driver = {
+       .probe  = dcss_drv_platform_probe,
+       .remove = dcss_drv_platform_remove,
+       .driver = {
+               .name = "imx-dcss",
+               .of_match_table = dcss_of_match,
+               .pm = &dcss_dev_pm,
+       },
+};
+
+module_platform_driver(dcss_platform_driver);
+
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>");
+MODULE_DESCRIPTION("DCSS driver for i.MX8MQ");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dtg.c b/drivers/gpu/drm/imx/dcss/dcss-dtg.c
new file mode 100644 (file)
index 0000000..30de005
--- /dev/null
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_DTG_TC_CONTROL_STATUS                     0x00
+#define   CH3_EN                                       BIT(0)
+#define   CH2_EN                                       BIT(1)
+#define   CH1_EN                                       BIT(2)
+#define   OVL_DATA_MODE                                        BIT(3)
+#define   BLENDER_VIDEO_ALPHA_SEL                      BIT(7)
+#define   DTG_START                                    BIT(8)
+#define   DBY_MODE_EN                                  BIT(9)
+#define   CH1_ALPHA_SEL                                        BIT(10)
+#define   CSS_PIX_COMP_SWAP_POS                                12
+#define   CSS_PIX_COMP_SWAP_MASK                       GENMASK(14, 12)
+#define   DEFAULT_FG_ALPHA_POS                         24
+#define   DEFAULT_FG_ALPHA_MASK                                GENMASK(31, 24)
+#define DCSS_DTG_TC_DTG                                        0x04
+#define DCSS_DTG_TC_DISP_TOP                           0x08
+#define DCSS_DTG_TC_DISP_BOT                           0x0C
+#define DCSS_DTG_TC_CH1_TOP                            0x10
+#define DCSS_DTG_TC_CH1_BOT                            0x14
+#define DCSS_DTG_TC_CH2_TOP                            0x18
+#define DCSS_DTG_TC_CH2_BOT                            0x1C
+#define DCSS_DTG_TC_CH3_TOP                            0x20
+#define DCSS_DTG_TC_CH3_BOT                            0x24
+#define   TC_X_POS                                     0
+#define   TC_X_MASK                                    GENMASK(12, 0)
+#define   TC_Y_POS                                     16
+#define   TC_Y_MASK                                    GENMASK(28, 16)
+#define DCSS_DTG_TC_CTXLD                              0x28
+#define   TC_CTXLD_DB_Y_POS                            0
+#define   TC_CTXLD_DB_Y_MASK                           GENMASK(12, 0)
+#define   TC_CTXLD_SB_Y_POS                            16
+#define   TC_CTXLD_SB_Y_MASK                           GENMASK(28, 16)
+#define DCSS_DTG_TC_CH1_BKRND                          0x2C
+#define DCSS_DTG_TC_CH2_BKRND                          0x30
+#define   BKRND_R_Y_COMP_POS                           20
+#define   BKRND_R_Y_COMP_MASK                          GENMASK(29, 20)
+#define   BKRND_G_U_COMP_POS                           10
+#define   BKRND_G_U_COMP_MASK                          GENMASK(19, 10)
+#define   BKRND_B_V_COMP_POS                           0
+#define   BKRND_B_V_COMP_MASK                          GENMASK(9, 0)
+#define DCSS_DTG_BLENDER_DBY_RANGEINV                  0x38
+#define DCSS_DTG_BLENDER_DBY_RANGEMIN                  0x3C
+#define DCSS_DTG_BLENDER_DBY_BDP                       0x40
+#define DCSS_DTG_BLENDER_BKRND_I                       0x44
+#define DCSS_DTG_BLENDER_BKRND_P                       0x48
+#define DCSS_DTG_BLENDER_BKRND_T                       0x4C
+#define DCSS_DTG_LINE0_INT                             0x50
+#define DCSS_DTG_LINE1_INT                             0x54
+#define DCSS_DTG_BG_ALPHA_DEFAULT                      0x58
+#define DCSS_DTG_INT_STATUS                            0x5C
+#define DCSS_DTG_INT_CONTROL                           0x60
+#define DCSS_DTG_TC_CH3_BKRND                          0x64
+#define DCSS_DTG_INT_MASK                              0x68
+#define   LINE0_IRQ                                    BIT(0)
+#define   LINE1_IRQ                                    BIT(1)
+#define   LINE2_IRQ                                    BIT(2)
+#define   LINE3_IRQ                                    BIT(3)
+#define DCSS_DTG_LINE2_INT                             0x6C
+#define DCSS_DTG_LINE3_INT                             0x70
+#define DCSS_DTG_DBY_OL                                        0x74
+#define DCSS_DTG_DBY_BL                                        0x78
+#define DCSS_DTG_DBY_EL                                        0x7C
+
+struct dcss_dtg {
+       struct device *dev;
+       struct dcss_ctxld *ctxld;
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       u32 ctx_id;
+
+       bool in_use;
+
+       u32 dis_ulc_x;
+       u32 dis_ulc_y;
+
+       u32 control_status;
+       u32 alpha;
+       u32 alpha_cfg;
+
+       int ctxld_kick_irq;
+       bool ctxld_kick_irq_en;
+};
+
+static void dcss_dtg_write(struct dcss_dtg *dtg, u32 val, u32 ofs)
+{
+       if (!dtg->in_use)
+               dcss_writel(val, dtg->base_reg + ofs);
+
+       dcss_ctxld_write(dtg->ctxld, dtg->ctx_id,
+                        val, dtg->base_ofs + ofs);
+}
+
+static irqreturn_t dcss_dtg_irq_handler(int irq, void *data)
+{
+       struct dcss_dtg *dtg = data;
+       u32 status;
+
+       status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+       if (!(status & LINE0_IRQ))
+               return IRQ_NONE;
+
+       dcss_ctxld_kick(dtg->ctxld);
+
+       dcss_writel(status & LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+
+       return IRQ_HANDLED;
+}
+
+static int dcss_dtg_irq_config(struct dcss_dtg *dtg,
+                              struct platform_device *pdev)
+{
+       int ret;
+
+       dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick");
+       if (dtg->ctxld_kick_irq < 0)
+               return dtg->ctxld_kick_irq;
+
+       dcss_update(0, LINE0_IRQ | LINE1_IRQ,
+                   dtg->base_reg + DCSS_DTG_INT_MASK);
+
+       ret = request_irq(dtg->ctxld_kick_irq, dcss_dtg_irq_handler,
+                         0, "dcss_ctxld_kick", dtg);
+       if (ret) {
+               dev_err(dtg->dev, "dtg: irq request failed.\n");
+               return ret;
+       }
+
+       disable_irq(dtg->ctxld_kick_irq);
+
+       dtg->ctxld_kick_irq_en = false;
+
+       return 0;
+}
+
+int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base)
+{
+       int ret = 0;
+       struct dcss_dtg *dtg;
+
+       dtg = kzalloc(sizeof(*dtg), GFP_KERNEL);
+       if (!dtg)
+               return -ENOMEM;
+
+       dcss->dtg = dtg;
+       dtg->dev = dcss->dev;
+       dtg->ctxld = dcss->ctxld;
+
+       dtg->base_reg = ioremap(dtg_base, SZ_4K);
+       if (!dtg->base_reg) {
+               dev_err(dcss->dev, "dtg: unable to remap dtg base\n");
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       dtg->base_ofs = dtg_base;
+       dtg->ctx_id = CTX_DB;
+
+       dtg->alpha = 255;
+
+       dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
+               ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);
+
+       ret = dcss_dtg_irq_config(dtg, to_platform_device(dcss->dev));
+       if (ret)
+               goto err_irq;
+
+       return 0;
+
+err_irq:
+       iounmap(dtg->base_reg);
+
+err_ioremap:
+       kfree(dtg);
+
+       return ret;
+}
+
+void dcss_dtg_exit(struct dcss_dtg *dtg)
+{
+       free_irq(dtg->ctxld_kick_irq, dtg);
+
+       if (dtg->base_reg)
+               iounmap(dtg->base_reg);
+
+       kfree(dtg);
+}
+
+void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm)
+{
+       struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dtg->dev);
+       u16 dtg_lrc_x, dtg_lrc_y;
+       u16 dis_ulc_x, dis_ulc_y;
+       u16 dis_lrc_x, dis_lrc_y;
+       u32 sb_ctxld_trig, db_ctxld_trig;
+       u32 pixclock = vm->pixelclock;
+       u32 actual_clk;
+
+       dtg_lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+                   vm->hactive - 1;
+       dtg_lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+                   vm->vactive - 1;
+       dis_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+       dis_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch - 1;
+       dis_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+       dis_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+                   vm->vactive - 1;
+
+       clk_disable_unprepare(dcss->pix_clk);
+       clk_set_rate(dcss->pix_clk, vm->pixelclock);
+       clk_prepare_enable(dcss->pix_clk);
+
+       actual_clk = clk_get_rate(dcss->pix_clk);
+       if (pixclock != actual_clk) {
+               dev_info(dtg->dev,
+                        "Pixel clock set to %u kHz instead of %u kHz.\n",
+                        (actual_clk / 1000), (pixclock / 1000));
+       }
+
+       dcss_dtg_write(dtg, ((dtg_lrc_y << TC_Y_POS) | dtg_lrc_x),
+                      DCSS_DTG_TC_DTG);
+       dcss_dtg_write(dtg, ((dis_ulc_y << TC_Y_POS) | dis_ulc_x),
+                      DCSS_DTG_TC_DISP_TOP);
+       dcss_dtg_write(dtg, ((dis_lrc_y << TC_Y_POS) | dis_lrc_x),
+                      DCSS_DTG_TC_DISP_BOT);
+
+       dtg->dis_ulc_x = dis_ulc_x;
+       dtg->dis_ulc_y = dis_ulc_y;
+
+       sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) &
+                                                       TC_CTXLD_SB_Y_MASK;
+       db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) &
+                                                       TC_CTXLD_DB_Y_MASK;
+
+       dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD);
+
+       /* vblank trigger */
+       dcss_dtg_write(dtg, 0, DCSS_DTG_LINE1_INT);
+
+       /* CTXLD trigger */
+       dcss_dtg_write(dtg, ((90 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE0_INT);
+}
+
+void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
+                           int px, int py, int pw, int ph)
+{
+       u16 p_ulc_x, p_ulc_y;
+       u16 p_lrc_x, p_lrc_y;
+
+       p_ulc_x = dtg->dis_ulc_x + px;
+       p_ulc_y = dtg->dis_ulc_y + py;
+       p_lrc_x = p_ulc_x + pw;
+       p_lrc_y = p_ulc_y + ph;
+
+       if (!px && !py && !pw && !ph) {
+               dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+               dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+       } else {
+               dcss_dtg_write(dtg, ((p_ulc_y << TC_Y_POS) | p_ulc_x),
+                              DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+               dcss_dtg_write(dtg, ((p_lrc_y << TC_Y_POS) | p_lrc_x),
+                              DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+       }
+}
+
+bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha)
+{
+       if (ch_num)
+               return false;
+
+       return alpha != dtg->alpha;
+}
+
+void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
+                             const struct drm_format_info *format, int alpha)
+{
+       /* we care about alpha only when channel 0 is concerned */
+       if (ch_num)
+               return;
+
+       /*
+        * Use global alpha if pixel format does not have alpha channel or the
+        * user explicitly chose to use global alpha (i.e. alpha is not OPAQUE).
+        */
+       if (!format->has_alpha || alpha != 255)
+               dtg->alpha_cfg = (alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK;
+       else /* use per-pixel alpha otherwise */
+               dtg->alpha_cfg = CH1_ALPHA_SEL;
+
+       dtg->alpha = alpha;
+}
+
+void dcss_dtg_css_set(struct dcss_dtg *dtg)
+{
+       dtg->control_status |=
+                       (0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK;
+}
+
+void dcss_dtg_enable(struct dcss_dtg *dtg)
+{
+       dtg->control_status |= DTG_START;
+
+       dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
+       dtg->control_status |= dtg->alpha_cfg;
+
+       dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+       dtg->in_use = true;
+}
+
+void dcss_dtg_shutoff(struct dcss_dtg *dtg)
+{
+       dtg->control_status &= ~DTG_START;
+
+       dcss_writel(dtg->control_status,
+                   dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+       dtg->in_use = false;
+}
+
+bool dcss_dtg_is_enabled(struct dcss_dtg *dtg)
+{
+       return dtg->in_use;
+}
+
+void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en)
+{
+       u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
+       u32 control_status;
+
+       control_status = dtg->control_status & ~ch_en_map[ch_num];
+       control_status |= en ? ch_en_map[ch_num] : 0;
+
+       control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
+       control_status |= dtg->alpha_cfg;
+
+       if (dtg->control_status != control_status)
+               dcss_dtg_write(dtg, control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+       dtg->control_status = control_status;
+}
+
+void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en)
+{
+       u32 status;
+       u32 mask = en ? LINE1_IRQ : 0;
+
+       if (en) {
+               status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+               dcss_writel(status & LINE1_IRQ,
+                           dtg->base_reg + DCSS_DTG_INT_CONTROL);
+       }
+
+       dcss_update(mask, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
+}
+
+void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en)
+{
+       u32 status;
+       u32 mask = en ? LINE0_IRQ : 0;
+
+       if (en) {
+               status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+               if (!dtg->ctxld_kick_irq_en) {
+                       dcss_writel(status & LINE0_IRQ,
+                                   dtg->base_reg + DCSS_DTG_INT_CONTROL);
+                       enable_irq(dtg->ctxld_kick_irq);
+                       dtg->ctxld_kick_irq_en = true;
+                       dcss_update(mask, LINE0_IRQ,
+                                   dtg->base_reg + DCSS_DTG_INT_MASK);
+               }
+
+               return;
+       }
+
+       if (!dtg->ctxld_kick_irq_en)
+               return;
+
+       disable_irq_nosync(dtg->ctxld_kick_irq);
+       dtg->ctxld_kick_irq_en = false;
+
+       dcss_update(mask, LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
+}
+
+void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg)
+{
+       dcss_update(LINE1_IRQ, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+}
+
+bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg)
+{
+       return !!(dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS) & LINE1_IRQ);
+}
+
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
new file mode 100644 (file)
index 0000000..135a623
--- /dev/null
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+DEFINE_DRM_GEM_CMA_FOPS(dcss_cma_fops);
+
+static const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
+       .fb_create = drm_gem_fb_create,
+       .output_poll_changed = drm_fb_helper_output_poll_changed,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = drm_atomic_helper_commit,
+};
+
+static struct drm_driver dcss_kms_driver = {
+       .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+       .gem_free_object_unlocked = drm_gem_cma_free_object,
+       .gem_vm_ops             = &drm_gem_cma_vm_ops,
+       .dumb_create            = drm_gem_cma_dumb_create,
+
+       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
+       .gem_prime_import       = drm_gem_prime_import,
+       .gem_prime_export       = drm_gem_prime_export,
+       .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+       .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+       .gem_prime_vmap         = drm_gem_cma_prime_vmap,
+       .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
+       .gem_prime_mmap         = drm_gem_cma_prime_mmap,
+       .fops                   = &dcss_cma_fops,
+       .name                   = "imx-dcss",
+       .desc                   = "i.MX8MQ Display Subsystem",
+       .date                   = "20190917",
+       .major                  = 1,
+       .minor                  = 0,
+       .patchlevel             = 0,
+};
+
+static const struct drm_mode_config_helper_funcs dcss_mode_config_helpers = {
+       .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
+static void dcss_kms_mode_config_init(struct dcss_kms_dev *kms)
+{
+       struct drm_mode_config *config = &kms->base.mode_config;
+
+       drm_mode_config_init(&kms->base);
+
+       config->min_width = 1;
+       config->min_height = 1;
+       config->max_width = 4096;
+       config->max_height = 4096;
+       config->allow_fb_modifiers = true;
+       config->normalize_zpos = true;
+
+       config->funcs = &dcss_drm_mode_config_funcs;
+       config->helper_private = &dcss_mode_config_helpers;
+}
+
+static const struct drm_encoder_funcs dcss_kms_simple_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms)
+{
+       struct drm_device *ddev = &kms->base;
+       struct drm_encoder *encoder = &kms->encoder;
+       struct drm_crtc *crtc = (struct drm_crtc *)&kms->crtc;
+       struct drm_panel *panel;
+       struct drm_bridge *bridge;
+       int ret;
+
+       ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0,
+                                         &panel, &bridge);
+       if (ret)
+               return ret;
+
+       if (!bridge) {
+               dev_err(ddev->dev, "No bridge found %d.\n", ret);
+               return -ENODEV;
+       }
+
+       encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+       ret = drm_encoder_init(&kms->base, encoder,
+                              &dcss_kms_simple_encoder_funcs,
+                              DRM_MODE_ENCODER_NONE, NULL);
+       if (ret) {
+               dev_err(ddev->dev, "Failed initializing encoder %d.\n", ret);
+               return ret;
+       }
+
+       ret = drm_bridge_attach(encoder, bridge, NULL,
+                               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (ret < 0) {
+               dev_err(ddev->dev, "Unable to attach bridge %pOF\n",
+                       bridge->of_node);
+               return ret;
+       }
+
+       kms->connector = drm_bridge_connector_init(ddev, encoder);
+       if (IS_ERR(kms->connector)) {
+               dev_err(ddev->dev, "Unable to create bridge connector.\n");
+               return PTR_ERR(kms->connector);
+       }
+
+       drm_connector_attach_encoder(kms->connector, encoder);
+
+       return 0;
+}
+
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
+{
+       struct dcss_kms_dev *kms;
+       struct drm_device *drm;
+       struct dcss_crtc *crtc;
+       int ret;
+
+       kms = devm_drm_dev_alloc(dcss->dev, &dcss_kms_driver,
+                                struct dcss_kms_dev, base);
+       if (IS_ERR(kms))
+               return kms;
+
+       drm = &kms->base;
+       crtc = &kms->crtc;
+
+       drm->dev_private = dcss;
+
+       dcss_kms_mode_config_init(kms);
+
+       ret = drm_vblank_init(drm, 1);
+       if (ret)
+               goto cleanup_mode_config;
+
+       drm->irq_enabled = true;
+
+       ret = dcss_kms_bridge_connector_init(kms);
+       if (ret)
+               goto cleanup_mode_config;
+
+       ret = dcss_crtc_init(crtc, drm);
+       if (ret)
+               goto cleanup_mode_config;
+
+       drm_mode_config_reset(drm);
+
+       drm_kms_helper_poll_init(drm);
+
+       drm_bridge_connector_enable_hpd(kms->connector);
+
+       ret = drm_dev_register(drm, 0);
+       if (ret)
+               goto cleanup_crtc;
+
+       drm_fbdev_generic_setup(drm, 32);
+
+       return kms;
+
+cleanup_crtc:
+       drm_bridge_connector_disable_hpd(kms->connector);
+       drm_kms_helper_poll_fini(drm);
+       dcss_crtc_deinit(crtc, drm);
+
+cleanup_mode_config:
+       drm_mode_config_cleanup(drm);
+       drm->dev_private = NULL;
+
+       return ERR_PTR(ret);
+}
+
+void dcss_kms_detach(struct dcss_kms_dev *kms)
+{
+       struct drm_device *drm = &kms->base;
+
+       drm_dev_unregister(drm);
+       drm_bridge_connector_disable_hpd(kms->connector);
+       drm_kms_helper_poll_fini(drm);
+       drm_atomic_helper_shutdown(drm);
+       drm_crtc_vblank_off(&kms->crtc.base);
+       drm->irq_enabled = false;
+       drm_mode_config_cleanup(drm);
+       dcss_crtc_deinit(&kms->crtc, drm);
+       drm->dev_private = NULL;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.h b/drivers/gpu/drm/imx/dcss/dcss-kms.h
new file mode 100644 (file)
index 0000000..dfe5dd9
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP.
+ */
+
+#ifndef _DCSS_KMS_H_
+#define _DCSS_KMS_H_
+
+#include <drm/drm_encoder.h>
+
+struct dcss_plane {
+       struct drm_plane base;
+
+       int ch_num;
+};
+
+struct dcss_crtc {
+       struct drm_crtc         base;
+       struct drm_crtc_state   *state;
+
+       struct dcss_plane       *plane[3];
+
+       int                     irq;
+
+       bool disable_ctxld_kick_irq;
+};
+
+struct dcss_kms_dev {
+       struct drm_device base;
+       struct dcss_crtc crtc;
+       struct drm_encoder encoder;
+       struct drm_connector *connector;
+};
+
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss);
+void dcss_kms_detach(struct dcss_kms_dev *kms);
+int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm);
+void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm);
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+                                  unsigned int possible_crtcs,
+                                  enum drm_plane_type type,
+                                  unsigned int zpos);
+
+#endif
diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.c b/drivers/gpu/drm/imx/dcss/dcss-plane.c
new file mode 100644 (file)
index 0000000..961d671
--- /dev/null
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static const u32 dcss_common_formats[] = {
+       /* RGB */
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ABGR8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_RGBA8888,
+       DRM_FORMAT_RGBX8888,
+       DRM_FORMAT_BGRA8888,
+       DRM_FORMAT_BGRX8888,
+       DRM_FORMAT_XRGB2101010,
+       DRM_FORMAT_XBGR2101010,
+       DRM_FORMAT_RGBX1010102,
+       DRM_FORMAT_BGRX1010102,
+       DRM_FORMAT_ARGB2101010,
+       DRM_FORMAT_ABGR2101010,
+       DRM_FORMAT_RGBA1010102,
+       DRM_FORMAT_BGRA1010102,
+};
+
+static const u64 dcss_video_format_modifiers[] = {
+       DRM_FORMAT_MOD_LINEAR,
+       DRM_FORMAT_MOD_INVALID,
+};
+
+static const u64 dcss_graphics_format_modifiers[] = {
+       DRM_FORMAT_MOD_VIVANTE_TILED,
+       DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+       DRM_FORMAT_MOD_LINEAR,
+       DRM_FORMAT_MOD_INVALID,
+};
+
+static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
+{
+       return container_of(p, struct dcss_plane, base);
+}
+
+static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
+{
+       return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
+              ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
+               fb->modifier == DRM_FORMAT_MOD_LINEAR);
+}
+
+static void dcss_plane_destroy(struct drm_plane *plane)
+{
+       struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
+                                                    base);
+
+       drm_plane_cleanup(plane);
+       kfree(dcss_plane);
+}
+
+static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
+                                           u32 format,
+                                           u64 modifier)
+{
+       switch (plane->type) {
+       case DRM_PLANE_TYPE_PRIMARY:
+               switch (format) {
+               case DRM_FORMAT_ARGB8888:
+               case DRM_FORMAT_XRGB8888:
+               case DRM_FORMAT_ARGB2101010:
+                       return modifier == DRM_FORMAT_MOD_LINEAR ||
+                              modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+                              modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
+               default:
+                       return modifier == DRM_FORMAT_MOD_LINEAR;
+               }
+               break;
+       case DRM_PLANE_TYPE_OVERLAY:
+               return modifier == DRM_FORMAT_MOD_LINEAR;
+       default:
+               return false;
+       }
+}
+
+static const struct drm_plane_funcs dcss_plane_funcs = {
+       .update_plane           = drm_atomic_helper_update_plane,
+       .disable_plane          = drm_atomic_helper_disable_plane,
+       .destroy                = dcss_plane_destroy,
+       .reset                  = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
+       .format_mod_supported   = dcss_plane_format_mod_supported,
+};
+
+static bool dcss_plane_can_rotate(const struct drm_format_info *format,
+                                 bool mod_present, u64 modifier,
+                                 unsigned int rotation)
+{
+       bool linear_format = !mod_present ||
+                            (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
+       u32 supported_rotation = DRM_MODE_ROTATE_0;
+
+       if (!format->is_yuv && linear_format)
+               supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+                                    DRM_MODE_REFLECT_MASK;
+       else if (!format->is_yuv &&
+                modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
+               supported_rotation = DRM_MODE_ROTATE_MASK |
+                                    DRM_MODE_REFLECT_MASK;
+       else if (format->is_yuv && linear_format &&
+                (format->format == DRM_FORMAT_NV12 ||
+                 format->format == DRM_FORMAT_NV21))
+               supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+                                    DRM_MODE_REFLECT_MASK;
+
+       return !!(rotation & supported_rotation);
+}
+
+static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
+{
+       if (src_w < 64 &&
+           (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
+               return false;
+       else if (src_w < 32 &&
+                (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
+                 pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
+               return false;
+
+       return src_w >= 16 && src_h >= 8;
+}
+
+static int dcss_plane_atomic_check(struct drm_plane *plane,
+                                  struct drm_plane_state *state)
+{
+       struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+       struct dcss_dev *dcss = plane->dev->dev_private;
+       struct drm_framebuffer *fb = state->fb;
+       bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
+       struct drm_gem_cma_object *cma_obj;
+       struct drm_crtc_state *crtc_state;
+       int hdisplay, vdisplay;
+       int min, max;
+       int ret;
+
+       if (!fb || !state->crtc)
+               return 0;
+
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       WARN_ON(!cma_obj);
+
+       crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+                                                       state->crtc);
+
+       hdisplay = crtc_state->adjusted_mode.hdisplay;
+       vdisplay = crtc_state->adjusted_mode.vdisplay;
+
+       if (!dcss_plane_is_source_size_allowed(state->src_w >> 16,
+                                              state->src_h >> 16,
+                                              fb->format->format)) {
+               DRM_DEBUG_KMS("Source plane size is not allowed!\n");
+               return -EINVAL;
+       }
+
+       dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
+                                      &min, &max);
+
+       ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+                                                 min, max, !is_primary_plane,
+                                                 false);
+       if (ret)
+               return ret;
+
+       if (!state->visible)
+               return 0;
+
+       if (!dcss_plane_can_rotate(fb->format,
+                                  !!(fb->flags & DRM_MODE_FB_MODIFIERS),
+                                  fb->modifier,
+                                  state->rotation)) {
+               DRM_DEBUG_KMS("requested rotation is not allowed!\n");
+               return -EINVAL;
+       }
+
+       if ((state->crtc_x < 0 || state->crtc_y < 0 ||
+            state->crtc_x + state->crtc_w > hdisplay ||
+            state->crtc_y + state->crtc_h > vdisplay) &&
+           !dcss_plane_fb_is_linear(fb)) {
+               DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
+               return -EINVAL;
+       }
+
+       if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
+           !plane->funcs->format_mod_supported(plane,
+                               fb->format->format,
+                               fb->modifier)) {
+               DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
+{
+       struct drm_plane *plane = &dcss_plane->base;
+       struct drm_plane_state *state = plane->state;
+       struct dcss_dev *dcss = plane->dev->dev_private;
+       struct drm_framebuffer *fb = state->fb;
+       const struct drm_format_info *format = fb->format;
+       struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       unsigned long p1_ba = 0, p2_ba = 0;
+
+       if (!format->is_yuv ||
+           format->format == DRM_FORMAT_NV12 ||
+           format->format == DRM_FORMAT_NV21)
+               p1_ba = cma_obj->paddr + fb->offsets[0] +
+                       fb->pitches[0] * (state->src.y1 >> 16) +
+                       format->char_per_block[0] * (state->src.x1 >> 16);
+       else if (format->format == DRM_FORMAT_UYVY ||
+                format->format == DRM_FORMAT_VYUY ||
+                format->format == DRM_FORMAT_YUYV ||
+                format->format == DRM_FORMAT_YVYU)
+               p1_ba = cma_obj->paddr + fb->offsets[0] +
+                       fb->pitches[0] * (state->src.y1 >> 16) +
+                       2 * format->char_per_block[0] * (state->src.x1 >> 17);
+
+       if (format->format == DRM_FORMAT_NV12 ||
+           format->format == DRM_FORMAT_NV21)
+               p2_ba = cma_obj->paddr + fb->offsets[1] +
+                       (((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
+                       (state->src.x1 >> 17)) << 1);
+
+       dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
+                         fb->pitches[0]);
+}
+
+static bool dcss_plane_needs_setup(struct drm_plane_state *state,
+                                  struct drm_plane_state *old_state)
+{
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_framebuffer *old_fb = old_state->fb;
+
+       return state->crtc_x != old_state->crtc_x ||
+              state->crtc_y != old_state->crtc_y ||
+              state->crtc_w != old_state->crtc_w ||
+              state->crtc_h != old_state->crtc_h ||
+              state->src_x  != old_state->src_x  ||
+              state->src_y  != old_state->src_y  ||
+              state->src_w  != old_state->src_w  ||
+              state->src_h  != old_state->src_h  ||
+              fb->format->format != old_fb->format->format ||
+              fb->modifier  != old_fb->modifier ||
+              state->rotation != old_state->rotation;
+}
+
+static void dcss_plane_atomic_update(struct drm_plane *plane,
+                                    struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = plane->state;
+       struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+       struct dcss_dev *dcss = plane->dev->dev_private;
+       struct drm_framebuffer *fb = state->fb;
+       u32 pixel_format;
+       struct drm_crtc_state *crtc_state;
+       bool modifiers_present;
+       u32 src_w, src_h, dst_w, dst_h;
+       struct drm_rect src, dst;
+       bool enable = true;
+
+       if (!fb || !state->crtc || !state->visible)
+               return;
+
+       pixel_format = state->fb->format->format;
+       crtc_state = state->crtc->state;
+       modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
+
+       if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
+           !dcss_plane_needs_setup(state, old_state)) {
+               dcss_plane_atomic_set_base(dcss_plane);
+               return;
+       }
+
+       src = plane->state->src;
+       dst = plane->state->dst;
+
+       /*
+        * The width and height after clipping.
+        */
+       src_w = drm_rect_width(&src) >> 16;
+       src_h = drm_rect_height(&src) >> 16;
+       dst_w = drm_rect_width(&dst);
+       dst_h = drm_rect_height(&dst);
+
+       if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
+           modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
+               modifiers_present = false;
+
+       dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num, state->fb->format,
+                           modifiers_present ? fb->modifier :
+                                               DRM_FORMAT_MOD_LINEAR);
+       dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
+       dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
+                             state->rotation);
+
+       dcss_plane_atomic_set_base(dcss_plane);
+
+       dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
+                         state->fb->format, src_w, src_h,
+                         dst_w, dst_h,
+                         drm_mode_vrefresh(&crtc_state->mode));
+
+       dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
+                              dst.x1, dst.y1, dst_w, dst_h);
+       dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
+                                fb->format, state->alpha >> 8);
+
+       if (!dcss_plane->ch_num && (state->alpha >> 8) == 0)
+               enable = false;
+
+       dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
+       dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
+
+       if (!enable)
+               dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
+                                      0, 0, 0, 0);
+
+       dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
+}
+
+static void dcss_plane_atomic_disable(struct drm_plane *plane,
+                                     struct drm_plane_state *old_state)
+{
+       struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+       struct dcss_dev *dcss = plane->dev->dev_private;
+
+       dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
+       dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
+       dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
+       dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
+}
+
+static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
+       .prepare_fb = drm_gem_fb_prepare_fb,
+       .atomic_check = dcss_plane_atomic_check,
+       .atomic_update = dcss_plane_atomic_update,
+       .atomic_disable = dcss_plane_atomic_disable,
+};
+
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+                                  unsigned int possible_crtcs,
+                                  enum drm_plane_type type,
+                                  unsigned int zpos)
+{
+       struct dcss_plane *dcss_plane;
+       const u64 *format_modifiers = dcss_video_format_modifiers;
+       int ret;
+
+       if (zpos > 2)
+               return ERR_PTR(-EINVAL);
+
+       dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
+       if (!dcss_plane) {
+               DRM_ERROR("failed to allocate plane\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       if (type == DRM_PLANE_TYPE_PRIMARY)
+               format_modifiers = dcss_graphics_format_modifiers;
+
+       ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
+                                      &dcss_plane_funcs, dcss_common_formats,
+                                      ARRAY_SIZE(dcss_common_formats),
+                                      format_modifiers, type, NULL);
+       if (ret) {
+               DRM_ERROR("failed to initialize plane\n");
+               kfree(dcss_plane);
+               return ERR_PTR(ret);
+       }
+
+       drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
+
+       ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
+       if (ret)
+               return ERR_PTR(ret);
+
+       drm_plane_create_rotation_property(&dcss_plane->base,
+                                          DRM_MODE_ROTATE_0,
+                                          DRM_MODE_ROTATE_0   |
+                                          DRM_MODE_ROTATE_90  |
+                                          DRM_MODE_ROTATE_180 |
+                                          DRM_MODE_ROTATE_270 |
+                                          DRM_MODE_REFLECT_X  |
+                                          DRM_MODE_REFLECT_Y);
+
+       dcss_plane->ch_num = zpos;
+
+       return dcss_plane;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c
new file mode 100644 (file)
index 0000000..cd21905
--- /dev/null
@@ -0,0 +1,826 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ *
+ * Scaling algorithms were contributed by Dzung Hoang <dzung.hoang@nxp.com>
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_SCALER_CTRL                       0x00
+#define   SCALER_EN                            BIT(0)
+#define   REPEAT_EN                            BIT(4)
+#define   SCALE2MEM_EN                         BIT(8)
+#define   MEM2OFIFO_EN                         BIT(12)
+#define DCSS_SCALER_OFIFO_CTRL                 0x04
+#define   OFIFO_LOW_THRES_POS                  0
+#define   OFIFO_LOW_THRES_MASK                 GENMASK(9, 0)
+#define   OFIFO_HIGH_THRES_POS                 16
+#define   OFIFO_HIGH_THRES_MASK                        GENMASK(25, 16)
+#define   UNDERRUN_DETECT_CLR                  BIT(26)
+#define   LOW_THRES_DETECT_CLR                 BIT(27)
+#define   HIGH_THRES_DETECT_CLR                        BIT(28)
+#define   UNDERRUN_DETECT_EN                   BIT(29)
+#define   LOW_THRES_DETECT_EN                  BIT(30)
+#define   HIGH_THRES_DETECT_EN                 BIT(31)
+#define DCSS_SCALER_SDATA_CTRL                 0x08
+#define   YUV_EN                               BIT(0)
+#define   RTRAM_8LINES                         BIT(1)
+#define   Y_UV_BYTE_SWAP                       BIT(4)
+#define   A2R10G10B10_FORMAT_POS               8
+#define   A2R10G10B10_FORMAT_MASK              GENMASK(11, 8)
+#define DCSS_SCALER_BIT_DEPTH                  0x0C
+#define   LUM_BIT_DEPTH_POS                    0
+#define   LUM_BIT_DEPTH_MASK                   GENMASK(1, 0)
+#define   CHR_BIT_DEPTH_POS                    4
+#define   CHR_BIT_DEPTH_MASK                   GENMASK(5, 4)
+#define DCSS_SCALER_SRC_FORMAT                 0x10
+#define DCSS_SCALER_DST_FORMAT                 0x14
+#define   FORMAT_MASK                          GENMASK(1, 0)
+#define DCSS_SCALER_SRC_LUM_RES                        0x18
+#define DCSS_SCALER_SRC_CHR_RES                        0x1C
+#define DCSS_SCALER_DST_LUM_RES                        0x20
+#define DCSS_SCALER_DST_CHR_RES                        0x24
+#define   WIDTH_POS                            0
+#define   WIDTH_MASK                           GENMASK(11, 0)
+#define   HEIGHT_POS                           16
+#define   HEIGHT_MASK                          GENMASK(27, 16)
+#define DCSS_SCALER_V_LUM_START                        0x48
+#define   V_START_MASK                         GENMASK(15, 0)
+#define DCSS_SCALER_V_LUM_INC                  0x4C
+#define   V_INC_MASK                           GENMASK(15, 0)
+#define DCSS_SCALER_H_LUM_START                        0x50
+#define   H_START_MASK                         GENMASK(18, 0)
+#define DCSS_SCALER_H_LUM_INC                  0x54
+#define   H_INC_MASK                           GENMASK(15, 0)
+#define DCSS_SCALER_V_CHR_START                        0x58
+#define DCSS_SCALER_V_CHR_INC                  0x5C
+#define DCSS_SCALER_H_CHR_START                        0x60
+#define DCSS_SCALER_H_CHR_INC                  0x64
+#define DCSS_SCALER_COEF_VLUM                  0x80
+#define DCSS_SCALER_COEF_HLUM                  0x140
+#define DCSS_SCALER_COEF_VCHR                  0x200
+#define DCSS_SCALER_COEF_HCHR                  0x300
+
+struct dcss_scaler_ch {
+       void __iomem *base_reg;
+       u32 base_ofs;
+       struct dcss_scaler *scl;
+
+       u32 sdata_ctrl;
+       u32 scaler_ctrl;
+
+       bool scaler_ctrl_chgd;
+
+       u32 c_vstart;
+       u32 c_hstart;
+};
+
+struct dcss_scaler {
+       struct device *dev;
+
+       struct dcss_ctxld *ctxld;
+       u32 ctx_id;
+
+       struct dcss_scaler_ch ch[3];
+};
+
+/* scaler coefficients generator */
+#define PSC_FRAC_BITS 30
+#define PSC_FRAC_SCALE BIT(PSC_FRAC_BITS)
+#define PSC_BITS_FOR_PHASE 4
+#define PSC_NUM_PHASES 16
+#define PSC_STORED_PHASES (PSC_NUM_PHASES / 2 + 1)
+#define PSC_NUM_TAPS 7
+#define PSC_NUM_TAPS_RGBA 5
+#define PSC_COEFF_PRECISION 10
+#define PSC_PHASE_FRACTION_BITS 13
+#define PSC_PHASE_MASK (PSC_NUM_PHASES - 1)
+#define PSC_Q_FRACTION 19
+#define PSC_Q_ROUND_OFFSET (1 << (PSC_Q_FRACTION - 1))
+
+/**
+ * mult_q() - Performs fixed-point multiplication.
+ * @A: multiplier
+ * @B: multiplicand
+ */
+static int mult_q(int A, int B)
+{
+       int result;
+       s64 temp;
+
+       temp = (int64_t)A * (int64_t)B;
+       temp += PSC_Q_ROUND_OFFSET;
+       result = (int)(temp >> PSC_Q_FRACTION);
+       return result;
+}
+
+/**
+ * div_q() - Performs fixed-point division.
+ * @A: dividend
+ * @B: divisor
+ */
+static int div_q(int A, int B)
+{
+       int result;
+       s64 temp;
+
+       temp = (int64_t)A << PSC_Q_FRACTION;
+       if ((temp >= 0 && B >= 0) || (temp < 0 && B < 0))
+               temp += B / 2;
+       else
+               temp -= B / 2;
+
+       result = (int)(temp / B);
+       return result;
+}
+
+/**
+ * exp_approx_q() - Compute approximation to exp(x) function using Taylor
+ *                 series.
+ * @x: fixed-point argument of exp function
+ */
+static int exp_approx_q(int x)
+{
+       int sum = 1 << PSC_Q_FRACTION;
+       int term = 1 << PSC_Q_FRACTION;
+
+       term = mult_q(term, div_q(x, 1 << PSC_Q_FRACTION));
+       sum += term;
+       term = mult_q(term, div_q(x, 2 << PSC_Q_FRACTION));
+       sum += term;
+       term = mult_q(term, div_q(x, 3 << PSC_Q_FRACTION));
+       sum += term;
+       term = mult_q(term, div_q(x, 4 << PSC_Q_FRACTION));
+       sum += term;
+
+       return sum;
+}
+
+/**
+ * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
+ * @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
+ * @use_5_taps: indicates whether to use 5 taps or 7 taps
+ * @coef: output filter coefficients
+ */
+static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
+                                       bool phase0_identity,
+                                       int coef[][PSC_NUM_TAPS])
+{
+       int sigma_q, g0_q, g1_q, g2_q;
+       int tap_cnt1, tap_cnt2, tap_idx, phase_cnt;
+       int mid;
+       int phase;
+       int i;
+       int taps;
+
+       if (use_5_taps)
+               for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+                       coef[phase][0] = 0;
+                       coef[phase][PSC_NUM_TAPS - 1] = 0;
+               }
+
+       /* seed coefficient scanner */
+       taps = use_5_taps ? PSC_NUM_TAPS_RGBA : PSC_NUM_TAPS;
+       mid = (PSC_NUM_PHASES * taps) / 2 - 1;
+       phase_cnt = (PSC_NUM_PHASES * (PSC_NUM_TAPS + 1)) / 2;
+       tap_cnt1 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+       tap_cnt2 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+
+       /* seed gaussian filter generator */
+       sigma_q = div_q(PSC_Q_ROUND_OFFSET, fc_q);
+       g0_q = 1 << PSC_Q_FRACTION;
+       g1_q = exp_approx_q(div_q(-PSC_Q_ROUND_OFFSET,
+                                 mult_q(sigma_q, sigma_q)));
+       g2_q = mult_q(g1_q, g1_q);
+       coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
+
+       for (i = 0; i < mid; i++) {
+               phase_cnt++;
+               tap_cnt1--;
+               tap_cnt2++;
+
+               g0_q = mult_q(g0_q, g1_q);
+               g1_q = mult_q(g1_q, g2_q);
+
+               if ((phase_cnt & PSC_PHASE_MASK) <= 8) {
+                       tap_idx = tap_cnt1 >> PSC_BITS_FOR_PHASE;
+                       coef[phase_cnt & PSC_PHASE_MASK][tap_idx] = g0_q;
+               }
+               if (((-phase_cnt) & PSC_PHASE_MASK) <= 8) {
+                       tap_idx = tap_cnt2 >> PSC_BITS_FOR_PHASE;
+                       coef[(-phase_cnt) & PSC_PHASE_MASK][tap_idx] = g0_q;
+               }
+       }
+
+       phase_cnt++;
+       tap_cnt1--;
+       coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = 0;
+
+       /* override phase 0 with identity filter if specified */
+       if (phase0_identity)
+               for (i = 0; i < PSC_NUM_TAPS; i++)
+                       coef[0][i] = i == (PSC_NUM_TAPS >> 1) ?
+                                               (1 << PSC_COEFF_PRECISION) : 0;
+
+       /* normalize coef */
+       for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+               int sum = 0;
+               s64 ll_temp;
+
+               for (i = 0; i < PSC_NUM_TAPS; i++)
+                       sum += coef[phase][i];
+               for (i = 0; i < PSC_NUM_TAPS; i++) {
+                       ll_temp = coef[phase][i];
+                       ll_temp <<= PSC_COEFF_PRECISION;
+                       ll_temp += sum >> 1;
+                       ll_temp /= sum;
+                       coef[phase][i] = (int)ll_temp;
+               }
+       }
+}
+
+/**
+ * dcss_scaler_filter_design() - Compute filter coefficients using
+ *                              Gaussian filter.
+ * @src_length: length of input
+ * @dst_length: length of output
+ * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
+ * @coef: output coefficients
+ */
+static void dcss_scaler_filter_design(int src_length, int dst_length,
+                                     bool use_5_taps, bool phase0_identity,
+                                     int coef[][PSC_NUM_TAPS])
+{
+       int fc_q;
+
+       /* compute cutoff frequency */
+       if (dst_length >= src_length)
+               fc_q = div_q(1, PSC_NUM_PHASES);
+       else
+               fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
+
+       /* compute gaussian filter coefficients */
+       dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
+}
+
+static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs)
+{
+       struct dcss_scaler *scl = ch->scl;
+
+       dcss_ctxld_write(scl->ctxld, scl->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static int dcss_scaler_ch_init_all(struct dcss_scaler *scl,
+                                  unsigned long scaler_base)
+{
+       struct dcss_scaler_ch *ch;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               ch = &scl->ch[i];
+
+               ch->base_ofs = scaler_base + i * 0x400;
+
+               ch->base_reg = ioremap(ch->base_ofs, SZ_4K);
+               if (!ch->base_reg) {
+                       dev_err(scl->dev, "scaler: unable to remap ch base\n");
+                       return -ENOMEM;
+               }
+
+               ch->scl = scl;
+       }
+
+       return 0;
+}
+
+int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base)
+{
+       struct dcss_scaler *scaler;
+
+       scaler = kzalloc(sizeof(*scaler), GFP_KERNEL);
+       if (!scaler)
+               return -ENOMEM;
+
+       dcss->scaler = scaler;
+       scaler->dev = dcss->dev;
+       scaler->ctxld = dcss->ctxld;
+       scaler->ctx_id = CTX_SB_HP;
+
+       if (dcss_scaler_ch_init_all(scaler, scaler_base)) {
+               int i;
+
+               for (i = 0; i < 3; i++) {
+                       if (scaler->ch[i].base_reg)
+                               iounmap(scaler->ch[i].base_reg);
+               }
+
+               kfree(scaler);
+
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void dcss_scaler_exit(struct dcss_scaler *scl)
+{
+       int ch_no;
+
+       for (ch_no = 0; ch_no < 3; ch_no++) {
+               struct dcss_scaler_ch *ch = &scl->ch[ch_no];
+
+               dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
+
+               if (ch->base_reg)
+                       iounmap(ch->base_reg);
+       }
+
+       kfree(scl);
+}
+
+void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en)
+{
+       struct dcss_scaler_ch *ch = &scl->ch[ch_num];
+       u32 scaler_ctrl;
+
+       scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
+
+       if (en)
+               dcss_scaler_write(ch, ch->sdata_ctrl, DCSS_SCALER_SDATA_CTRL);
+
+       if (ch->scaler_ctrl != scaler_ctrl)
+               ch->scaler_ctrl_chgd = true;
+
+       ch->scaler_ctrl = scaler_ctrl;
+}
+
+static void dcss_scaler_yuv_enable(struct dcss_scaler_ch *ch, bool en)
+{
+       ch->sdata_ctrl &= ~YUV_EN;
+       ch->sdata_ctrl |= en ? YUV_EN : 0;
+}
+
+static void dcss_scaler_rtr_8lines_enable(struct dcss_scaler_ch *ch, bool en)
+{
+       ch->sdata_ctrl &= ~RTRAM_8LINES;
+       ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
+}
+
+static void dcss_scaler_bit_depth_set(struct dcss_scaler_ch *ch, int depth)
+{
+       u32 val;
+
+       val = depth == 30 ? 2 : 0;
+
+       dcss_scaler_write(ch,
+                         ((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
+                         ((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
+                         DCSS_SCALER_BIT_DEPTH);
+}
+
+enum buffer_format {
+       BUF_FMT_YUV420,
+       BUF_FMT_YUV422,
+       BUF_FMT_ARGB8888_YUV444,
+};
+
+enum chroma_location {
+       PSC_LOC_HORZ_0_VERT_1_OVER_4 = 0,
+       PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4 = 1,
+       PSC_LOC_HORZ_0_VERT_0 = 2,
+       PSC_LOC_HORZ_1_OVER_4_VERT_0 = 3,
+       PSC_LOC_HORZ_0_VERT_1_OVER_2 = 4,
+       PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2 = 5
+};
+
+static void dcss_scaler_format_set(struct dcss_scaler_ch *ch,
+                                  enum buffer_format src_fmt,
+                                  enum buffer_format dst_fmt)
+{
+       dcss_scaler_write(ch, src_fmt, DCSS_SCALER_SRC_FORMAT);
+       dcss_scaler_write(ch, dst_fmt, DCSS_SCALER_DST_FORMAT);
+}
+
+static void dcss_scaler_res_set(struct dcss_scaler_ch *ch,
+                               int src_xres, int src_yres,
+                               int dst_xres, int dst_yres,
+                               u32 pix_format, enum buffer_format dst_format)
+{
+       u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
+       u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
+       bool src_is_444 = true;
+
+       lsrc_xres = src_xres;
+       csrc_xres = src_xres;
+       lsrc_yres = src_yres;
+       csrc_yres = src_yres;
+       ldst_xres = dst_xres;
+       cdst_xres = dst_xres;
+       ldst_yres = dst_yres;
+       cdst_yres = dst_yres;
+
+       if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
+           pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
+               csrc_xres >>= 1;
+               src_is_444 = false;
+       } else if (pix_format == DRM_FORMAT_NV12 ||
+                  pix_format == DRM_FORMAT_NV21) {
+               csrc_xres >>= 1;
+               csrc_yres >>= 1;
+               src_is_444 = false;
+       }
+
+       if (dst_format == BUF_FMT_YUV422)
+               cdst_xres >>= 1;
+
+       /* for 4:4:4 to 4:2:2 conversion, source height should be 1 less */
+       if (src_is_444 && dst_format == BUF_FMT_YUV422) {
+               lsrc_yres--;
+               csrc_yres--;
+       }
+
+       dcss_scaler_write(ch, (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                              (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_SRC_LUM_RES);
+       dcss_scaler_write(ch, (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                              (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_SRC_CHR_RES);
+       dcss_scaler_write(ch, (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                              (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_DST_LUM_RES);
+       dcss_scaler_write(ch, (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                              (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_DST_CHR_RES);
+}
+
+#define downscale_fp(factor, fp_pos)           ((factor) << (fp_pos))
+#define upscale_fp(factor, fp_pos)             ((1 << (fp_pos)) / (factor))
+
+struct dcss_scaler_factors {
+       int downscale;
+       int upscale;
+};
+
+static const struct dcss_scaler_factors dcss_scaler_factors[] = {
+       {3, 8}, {5, 8}, {5, 8},
+};
+
+static void dcss_scaler_fractions_set(struct dcss_scaler_ch *ch,
+                                     int src_xres, int src_yres,
+                                     int dst_xres, int dst_yres,
+                                     u32 src_format, u32 dst_format,
+                                     enum chroma_location src_chroma_loc)
+{
+       int src_c_xres, src_c_yres, dst_c_xres, dst_c_yres;
+       u32 l_vinc, l_hinc, c_vinc, c_hinc;
+       u32 c_vstart, c_hstart;
+
+       src_c_xres = src_xres;
+       src_c_yres = src_yres;
+       dst_c_xres = dst_xres;
+       dst_c_yres = dst_yres;
+
+       c_vstart = 0;
+       c_hstart = 0;
+
+       /* adjustments for source chroma location */
+       if (src_format == BUF_FMT_YUV420) {
+               /* vertical input chroma position adjustment */
+               switch (src_chroma_loc) {
+               case PSC_LOC_HORZ_0_VERT_1_OVER_4:
+               case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+                       /*
+                        * move chroma up to first luma line
+                        * (1/4 chroma input line spacing)
+                        */
+                       c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+                       break;
+               case PSC_LOC_HORZ_0_VERT_1_OVER_2:
+               case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+                       /*
+                        * move chroma up to first luma line
+                        * (1/2 chroma input line spacing)
+                        */
+                       c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 1));
+                       break;
+               default:
+                       break;
+               }
+               /* horizontal input chroma position adjustment */
+               switch (src_chroma_loc) {
+               case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+               case PSC_LOC_HORZ_1_OVER_4_VERT_0:
+               case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+                       /* move chroma left 1/4 chroma input sample spacing */
+                       c_hstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* adjustments to chroma resolution */
+       if (src_format == BUF_FMT_YUV420) {
+               src_c_xres >>= 1;
+               src_c_yres >>= 1;
+       } else if (src_format == BUF_FMT_YUV422) {
+               src_c_xres >>= 1;
+       }
+
+       if (dst_format == BUF_FMT_YUV422)
+               dst_c_xres >>= 1;
+
+       l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
+       c_vinc = ((src_c_yres << 13) + (dst_c_yres >> 1)) / dst_c_yres;
+       l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
+       c_hinc = ((src_c_xres << 13) + (dst_c_xres >> 1)) / dst_c_xres;
+
+       /* save chroma start phase */
+       ch->c_vstart = c_vstart;
+       ch->c_hstart = c_hstart;
+
+       dcss_scaler_write(ch, 0, DCSS_SCALER_V_LUM_START);
+       dcss_scaler_write(ch, l_vinc, DCSS_SCALER_V_LUM_INC);
+
+       dcss_scaler_write(ch, 0, DCSS_SCALER_H_LUM_START);
+       dcss_scaler_write(ch, l_hinc, DCSS_SCALER_H_LUM_INC);
+
+       dcss_scaler_write(ch, c_vstart, DCSS_SCALER_V_CHR_START);
+       dcss_scaler_write(ch, c_vinc, DCSS_SCALER_V_CHR_INC);
+
+       dcss_scaler_write(ch, c_hstart, DCSS_SCALER_H_CHR_START);
+       dcss_scaler_write(ch, c_hinc, DCSS_SCALER_H_CHR_INC);
+}
+
+int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
+                                  int *min, int *max)
+{
+       *min = upscale_fp(dcss_scaler_factors[ch_num].upscale, 16);
+       *max = downscale_fp(dcss_scaler_factors[ch_num].downscale, 16);
+
+       return 0;
+}
+
+static void dcss_scaler_program_5_coef_set(struct dcss_scaler_ch *ch,
+                                          int base_addr,
+                                          int coef[][PSC_NUM_TAPS])
+{
+       int i, phase;
+
+       for (i = 0; i < PSC_STORED_PHASES; i++) {
+               dcss_scaler_write(ch, ((coef[i][1] & 0xfff) << 16 |
+                                      (coef[i][2] & 0xfff) << 4  |
+                                      (coef[i][3] & 0xf00) >> 8),
+                                 base_addr + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[i][3] & 0x0ff) << 20 |
+                                      (coef[i][4] & 0xfff) << 8  |
+                                      (coef[i][5] & 0xff0) >> 4),
+                                 base_addr + 0x40 + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[i][5] & 0x00f) << 24),
+                                 base_addr + 0x80 + i * sizeof(u32));
+       }
+
+       /* reverse both phase and tap orderings */
+       for (phase = (PSC_NUM_PHASES >> 1) - 1;
+                       i < PSC_NUM_PHASES; i++, phase--) {
+               dcss_scaler_write(ch, ((coef[phase][5] & 0xfff) << 16 |
+                                      (coef[phase][4] & 0xfff) << 4  |
+                                      (coef[phase][3] & 0xf00) >> 8),
+                                 base_addr + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[phase][3] & 0x0ff) << 20 |
+                                      (coef[phase][2] & 0xfff) << 8  |
+                                      (coef[phase][1] & 0xff0) >> 4),
+                                 base_addr + 0x40 + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[phase][1] & 0x00f) << 24),
+                                 base_addr + 0x80 + i * sizeof(u32));
+       }
+}
+
+static void dcss_scaler_program_7_coef_set(struct dcss_scaler_ch *ch,
+                                          int base_addr,
+                                          int coef[][PSC_NUM_TAPS])
+{
+       int i, phase;
+
+       for (i = 0; i < PSC_STORED_PHASES; i++) {
+               dcss_scaler_write(ch, ((coef[i][0] & 0xfff) << 16 |
+                                      (coef[i][1] & 0xfff) << 4  |
+                                      (coef[i][2] & 0xf00) >> 8),
+                                 base_addr + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[i][2] & 0x0ff) << 20 |
+                                      (coef[i][3] & 0xfff) << 8  |
+                                      (coef[i][4] & 0xff0) >> 4),
+                                 base_addr + 0x40 + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[i][4] & 0x00f) << 24 |
+                                      (coef[i][5] & 0xfff) << 12 |
+                                      (coef[i][6] & 0xfff)),
+                                 base_addr + 0x80 + i * sizeof(u32));
+       }
+
+       /* reverse both phase and tap orderings */
+       for (phase = (PSC_NUM_PHASES >> 1) - 1;
+                       i < PSC_NUM_PHASES; i++, phase--) {
+               dcss_scaler_write(ch, ((coef[phase][6] & 0xfff) << 16 |
+                                      (coef[phase][5] & 0xfff) << 4  |
+                                      (coef[phase][4] & 0xf00) >> 8),
+                                 base_addr + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[phase][4] & 0x0ff) << 20 |
+                                      (coef[phase][3] & 0xfff) << 8  |
+                                      (coef[phase][2] & 0xff0) >> 4),
+                                 base_addr + 0x40 + i * sizeof(u32));
+               dcss_scaler_write(ch, ((coef[phase][2] & 0x00f) << 24 |
+                                      (coef[phase][1] & 0xfff) << 12 |
+                                      (coef[phase][0] & 0xfff)),
+                                 base_addr + 0x80 + i * sizeof(u32));
+       }
+}
+
+static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
+                                    enum buffer_format src_format,
+                                    enum buffer_format dst_format,
+                                    bool use_5_taps,
+                                    int src_xres, int src_yres, int dst_xres,
+                                    int dst_yres)
+{
+       int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+       bool program_5_taps = use_5_taps ||
+                             (dst_format == BUF_FMT_YUV422 &&
+                              src_format == BUF_FMT_ARGB8888_YUV444);
+
+       /* horizontal luma */
+       dcss_scaler_filter_design(src_xres, dst_xres, false,
+                                 src_xres == dst_xres, coef);
+       dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
+
+       /* vertical luma */
+       dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
+                                 src_yres == dst_yres, coef);
+
+       if (program_5_taps)
+               dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+       else
+               dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+
+       /* adjust chroma resolution */
+       if (src_format != BUF_FMT_ARGB8888_YUV444)
+               src_xres >>= 1;
+       if (src_format == BUF_FMT_YUV420)
+               src_yres >>= 1;
+       if (dst_format != BUF_FMT_ARGB8888_YUV444)
+               dst_xres >>= 1;
+       if (dst_format == BUF_FMT_YUV420) /* should not happen */
+               dst_yres >>= 1;
+
+       /* horizontal chroma */
+       dcss_scaler_filter_design(src_xres, dst_xres, false,
+                                 (src_xres == dst_xres) && (ch->c_hstart == 0),
+                                 coef);
+
+       dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef);
+
+       /* vertical chroma */
+       dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
+                                 (src_yres == dst_yres) && (ch->c_vstart == 0),
+                                 coef);
+       if (program_5_taps)
+               dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
+       else
+               dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
+}
+
+static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch,
+                                    int src_xres, int src_yres, int dst_xres,
+                                    int dst_yres)
+{
+       int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+
+       /* horizontal RGB */
+       dcss_scaler_filter_design(src_xres, dst_xres, false,
+                                 src_xres == dst_xres, coef);
+       dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
+
+       /* vertical RGB */
+       dcss_scaler_filter_design(src_yres, dst_yres, false,
+                                 src_yres == dst_yres, coef);
+       dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+}
+
+static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch,
+                                       const struct drm_format_info *format)
+{
+       u32 a2r10g10b10_format;
+
+       if (format->is_yuv)
+               return;
+
+       ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
+
+       if (format->depth != 30)
+               return;
+
+       switch (format->format) {
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_XRGB2101010:
+               a2r10g10b10_format = 0;
+               break;
+
+       case DRM_FORMAT_ABGR2101010:
+       case DRM_FORMAT_XBGR2101010:
+               a2r10g10b10_format = 5;
+               break;
+
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_RGBX1010102:
+               a2r10g10b10_format = 6;
+               break;
+
+       case DRM_FORMAT_BGRA1010102:
+       case DRM_FORMAT_BGRX1010102:
+               a2r10g10b10_format = 11;
+               break;
+
+       default:
+               a2r10g10b10_format = 0;
+               break;
+       }
+
+       ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
+}
+
+void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
+                      const struct drm_format_info *format,
+                      int src_xres, int src_yres, int dst_xres, int dst_yres,
+                      u32 vrefresh_hz)
+{
+       struct dcss_scaler_ch *ch = &scl->ch[ch_num];
+       unsigned int pixel_depth = 0;
+       bool rtr_8line_en = false;
+       bool use_5_taps = false;
+       enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
+       enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
+       u32 pix_format = format->format;
+
+       if (format->is_yuv) {
+               dcss_scaler_yuv_enable(ch, true);
+
+               if (pix_format == DRM_FORMAT_NV12 ||
+                   pix_format == DRM_FORMAT_NV21) {
+                       rtr_8line_en = true;
+                       src_format = BUF_FMT_YUV420;
+               } else if (pix_format == DRM_FORMAT_UYVY ||
+                          pix_format == DRM_FORMAT_VYUY ||
+                          pix_format == DRM_FORMAT_YUYV ||
+                          pix_format == DRM_FORMAT_YVYU) {
+                       src_format = BUF_FMT_YUV422;
+               }
+
+               use_5_taps = !rtr_8line_en;
+       } else {
+               dcss_scaler_yuv_enable(ch, false);
+
+               pixel_depth = format->depth;
+       }
+
+       dcss_scaler_fractions_set(ch, src_xres, src_yres, dst_xres,
+                                 dst_yres, src_format, dst_format,
+                                 PSC_LOC_HORZ_0_VERT_1_OVER_4);
+
+       if (format->is_yuv)
+               dcss_scaler_yuv_coef_set(ch, src_format, dst_format,
+                                        use_5_taps, src_xres, src_yres,
+                                        dst_xres, dst_yres);
+       else
+               dcss_scaler_rgb_coef_set(ch, src_xres, src_yres,
+                                        dst_xres, dst_yres);
+
+       dcss_scaler_rtr_8lines_enable(ch, rtr_8line_en);
+       dcss_scaler_bit_depth_set(ch, pixel_depth);
+       dcss_scaler_set_rgb10_order(ch, format);
+       dcss_scaler_format_set(ch, src_format, dst_format);
+       dcss_scaler_res_set(ch, src_xres, src_yres, dst_xres, dst_yres,
+                           pix_format, dst_format);
+}
+
+/* This function will be called from interrupt context. */
+void dcss_scaler_write_sclctrl(struct dcss_scaler *scl)
+{
+       int chnum;
+
+       dcss_ctxld_assert_locked(scl->ctxld);
+
+       for (chnum = 0; chnum < 3; chnum++) {
+               struct dcss_scaler_ch *ch = &scl->ch[chnum];
+
+               if (ch->scaler_ctrl_chgd) {
+                       dcss_ctxld_write_irqsafe(scl->ctxld, scl->ctx_id,
+                                                ch->scaler_ctrl,
+                                                ch->base_ofs +
+                                                DCSS_SCALER_CTRL);
+                       ch->scaler_ctrl_chgd = false;
+               }
+       }
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-ss.c b/drivers/gpu/drm/imx/dcss/dcss-ss.c
new file mode 100644 (file)
index 0000000..8ddf08d
--- /dev/null
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_SS_SYS_CTRL                       0x00
+#define   RUN_EN                               BIT(0)
+#define DCSS_SS_DISPLAY                                0x10
+#define   LRC_X_POS                            0
+#define   LRC_X_MASK                           GENMASK(12, 0)
+#define   LRC_Y_POS                            16
+#define   LRC_Y_MASK                           GENMASK(28, 16)
+#define DCSS_SS_HSYNC                          0x20
+#define DCSS_SS_VSYNC                          0x30
+#define   SYNC_START_POS                       0
+#define   SYNC_START_MASK                      GENMASK(12, 0)
+#define   SYNC_END_POS                         16
+#define   SYNC_END_MASK                                GENMASK(28, 16)
+#define   SYNC_POL                             BIT(31)
+#define DCSS_SS_DE_ULC                         0x40
+#define   ULC_X_POS                            0
+#define   ULC_X_MASK                           GENMASK(12, 0)
+#define   ULC_Y_POS                            16
+#define   ULC_Y_MASK                           GENMASK(28, 16)
+#define   ULC_POL                              BIT(31)
+#define DCSS_SS_DE_LRC                         0x50
+#define DCSS_SS_MODE                           0x60
+#define   PIPE_MODE_POS                                0
+#define   PIPE_MODE_MASK                       GENMASK(1, 0)
+#define DCSS_SS_COEFF                          0x70
+#define   HORIZ_A_POS                          0
+#define   HORIZ_A_MASK                         GENMASK(3, 0)
+#define   HORIZ_B_POS                          4
+#define   HORIZ_B_MASK                         GENMASK(7, 4)
+#define   HORIZ_C_POS                          8
+#define   HORIZ_C_MASK                         GENMASK(11, 8)
+#define   HORIZ_H_NORM_POS                     12
+#define   HORIZ_H_NORM_MASK                    GENMASK(14, 12)
+#define   VERT_A_POS                           16
+#define   VERT_A_MASK                          GENMASK(19, 16)
+#define   VERT_B_POS                           20
+#define   VERT_B_MASK                          GENMASK(23, 20)
+#define   VERT_C_POS                           24
+#define   VERT_C_MASK                          GENMASK(27, 24)
+#define   VERT_H_NORM_POS                      28
+#define   VERT_H_NORM_MASK                     GENMASK(30, 28)
+#define DCSS_SS_CLIP_CB                                0x80
+#define DCSS_SS_CLIP_CR                                0x90
+#define   CLIP_MIN_POS                         0
+#define   CLIP_MIN_MASK                                GENMASK(9, 0)
+#define   CLIP_MAX_POS                         0
+#define   CLIP_MAX_MASK                                GENMASK(23, 16)
+#define DCSS_SS_INTER_MODE                     0xA0
+#define   INT_EN                               BIT(0)
+#define   VSYNC_SHIFT                          BIT(1)
+
+struct dcss_ss {
+       struct device *dev;
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       struct dcss_ctxld *ctxld;
+       u32 ctx_id;
+
+       bool in_use;
+};
+
+static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs)
+{
+       if (!ss->in_use)
+               dcss_writel(val, ss->base_reg + ofs);
+
+       dcss_ctxld_write(ss->ctxld, ss->ctx_id, val,
+                        ss->base_ofs + ofs);
+}
+
+int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
+{
+       struct dcss_ss *ss;
+
+       ss = kzalloc(sizeof(*ss), GFP_KERNEL);
+       if (!ss)
+               return -ENOMEM;
+
+       dcss->ss = ss;
+       ss->dev = dcss->dev;
+       ss->ctxld = dcss->ctxld;
+
+       ss->base_reg = ioremap(ss_base, SZ_4K);
+       if (!ss->base_reg) {
+               dev_err(dcss->dev, "ss: unable to remap ss base\n");
+               kfree(ss);
+               return -ENOMEM;
+       }
+
+       ss->base_ofs = ss_base;
+       ss->ctx_id = CTX_SB_HP;
+
+       return 0;
+}
+
+void dcss_ss_exit(struct dcss_ss *ss)
+{
+       /* stop SS */
+       dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
+
+       if (ss->base_reg)
+               iounmap(ss->base_reg);
+
+       kfree(ss);
+}
+
+void dcss_ss_subsam_set(struct dcss_ss *ss)
+{
+       dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF);
+       dcss_ss_write(ss, 0, DCSS_SS_MODE);
+       dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
+       dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
+}
+
+void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
+                     bool phsync, bool pvsync)
+{
+       u16 lrc_x, lrc_y;
+       u16 hsync_start, hsync_end;
+       u16 vsync_start, vsync_end;
+       u16 de_ulc_x, de_ulc_y;
+       u16 de_lrc_x, de_lrc_y;
+
+       lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+               vm->hactive - 1;
+       lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+               vm->vactive - 1;
+
+       dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
+
+       hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+                     vm->hactive - 1;
+       hsync_end = vm->hsync_len - 1;
+
+       dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
+                     ((u32)hsync_end << SYNC_END_POS) | hsync_start,
+                     DCSS_SS_HSYNC);
+
+       vsync_start = vm->vfront_porch - 1;
+       vsync_end = vm->vfront_porch + vm->vsync_len - 1;
+
+       dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
+                     ((u32)vsync_end << SYNC_END_POS) | vsync_start,
+                     DCSS_SS_VSYNC);
+
+       de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+       de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
+
+       dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x,
+                     DCSS_SS_DE_ULC);
+
+       de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+       de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+                  vm->vactive - 1;
+
+       dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
+}
+
+void dcss_ss_enable(struct dcss_ss *ss)
+{
+       dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
+       ss->in_use = true;
+}
+
+void dcss_ss_shutoff(struct dcss_ss *ss)
+{
+       dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
+       ss->in_use = false;
+}
index b2f49152b4d4c268ac47fc9634bb1c5d20dcf908..b4553caaa196b1965b6b701334101d6004cdf8ec 100644 (file)
@@ -126,7 +126,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
 
                msm_obj->pages = p;
 
-               msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
+               msm_obj->sgt = drm_prime_pages_to_sg(obj->dev, p, npages);
                if (IS_ERR(msm_obj->sgt)) {
                        void *ptr = ERR_CAST(msm_obj->sgt);
 
index d7c8948427fe005e7f315e0cc8aafe1e14068445..515ef80816a0d277d6b77dca4b1dd7e3246bfdef 100644 (file)
@@ -19,7 +19,7 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
        if (WARN_ON(!msm_obj->pages))  /* should have already pinned! */
                return NULL;
 
-       return drm_prime_pages_to_sg(msm_obj->pages, npages);
+       return drm_prime_pages_to_sg(obj->dev, msm_obj->pages, npages);
 }
 
 void *msm_gem_prime_vmap(struct drm_gem_object *obj)
index 6416b6907aeb0d737690a4d517e0228baa44bf0d..f9e962fd94d0d31f01d342fd7c44ad11d60ac95f 100644 (file)
@@ -615,7 +615,7 @@ nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ret;
 
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false);
+       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
        if (ret == 0) {
                if (disp->image[nv_crtc->index])
                        nouveau_bo_unpin(disp->image[nv_crtc->index]);
@@ -1172,7 +1172,7 @@ nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                return -ENOMEM;
 
        if (new_bo != old_bo) {
-               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true);
+               ret = nouveau_bo_pin(new_bo, NOUVEAU_GEM_DOMAIN_VRAM, true);
                if (ret)
                        goto fail_free;
        }
@@ -1336,10 +1336,11 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
        drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
 
        ret = nouveau_bo_new(&nouveau_drm(dev)->client, 64*64*4, 0x100,
-                            TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL,
+                            NOUVEAU_GEM_DOMAIN_VRAM, 0, 0x0000, NULL, NULL,
                             &nv_crtc->cursor.nvbo);
        if (!ret) {
-               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, false);
+               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo,
+                                    NOUVEAU_GEM_DOMAIN_VRAM, false);
                if (!ret) {
                        ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
                        if (ret)
index 3ee836dc5058f5799997a1836c7a9855ab270a9c..7739f46470d3e1215402e541f55194d6764d34a9 100644 (file)
@@ -134,7 +134,7 @@ nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
                if (!fb || !fb->obj[0])
                        continue;
                nvbo = nouveau_gem_object(fb->obj[0]);
-               ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
+               ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, true);
                if (ret)
                        NV_ERROR(drm, "Could not pin framebuffer\n");
        }
@@ -144,7 +144,8 @@ nv04_display_init(struct drm_device *dev, bool resume, bool runtime)
                if (!nv_crtc->cursor.nvbo)
                        continue;
 
-               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true);
+               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo,
+                                    NOUVEAU_GEM_DOMAIN_VRAM, true);
                if (!ret && nv_crtc->cursor.set_offset)
                        ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
                if (ret)
index 193ba9498f3d315fb20d3d5df697e93045f0d714..37e63e98cd08afbaf1b980ff456db43a98c75d50 100644 (file)
@@ -142,7 +142,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                return ret;
 
        nvbo = nouveau_gem_object(fb->obj[0]);
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false);
+       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
        if (ret)
                return ret;
 
@@ -387,7 +387,7 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                return ret;
 
        nvbo = nouveau_gem_object(fb->obj[0]);
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false);
+       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
        if (ret)
                return ret;
 
index 7799530e07c1f6f4cc477aff02acacf7d03ef6ae..852e1b56f3a7cbd7f806982a3aa9057a2bb51f0a 100644 (file)
@@ -2622,10 +2622,11 @@ nv50_display_create(struct drm_device *dev)
        dev->mode_config.normalize_zpos = true;
 
        /* small shared memory area we use for notifiers and semaphores */
-       ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+       ret = nouveau_bo_new(&drm->client, 4096, 0x1000,
+                            NOUVEAU_GEM_DOMAIN_VRAM,
                             0, 0x0000, NULL, NULL, &disp->sync);
        if (!ret) {
-               ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, true);
+               ret = nouveau_bo_pin(disp->sync, NOUVEAU_GEM_DOMAIN_VRAM, true);
                if (!ret) {
                        ret = nouveau_bo_map(disp->sync);
                        if (ret)
index 447ecc9fec42cc9f23d4545c7a74766091afaf8b..0356474ad6f6afcd37e5c9540968d406fb5b41bc 100644 (file)
@@ -542,7 +542,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
                return 0;
 
        nvbo = nouveau_gem_object(fb->obj[0]);
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
+       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, true);
        if (ret)
                return ret;
 
index 21537ca1dd392b1a84bd7ca499bf4a2d44bac3b8..9a5be6f3242496013779cd78c9f509a36e95bb8b 100644 (file)
@@ -328,7 +328,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
        ret = nouveau_gem_new(cli, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
                              0, 0, &chan->ntfy);
        if (ret == 0)
-               ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false);
+               ret = nouveau_bo_pin(chan->ntfy, NOUVEAU_GEM_DOMAIN_GART,
+                                    false);
        if (ret)
                goto done;
 
index 9140387f30dcbd694c271161b3b2ddf78e7d2ae1..97e1908eada07795c2fbc21abb522e3ee5238bcb 100644 (file)
@@ -137,6 +137,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
        struct nouveau_bo *nvbo = nouveau_bo(bo);
 
        WARN_ON(nvbo->pin_refcnt > 0);
+       nouveau_bo_del_io_reserve_lru(bo);
        nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
 
        /*
@@ -158,8 +159,7 @@ roundup_64(u64 x, u32 y)
 }
 
 static void
-nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
-                      int *align, u64 *size)
+nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, u64 *size)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct nvif_device *device = &drm->client.device;
@@ -192,7 +192,7 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
 }
 
 struct nouveau_bo *
-nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 flags,
+nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain,
                 u32 tile_mode, u32 tile_flags)
 {
        struct nouveau_drm *drm = cli->drm;
@@ -218,7 +218,7 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 flags,
         * mapping, but is what NOUVEAU_GEM_DOMAIN_COHERENT gets translated
         * into in nouveau_gem_new().
         */
-       if (flags & TTM_PL_FLAG_UNCACHED) {
+       if (domain & NOUVEAU_GEM_DOMAIN_COHERENT) {
                /* Determine if we can get a cache-coherent map, forcing
                 * uncached mapping if we can't.
                 */
@@ -258,9 +258,9 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 flags,
                 * Skip page sizes that can't support needed domains.
                 */
                if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE &&
-                   (flags & TTM_PL_FLAG_VRAM) && !vmm->page[i].vram)
+                   (domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram)
                        continue;
-               if ((flags & TTM_PL_FLAG_TT) &&
+               if ((domain & NOUVEAU_GEM_DOMAIN_GART) &&
                    (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT))
                        continue;
 
@@ -287,13 +287,13 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 flags,
        }
        nvbo->page = vmm->page[pi].shift;
 
-       nouveau_bo_fixup_align(nvbo, flags, align, size);
+       nouveau_bo_fixup_align(nvbo, align, size);
 
        return nvbo;
 }
 
 int
-nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 flags,
+nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 domain,
                struct sg_table *sg, struct dma_resv *robj)
 {
        int type = sg ? ttm_bo_type_sg : ttm_bo_type_device;
@@ -303,7 +303,8 @@ nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 flags,
        acc_size = ttm_bo_dma_acc_size(nvbo->bo.bdev, size, sizeof(*nvbo));
 
        nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
-       nouveau_bo_placement_set(nvbo, flags, 0);
+       nouveau_bo_placement_set(nvbo, domain, 0);
+       INIT_LIST_HEAD(&nvbo->io_reserve_lru);
 
        ret = ttm_bo_init(nvbo->bo.bdev, &nvbo->bo, size, type,
                          &nvbo->placement, align >> PAGE_SHIFT, false,
@@ -318,19 +319,19 @@ nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 flags,
 
 int
 nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
-              uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
+              uint32_t domain, uint32_t tile_mode, uint32_t tile_flags,
               struct sg_table *sg, struct dma_resv *robj,
               struct nouveau_bo **pnvbo)
 {
        struct nouveau_bo *nvbo;
        int ret;
 
-       nvbo = nouveau_bo_alloc(cli, &size, &align, flags, tile_mode,
+       nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode,
                                tile_flags);
        if (IS_ERR(nvbo))
                return PTR_ERR(nvbo);
 
-       ret = nouveau_bo_init(nvbo, size, align, flags, sg, robj);
+       ret = nouveau_bo_init(nvbo, size, align, domain, sg, robj);
        if (ret)
                return ret;
 
@@ -339,27 +340,34 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
 }
 
 static void
-set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t type, uint32_t flags)
+set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t domain,
+                  uint32_t flags)
 {
        *n = 0;
 
-       if (type & TTM_PL_FLAG_VRAM)
-               pl[(*n)++].flags = TTM_PL_FLAG_VRAM | flags;
-       if (type & TTM_PL_FLAG_TT)
-               pl[(*n)++].flags = TTM_PL_FLAG_TT | flags;
-       if (type & TTM_PL_FLAG_SYSTEM)
-               pl[(*n)++].flags = TTM_PL_FLAG_SYSTEM | flags;
+       if (domain & NOUVEAU_GEM_DOMAIN_VRAM) {
+               pl[*n].mem_type = TTM_PL_VRAM;
+               pl[(*n)++].flags = flags;
+       }
+       if (domain & NOUVEAU_GEM_DOMAIN_GART) {
+               pl[*n].mem_type = TTM_PL_TT;
+               pl[(*n)++].flags = flags;
+       }
+       if (domain & NOUVEAU_GEM_DOMAIN_CPU) {
+               pl[*n].mem_type = TTM_PL_SYSTEM;
+               pl[(*n)++].flags = flags;
+       }
 }
 
 static void
-set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
+set_placement_range(struct nouveau_bo *nvbo, uint32_t domain)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        u32 vram_pages = drm->client.device.info.ram_size >> PAGE_SHIFT;
        unsigned i, fpfn, lpfn;
 
        if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
-           nvbo->mode && (type & TTM_PL_FLAG_VRAM) &&
+           nvbo->mode && (domain & NOUVEAU_GEM_DOMAIN_VRAM) &&
            nvbo->bo.mem.num_pages < vram_pages / 4) {
                /*
                 * Make sure that the color and depth buffers are handled
@@ -386,7 +394,8 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
 }
 
 void
-nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
+nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t domain,
+                        uint32_t busy)
 {
        struct ttm_placement *pl = &nvbo->placement;
        uint32_t flags = (nvbo->force_coherent ? TTM_PL_FLAG_UNCACHED :
@@ -395,17 +404,17 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 
        pl->placement = nvbo->placements;
        set_placement_list(nvbo->placements, &pl->num_placement,
-                          type, flags);
+                          domain, flags);
 
        pl->busy_placement = nvbo->busy_placements;
        set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
-                          type | busy, flags);
+                          domain | busy, flags);
 
-       set_placement_range(nvbo, type);
+       set_placement_range(nvbo, domain);
 }
 
 int
-nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
+nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
@@ -417,7 +426,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
                return ret;
 
        if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
-           memtype == TTM_PL_FLAG_VRAM && contig) {
+           domain == NOUVEAU_GEM_DOMAIN_VRAM && contig) {
                if (!nvbo->contig) {
                        nvbo->contig = true;
                        force = true;
@@ -426,10 +435,22 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
        }
 
        if (nvbo->pin_refcnt) {
-               if (!(memtype & (1 << bo->mem.mem_type)) || evict) {
+               bool error = evict;
+
+               switch (bo->mem.mem_type) {
+               case TTM_PL_VRAM:
+                       error |= !(domain & NOUVEAU_GEM_DOMAIN_VRAM);
+                       break;
+               case TTM_PL_TT:
+                       error |= !(domain & NOUVEAU_GEM_DOMAIN_GART);
+               default:
+                       break;
+               }
+
+               if (error) {
                        NV_ERROR(drm, "bo %p pinned elsewhere: "
                                      "0x%08x vs 0x%08x\n", bo,
-                                1 << bo->mem.mem_type, memtype);
+                                bo->mem.mem_type, domain);
                        ret = -EBUSY;
                }
                nvbo->pin_refcnt++;
@@ -437,14 +458,14 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
        }
 
        if (evict) {
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT, 0);
+               nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
                ret = nouveau_bo_validate(nvbo, false, false);
                if (ret)
                        goto out;
        }
 
        nvbo->pin_refcnt++;
-       nouveau_bo_placement_set(nvbo, memtype, 0);
+       nouveau_bo_placement_set(nvbo, domain, 0);
 
        /* drop pin_refcnt temporarily, so we don't trip the assertion
         * in nouveau_bo_move() that makes sure we're not trying to
@@ -490,7 +511,16 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
        if (ref)
                goto out;
 
-       nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
+       switch (bo->mem.mem_type) {
+       case TTM_PL_VRAM:
+               nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, 0);
+               break;
+       case TTM_PL_TT:
+               nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
+               break;
+       default:
+               break;
+       }
 
        ret = nouveau_bo_validate(nvbo, false, false);
        if (ret == 0) {
@@ -574,6 +604,26 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
                                        PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
+void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo)
+{
+       struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
+       struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+       mutex_lock(&drm->ttm.io_reserve_mutex);
+       list_move_tail(&nvbo->io_reserve_lru, &drm->ttm.io_reserve_lru);
+       mutex_unlock(&drm->ttm.io_reserve_mutex);
+}
+
+void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo)
+{
+       struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
+       struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+       mutex_lock(&drm->ttm.io_reserve_mutex);
+       list_del_init(&nvbo->io_reserve_lru);
+       mutex_unlock(&drm->ttm.io_reserve_mutex);
+}
+
 int
 nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
                    bool no_wait_gpu)
@@ -646,6 +696,33 @@ nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
        return nouveau_sgdma_create_ttm(bo, page_flags);
 }
 
+static int
+nouveau_ttm_tt_bind(struct ttm_bo_device *bdev, struct ttm_tt *ttm,
+                   struct ttm_resource *reg)
+{
+#if IS_ENABLED(CONFIG_AGP)
+       struct nouveau_drm *drm = nouveau_bdev(bdev);
+
+       if (drm->agp.bridge)
+               return ttm_agp_bind(ttm, reg);
+#endif
+       return nouveau_sgdma_bind(bdev, ttm, reg);
+}
+
+static void
+nouveau_ttm_tt_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
+{
+#if IS_ENABLED(CONFIG_AGP)
+       struct nouveau_drm *drm = nouveau_bdev(bdev);
+
+       if (drm->agp.bridge) {
+               ttm_agp_unbind(ttm);
+               return;
+       }
+#endif
+       nouveau_sgdma_unbind(bdev, ttm);
+}
+
 static void
 nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 {
@@ -653,11 +730,11 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 
        switch (bo->mem.mem_type) {
        case TTM_PL_VRAM:
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT,
-                                        TTM_PL_FLAG_SYSTEM);
+               nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART,
+                                        NOUVEAU_GEM_DOMAIN_CPU);
                break;
        default:
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM, 0);
+               nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_CPU, 0);
                break;
        }
 
@@ -811,7 +888,8 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
        struct ttm_place placement_memtype = {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
+               .mem_type = TTM_PL_TT,
+               .flags = TTM_PL_MASK_CACHING
        };
        struct ttm_placement placement;
        struct ttm_resource tmp_reg;
@@ -826,7 +904,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                return ret;
 
-       ret = ttm_tt_bind(bo->ttm, &tmp_reg, &ctx);
+       ret = ttm_tt_bind(bo->bdev, bo->ttm, &tmp_reg, &ctx);
        if (ret)
                goto out;
 
@@ -848,7 +926,8 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
        struct ttm_place placement_memtype = {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
+               .mem_type = TTM_PL_TT,
+               .flags = TTM_PL_MASK_CACHING
        };
        struct ttm_placement placement;
        struct ttm_resource tmp_reg;
@@ -888,6 +967,8 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
        if (bo->destroy != nouveau_bo_del_ttm)
                return;
 
+       nouveau_bo_del_io_reserve_lru(bo);
+
        if (mem && new_reg->mem_type != TTM_PL_SYSTEM &&
            mem->mem.page == nvbo->page) {
                list_for_each_entry(vma, &nvbo->vma_list, head) {
@@ -969,9 +1050,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
 
        /* Fake bo copy. */
        if (old_reg->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
-               BUG_ON(bo->mem.mm_node != NULL);
-               bo->mem = *new_reg;
-               new_reg->mm_node = NULL;
+               ttm_bo_move_null(bo, new_reg);
                goto out;
        }
 
@@ -1018,32 +1097,60 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
                                          filp->private_data);
 }
 
+static void
+nouveau_ttm_io_mem_free_locked(struct nouveau_drm *drm,
+                              struct ttm_resource *reg)
+{
+       struct nouveau_mem *mem = nouveau_mem(reg);
+
+       if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
+               switch (reg->mem_type) {
+               case TTM_PL_TT:
+                       if (mem->kind)
+                               nvif_object_unmap_handle(&mem->mem.object);
+                       break;
+               case TTM_PL_VRAM:
+                       nvif_object_unmap_handle(&mem->mem.object);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
 static int
 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);
        struct nouveau_mem *mem = nouveau_mem(reg);
+       int ret;
 
+       mutex_lock(&drm->ttm.io_reserve_mutex);
+retry:
        switch (reg->mem_type) {
        case TTM_PL_SYSTEM:
                /* System memory */
-               return 0;
+               ret = 0;
+               goto out;
        case TTM_PL_TT:
 #if IS_ENABLED(CONFIG_AGP)
                if (drm->agp.bridge) {
-                       reg->bus.offset = reg->start << PAGE_SHIFT;
-                       reg->bus.base = drm->agp.base;
+                       reg->bus.offset = (reg->start << PAGE_SHIFT) +
+                               drm->agp.base;
                        reg->bus.is_iomem = !drm->agp.cma;
                }
 #endif
-               if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 || !mem->kind)
+               if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 ||
+                   !mem->kind) {
                        /* untiled */
+                       ret = 0;
                        break;
+               }
                fallthrough;    /* tiled memory */
        case TTM_PL_VRAM:
-               reg->bus.offset = reg->start << PAGE_SHIFT;
-               reg->bus.base = device->func->resource_addr(device, 1);
+               reg->bus.offset = (reg->start << PAGE_SHIFT) +
+                       device->func->resource_addr(device, 1);
                reg->bus.is_iomem = true;
                if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
                        union {
@@ -1052,7 +1159,6 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
                        } args;
                        u64 handle, length;
                        u32 argc = 0;
-                       int ret;
 
                        switch (mem->mem.object.oclass) {
                        case NVIF_CLASS_MEM_NV50:
@@ -1078,39 +1184,46 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
                                                     &handle, &length);
                        if (ret != 1) {
                                if (WARN_ON(ret == 0))
-                                       return -EINVAL;
-                               return ret;
+                                       ret = -EINVAL;
+                               goto out;
                        }
 
-                       reg->bus.base = 0;
                        reg->bus.offset = handle;
+                       ret = 0;
                }
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
-       return 0;
+
+out:
+       if (ret == -ENOSPC) {
+               struct nouveau_bo *nvbo;
+
+               nvbo = list_first_entry_or_null(&drm->ttm.io_reserve_lru,
+                                               typeof(*nvbo),
+                                               io_reserve_lru);
+               if (nvbo) {
+                       list_del_init(&nvbo->io_reserve_lru);
+                       drm_vma_node_unmap(&nvbo->bo.base.vma_node,
+                                          bdev->dev_mapping);
+                       nouveau_ttm_io_mem_free_locked(drm, &nvbo->bo.mem);
+                       goto retry;
+               }
+
+       }
+       mutex_unlock(&drm->ttm.io_reserve_mutex);
+       return ret;
 }
 
 static void
 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);
 
-       if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
-               switch (reg->mem_type) {
-               case TTM_PL_TT:
-                       if (mem->kind)
-                               nvif_object_unmap_handle(&mem->mem.object);
-                       break;
-               case TTM_PL_VRAM:
-                       nvif_object_unmap_handle(&mem->mem.object);
-                       break;
-               default:
-                       break;
-               }
-       }
+       mutex_lock(&drm->ttm.io_reserve_mutex);
+       nouveau_ttm_io_mem_free_locked(drm, reg);
+       mutex_unlock(&drm->ttm.io_reserve_mutex);
 }
 
 static int
@@ -1131,7 +1244,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
                        return 0;
 
                if (bo->mem.mem_type == TTM_PL_SYSTEM) {
-                       nouveau_bo_placement_set(nvbo, TTM_PL_TT, 0);
+                       nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART,
+                                                0);
 
                        ret = nouveau_bo_validate(nvbo, false, false);
                        if (ret)
@@ -1155,12 +1269,13 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
                nvbo->busy_placements[i].lpfn = mappable;
        }
 
-       nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0);
+       nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, 0);
        return nouveau_bo_validate(nvbo, false, false);
 }
 
 static int
-nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
+nouveau_ttm_tt_populate(struct ttm_bo_device *bdev,
+                       struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
 {
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
@@ -1178,12 +1293,12 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
                return 0;
        }
 
-       drm = nouveau_bdev(ttm->bdev);
+       drm = nouveau_bdev(bdev);
        dev = drm->dev->dev;
 
 #if IS_ENABLED(CONFIG_AGP)
        if (drm->agp.bridge) {
-               return ttm_agp_tt_populate(ttm, ctx);
+               return ttm_pool_populate(ttm, ctx);
        }
 #endif
 
@@ -1196,7 +1311,8 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
 }
 
 static void
-nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
+nouveau_ttm_tt_unpopulate(struct ttm_bo_device *bdev,
+                         struct ttm_tt *ttm)
 {
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
@@ -1206,12 +1322,12 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
        if (slave)
                return;
 
-       drm = nouveau_bdev(ttm->bdev);
+       drm = nouveau_bdev(bdev);
        dev = drm->dev->dev;
 
 #if IS_ENABLED(CONFIG_AGP)
        if (drm->agp.bridge) {
-               ttm_agp_tt_unpopulate(ttm);
+               ttm_pool_unpopulate(ttm);
                return;
        }
 #endif
@@ -1226,6 +1342,20 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
        ttm_unmap_and_unpopulate_pages(dev, ttm_dma);
 }
 
+static void
+nouveau_ttm_tt_destroy(struct ttm_bo_device *bdev,
+                      struct ttm_tt *ttm)
+{
+#if IS_ENABLED(CONFIG_AGP)
+       struct nouveau_drm *drm = nouveau_bdev(bdev);
+       if (drm->agp.bridge) {
+               ttm_agp_destroy(ttm);
+               return;
+       }
+#endif
+       nouveau_sgdma_destroy(bdev, ttm);
+}
+
 void
 nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive)
 {
@@ -1241,6 +1371,9 @@ 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,
+       .ttm_tt_bind = &nouveau_ttm_tt_bind,
+       .ttm_tt_unbind = &nouveau_ttm_tt_unbind,
+       .ttm_tt_destroy = &nouveau_ttm_tt_destroy,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = nouveau_bo_evict_flags,
        .move_notify = nouveau_bo_move_ntfy,
index aecb7481df0daca1a3e54678aa97d767f4ddface..2a23c820743625f940b91a0eae2e136b75a40480 100644 (file)
@@ -18,6 +18,7 @@ struct nouveau_bo {
        bool force_coherent;
        struct ttm_bo_kmap_obj kmap;
        struct list_head head;
+       struct list_head io_reserve_lru;
 
        /* protected by ttm_bo_reserve() */
        struct drm_file *reserved_by;
@@ -76,10 +77,10 @@ extern struct ttm_bo_driver nouveau_bo_driver;
 
 void nouveau_bo_move_init(struct nouveau_drm *);
 struct nouveau_bo *nouveau_bo_alloc(struct nouveau_cli *, u64 *size, int *align,
-                                   u32 flags, u32 tile_mode, u32 tile_flags);
-int  nouveau_bo_init(struct nouveau_bo *, u64 size, int align, u32 flags,
+                                   u32 domain, u32 tile_mode, u32 tile_flags);
+int  nouveau_bo_init(struct nouveau_bo *, u64 size, int align, u32 domain,
                     struct sg_table *sg, struct dma_resv *robj);
-int  nouveau_bo_new(struct nouveau_cli *, u64 size, int align, u32 flags,
+int  nouveau_bo_new(struct nouveau_cli *, u64 size, int align, u32 domain,
                    u32 tile_mode, u32 tile_flags, struct sg_table *sg,
                    struct dma_resv *robj,
                    struct nouveau_bo **);
@@ -96,6 +97,8 @@ int  nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
                         bool no_wait_gpu);
 void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
 void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
+void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo);
+void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo);
 
 /* TODO: submit equivalent to TTM generic API upstream? */
 static inline void __iomem *
@@ -119,13 +122,13 @@ nouveau_bo_unmap_unpin_unref(struct nouveau_bo **pnvbo)
 }
 
 static inline int
-nouveau_bo_new_pin_map(struct nouveau_cli *cli, u64 size, int align, u32 flags,
+nouveau_bo_new_pin_map(struct nouveau_cli *cli, u64 size, int align, u32 domain,
                       struct nouveau_bo **pnvbo)
 {
-       int ret = nouveau_bo_new(cli, size, align, flags,
+       int ret = nouveau_bo_new(cli, size, align, domain,
                                 0, 0, NULL, NULL, pnvbo);
        if (ret == 0) {
-               ret = nouveau_bo_pin(*pnvbo, flags, true);
+               ret = nouveau_bo_pin(*pnvbo, domain, true);
                if (ret == 0) {
                        ret = nouveau_bo_map(*pnvbo);
                        if (ret == 0)
index b80e4ebf14a6e78a12adca09a5f396cc6e0785a5..8f099601d2f2d828d2b75a660f68d76328672753 100644 (file)
@@ -163,9 +163,9 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
        atomic_set(&chan->killed, 0);
 
        /* allocate memory for dma push buffer */
-       target = TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED;
+       target = NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
        if (nouveau_vram_pushbuf)
-               target = TTM_PL_FLAG_VRAM;
+               target = NOUVEAU_GEM_DOMAIN_VRAM;
 
        ret = nouveau_bo_new(cli, size, 0, target, 0, 0, NULL, NULL,
                            &chan->push.buffer);
index 4e8112fde3e6be502e4528e6f98bc04c125c6c5e..af70ef8e5471d21b5f8c04a568a491339580e98b 100644 (file)
@@ -254,12 +254,12 @@ nouveau_dmem_chunk_alloc(struct nouveau_drm *drm, struct page **ppage)
        chunk->pagemap.owner = drm->dev;
 
        ret = nouveau_bo_new(&drm->client, DMEM_CHUNK_SIZE, 0,
-                            TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL,
+                            NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, NULL, NULL,
                             &chunk->bo);
        if (ret)
                goto out_release;
 
-       ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
+       ret = nouveau_bo_pin(chunk->bo, NOUVEAU_GEM_DOMAIN_VRAM, false);
        if (ret)
                goto out_bo_free;
 
@@ -346,7 +346,7 @@ nouveau_dmem_resume(struct nouveau_drm *drm)
 
        mutex_lock(&drm->dmem->mutex);
        list_for_each_entry(chunk, &drm->dmem->chunks, list) {
-               ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
+               ret = nouveau_bo_pin(chunk->bo, NOUVEAU_GEM_DOMAIN_VRAM, false);
                /* FIXME handle pin failure */
                WARN_ON(ret);
        }
index 73ebf5fba2fcd7990bb9f2fe36f2e1d730761a3d..b8025507a9e4c9de9331979cf7f8a7a7bbed675a 100644 (file)
@@ -164,6 +164,8 @@ struct nouveau_drm {
                int type_vram;
                int type_host[2];
                int type_ncoh[2];
+               struct mutex io_reserve_mutex;
+               struct list_head io_reserve_lru;
        } ttm;
 
        /* GEM interface support */
index fad8030ec1f811084fcdef85c3615a7326aa34d3..24ec5339efb46880bda75eae5eb41631b0a6b02b 100644 (file)
@@ -341,7 +341,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
        if (ret)
                goto out_unref;
 
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false);
+       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
        if (ret) {
                NV_ERROR(drm, "failed to pin fb: %d\n", ret);
                goto out_unref;
@@ -378,8 +378,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
                              FBINFO_HWACCEL_FILLRECT |
                              FBINFO_HWACCEL_IMAGEBLIT;
        info->fbops = &nouveau_fbcon_sw_ops;
-       info->fix.smem_start = nvbo->bo.mem.bus.base +
-                              nvbo->bo.mem.bus.offset;
+       info->fix.smem_start = nvbo->bo.mem.bus.offset;
        info->fix.smem_len = nvbo->bo.mem.num_pages << PAGE_SHIFT;
 
        info->screen_base = nvbo_kmap_obj_iovirtual(nvbo);
index 81f111ad3f4fd8eebd2953dcde9b95077161a1da..89adadf4706b456b5f1a0d8a85ae91273dc7e842 100644 (file)
@@ -176,20 +176,12 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain,
 {
        struct nouveau_drm *drm = cli->drm;
        struct nouveau_bo *nvbo;
-       u32 flags = 0;
        int ret;
 
-       if (domain & NOUVEAU_GEM_DOMAIN_VRAM)
-               flags |= TTM_PL_FLAG_VRAM;
-       if (domain & NOUVEAU_GEM_DOMAIN_GART)
-               flags |= TTM_PL_FLAG_TT;
-       if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU)
-               flags |= TTM_PL_FLAG_SYSTEM;
+       if (!(domain & (NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART)))
+               domain |= NOUVEAU_GEM_DOMAIN_CPU;
 
-       if (domain & NOUVEAU_GEM_DOMAIN_COHERENT)
-               flags |= TTM_PL_FLAG_UNCACHED;
-
-       nvbo = nouveau_bo_alloc(cli, &size, &align, flags, tile_mode,
+       nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode,
                                tile_flags);
        if (IS_ERR(nvbo))
                return PTR_ERR(nvbo);
@@ -202,7 +194,7 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain,
                return ret;
        }
 
-       ret = nouveau_bo_init(nvbo, size, align, flags, NULL, NULL);
+       ret = nouveau_bo_init(nvbo, size, align, domain, NULL, NULL);
        if (ret) {
                nouveau_bo_ref(NULL, &nvbo);
                return ret;
@@ -296,32 +288,28 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
        struct ttm_buffer_object *bo = &nvbo->bo;
        uint32_t domains = valid_domains & nvbo->valid_domains &
                (write_domains ? write_domains : read_domains);
-       uint32_t pref_flags = 0, valid_flags = 0;
+       uint32_t pref_domains = 0;;
 
        if (!domains)
                return -EINVAL;
 
-       if (valid_domains & NOUVEAU_GEM_DOMAIN_VRAM)
-               valid_flags |= TTM_PL_FLAG_VRAM;
-
-       if (valid_domains & NOUVEAU_GEM_DOMAIN_GART)
-               valid_flags |= TTM_PL_FLAG_TT;
+       valid_domains &= ~(NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART);
 
        if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
            bo->mem.mem_type == TTM_PL_VRAM)
-               pref_flags |= TTM_PL_FLAG_VRAM;
+               pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM;
 
        else if ((domains & NOUVEAU_GEM_DOMAIN_GART) &&
                 bo->mem.mem_type == TTM_PL_TT)
-               pref_flags |= TTM_PL_FLAG_TT;
+               pref_domains |= NOUVEAU_GEM_DOMAIN_GART;
 
        else if (domains & NOUVEAU_GEM_DOMAIN_VRAM)
-               pref_flags |= TTM_PL_FLAG_VRAM;
+               pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM;
 
        else
-               pref_flags |= TTM_PL_FLAG_TT;
+               pref_domains |= NOUVEAU_GEM_DOMAIN_GART;
 
-       nouveau_bo_placement_set(nvbo, pref_flags, valid_flags);
+       nouveau_bo_placement_set(nvbo, pref_domains, valid_domains);
 
        return 0;
 }
index bae6a3eccee0b284c996c7f43b283b48aa51e835..b2ecb91f8ddc0357e74e6dbec2c9aeed8eae1abe 100644 (file)
@@ -32,7 +32,7 @@ struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *obj)
        struct nouveau_bo *nvbo = nouveau_gem_object(obj);
        int npages = nvbo->bo.num_pages;
 
-       return drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages);
+       return drm_prime_pages_to_sg(obj->dev, nvbo->bo.ttm->pages, npages);
 }
 
 void *nouveau_gem_prime_vmap(struct drm_gem_object *obj)
@@ -64,14 +64,12 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
        struct nouveau_bo *nvbo;
        struct dma_resv *robj = attach->dmabuf->resv;
        u64 size = attach->dmabuf->size;
-       u32 flags = 0;
        int align = 0;
        int ret;
 
-       flags = TTM_PL_FLAG_TT;
-
        dma_resv_lock(robj, NULL);
-       nvbo = nouveau_bo_alloc(&drm->client, &size, &align, flags, 0, 0);
+       nvbo = nouveau_bo_alloc(&drm->client, &size, &align,
+                               NOUVEAU_GEM_DOMAIN_GART, 0, 0);
        if (IS_ERR(nvbo)) {
                obj = ERR_CAST(nvbo);
                goto unlock;
@@ -88,7 +86,8 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
                goto unlock;
        }
 
-       ret = nouveau_bo_init(nvbo, size, align, flags, sg, robj);
+       ret = nouveau_bo_init(nvbo, size, align, NOUVEAU_GEM_DOMAIN_GART,
+                             sg, robj);
        if (ret) {
                nouveau_bo_ref(NULL, &nvbo);
                obj = ERR_PTR(ret);
@@ -108,7 +107,7 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj)
        int ret;
 
        /* pin buffer into GTT */
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT, false);
+       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_GART, false);
        if (ret)
                return -EINVAL;
 
index eef75c53a19713d1cc4e69400d9ad26847ce9ea7..05e542254e1f4d50140b8d85753c5aaffbabaaf9 100644 (file)
@@ -14,8 +14,8 @@ struct nouveau_sgdma_be {
        struct nouveau_mem *mem;
 };
 
-static void
-nouveau_sgdma_destroy(struct ttm_tt *ttm)
+void
+nouveau_sgdma_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
 
@@ -25,10 +25,11 @@ nouveau_sgdma_destroy(struct ttm_tt *ttm)
        }
 }
 
-static int
-nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg)
+int
+nouveau_sgdma_bind(struct ttm_bo_device *bdev, struct ttm_tt *ttm, struct ttm_resource *reg)
 {
        struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
+       struct nouveau_drm *drm = nouveau_bdev(bdev);
        struct nouveau_mem *mem = nouveau_mem(reg);
        int ret;
 
@@ -36,65 +37,34 @@ nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg)
        if (ret)
                return ret;
 
-       ret = nouveau_mem_map(mem, &mem->cli->vmm.vmm, &mem->vma[0]);
-       if (ret) {
-               nouveau_mem_fini(mem);
-               return ret;
+       if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
+               ret = nouveau_mem_map(mem, &mem->cli->vmm.vmm, &mem->vma[0]);
+               if (ret) {
+                       nouveau_mem_fini(mem);
+                       return ret;
+               }
        }
 
        nvbe->mem = mem;
        return 0;
 }
 
-static void
-nv04_sgdma_unbind(struct ttm_tt *ttm)
+void
+nouveau_sgdma_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
        nouveau_mem_fini(nvbe->mem);
 }
 
-static struct ttm_backend_func nv04_sgdma_backend = {
-       .bind                   = nv04_sgdma_bind,
-       .unbind                 = nv04_sgdma_unbind,
-       .destroy                = nouveau_sgdma_destroy
-};
-
-static int
-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);
-       int ret;
-
-       ret = nouveau_mem_host(reg, &nvbe->ttm);
-       if (ret)
-               return ret;
-
-       nvbe->mem = mem;
-       return 0;
-}
-
-static struct ttm_backend_func nv50_sgdma_backend = {
-       .bind                   = nv50_sgdma_bind,
-       .unbind                 = nv04_sgdma_unbind,
-       .destroy                = nouveau_sgdma_destroy
-};
-
 struct ttm_tt *
 nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, uint32_t page_flags)
 {
-       struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct nouveau_sgdma_be *nvbe;
 
        nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL);
        if (!nvbe)
                return NULL;
 
-       if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA)
-               nvbe->ttm.ttm.func = &nv04_sgdma_backend;
-       else
-               nvbe->ttm.ttm.func = &nv50_sgdma_backend;
-
        if (ttm_dma_tt_init(&nvbe->ttm, bo, page_flags)) {
                kfree(nvbe);
                return NULL;
index 53c6f882732283a47d58a5758c021da924b80e06..a62f37b1131ca68ab440021dba83c37e6e719e5c 100644 (file)
@@ -123,13 +123,51 @@ const struct ttm_resource_manager_func nv04_gart_manager = {
        .free = nouveau_manager_del,
 };
 
+static vm_fault_t nouveau_ttm_fault(struct vm_fault *vmf)
+{
+       struct vm_area_struct *vma = vmf->vma;
+       struct ttm_buffer_object *bo = vma->vm_private_data;
+       pgprot_t prot;
+       vm_fault_t ret;
+
+       ret = ttm_bo_vm_reserve(bo, vmf);
+       if (ret)
+               return ret;
+
+       nouveau_bo_del_io_reserve_lru(bo);
+
+       prot = vm_get_page_prot(vma->vm_flags);
+       ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT, 1);
+       if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
+               return ret;
+
+       nouveau_bo_add_io_reserve_lru(bo);
+
+       dma_resv_unlock(bo->base.resv);
+
+       return ret;
+}
+
+static struct vm_operations_struct nouveau_ttm_vm_ops = {
+       .fault = nouveau_ttm_fault,
+       .open = ttm_bo_vm_open,
+       .close = ttm_bo_vm_close,
+       .access = ttm_bo_vm_access
+};
+
 int
 nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *file_priv = filp->private_data;
        struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev);
+       int ret;
 
-       return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
+       ret = ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
+       if (ret)
+               return ret;
+
+       vma->vm_ops = &nouveau_ttm_vm_ops;
+       return 0;
 }
 
 static int
@@ -173,7 +211,6 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm)
                }
 
                man->func = &nouveau_vram_manager;
-               man->use_io_reserve_lru = true;
 
                ttm_resource_manager_init(man,
                                          drm->gem.vram_available >> PAGE_SHIFT);
@@ -339,6 +376,9 @@ nouveau_ttm_init(struct nouveau_drm *drm)
                return ret;
        }
 
+       mutex_init(&drm->ttm.io_reserve_mutex);
+       INIT_LIST_HEAD(&drm->ttm.io_reserve_lru);
+
        NV_INFO(drm, "VRAM: %d MiB\n", (u32)(drm->gem.vram_available >> 20));
        NV_INFO(drm, "GART: %d MiB\n", (u32)(drm->gem.gart_available >> 20));
        return 0;
index eaf25461cd917fec6280edac3f71bb3833bed3d6..69552049bb96d346cdcd1bfa43ceae991afe7fb1 100644 (file)
@@ -22,4 +22,7 @@ int  nouveau_ttm_mmap(struct file *, struct vm_area_struct *);
 int  nouveau_ttm_global_init(struct nouveau_drm *);
 void nouveau_ttm_global_release(struct nouveau_drm *);
 
+int nouveau_sgdma_bind(struct ttm_bo_device *bdev, struct ttm_tt *ttm, struct ttm_resource *reg);
+void nouveau_sgdma_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
+void nouveau_sgdma_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
 #endif
index 6b697ee6bc0ec1b20a9bf3abf01b47b089d63096..1253fdec712d40eb9c7ef67e82f38ee8a99d2b88 100644 (file)
@@ -130,10 +130,11 @@ nv17_fence_create(struct nouveau_drm *drm)
        priv->base.context_del = nv10_fence_context_del;
        spin_lock_init(&priv->lock);
 
-       ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+       ret = nouveau_bo_new(&drm->client, 4096, 0x1000,
+                            NOUVEAU_GEM_DOMAIN_VRAM,
                             0, 0x0000, NULL, NULL, &priv->bo);
        if (!ret) {
-               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false);
+               ret = nouveau_bo_pin(priv->bo, NOUVEAU_GEM_DOMAIN_VRAM, false);
                if (!ret) {
                        ret = nouveau_bo_map(priv->bo);
                        if (ret)
index 49b46f51073c774fa059f4e6b71d20156be67cfe..447238e3cbe776d7f7ab30c666511e4bc0f08bc2 100644 (file)
@@ -81,10 +81,11 @@ nv50_fence_create(struct nouveau_drm *drm)
        priv->base.context_del = nv10_fence_context_del;
        spin_lock_init(&priv->lock);
 
-       ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+       ret = nouveau_bo_new(&drm->client, 4096, 0x1000,
+                            NOUVEAU_GEM_DOMAIN_VRAM,
                             0, 0x0000, NULL, NULL, &priv->bo);
        if (!ret) {
-               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false);
+               ret = nouveau_bo_pin(priv->bo, NOUVEAU_GEM_DOMAIN_VRAM, false);
                if (!ret) {
                        ret = nouveau_bo_map(priv->bo);
                        if (ret)
index 7ed36b3a6b7dad43f7cdb493f4b43876c76759f0..7c9c928c319668d48b11d0081f0c60153b36c3c6 100644 (file)
@@ -209,12 +209,13 @@ nv84_fence_create(struct nouveau_drm *drm)
        mutex_init(&priv->mutex);
 
        /* Use VRAM if there is any ; otherwise fallback to system memory */
-       domain = drm->client.device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM :
-                        /*
-                         * fences created in sysmem must be non-cached or we
-                         * will lose CPU/GPU coherency!
-                         */
-                        TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED;
+       domain = drm->client.device.info.ram_size != 0 ?
+               NOUVEAU_GEM_DOMAIN_VRAM :
+                /*
+                 * fences created in sysmem must be non-cached or we
+                 * will lose CPU/GPU coherency!
+                 */
+               NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
        ret = nouveau_bo_new(&drm->client, 16 * drm->chan.nr, 0,
                             domain, 0, 0, NULL, NULL, &priv->bo);
        if (ret == 0) {
index 8d97d07c587138ab9d1f484c4aaea3686cfa1a10..b9dbedf8f15e8a79505af4b1ff985f55586c0c1b 100644 (file)
@@ -324,13 +324,30 @@ config DRM_PANEL_SAMSUNG_S6E63J0X03
        select VIDEOMODE_HELPERS
 
 config DRM_PANEL_SAMSUNG_S6E63M0
-       tristate "Samsung S6E63M0 RGB/SPI panel"
+       tristate "Samsung S6E63M0 RGB panel"
        depends on OF
-       depends on SPI
        depends on BACKLIGHT_CLASS_DEVICE
        help
          Say Y here if you want to enable support for Samsung S6E63M0
-         AMOLED LCD panel.
+         AMOLED LCD panel. This panel can be accessed using SPI or
+         DSI.
+
+config DRM_PANEL_SAMSUNG_S6E63M0_SPI
+       tristate "Samsung S6E63M0 RGB SPI interface"
+       depends on SPI
+       depends on DRM_PANEL_SAMSUNG_S6E63M0
+       default DRM_PANEL_SAMSUNG_S6E63M0
+       help
+         Say Y here if you want to be able to access the Samsung
+         S6E63M0 panel using SPI.
+
+config DRM_PANEL_SAMSUNG_S6E63M0_DSI
+       tristate "Samsung S6E63M0 RGB DSI interface"
+       depends on DRM_MIPI_DSI
+       depends on DRM_PANEL_SAMSUNG_S6E63M0
+       help
+         Say Y here if you want to be able to access the Samsung
+         S6E63M0 panel using DSI.
 
 config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01
        tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller"
index 15a4e775295147a6d37d33e3b2c4f55aa0f9b730..2ba560bca61d7eae6f00c9a040bd9e3588b830ae 100644 (file)
@@ -34,6 +34,8 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI) += panel-samsung-s6e63m0-spi.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
 obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c
new file mode 100644 (file)
index 0000000..eec74c1
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DSI interface to the Samsung S6E63M0 panel.
+ * (C) 2019 Linus Walleij
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_print.h>
+
+#include "panel-samsung-s6e63m0.h"
+
+#define MCS_GLOBAL_PARAM       0xb0
+#define S6E63M0_DSI_MAX_CHUNK  15 /* CMD + 15 bytes max */
+
+static int s6e63m0_dsi_dcs_read(struct device *dev, const u8 cmd, u8 *data)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+       int ret;
+
+       ret = mipi_dsi_dcs_read(dsi, cmd, data, 1);
+       if (ret < 0) {
+               dev_err(dev, "could not read DCS CMD %02x\n", cmd);
+               return ret;
+       }
+
+       dev_info(dev, "DSI read CMD %02x = %02x\n", cmd, *data);
+
+       return 0;
+}
+
+static int s6e63m0_dsi_dcs_write(struct device *dev, const u8 *data, size_t len)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+       const u8 *seqp = data;
+       u8 cmd;
+       u8 cmdwritten;
+       int remain;
+       int chunk;
+       int ret;
+
+       dev_info(dev, "DSI writing dcs seq: %*ph\n", (int)len, data);
+
+       /* Pick out and skip past the DCS command */
+       cmd = *seqp;
+       seqp++;
+       cmdwritten = 0;
+       remain = len - 1;
+       chunk = remain;
+
+       /* Send max S6E63M0_DSI_MAX_CHUNK bytes at a time */
+       if (chunk > S6E63M0_DSI_MAX_CHUNK)
+               chunk = S6E63M0_DSI_MAX_CHUNK;
+       ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk);
+       if (ret < 0) {
+               dev_err(dev, "error sending DCS command seq cmd %02x\n", cmd);
+               return ret;
+       }
+       cmdwritten += chunk;
+       seqp += chunk;
+
+       while (cmdwritten < remain) {
+               chunk = remain - cmdwritten;
+               if (chunk > S6E63M0_DSI_MAX_CHUNK)
+                       chunk = S6E63M0_DSI_MAX_CHUNK;
+               ret = mipi_dsi_dcs_write(dsi, MCS_GLOBAL_PARAM, &cmdwritten, 1);
+               if (ret < 0) {
+                       dev_err(dev, "error sending CMD %02x global param %02x\n",
+                               cmd, cmdwritten);
+                       return ret;
+               }
+               ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk);
+               if (ret < 0) {
+                       dev_err(dev, "error sending CMD %02x chunk\n", cmd);
+                       return ret;
+               }
+               cmdwritten += chunk;
+               seqp += chunk;
+       }
+       dev_info(dev, "sent command %02x %02x bytes\n", cmd, cmdwritten);
+
+       usleep_range(8000, 9000);
+
+       return 0;
+}
+
+static int s6e63m0_dsi_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       int ret;
+
+       dsi->lanes = 2;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->hs_rate = 349440000;
+       dsi->lp_rate = 9600000;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+               MIPI_DSI_MODE_EOT_PACKET |
+               MIPI_DSI_MODE_VIDEO_BURST;
+
+       ret = s6e63m0_probe(dev, s6e63m0_dsi_dcs_read, s6e63m0_dsi_dcs_write,
+                           true);
+       if (ret)
+               return ret;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0)
+               s6e63m0_remove(dev);
+
+       return ret;
+}
+
+static int s6e63m0_dsi_remove(struct mipi_dsi_device *dsi)
+{
+       mipi_dsi_detach(dsi);
+       return s6e63m0_remove(&dsi->dev);
+}
+
+static const struct of_device_id s6e63m0_dsi_of_match[] = {
+       { .compatible = "samsung,s6e63m0" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s6e63m0_dsi_of_match);
+
+static struct mipi_dsi_driver s6e63m0_dsi_driver = {
+       .probe                  = s6e63m0_dsi_probe,
+       .remove                 = s6e63m0_dsi_remove,
+       .driver                 = {
+               .name           = "panel-samsung-s6e63m0",
+               .of_match_table = s6e63m0_dsi_of_match,
+       },
+};
+module_mipi_dsi_driver(s6e63m0_dsi_driver);
+
+MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");
+MODULE_DESCRIPTION("s6e63m0 LCD DSI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c
new file mode 100644 (file)
index 0000000..d298d78
--- /dev/null
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include <drm/drm_print.h>
+
+#include "panel-samsung-s6e63m0.h"
+
+#define DATA_MASK      0x100
+
+static int s6e63m0_spi_dcs_read(struct device *dev, const u8 cmd, u8 *data)
+{
+       /*
+        * FIXME: implement reading DCS commands over SPI so we can
+        * properly identify which physical panel is connected.
+        */
+       *data = 0;
+
+       return 0;
+}
+
+static int s6e63m0_spi_write_word(struct device *dev, u16 data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct spi_transfer xfer = {
+               .len    = 2,
+               .tx_buf = &data,
+       };
+       struct spi_message msg;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       return spi_sync(spi, &msg);
+}
+
+static int s6e63m0_spi_dcs_write(struct device *dev, const u8 *data, size_t len)
+{
+       int ret = 0;
+
+       dev_dbg(dev, "SPI writing dcs seq: %*ph\n", (int)len, data);
+       ret = s6e63m0_spi_write_word(dev, *data);
+
+       while (!ret && --len) {
+               ++data;
+               ret = s6e63m0_spi_write_word(dev, *data | DATA_MASK);
+       }
+
+       if (ret) {
+               dev_err(dev, "SPI error %d writing dcs seq: %*ph\n", ret,
+                       (int)len, data);
+       }
+
+       usleep_range(300, 310);
+
+       return ret;
+}
+
+static int s6e63m0_spi_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       int ret;
+
+       spi->bits_per_word = 9;
+       spi->mode = SPI_MODE_3;
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(dev, "spi setup failed.\n");
+               return ret;
+       }
+       return s6e63m0_probe(dev, s6e63m0_spi_dcs_read, s6e63m0_spi_dcs_write,
+                            false);
+}
+
+static int s6e63m0_spi_remove(struct spi_device *spi)
+{
+       return s6e63m0_remove(&spi->dev);
+}
+
+static const struct of_device_id s6e63m0_spi_of_match[] = {
+       { .compatible = "samsung,s6e63m0" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s6e63m0_spi_of_match);
+
+static struct spi_driver s6e63m0_spi_driver = {
+       .probe                  = s6e63m0_spi_probe,
+       .remove                 = s6e63m0_spi_remove,
+       .driver                 = {
+               .name           = "panel-samsung-s6e63m0",
+               .of_match_table = s6e63m0_spi_of_match,
+       },
+};
+module_spi_driver(s6e63m0_spi_driver);
+
+MODULE_AUTHOR("PaweÅ‚ Chmiel <pawel.mikolaj.chmiel@gmail.com>");
+MODULE_DESCRIPTION("s6e63m0 LCD SPI Driver");
+MODULE_LICENSE("GPL v2");
index 2cc772fdc456dbda2c50150eea0fc7ce11d52289..3eee67e2d86a4eae3a37d19eacbbbb6bdc1c4235 100644 (file)
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
-#include <linux/spi/spi.h>
 
 #include <video/mipi_display.h>
 
+#include "panel-samsung-s6e63m0.h"
+
 /* Manufacturer Command Set */
 #define MCS_ELVSS_ON                0xb1
 #define MCS_MIECTL1                0xc0
 #define MCS_BCMODE                              0xc1
+#define MCS_ERROR_CHECK                0xd5
+#define MCS_READ_ID1           0xda
+#define MCS_READ_ID2           0xdb
+#define MCS_READ_ID3           0xdc
+#define MCS_LEVEL_2_KEY                0xf0
+#define MCS_MTP_KEY            0xf1
 #define MCS_DISCTL   0xf2
 #define MCS_SRCCTL           0xf6
 #define MCS_IFCTL                       0xf7
 #define MCS_PANELCTL         0xF8
 #define MCS_PGAMMACTL                   0xfa
 
+#define S6E63M0_LCD_ID_VALUE_M2                0xA4
+#define S6E63M0_LCD_ID_VALUE_SM2       0xB4
+#define S6E63M0_LCD_ID_VALUE_SM2_1     0xB6
+
 #define NUM_GAMMA_LEVELS             11
 #define GAMMA_TABLE_COUNT           23
 
-#define DATA_MASK                                       0x100
-
 #define MAX_BRIGHTNESS              (NUM_GAMMA_LEVELS - 1)
 
 /* array of gamma tables for gamma value 2.2 */
@@ -87,8 +96,11 @@ static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = {
 
 struct s6e63m0 {
        struct device *dev;
+       int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val);
+       int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
        struct drm_panel panel;
        struct backlight_device *bl_dev;
+       u8 lcd_type;
 
        struct regulator_bulk_data supplies[2];
        struct gpio_desc *reset_gpio;
@@ -134,42 +146,20 @@ static int s6e63m0_clear_error(struct s6e63m0 *ctx)
        return ret;
 }
 
-static int s6e63m0_spi_write_word(struct s6e63m0 *ctx, u16 data)
+static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
 {
-       struct spi_device *spi = to_spi_device(ctx->dev);
-       struct spi_transfer xfer = {
-               .len    = 2,
-               .tx_buf = &data,
-       };
-       struct spi_message msg;
-
-       spi_message_init(&msg);
-       spi_message_add_tail(&xfer, &msg);
+       if (ctx->error < 0)
+               return;
 
-       return spi_sync(spi, &msg);
+       ctx->error = ctx->dcs_read(ctx->dev, cmd, data);
 }
 
 static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
 {
-       int ret = 0;
-
        if (ctx->error < 0 || len == 0)
                return;
 
-       dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
-       ret = s6e63m0_spi_write_word(ctx, *data);
-
-       while (!ret && --len) {
-               ++data;
-               ret = s6e63m0_spi_write_word(ctx, *data | DATA_MASK);
-       }
-
-       if (ret) {
-               dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, (int)len, data);
-               ctx->error = ret;
-       }
-
-       usleep_range(300, 310);
+       ctx->error = ctx->dcs_write(ctx->dev, data, len);
 }
 
 #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
@@ -178,6 +168,43 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
                s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \
        })
 
+static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx)
+{
+       u8 id1, id2, id3;
+       int ret;
+
+       s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1);
+       s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2);
+       s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3);
+
+       ret = s6e63m0_clear_error(ctx);
+       if (ret) {
+               dev_err(ctx->dev, "error checking LCD type (%d)\n", ret);
+               ctx->lcd_type = 0x00;
+               return ret;
+       }
+
+       dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
+
+       /* We attempt to detect what panel is mounted on the controller */
+       switch (id2) {
+       case S6E63M0_LCD_ID_VALUE_M2:
+               dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n");
+               break;
+       case S6E63M0_LCD_ID_VALUE_SM2:
+       case S6E63M0_LCD_ID_VALUE_SM2_1:
+               dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n");
+               break;
+       default:
+               dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2);
+               break;
+       }
+
+       ctx->lcd_type = id2;
+
+       return 0;
+}
+
 static void s6e63m0_init(struct s6e63m0 *ctx)
 {
        s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
@@ -249,8 +276,6 @@ static void s6e63m0_init(struct s6e63m0 *ctx)
 
        s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON,
                                     0x0b);
-
-       s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
 }
 
 static int s6e63m0_power_on(struct s6e63m0 *ctx)
@@ -263,6 +288,9 @@ static int s6e63m0_power_on(struct s6e63m0 *ctx)
 
        msleep(25);
 
+       /* Be sure to send a reset pulse */
+       gpiod_set_value(ctx->reset_gpio, 1);
+       msleep(5);
        gpiod_set_value(ctx->reset_gpio, 0);
        msleep(120);
 
@@ -292,8 +320,10 @@ static int s6e63m0_disable(struct drm_panel *panel)
 
        backlight_disable(ctx->bl_dev);
 
+       s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
+       msleep(10);
        s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
-       msleep(200);
+       msleep(120);
 
        ctx->enabled = false;
 
@@ -331,6 +361,15 @@ static int s6e63m0_prepare(struct drm_panel *panel)
        if (ret < 0)
                return ret;
 
+       /* Magic to unlock level 2 control of the display */
+       s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a);
+       /* Magic to unlock MTP reading */
+       s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a);
+
+       ret = s6e63m0_check_lcd_type(ctx);
+       if (ret < 0)
+               return ret;
+
        s6e63m0_init(ctx);
 
        ret = s6e63m0_clear_error(ctx);
@@ -350,7 +389,15 @@ static int s6e63m0_enable(struct drm_panel *panel)
        if (ctx->enabled)
                return 0;
 
+       s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+       msleep(120);
        s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
+       msleep(10);
+
+       s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK,
+                                    0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3,
+                                    0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20,
+                                    0x0F, 0x00);
 
        backlight_enable(ctx->bl_dev);
 
@@ -429,9 +476,11 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx)
        return ret;
 }
 
-static int s6e63m0_probe(struct spi_device *spi)
+int s6e63m0_probe(struct device *dev,
+                 int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
+                 int (*dcs_write)(struct device *dev, const u8 *data, size_t len),
+                 bool dsi_mode)
 {
-       struct device *dev = &spi->dev;
        struct s6e63m0 *ctx;
        int ret;
 
@@ -439,7 +488,9 @@ static int s6e63m0_probe(struct spi_device *spi)
        if (!ctx)
                return -ENOMEM;
 
-       spi_set_drvdata(spi, ctx);
+       ctx->dcs_read = dcs_read;
+       ctx->dcs_write = dcs_write;
+       dev_set_drvdata(dev, ctx);
 
        ctx->dev = dev;
        ctx->enabled = false;
@@ -460,15 +511,8 @@ static int s6e63m0_probe(struct spi_device *spi)
                return PTR_ERR(ctx->reset_gpio);
        }
 
-       spi->bits_per_word = 9;
-       spi->mode = SPI_MODE_3;
-       ret = spi_setup(spi);
-       if (ret < 0) {
-               dev_err(dev, "spi setup failed.\n");
-               return ret;
-       }
-
        drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
+                      dsi_mode ? DRM_MODE_CONNECTOR_DSI :
                       DRM_MODE_CONNECTOR_DPI);
 
        ret = s6e63m0_backlight_register(ctx);
@@ -479,31 +523,17 @@ static int s6e63m0_probe(struct spi_device *spi)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(s6e63m0_probe);
 
-static int s6e63m0_remove(struct spi_device *spi)
+int s6e63m0_remove(struct device *dev)
 {
-       struct s6e63m0 *ctx = spi_get_drvdata(spi);
+       struct s6e63m0 *ctx = dev_get_drvdata(dev);
 
        drm_panel_remove(&ctx->panel);
 
        return 0;
 }
-
-static const struct of_device_id s6e63m0_of_match[] = {
-       { .compatible = "samsung,s6e63m0" },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, s6e63m0_of_match);
-
-static struct spi_driver s6e63m0_driver = {
-       .probe                  = s6e63m0_probe,
-       .remove                 = s6e63m0_remove,
-       .driver                 = {
-               .name           = "panel-samsung-s6e63m0",
-               .of_match_table = s6e63m0_of_match,
-       },
-};
-module_spi_driver(s6e63m0_driver);
+EXPORT_SYMBOL_GPL(s6e63m0_remove);
 
 MODULE_AUTHOR("PaweÅ‚ Chmiel <pawel.mikolaj.chmiel@gmail.com>");
 MODULE_DESCRIPTION("s6e63m0 LCD Driver");
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h
new file mode 100644 (file)
index 0000000..c669fec
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _PANEL_SAMSUNG_S6E63M0_H
+#define _PANEL_SAMSUNG_S6E63M0_H
+
+int s6e63m0_probe(struct device *dev,
+                 int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
+                 int (*dcs_write)(struct device *dev, const u8 *data,
+                                  size_t len),
+                 bool dsi_mode);
+int s6e63m0_remove(struct device *dev);
+
+#endif /* _PANEL_SAMSUNG_S6E63M0_H */
index e0f190e43813915459f36f126649981905f7956b..c7c5da5a31d4764a48ea4fc5bcc020632650b9cc 100644 (file)
@@ -305,6 +305,8 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev)
        int ret;
        u32 val;
 
+       panfrost_gpu_init_quirks(pfdev);
+
        /* Just turn on everything for now */
        gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present);
        ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO,
@@ -344,6 +346,7 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
 
        dma_set_mask_and_coherent(pfdev->dev,
                DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features)));
+       dma_set_max_seg_size(pfdev->dev, UINT_MAX);
 
        irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu");
        if (irq <= 0)
@@ -356,7 +359,6 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
                return err;
        }
 
-       panfrost_gpu_init_quirks(pfdev);
        panfrost_gpu_power_on(pfdev);
 
        return 0;
index f838b6d689aad58850eb7446a48f86f4515bb1b0..2bc364412e8b8f5574d19c36a3898316b3f4cf35 100644 (file)
@@ -64,16 +64,24 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
 
        qbo->placement.placement = qbo->placements;
        qbo->placement.busy_placement = qbo->placements;
-       if (domain == QXL_GEM_DOMAIN_VRAM)
-               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
+       if (domain == QXL_GEM_DOMAIN_VRAM) {
+               qbo->placements[c].mem_type = TTM_PL_VRAM;
+               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | pflag;
+       }
        if (domain == QXL_GEM_DOMAIN_SURFACE) {
-               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV | pflag;
-               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
+               qbo->placements[c].mem_type = TTM_PL_PRIV;
+               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | pflag;
+               qbo->placements[c].mem_type = TTM_PL_VRAM;
+               qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | pflag;
+       }
+       if (domain == QXL_GEM_DOMAIN_CPU) {
+               qbo->placements[c].mem_type = TTM_PL_SYSTEM;
+               qbo->placements[c++].flags = TTM_PL_MASK_CACHING | pflag;
+       }
+       if (!c) {
+               qbo->placements[c].mem_type = TTM_PL_SYSTEM;
+               qbo->placements[c++].flags = TTM_PL_MASK_CACHING;
        }
-       if (domain == QXL_GEM_DOMAIN_CPU)
-               qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
-       if (!c)
-               qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        qbo->placement.num_placement = c;
        qbo->placement.num_busy_placement = c;
        for (i = 0; i < c; ++i) {
@@ -167,6 +175,7 @@ int qxl_bo_kmap(struct qxl_bo *bo, void **ptr)
 void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev,
                              struct qxl_bo *bo, int page_offset)
 {
+       unsigned long offset;
        void *rptr;
        int ret;
        struct io_mapping *map;
@@ -178,9 +187,8 @@ void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev,
        else
                goto fallback;
 
-       ret = qxl_ttm_io_mem_reserve(bo->tbo.bdev, &bo->tbo.mem);
-
-       return io_mapping_map_atomic_wc(map, bo->tbo.mem.bus.offset + page_offset);
+       offset = bo->tbo.mem.start << PAGE_SHIFT;
+       return io_mapping_map_atomic_wc(map, offset + page_offset);
 fallback:
        if (bo->kptr) {
                rptr = bo->kptr + (page_offset * PAGE_SIZE);
index 7aae0a96f043eb04abeecb93d4d9443031b4e558..5ffc8b752f01b5e4014ee506c9db4b2ec540de8d 100644 (file)
@@ -55,7 +55,8 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
        static const struct ttm_place placements = {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
+               .mem_type = TTM_PL_SYSTEM,
+               .flags = TTM_PL_MASK_CACHING
        };
 
        if (!qxl_ttm_bo_is_qxl_bo(bo)) {
@@ -81,13 +82,12 @@ int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
                return 0;
        case TTM_PL_VRAM:
                mem->bus.is_iomem = true;
-               mem->bus.base = qdev->vram_base;
-               mem->bus.offset = mem->start << PAGE_SHIFT;
+               mem->bus.offset = (mem->start << PAGE_SHIFT) + qdev->vram_base;
                break;
        case TTM_PL_PRIV:
                mem->bus.is_iomem = true;
-               mem->bus.base = qdev->surfaceram_base;
-               mem->bus.offset = mem->start << PAGE_SHIFT;
+               mem->bus.offset = (mem->start << PAGE_SHIFT) +
+                       qdev->surfaceram_base;
                break;
        default:
                return -EINVAL;
@@ -104,7 +104,8 @@ struct qxl_ttm_tt {
        u64                             offset;
 };
 
-static int qxl_ttm_backend_bind(struct ttm_tt *ttm,
+static int qxl_ttm_backend_bind(struct ttm_bo_device *bdev,
+                               struct ttm_tt *ttm,
                                struct ttm_resource *bo_mem)
 {
        struct qxl_ttm_tt *gtt = (void *)ttm;
@@ -118,12 +119,14 @@ static int qxl_ttm_backend_bind(struct ttm_tt *ttm,
        return -1;
 }
 
-static void qxl_ttm_backend_unbind(struct ttm_tt *ttm)
+static void qxl_ttm_backend_unbind(struct ttm_bo_device *bdev,
+                                  struct ttm_tt *ttm)
 {
        /* Not implemented */
 }
 
-static void qxl_ttm_backend_destroy(struct ttm_tt *ttm)
+static void qxl_ttm_backend_destroy(struct ttm_bo_device *bdev,
+                                   struct ttm_tt *ttm)
 {
        struct qxl_ttm_tt *gtt = (void *)ttm;
 
@@ -131,12 +134,6 @@ static void qxl_ttm_backend_destroy(struct ttm_tt *ttm)
        kfree(gtt);
 }
 
-static struct ttm_backend_func qxl_backend_func = {
-       .bind = &qxl_ttm_backend_bind,
-       .unbind = &qxl_ttm_backend_unbind,
-       .destroy = &qxl_ttm_backend_destroy,
-};
-
 static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
                                        uint32_t page_flags)
 {
@@ -147,7 +144,6 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
        gtt = kzalloc(sizeof(struct qxl_ttm_tt), GFP_KERNEL);
        if (gtt == NULL)
                return NULL;
-       gtt->ttm.func = &qxl_backend_func;
        gtt->qdev = qdev;
        if (ttm_tt_init(&gtt->ttm, bo, page_flags)) {
                kfree(gtt);
@@ -156,16 +152,6 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo,
        return &gtt->ttm;
 }
 
-static void qxl_move_null(struct ttm_buffer_object *bo,
-                            struct ttm_resource *new_mem)
-{
-       struct ttm_resource *old_mem = &bo->mem;
-
-       BUG_ON(old_mem->mm_node != NULL);
-       *old_mem = *new_mem;
-       new_mem->mm_node = NULL;
-}
-
 static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
                       struct ttm_operation_ctx *ctx,
                       struct ttm_resource *new_mem)
@@ -178,7 +164,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
                return ret;
 
        if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
-               qxl_move_null(bo, new_mem);
+               ttm_bo_move_null(bo, new_mem);
                return 0;
        }
        return ttm_bo_move_memcpy(bo, ctx, new_mem);
@@ -202,6 +188,9 @@ 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,
+       .ttm_tt_bind = &qxl_ttm_backend_bind,
+       .ttm_tt_destroy = &qxl_ttm_backend_destroy,
+       .ttm_tt_unbind = &qxl_ttm_backend_unbind,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = &qxl_evict_flags,
        .move = &qxl_bo_move,
index cc4f58d165896e77640baba9f2995bbae01fd120..df6f0b49836b7e156a1b9512b76a2d5523d7934b 100644 (file)
@@ -2815,10 +2815,11 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
 extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
 extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
 extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
-extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
+extern int radeon_ttm_tt_set_userptr(struct radeon_device *rdev,
+                                    struct ttm_tt *ttm, uint64_t addr,
                                     uint32_t flags);
-extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
-extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm);
+extern bool radeon_ttm_tt_has_userptr(struct radeon_device *rdev, struct ttm_tt *ttm);
+extern bool radeon_ttm_tt_is_readonly(struct radeon_device *rdev, struct ttm_tt *ttm);
 extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
 extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
index 33ae1b883268970ac307886628e497d1d62f8471..21ce2f9502c09d2146cee08457bf1919337a67a5 100644 (file)
@@ -160,7 +160,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                        p->relocs[i].allowed_domains = domain;
                }
 
-               if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
+               if (radeon_ttm_tt_has_userptr(p->rdev, p->relocs[i].robj->tbo.ttm)) {
                        uint32_t domain = p->relocs[i].preferred_domains;
                        if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
                                DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
index 7f5dfe04789eaf76baa901205bb480b6d5afc6e7..e5c4271e64edec66ff8a4d79e69fe113e3526b10 100644 (file)
@@ -331,7 +331,7 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data,
                goto handle_lockup;
 
        bo = gem_to_radeon_bo(gobj);
-       r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags);
+       r = radeon_ttm_tt_set_userptr(rdev, bo->tbo.ttm, args->addr, args->flags);
        if (r)
                goto release_object;
 
@@ -420,7 +420,7 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
                return -ENOENT;
        }
        robj = gem_to_radeon_bo(gobj);
-       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
+       if (radeon_ttm_tt_has_userptr(robj->rdev, robj->tbo.ttm)) {
                drm_gem_object_put(gobj);
                return -EPERM;
        }
@@ -721,7 +721,7 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
        robj = gem_to_radeon_bo(gobj);
 
        r = -EPERM;
-       if (radeon_ttm_tt_has_userptr(robj->tbo.ttm))
+       if (radeon_ttm_tt_has_userptr(robj->rdev, robj->tbo.ttm))
                goto out;
 
        r = radeon_bo_reserve(robj, false);
index bb7582afd803e0d5484c852615ad36f6aad9efad..316e35d3f8a9dd9f7132f391de55fb1c4b6240f5 100644 (file)
@@ -112,58 +112,58 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
                    rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size) {
                        rbo->placements[c].fpfn =
                                rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
+                       rbo->placements[c].mem_type = TTM_PL_VRAM;
                        rbo->placements[c++].flags = TTM_PL_FLAG_WC |
-                                                    TTM_PL_FLAG_UNCACHED |
-                                                    TTM_PL_FLAG_VRAM;
+                                                    TTM_PL_FLAG_UNCACHED;
                }
 
                rbo->placements[c].fpfn = 0;
+               rbo->placements[c].mem_type = TTM_PL_VRAM;
                rbo->placements[c++].flags = TTM_PL_FLAG_WC |
-                                            TTM_PL_FLAG_UNCACHED |
-                                            TTM_PL_FLAG_VRAM;
+                                            TTM_PL_FLAG_UNCACHED;
        }
 
        if (domain & RADEON_GEM_DOMAIN_GTT) {
                if (rbo->flags & RADEON_GEM_GTT_UC) {
                        rbo->placements[c].fpfn = 0;
-                       rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
-                               TTM_PL_FLAG_TT;
+                       rbo->placements[c].mem_type = TTM_PL_TT;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED;
 
                } else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
                           (rbo->rdev->flags & RADEON_IS_AGP)) {
                        rbo->placements[c].fpfn = 0;
+                       rbo->placements[c].mem_type = TTM_PL_TT;
                        rbo->placements[c++].flags = TTM_PL_FLAG_WC |
-                               TTM_PL_FLAG_UNCACHED |
-                               TTM_PL_FLAG_TT;
+                               TTM_PL_FLAG_UNCACHED;
                } else {
                        rbo->placements[c].fpfn = 0;
-                       rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
-                                                    TTM_PL_FLAG_TT;
+                       rbo->placements[c].mem_type = TTM_PL_TT;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_CACHED;
                }
        }
 
        if (domain & RADEON_GEM_DOMAIN_CPU) {
                if (rbo->flags & RADEON_GEM_GTT_UC) {
                        rbo->placements[c].fpfn = 0;
-                       rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
-                               TTM_PL_FLAG_SYSTEM;
+                       rbo->placements[c].mem_type = TTM_PL_SYSTEM;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED;
 
                } else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
                    rbo->rdev->flags & RADEON_IS_AGP) {
                        rbo->placements[c].fpfn = 0;
+                       rbo->placements[c].mem_type = TTM_PL_SYSTEM;
                        rbo->placements[c++].flags = TTM_PL_FLAG_WC |
-                               TTM_PL_FLAG_UNCACHED |
-                               TTM_PL_FLAG_SYSTEM;
+                               TTM_PL_FLAG_UNCACHED;
                } else {
                        rbo->placements[c].fpfn = 0;
-                       rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
-                                                    TTM_PL_FLAG_SYSTEM;
+                       rbo->placements[c].mem_type = TTM_PL_SYSTEM;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_CACHED;
                }
        }
        if (!c) {
                rbo->placements[c].fpfn = 0;
-               rbo->placements[c++].flags = TTM_PL_MASK_CACHING |
-                                            TTM_PL_FLAG_SYSTEM;
+               rbo->placements[c].mem_type = TTM_PL_SYSTEM;
+               rbo->placements[c++].flags = TTM_PL_MASK_CACHING;
        }
 
        rbo->placement.num_placement = c;
@@ -171,7 +171,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
 
        for (i = 0; i < c; ++i) {
                if ((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
-                   (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+                   (rbo->placements[i].mem_type == TTM_PL_VRAM) &&
                    !rbo->placements[i].fpfn)
                        rbo->placements[i].lpfn =
                                rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
@@ -331,7 +331,7 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
        struct ttm_operation_ctx ctx = { false, false };
        int r, i;
 
-       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+       if (radeon_ttm_tt_has_userptr(bo->rdev, bo->tbo.ttm))
                return -EPERM;
 
        if (bo->pin_count) {
@@ -360,7 +360,7 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
        radeon_ttm_placement_from_domain(bo, domain);
        for (i = 0; i < bo->placement.num_placement; i++) {
                /* force to pin into visible video ram */
-               if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+               if ((bo->placements[i].mem_type == TTM_PL_VRAM) &&
                    !(bo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
                    (!max_offset || max_offset > bo->rdev->mc.visible_vram_size))
                        bo->placements[i].lpfn =
@@ -824,7 +824,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
        lpfn =  rdev->mc.visible_vram_size >> PAGE_SHIFT;
        for (i = 0; i < rbo->placement.num_placement; i++) {
                /* Force into visible VRAM */
-               if ((rbo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+               if ((rbo->placements[i].mem_type == TTM_PL_VRAM) &&
                    (!rbo->placements[i].lpfn || rbo->placements[i].lpfn > lpfn))
                        rbo->placements[i].lpfn = lpfn;
        }
index b906e8fbd5f3ab49f6bb8f6dcbab6ae1e2eb7503..b9de0e51c0be9871157d7bd7249ea43b397a32fa 100644 (file)
@@ -36,7 +36,7 @@ struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj)
        struct radeon_bo *bo = gem_to_radeon_bo(obj);
        int npages = bo->tbo.num_pages;
 
-       return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
+       return drm_prime_pages_to_sg(obj->dev, bo->tbo.ttm->pages, npages);
 }
 
 void *radeon_gem_prime_vmap(struct drm_gem_object *obj)
@@ -121,7 +121,7 @@ struct dma_buf *radeon_gem_prime_export(struct drm_gem_object *gobj,
                                        int flags)
 {
        struct radeon_bo *bo = gem_to_radeon_bo(gobj);
-       if (radeon_ttm_tt_has_userptr(bo->tbo.ttm))
+       if (radeon_ttm_tt_has_userptr(bo->rdev, bo->tbo.ttm))
                return ERR_PTR(-EPERM);
        return drm_gem_prime_export(gobj, flags);
 }
index 74ad50c7491c14e00c5f0bf6c5417036c2417c87..602a591a53dc71aa1339ccdbd1e15a461151a6f2 100644 (file)
@@ -88,7 +88,8 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
        static const struct ttm_place placements = {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
+               .mem_type = TTM_PL_SYSTEM,
+               .flags = TTM_PL_MASK_CACHING
        };
 
        struct radeon_bo *rbo;
@@ -119,7 +120,7 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
                                                         RADEON_GEM_DOMAIN_GTT);
                        rbo->placement.num_busy_placement = 0;
                        for (i = 0; i < rbo->placement.num_placement; i++) {
-                               if (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) {
+                               if (rbo->placements[i].mem_type == TTM_PL_VRAM) {
                                        if (rbo->placements[i].fpfn < fpfn)
                                                rbo->placements[i].fpfn = fpfn;
                                } else {
@@ -141,23 +142,14 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
 static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 {
        struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo);
+       struct radeon_device *rdev = radeon_get_rdev(bo->bdev);
 
-       if (radeon_ttm_tt_has_userptr(bo->ttm))
+       if (radeon_ttm_tt_has_userptr(rdev, bo->ttm))
                return -EPERM;
        return drm_vma_node_verify_access(&rbo->tbo.base.vma_node,
                                          filp->private_data);
 }
 
-static void radeon_move_null(struct ttm_buffer_object *bo,
-                            struct ttm_resource *new_mem)
-{
-       struct ttm_resource *old_mem = &bo->mem;
-
-       BUG_ON(old_mem->mm_node != NULL);
-       *old_mem = *new_mem;
-       new_mem->mm_node = NULL;
-}
-
 static int radeon_move_blit(struct ttm_buffer_object *bo,
                        bool evict, bool no_wait_gpu,
                        struct ttm_resource *new_mem,
@@ -233,7 +225,8 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
        placement.busy_placement = &placements;
        placements.fpfn = 0;
        placements.lpfn = 0;
-       placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+       placements.mem_type = TTM_PL_TT;
+       placements.flags = TTM_PL_MASK_CACHING;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem, &ctx);
        if (unlikely(r)) {
                return r;
@@ -244,7 +237,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
                goto out_cleanup;
        }
 
-       r = ttm_tt_bind(bo->ttm, &tmp_mem, &ctx);
+       r = ttm_tt_bind(bo->bdev, bo->ttm, &tmp_mem, &ctx);
        if (unlikely(r)) {
                goto out_cleanup;
        }
@@ -278,7 +271,8 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
        placement.busy_placement = &placements;
        placements.fpfn = 0;
        placements.lpfn = 0;
-       placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+       placements.mem_type = TTM_PL_TT;
+       placements.flags = TTM_PL_MASK_CACHING;
        r = ttm_bo_mem_space(bo, &placement, &tmp_mem, &ctx);
        if (unlikely(r)) {
                return r;
@@ -316,7 +310,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
 
        rdev = radeon_get_rdev(bo->bdev);
        if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
-               radeon_move_null(bo, new_mem);
+               ttm_bo_move_null(bo, new_mem);
                return 0;
        }
        if ((old_mem->mem_type == TTM_PL_TT &&
@@ -324,7 +318,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
            (old_mem->mem_type == TTM_PL_SYSTEM &&
             new_mem->mem_type == TTM_PL_TT)) {
                /* bind is enough */
-               radeon_move_null(bo, new_mem);
+               ttm_bo_move_null(bo, new_mem);
                return 0;
        }
        if (!rdev->ring[radeon_copy_ring_index(rdev)].ready ||
@@ -372,8 +366,8 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
 #if IS_ENABLED(CONFIG_AGP)
                if (rdev->flags & RADEON_IS_AGP) {
                        /* RADEON_IS_AGP is set only if AGP is active */
-                       mem->bus.offset = mem->start << PAGE_SHIFT;
-                       mem->bus.base = rdev->mc.agp_base;
+                       mem->bus.offset = (mem->start << PAGE_SHIFT) +
+                               rdev->mc.agp_base;
                        mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture;
                }
 #endif
@@ -383,7 +377,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
                /* check if it's visible */
                if ((mem->bus.offset + bus_size) > rdev->mc.visible_vram_size)
                        return -EINVAL;
-               mem->bus.base = rdev->mc.aper_base;
+               mem->bus.offset += rdev->mc.aper_base;
                mem->bus.is_iomem = true;
 #ifdef __alpha__
                /*
@@ -392,12 +386,10 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
                 */
                if (mem->placement & TTM_PL_FLAG_WC)
                        mem->bus.addr =
-                               ioremap_wc(mem->bus.base + mem->bus.offset,
-                                          bus_size);
+                               ioremap_wc(mem->bus.offset, bus_size);
                else
                        mem->bus.addr =
-                               ioremap(mem->bus.base + mem->bus.offset,
-                                       bus_size);
+                               ioremap(mem->bus.offset, bus_size);
                if (!mem->bus.addr)
                        return -ENOMEM;
 
@@ -407,7 +399,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
                 * It then can be used to build PTEs for VRAM
                 * access, as done in ttm_bo_vm_fault().
                 */
-               mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
+               mem->bus.offset = (mem->bus.offset & 0x0ffffffffUL) +
                        rdev->ddev->hose->dense_mem_base;
 #endif
                break;
@@ -430,9 +422,9 @@ struct radeon_ttm_tt {
 };
 
 /* prepare the sg table with the user pages */
-static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
+static int radeon_ttm_tt_pin_userptr(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
-       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
        struct radeon_ttm_tt *gtt = (void *)ttm;
        unsigned pinned = 0;
        int r;
@@ -491,9 +483,9 @@ release_pages:
        return r;
 }
 
-static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
+static void radeon_ttm_tt_unpin_userptr(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
-       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
        struct radeon_ttm_tt *gtt = (void *)ttm;
        struct sg_page_iter sg_iter;
 
@@ -520,17 +512,18 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
        sg_free_table(ttm->sg);
 }
 
-static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
+static int radeon_ttm_backend_bind(struct ttm_bo_device *bdev,
+                                  struct ttm_tt *ttm,
                                   struct ttm_resource *bo_mem)
 {
        struct radeon_ttm_tt *gtt = (void*)ttm;
-       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
        uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ |
                RADEON_GART_PAGE_WRITE;
        int r;
 
        if (gtt->userptr) {
-               radeon_ttm_tt_pin_userptr(ttm);
+               radeon_ttm_tt_pin_userptr(bdev, ttm);
                flags &= ~RADEON_GART_PAGE_WRITE;
        }
 
@@ -551,18 +544,18 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
        return 0;
 }
 
-static void radeon_ttm_backend_unbind(struct ttm_tt *ttm)
+static void radeon_ttm_backend_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        struct radeon_ttm_tt *gtt = (void *)ttm;
-       struct radeon_device *rdev = radeon_get_rdev(ttm->bdev);
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
 
        radeon_gart_unbind(rdev, gtt->offset, ttm->num_pages);
 
        if (gtt->userptr)
-               radeon_ttm_tt_unpin_userptr(ttm);
+               radeon_ttm_tt_unpin_userptr(bdev, ttm);
 }
 
-static void radeon_ttm_backend_destroy(struct ttm_tt *ttm)
+static void radeon_ttm_backend_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        struct radeon_ttm_tt *gtt = (void *)ttm;
 
@@ -570,12 +563,6 @@ static void radeon_ttm_backend_destroy(struct ttm_tt *ttm)
        kfree(gtt);
 }
 
-static struct ttm_backend_func radeon_backend_func = {
-       .bind = &radeon_ttm_backend_bind,
-       .unbind = &radeon_ttm_backend_unbind,
-       .destroy = &radeon_ttm_backend_destroy,
-};
-
 static struct ttm_tt *radeon_ttm_tt_create(struct ttm_buffer_object *bo,
                                           uint32_t page_flags)
 {
@@ -594,7 +581,6 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_buffer_object *bo,
        if (gtt == NULL) {
                return NULL;
        }
-       gtt->ttm.ttm.func = &radeon_backend_func;
        if (ttm_dma_tt_init(&gtt->ttm, bo, page_flags)) {
                kfree(gtt);
                return NULL;
@@ -602,18 +588,25 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_buffer_object *bo,
        return &gtt->ttm.ttm;
 }
 
-static struct radeon_ttm_tt *radeon_ttm_tt_to_gtt(struct ttm_tt *ttm)
+static struct radeon_ttm_tt *radeon_ttm_tt_to_gtt(struct radeon_device *rdev,
+                                                 struct ttm_tt *ttm)
 {
-       if (!ttm || ttm->func != &radeon_backend_func)
+#if IS_ENABLED(CONFIG_AGP)
+       if (rdev->flags & RADEON_IS_AGP)
                return NULL;
-       return (struct radeon_ttm_tt *)ttm;
+#endif
+
+       if (!ttm)
+               return NULL;
+       return container_of(ttm, struct radeon_ttm_tt, ttm.ttm);
 }
 
-static int radeon_ttm_tt_populate(struct ttm_tt *ttm,
-                       struct ttm_operation_ctx *ctx)
+static int radeon_ttm_tt_populate(struct ttm_bo_device *bdev,
+                                 struct ttm_tt *ttm,
+                                 struct ttm_operation_ctx *ctx)
 {
-       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
-       struct radeon_device *rdev;
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
 
        if (gtt && gtt->userptr) {
@@ -633,10 +626,9 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm,
                return 0;
        }
 
-       rdev = radeon_get_rdev(ttm->bdev);
 #if IS_ENABLED(CONFIG_AGP)
        if (rdev->flags & RADEON_IS_AGP) {
-               return ttm_agp_tt_populate(ttm, ctx);
+               return ttm_pool_populate(ttm, ctx);
        }
 #endif
 
@@ -649,10 +641,10 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm,
        return ttm_populate_and_map_pages(rdev->dev, &gtt->ttm, ctx);
 }
 
-static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
+static void radeon_ttm_tt_unpopulate(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
-       struct radeon_device *rdev;
-       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
 
        if (gtt && gtt->userptr) {
@@ -664,10 +656,9 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
        if (slave)
                return;
 
-       rdev = radeon_get_rdev(ttm->bdev);
 #if IS_ENABLED(CONFIG_AGP)
        if (rdev->flags & RADEON_IS_AGP) {
-               ttm_agp_tt_unpopulate(ttm);
+               ttm_pool_unpopulate(ttm);
                return;
        }
 #endif
@@ -682,10 +673,11 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
        ttm_unmap_and_unpopulate_pages(rdev->dev, &gtt->ttm);
 }
 
-int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
+int radeon_ttm_tt_set_userptr(struct radeon_device *rdev,
+                             struct ttm_tt *ttm, uint64_t addr,
                              uint32_t flags)
 {
-       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
 
        if (gtt == NULL)
                return -EINVAL;
@@ -696,9 +688,52 @@ int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
        return 0;
 }
 
-bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)
+static int radeon_ttm_tt_bind(struct ttm_bo_device *bdev,
+                             struct ttm_tt *ttm,
+                             struct ttm_resource *bo_mem)
+{
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
+
+#if IS_ENABLED(CONFIG_AGP)
+       if (rdev->flags & RADEON_IS_AGP)
+               return ttm_agp_bind(ttm, bo_mem);
+#endif
+
+       return radeon_ttm_backend_bind(bdev, ttm, bo_mem);
+}
+
+static void radeon_ttm_tt_unbind(struct ttm_bo_device *bdev,
+                                struct ttm_tt *ttm)
+{
+#if IS_ENABLED(CONFIG_AGP)
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
+
+       if (rdev->flags & RADEON_IS_AGP) {
+               ttm_agp_unbind(ttm);
+               return;
+       }
+#endif
+       radeon_ttm_backend_unbind(bdev, ttm);
+}
+
+static void radeon_ttm_tt_destroy(struct ttm_bo_device *bdev,
+                                 struct ttm_tt *ttm)
+{
+#if IS_ENABLED(CONFIG_AGP)
+       struct radeon_device *rdev = radeon_get_rdev(bdev);
+
+       if (rdev->flags & RADEON_IS_AGP) {
+               ttm_agp_destroy(ttm);
+               return;
+       }
+#endif
+       radeon_ttm_backend_destroy(bdev, ttm);
+}
+
+bool radeon_ttm_tt_has_userptr(struct radeon_device *rdev,
+                              struct ttm_tt *ttm)
 {
-       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
 
        if (gtt == NULL)
                return false;
@@ -706,9 +741,10 @@ bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm)
        return !!gtt->userptr;
 }
 
-bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm)
+bool radeon_ttm_tt_is_readonly(struct radeon_device *rdev,
+                              struct ttm_tt *ttm)
 {
-       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
+       struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
 
        if (gtt == NULL)
                return false;
@@ -720,6 +756,9 @@ 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,
+       .ttm_tt_bind = &radeon_ttm_tt_bind,
+       .ttm_tt_unbind = &radeon_ttm_tt_unbind,
+       .ttm_tt_destroy = &radeon_ttm_tt_destroy,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = &radeon_evict_flags,
        .move = &radeon_bo_move,
index 71e2c3785ab9d4985c86b83051f2b537a27b7b0a..ebad27c91a0d29137b231364da0cd798273302ba 100644 (file)
@@ -942,7 +942,7 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
        bo_va->flags &= ~RADEON_VM_PAGE_VALID;
        bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
        bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED;
-       if (bo_va->bo && radeon_ttm_tt_is_readonly(bo_va->bo->tbo.ttm))
+       if (bo_va->bo && radeon_ttm_tt_is_readonly(rdev, bo_va->bo->tbo.ttm))
                bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
 
        if (mem) {
index b9275ba7c5a53aa0818099d1b409864619abb4dc..0055d86576f79fe65c394ed85ab732df44c8338d 100644 (file)
@@ -85,7 +85,8 @@ static int rockchip_gem_get_pages(struct rockchip_gem_object *rk_obj)
 
        rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT;
 
-       rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
+       rk_obj->sgt = drm_prime_pages_to_sg(rk_obj->base.dev,
+                                           rk_obj->pages, rk_obj->num_pages);
        if (IS_ERR(rk_obj->sgt)) {
                ret = PTR_ERR(rk_obj->sgt);
                goto err_put_pages;
@@ -442,7 +443,7 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
        int ret;
 
        if (rk_obj->pages)
-               return drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages);
+               return drm_prime_pages_to_sg(obj->dev, rk_obj->pages, rk_obj->num_pages);
 
        sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
        if (!sgt)
index 723df142a9818d574f0eea8451acaeca2c057996..47e2935b8c68131eead6e6df54d286d124c220fa 100644 (file)
@@ -284,7 +284,7 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
 
        bo->num_pages = bo->gem.size >> PAGE_SHIFT;
 
-       bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
+       bo->sgt = drm_prime_pages_to_sg(bo->gem.dev, bo->pages, bo->num_pages);
        if (IS_ERR(bo->sgt)) {
                err = PTR_ERR(bo->sgt);
                goto put_pages;
index 09fe80e215c58d91891254e1297d7b73e76b7ef8..7b36fdaab7667795ba3fa9ec27cfc344ae2723f3 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_resource *bo_mem)
+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;
@@ -81,8 +81,9 @@ static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem)
 
        return ret;
 }
+EXPORT_SYMBOL(ttm_agp_bind);
 
-static void ttm_agp_unbind(struct ttm_tt *ttm)
+void ttm_agp_unbind(struct ttm_tt *ttm)
 {
        struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm);
 
@@ -95,8 +96,9 @@ static void ttm_agp_unbind(struct ttm_tt *ttm)
                agp_be->mem = NULL;
        }
 }
+EXPORT_SYMBOL(ttm_agp_unbind);
 
-static void ttm_agp_destroy(struct ttm_tt *ttm)
+void ttm_agp_destroy(struct ttm_tt *ttm)
 {
        struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm);
 
@@ -105,12 +107,7 @@ static void ttm_agp_destroy(struct ttm_tt *ttm)
        ttm_tt_fini(ttm);
        kfree(agp_be);
 }
-
-static struct ttm_backend_func ttm_agp_func = {
-       .bind = ttm_agp_bind,
-       .unbind = ttm_agp_unbind,
-       .destroy = ttm_agp_destroy,
-};
+EXPORT_SYMBOL(ttm_agp_destroy);
 
 struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo,
                                 struct agp_bridge_data *bridge,
@@ -124,7 +121,6 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo,
 
        agp_be->mem = NULL;
        agp_be->bridge = bridge;
-       agp_be->ttm.func = &ttm_agp_func;
 
        if (ttm_tt_init(&agp_be->ttm, bo, page_flags)) {
                kfree(agp_be);
@@ -134,18 +130,3 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo,
        return &agp_be->ttm;
 }
 EXPORT_SYMBOL(ttm_agp_tt_create);
-
-int ttm_agp_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
-{
-       if (ttm->state != tt_unpopulated)
-               return 0;
-
-       return ttm_pool_populate(ttm, ctx);
-}
-EXPORT_SYMBOL(ttm_agp_tt_populate);
-
-void ttm_agp_tt_unpopulate(struct ttm_tt *ttm)
-{
-       ttm_pool_unpopulate(ttm);
-}
-EXPORT_SYMBOL(ttm_agp_tt_unpopulate);
index e3931e515906e80f5007742ca75944d9d55a11b8..e2bfe3a13c63d71096710f67b9ee991c9b654707 100644 (file)
@@ -64,34 +64,18 @@ static void ttm_bo_default_destroy(struct ttm_buffer_object *bo)
        kfree(bo);
 }
 
-static inline int ttm_mem_type_from_place(const struct ttm_place *place,
-                                         uint32_t *mem_type)
-{
-       int pos;
-
-       pos = ffs(place->flags & TTM_PL_MASK_MEM);
-       if (unlikely(!pos))
-               return -EINVAL;
-
-       *mem_type = pos - 1;
-       return 0;
-}
-
 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;
+       int i, mem_type;
 
        drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n",
                   bo, bo->mem.num_pages, bo->mem.size >> 10,
                   bo->mem.size >> 20);
        for (i = 0; i < placement->num_placement; i++) {
-               ret = ttm_mem_type_from_place(&placement->placement[i],
-                                               &mem_type);
-               if (ret)
-                       return;
+               mem_type = placement->placement[i].mem_type;
                drm_printf(&p, "  placement[%d]=0x%08X (%d)\n",
                           i, placement->placement[i].flags, mem_type);
                man = ttm_manager_type(bo->bdev, mem_type);
@@ -125,12 +109,6 @@ static struct kobj_type ttm_bo_glob_kobj_type  = {
        .default_attrs = ttm_bo_global_attrs
 };
 
-
-static inline uint32_t ttm_bo_type_flags(unsigned type)
-{
-       return 1 << (type);
-}
-
 static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
                                  struct ttm_resource *mem)
 {
@@ -263,11 +241,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
        struct ttm_resource_manager *new_man = ttm_manager_type(bdev, mem->mem_type);
        int ret;
 
-       ret = ttm_mem_io_lock(old_man, true);
-       if (unlikely(ret != 0))
-               goto out_err;
-       ttm_bo_unmap_virtual_locked(bo);
-       ttm_mem_io_unlock(old_man);
+       ttm_bo_unmap_virtual(bo);
 
        /*
         * Create and bind a ttm if required.
@@ -286,7 +260,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
                        goto out_err;
 
                if (mem->mem_type != TTM_PL_SYSTEM) {
-                       ret = ttm_tt_bind(bo->ttm, mem, ctx);
+                       ret = ttm_tt_bind(bdev, bo->ttm, mem, ctx);
                        if (ret)
                                goto out_err;
                }
@@ -328,7 +302,7 @@ moved:
 out_err:
        new_man = ttm_manager_type(bdev, bo->mem.mem_type);
        if (!new_man->use_tt) {
-               ttm_tt_destroy(bo->ttm);
+               ttm_tt_destroy(bdev, bo->ttm);
                bo->ttm = NULL;
        }
 
@@ -348,7 +322,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
        if (bo->bdev->driver->move_notify)
                bo->bdev->driver->move_notify(bo, false, NULL);
 
-       ttm_tt_destroy(bo->ttm);
+       ttm_tt_destroy(bo->bdev, bo->ttm);
        bo->ttm = NULL;
        ttm_resource_free(bo, &bo->mem);
 }
@@ -538,7 +512,6 @@ 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_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type);
        size_t acc_size = bo->acc_size;
        int ret;
 
@@ -556,9 +529,7 @@ static void ttm_bo_release(struct kref *kref)
                        bo->bdev->driver->release_notify(bo);
 
                drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node);
-               ttm_mem_io_lock(man, false);
-               ttm_mem_io_free_vm(bo);
-               ttm_mem_io_unlock(man);
+               ttm_mem_io_free(bdev, &bo->mem);
        }
 
        if (!dma_resv_test_signaled_rcu(bo->base.resv, true) ||
@@ -648,8 +619,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
 
        evict_mem = bo->mem;
        evict_mem.mm_node = NULL;
-       evict_mem.bus.io_reserved_vm = false;
-       evict_mem.bus.io_reserved_count = 0;
+       evict_mem.bus.offset = 0;
+       evict_mem.bus.addr = NULL;
 
        ret = ttm_bo_mem_space(bo, &placement, &evict_mem, ctx);
        if (ret) {
@@ -917,25 +888,6 @@ static uint32_t ttm_bo_select_caching(struct ttm_resource_manager *man,
        return result;
 }
 
-static bool ttm_bo_mt_compatible(struct ttm_resource_manager *man,
-                                uint32_t mem_type,
-                                const struct ttm_place *place,
-                                uint32_t *masked_placement)
-{
-       uint32_t cur_flags = ttm_bo_type_flags(mem_type);
-
-       if ((cur_flags & place->flags & TTM_PL_MASK_MEM) == 0)
-               return false;
-
-       if ((place->flags & man->available_caching) == 0)
-               return false;
-
-       cur_flags |= (place->flags & man->available_caching);
-
-       *masked_placement = cur_flags;
-       return true;
-}
-
 /**
  * ttm_bo_mem_placement - check if placement is compatible
  * @bo: BO to find memory for
@@ -953,30 +905,21 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo,
                                struct ttm_operation_ctx *ctx)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       uint32_t mem_type = TTM_PL_SYSTEM;
        struct ttm_resource_manager *man;
        uint32_t cur_flags = 0;
-       int ret;
 
-       ret = ttm_mem_type_from_place(place, &mem_type);
-       if (ret)
-               return ret;
-
-       man = ttm_manager_type(bdev, mem_type);
+       man = ttm_manager_type(bdev, place->mem_type);
        if (!man || !ttm_resource_manager_used(man))
                return -EBUSY;
 
-       if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags))
+       if ((place->flags & man->available_caching) == 0)
                return -EBUSY;
 
+       cur_flags = place->flags & man->available_caching;
        cur_flags = ttm_bo_select_caching(man, bo->mem.placement, cur_flags);
-       /*
-        * Use the access and other non-mapping-related flag bits from
-        * the memory placement flags to the current flags
-        */
-       ttm_flag_masked(&cur_flags, place->flags, ~TTM_PL_MASK_MEMTYPE);
+       cur_flags |= place->flags & ~TTM_PL_MASK_CACHING;
 
-       mem->mem_type = mem_type;
+       mem->mem_type = place->mem_type;
        mem->placement = cur_flags;
 
        spin_lock(&ttm_bo_glob.lru_lock);
@@ -1013,10 +956,8 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                struct ttm_resource_manager *man;
 
                ret = ttm_bo_mem_placement(bo, place, mem, ctx);
-               if (ret == -EBUSY)
-                       continue;
                if (ret)
-                       goto error;
+                       continue;
 
                type_found = true;
                ret = ttm_resource_alloc(bo, place, mem);
@@ -1041,10 +982,8 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                const struct ttm_place *place = &placement->busy_placement[i];
 
                ret = ttm_bo_mem_placement(bo, place, mem, ctx);
-               if (ret == -EBUSY)
-                       continue;
                if (ret)
-                       goto error;
+                       continue;
 
                type_found = true;
                ret = ttm_bo_mem_force_space(bo, place, mem, ctx);
@@ -1082,8 +1021,8 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
        mem.num_pages = bo->num_pages;
        mem.size = mem.num_pages << PAGE_SHIFT;
        mem.page_alignment = bo->mem.page_alignment;
-       mem.bus.io_reserved_vm = false;
-       mem.bus.io_reserved_count = 0;
+       mem.bus.offset = 0;
+       mem.bus.addr = NULL;
        mem.mm_node = NULL;
 
        /*
@@ -1115,7 +1054,7 @@ static bool ttm_bo_places_compat(const struct ttm_place *places,
 
                *new_flags = heap->flags;
                if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) &&
-                   (*new_flags & mem->placement & TTM_PL_MASK_MEM) &&
+                   (mem->mem_type == heap->mem_type) &&
                    (!(*new_flags & TTM_PL_FLAG_CONTIGUOUS) ||
                     (mem->placement & TTM_PL_FLAG_CONTIGUOUS)))
                        return true;
@@ -1170,12 +1109,8 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
                if (ret)
                        return ret;
        } else {
-               /*
-                * Use the access and other non-mapping-related flag bits from
-                * the compatible memory placement flags to the active flags
-                */
-               ttm_flag_masked(&bo->mem.placement, new_flags,
-                               ~TTM_PL_MASK_MEMTYPE);
+               bo->mem.placement &= TTM_PL_MASK_CACHING;
+               bo->mem.placement |= new_flags & ~TTM_PL_MASK_CACHING;
        }
        /*
         * We might need to add a TTM.
@@ -1232,7 +1167,6 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
        INIT_LIST_HEAD(&bo->lru);
        INIT_LIST_HEAD(&bo->ddestroy);
        INIT_LIST_HEAD(&bo->swap);
-       INIT_LIST_HEAD(&bo->io_reserve_lru);
        bo->bdev = bdev;
        bo->type = type;
        bo->num_pages = num_pages;
@@ -1241,10 +1175,10 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
        bo->mem.num_pages = bo->num_pages;
        bo->mem.mm_node = NULL;
        bo->mem.page_alignment = page_alignment;
-       bo->mem.bus.io_reserved_vm = false;
-       bo->mem.bus.io_reserved_count = 0;
+       bo->mem.bus.offset = 0;
+       bo->mem.bus.addr = NULL;
        bo->moving = NULL;
-       bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
+       bo->mem.placement = TTM_PL_FLAG_CACHED;
        bo->acc_size = acc_size;
        bo->sg = sg;
        if (resv) {
@@ -1545,25 +1479,13 @@ EXPORT_SYMBOL(ttm_bo_device_init);
  * buffer object vm functions.
  */
 
-void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo)
-{
-       struct ttm_bo_device *bdev = bo->bdev;
-
-       drm_vma_node_unmap(&bo->base.vma_node, bdev->dev_mapping);
-       ttm_mem_io_free_vm(bo);
-}
-
 void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       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);
-       ttm_mem_io_unlock(man);
+       drm_vma_node_unmap(&bo->base.vma_node, bdev->dev_mapping);
+       ttm_mem_io_free(bdev, &bo->mem);
 }
-
-
 EXPORT_SYMBOL(ttm_bo_unmap_virtual);
 
 int ttm_bo_wait(struct ttm_buffer_object *bo,
@@ -1647,7 +1569,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
 
                evict_mem = bo->mem;
                evict_mem.mm_node = NULL;
-               evict_mem.placement = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED;
+               evict_mem.placement = TTM_PL_FLAG_CACHED;
                evict_mem.mem_type = TTM_PL_SYSTEM;
 
                ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, &ctx);
@@ -1673,7 +1595,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
        if (bo->bdev->driver->swap_notify)
                bo->bdev->driver->swap_notify(bo);
 
-       ret = ttm_tt_swapout(bo->ttm, bo->persistent_swap_storage);
+       ret = ttm_tt_swapout(bo->bdev, bo->ttm, bo->persistent_swap_storage);
 out:
 
        /**
index ee04716b2603db53aa83c48dfadf8fe07a70342c..1b56432dfa4385125510ba76550b789fd8f53674 100644 (file)
@@ -67,10 +67,8 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
                        return ret;
                }
 
-               ttm_tt_unbind(ttm);
+               ttm_tt_unbind(bo->bdev, ttm);
                ttm_bo_free_old_node(bo);
-               ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM,
-                               TTM_PL_MASK_MEM);
                old_mem->mem_type = TTM_PL_SYSTEM;
        }
 
@@ -79,7 +77,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
                return ret;
 
        if (new_mem->mem_type != TTM_PL_SYSTEM) {
-               ret = ttm_tt_bind(ttm, new_mem, ctx);
+               ret = ttm_tt_bind(bo->bdev, ttm, new_mem, ctx);
                if (unlikely(ret != 0))
                        return ret;
        }
@@ -91,122 +89,41 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
 }
 EXPORT_SYMBOL(ttm_bo_move_ttm);
 
-int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible)
-{
-       if (likely(!man->use_io_reserve_lru))
-               return 0;
-
-       if (interruptible)
-               return mutex_lock_interruptible(&man->io_reserve_mutex);
-
-       mutex_lock(&man->io_reserve_mutex);
-       return 0;
-}
-
-void ttm_mem_io_unlock(struct ttm_resource_manager *man)
-{
-       if (likely(!man->use_io_reserve_lru))
-               return;
-
-       mutex_unlock(&man->io_reserve_mutex);
-}
-
-static int ttm_mem_io_evict(struct ttm_resource_manager *man)
-{
-       struct ttm_buffer_object *bo;
-
-       bo = list_first_entry_or_null(&man->io_reserve_lru,
-                                     struct ttm_buffer_object,
-                                     io_reserve_lru);
-       if (!bo)
-               return -ENOSPC;
-
-       list_del_init(&bo->io_reserve_lru);
-       ttm_bo_unmap_virtual_locked(bo);
-       return 0;
-}
-
 int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
                       struct ttm_resource *mem)
 {
-       struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
-       int ret;
-
-       if (mem->bus.io_reserved_count++)
+       if (mem->bus.offset || mem->bus.addr)
                return 0;
 
+       mem->bus.is_iomem = false;
        if (!bdev->driver->io_mem_reserve)
                return 0;
 
-       mem->bus.addr = NULL;
-       mem->bus.offset = 0;
-       mem->bus.base = 0;
-       mem->bus.is_iomem = false;
-retry:
-       ret = bdev->driver->io_mem_reserve(bdev, mem);
-       if (ret == -ENOSPC) {
-               ret = ttm_mem_io_evict(man);
-               if (ret == 0)
-                       goto retry;
-       }
-       return ret;
+       return bdev->driver->io_mem_reserve(bdev, mem);
 }
 
 void ttm_mem_io_free(struct ttm_bo_device *bdev,
                     struct ttm_resource *mem)
 {
-       if (--mem->bus.io_reserved_count)
-               return;
-
-       if (!bdev->driver->io_mem_free)
+       if (!mem->bus.offset && !mem->bus.addr)
                return;
 
-       bdev->driver->io_mem_free(bdev, mem);
-}
+       if (bdev->driver->io_mem_free)
+               bdev->driver->io_mem_free(bdev, mem);
 
-int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo)
-{
-       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)
-               return 0;
-
-       ret = ttm_mem_io_reserve(bo->bdev, mem);
-       if (unlikely(ret != 0))
-               return ret;
-       mem->bus.io_reserved_vm = true;
-       if (man->use_io_reserve_lru)
-               list_add_tail(&bo->io_reserve_lru,
-                             &man->io_reserve_lru);
-       return 0;
-}
-
-void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
-{
-       struct ttm_resource *mem = &bo->mem;
-
-       if (!mem->bus.io_reserved_vm)
-               return;
-
-       mem->bus.io_reserved_vm = false;
-       list_del_init(&bo->io_reserve_lru);
-       ttm_mem_io_free(bo->bdev, mem);
+       mem->bus.offset = 0;
+       mem->bus.addr = NULL;
 }
 
 static int ttm_resource_ioremap(struct ttm_bo_device *bdev,
                               struct ttm_resource *mem,
                               void **virtual)
 {
-       struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type);
        int ret;
        void *addr;
 
        *virtual = NULL;
-       (void) ttm_mem_io_lock(man, false);
        ret = ttm_mem_io_reserve(bdev, mem);
-       ttm_mem_io_unlock(man);
        if (ret || !mem->bus.is_iomem)
                return ret;
 
@@ -216,15 +133,11 @@ static int ttm_resource_ioremap(struct ttm_bo_device *bdev,
                size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
 
                if (mem->placement & TTM_PL_FLAG_WC)
-                       addr = ioremap_wc(mem->bus.base + mem->bus.offset,
-                                         bus_size);
+                       addr = ioremap_wc(mem->bus.offset, bus_size);
                else
-                       addr = ioremap(mem->bus.base + mem->bus.offset,
-                                      bus_size);
+                       addr = ioremap(mem->bus.offset, bus_size);
                if (!addr) {
-                       (void) ttm_mem_io_lock(man, false);
                        ttm_mem_io_free(bdev, mem);
-                       ttm_mem_io_unlock(man);
                        return -ENOMEM;
                }
        }
@@ -236,15 +149,9 @@ static void ttm_resource_iounmap(struct ttm_bo_device *bdev,
                                struct ttm_resource *mem,
                                void *virtual)
 {
-       struct ttm_resource_manager *man;
-
-       man = ttm_manager_type(bdev, mem->mem_type);
-
        if (virtual && mem->bus.addr == NULL)
                iounmap(virtual);
-       (void) ttm_mem_io_lock(man, false);
        ttm_mem_io_free(bdev, mem);
-       ttm_mem_io_unlock(man);
 }
 
 static int ttm_copy_io_page(void *dst, void *src, unsigned long page)
@@ -352,7 +259,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
         * TTM might be null for moves within the same region.
         */
        if (ttm) {
-               ret = ttm_tt_populate(ttm, ctx);
+               ret = ttm_tt_populate(bdev, ttm, ctx);
                if (ret)
                        goto out1;
        }
@@ -391,7 +298,7 @@ out2:
        new_mem->mm_node = NULL;
 
        if (!man->use_tt) {
-               ttm_tt_destroy(ttm);
+               ttm_tt_destroy(bdev, ttm);
                bo->ttm = NULL;
        }
 
@@ -458,7 +365,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        INIT_LIST_HEAD(&fbo->base.ddestroy);
        INIT_LIST_HEAD(&fbo->base.lru);
        INIT_LIST_HEAD(&fbo->base.swap);
-       INIT_LIST_HEAD(&fbo->base.io_reserve_lru);
        fbo->base.moving = NULL;
        drm_vma_node_reset(&fbo->base.base.vma_node);
 
@@ -516,12 +422,10 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo,
        } else {
                map->bo_kmap_type = ttm_bo_map_iomap;
                if (mem->placement & TTM_PL_FLAG_WC)
-                       map->virtual = ioremap_wc(bo->mem.bus.base +
-                                                 bo->mem.bus.offset + offset,
+                       map->virtual = ioremap_wc(bo->mem.bus.offset + offset,
                                                  size);
                else
-                       map->virtual = ioremap(bo->mem.bus.base +
-                                              bo->mem.bus.offset + offset,
+                       map->virtual = ioremap(bo->mem.bus.offset + offset,
                                               size);
        }
        return (!map->virtual) ? -ENOMEM : 0;
@@ -543,7 +447,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
 
        BUG_ON(!ttm);
 
-       ret = ttm_tt_populate(ttm, &ctx);
+       ret = ttm_tt_populate(bo->bdev, ttm, &ctx);
        if (ret)
                return ret;
 
@@ -573,8 +477,6 @@ 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_resource_manager *man =
-               ttm_manager_type(bo->bdev, bo->mem.mem_type);
        unsigned long offset, size;
        int ret;
 
@@ -585,9 +487,7 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
        if (start_page > bo->num_pages)
                return -EINVAL;
 
-       (void) ttm_mem_io_lock(man, false);
        ret = ttm_mem_io_reserve(bo->bdev, &bo->mem);
-       ttm_mem_io_unlock(man);
        if (ret)
                return ret;
        if (!bo->mem.bus.is_iomem) {
@@ -602,10 +502,6 @@ EXPORT_SYMBOL(ttm_bo_kmap);
 
 void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
 {
-       struct ttm_buffer_object *bo = map->bo;
-       struct ttm_resource_manager *man =
-               ttm_manager_type(bo->bdev, bo->mem.mem_type);
-
        if (!map->virtual)
                return;
        switch (map->bo_kmap_type) {
@@ -623,9 +519,7 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
        default:
                BUG();
        }
-       (void) ttm_mem_io_lock(man, false);
        ttm_mem_io_free(map->bo->bdev, &map->bo->mem);
-       ttm_mem_io_unlock(man);
        map->virtual = NULL;
        map->page = NULL;
 }
@@ -649,7 +543,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
                        return ret;
 
                if (!man->use_tt) {
-                       ttm_tt_destroy(bo->ttm);
+                       ttm_tt_destroy(bdev, bo->ttm);
                        bo->ttm = NULL;
                }
                ttm_bo_free_old_node(bo);
@@ -772,7 +666,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
                        return ret;
 
                if (!to->use_tt) {
-                       ttm_tt_destroy(bo->ttm);
+                       ttm_tt_destroy(bdev, bo->ttm);
                        bo->ttm = NULL;
                }
                ttm_bo_free_old_node(bo);
index 01693e8f24b73890e5d3cbc5fe80a3a3b90d61a0..98a006fc30a58db3b1e097ca309af1d8556a6765 100644 (file)
@@ -101,8 +101,7 @@ static unsigned long ttm_bo_io_mem_pfn(struct ttm_buffer_object *bo,
        if (bdev->driver->io_mem_pfn)
                return bdev->driver->io_mem_pfn(bo, page_offset);
 
-       return ((bo->mem.bus.base + bo->mem.bus.offset) >> PAGE_SHIFT)
-               + page_offset;
+       return (bo->mem.bus.offset >> PAGE_SHIFT) + page_offset;
 }
 
 /**
@@ -281,8 +280,6 @@ 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_resource_manager *man =
-               ttm_manager_type(bdev, bo->mem.mem_type);
 
        /*
         * Refuse to fault imported pages. This should be handled
@@ -321,24 +318,17 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
        if (unlikely(ret != 0))
                return ret;
 
-       err = ttm_mem_io_lock(man, true);
+       err = ttm_mem_io_reserve(bdev, &bo->mem);
        if (unlikely(err != 0))
-               return VM_FAULT_NOPAGE;
-       err = ttm_mem_io_reserve_vm(bo);
-       if (unlikely(err != 0)) {
-               ret = VM_FAULT_SIGBUS;
-               goto out_io_unlock;
-       }
+               return VM_FAULT_SIGBUS;
 
        page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) +
                vma->vm_pgoff - drm_vma_node_start(&bo->base.vma_node);
        page_last = vma_pages(vma) + vma->vm_pgoff -
                drm_vma_node_start(&bo->base.vma_node);
 
-       if (unlikely(page_offset >= bo->num_pages)) {
-               ret = VM_FAULT_SIGBUS;
-               goto out_io_unlock;
-       }
+       if (unlikely(page_offset >= bo->num_pages))
+               return VM_FAULT_SIGBUS;
 
        prot = ttm_io_prot(bo->mem.placement, prot);
        if (!bo->mem.bus.is_iomem) {
@@ -350,21 +340,17 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
                };
 
                ttm = bo->ttm;
-               if (ttm_tt_populate(bo->ttm, &ctx)) {
-                       ret = VM_FAULT_OOM;
-                       goto out_io_unlock;
-               }
+               if (ttm_tt_populate(bdev, bo->ttm, &ctx))
+                       return VM_FAULT_OOM;
        } else {
                /* Iomem should not be marked encrypted */
                prot = pgprot_decrypted(prot);
        }
 
        /* We don't prefault on huge faults. Yet. */
-       if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && fault_page_size != 1) {
-               ret = ttm_bo_vm_insert_huge(vmf, bo, page_offset,
-                                           fault_page_size, prot);
-               goto out_io_unlock;
-       }
+       if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && fault_page_size != 1)
+               return ttm_bo_vm_insert_huge(vmf, bo, page_offset,
+                                            fault_page_size, prot);
 
        /*
         * Speculatively prefault a number of pages. Only error on
@@ -376,8 +362,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
                } else {
                        page = ttm->pages[page_offset];
                        if (unlikely(!page && i == 0)) {
-                               ret = VM_FAULT_OOM;
-                               goto out_io_unlock;
+                               return VM_FAULT_OOM;
                        } else if (unlikely(!page)) {
                                break;
                        }
@@ -404,7 +389,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
                /* Never error on prefaulted PTEs */
                if (unlikely((ret & VM_FAULT_ERROR))) {
                        if (i == 0)
-                               goto out_io_unlock;
+                               return VM_FAULT_NOPAGE;
                        else
                                break;
                }
@@ -413,9 +398,6 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
                if (unlikely(++page_offset >= page_last))
                        break;
        }
-       ret = VM_FAULT_NOPAGE;
-out_io_unlock:
-       ttm_mem_io_unlock(man);
        return ret;
 }
 EXPORT_SYMBOL(ttm_bo_vm_fault_reserved);
index 33b642532e5ca9882e02889fa5e2d8f1b274a666..3a4602f9a03bdce2e1c1263bd468b5f5830004c9 100644 (file)
@@ -65,10 +65,7 @@ void ttm_resource_manager_init(struct ttm_resource_manager *man,
 {
        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)
index 1ccf1ef050d6cf71cc83b3323c7498ad720a120e..67aa7fe39432dc327b7f044854b8fd4eb16b79f3 100644 (file)
@@ -207,29 +207,28 @@ int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement)
 }
 EXPORT_SYMBOL(ttm_tt_set_placement_caching);
 
-void ttm_tt_destroy(struct ttm_tt *ttm)
+void ttm_tt_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        if (ttm == NULL)
                return;
 
-       ttm_tt_unbind(ttm);
+       ttm_tt_unbind(bdev, ttm);
 
        if (ttm->state == tt_unbound)
-               ttm_tt_unpopulate(ttm);
+               ttm_tt_unpopulate(bdev, ttm);
 
        if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) &&
            ttm->swap_storage)
                fput(ttm->swap_storage);
 
        ttm->swap_storage = NULL;
-       ttm->func->destroy(ttm);
+       bdev->driver->ttm_tt_destroy(bdev, ttm);
 }
 
 static void ttm_tt_init_fields(struct ttm_tt *ttm,
                               struct ttm_buffer_object *bo,
                               uint32_t page_flags)
 {
-       ttm->bdev = bo->bdev;
        ttm->num_pages = bo->num_pages;
        ttm->caching_state = tt_cached;
        ttm->page_flags = page_flags;
@@ -308,15 +307,16 @@ void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma)
 }
 EXPORT_SYMBOL(ttm_dma_tt_fini);
 
-void ttm_tt_unbind(struct ttm_tt *ttm)
+void ttm_tt_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        if (ttm->state == tt_bound) {
-               ttm->func->unbind(ttm);
+               bdev->driver->ttm_tt_unbind(bdev, ttm);
                ttm->state = tt_unbound;
        }
 }
 
-int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
+int ttm_tt_bind(struct ttm_bo_device *bdev,
+               struct ttm_tt *ttm, struct ttm_resource *bo_mem,
                struct ttm_operation_ctx *ctx)
 {
        int ret = 0;
@@ -327,11 +327,11 @@ int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
        if (ttm->state == tt_bound)
                return 0;
 
-       ret = ttm_tt_populate(ttm, ctx);
+       ret = ttm_tt_populate(bdev, ttm, ctx);
        if (ret)
                return ret;
 
-       ret = ttm->func->bind(ttm, bo_mem);
+       ret = bdev->driver->ttm_tt_bind(bdev, ttm, bo_mem);
        if (unlikely(ret != 0))
                return ret;
 
@@ -383,7 +383,8 @@ out_err:
        return ret;
 }
 
-int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
+int ttm_tt_swapout(struct ttm_bo_device *bdev,
+                  struct ttm_tt *ttm, struct file *persistent_swap_storage)
 {
        struct address_space *swap_space;
        struct file *swap_storage;
@@ -429,7 +430,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
                put_page(to_page);
        }
 
-       ttm_tt_unpopulate(ttm);
+       ttm_tt_unpopulate(bdev, ttm);
        ttm->swap_storage = swap_storage;
        ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED;
        if (persistent_swap_storage)
@@ -443,7 +444,7 @@ out_err:
        return ret;
 }
 
-static void ttm_tt_add_mapping(struct ttm_tt *ttm)
+static void ttm_tt_add_mapping(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        pgoff_t i;
 
@@ -451,22 +452,23 @@ static void ttm_tt_add_mapping(struct ttm_tt *ttm)
                return;
 
        for (i = 0; i < ttm->num_pages; ++i)
-               ttm->pages[i]->mapping = ttm->bdev->dev_mapping;
+               ttm->pages[i]->mapping = bdev->dev_mapping;
 }
 
-int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
+int ttm_tt_populate(struct ttm_bo_device *bdev,
+                   struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
 {
        int ret;
 
        if (ttm->state != tt_unpopulated)
                return 0;
 
-       if (ttm->bdev->driver->ttm_tt_populate)
-               ret = ttm->bdev->driver->ttm_tt_populate(ttm, ctx);
+       if (bdev->driver->ttm_tt_populate)
+               ret = bdev->driver->ttm_tt_populate(bdev, ttm, ctx);
        else
                ret = ttm_pool_populate(ttm, ctx);
        if (!ret)
-               ttm_tt_add_mapping(ttm);
+               ttm_tt_add_mapping(bdev, ttm);
        return ret;
 }
 
@@ -484,14 +486,15 @@ static void ttm_tt_clear_mapping(struct ttm_tt *ttm)
        }
 }
 
-void ttm_tt_unpopulate(struct ttm_tt *ttm)
+void ttm_tt_unpopulate(struct ttm_bo_device *bdev,
+                      struct ttm_tt *ttm)
 {
        if (ttm->state == tt_unpopulated)
                return;
 
        ttm_tt_clear_mapping(ttm);
-       if (ttm->bdev->driver->ttm_tt_unpopulate)
-               ttm->bdev->driver->ttm_tt_unpopulate(ttm);
+       if (bdev->driver->ttm_tt_unpopulate)
+               bdev->driver->ttm_tt_unpopulate(bdev, ttm);
        else
                ttm_pool_unpopulate(ttm);
 }
index d9a5af62af890abc2cbb860da6aabb17109af54e..4fcc0a542b8a65ba54ab369f488402f402be1cd0 100644 (file)
@@ -397,11 +397,13 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane,
 
        vbox_crtc->cursor_enabled = true;
 
-       /* pinning is done in prepare/cleanup framebuffer */
-       src = drm_gem_vram_kmap(gbo, true, NULL);
+       src = drm_gem_vram_vmap(gbo);
        if (IS_ERR(src)) {
+               /*
+                * BUG: we should have pinned the BO in prepare_fb().
+                */
                mutex_unlock(&vbox->hw_mutex);
-               DRM_WARN("Could not kmap cursor bo, skipping update\n");
+               DRM_WARN("Could not map cursor bo, skipping update\n");
                return;
        }
 
@@ -414,7 +416,7 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane,
        data_size = width * height * 4 + mask_size;
 
        copy_cursor_image(src, vbox->cursor_data, width, height, mask_size);
-       drm_gem_vram_kunmap(gbo);
+       drm_gem_vram_vunmap(gbo, src);
 
        flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE |
                VBOX_MOUSE_POINTER_ALPHA;
index b303703bc7f37e3f1b032096c0dc00a6d7326bb6..d0163e18e9caaa52392ae478d6691db0c999f8fc 100644 (file)
@@ -12,6 +12,7 @@ vc4-y := \
        vc4_kms.o \
        vc4_gem.o \
        vc4_hdmi.o \
+       vc4_hdmi_phy.o \
        vc4_vec.o \
        vc4_hvs.o \
        vc4_irq.o \
index 6d8fa6118fc1a559585184977d31c26dae5e9052..a393f93390a2e860e6eedb2dfda23ff7b4b7e3d1 100644 (file)
@@ -65,6 +65,20 @@ static const struct debugfs_reg32 crtc_regs[] = {
        VC4_REG32(PV_HACT_ACT),
 };
 
+static unsigned int
+vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
+{
+       u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
+       /* Top/base are supposed to be 4-pixel aligned, but the
+        * Raspberry Pi firmware fills the low bits (which are
+        * presumably ignored).
+        */
+       u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
+       u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
+
+       return top - base + 4;
+}
+
 static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
                                          bool in_vblank_irq,
                                          int *vpos, int *hpos,
@@ -74,6 +88,8 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
+       unsigned int cob_size;
        u32 val;
        int fifo_lines;
        int vblank_lines;
@@ -89,7 +105,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
         * Read vertical scanline which is currently composed for our
         * pixelvalve by the HVS, and also the scaler status.
         */
-       val = HVS_READ(SCALER_DISPSTATX(vc4_crtc->channel));
+       val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel));
 
        /* Get optional system timestamp after query. */
        if (etime)
@@ -109,8 +125,9 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
                        *hpos += mode->crtc_htotal / 2;
        }
 
+       cob_size = vc4_crtc_get_cob_allocation(vc4, vc4_crtc_state->assigned_channel);
        /* This is the offset we need for translating hvs -> pv scanout pos. */
-       fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
+       fifo_lines = cob_size / mode->crtc_hdisplay;
 
        if (fifo_lines > 0)
                ret = true;
@@ -189,10 +206,22 @@ void vc4_crtc_destroy(struct drm_crtc *crtc)
        drm_crtc_cleanup(crtc);
 }
 
-static u32 vc4_get_fifo_full_level(u32 format)
+static u32 vc4_get_fifo_full_level(struct vc4_crtc *vc4_crtc, u32 format)
 {
-       static const u32 fifo_len_bytes = 64;
+       const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc);
+       const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
+       u32 fifo_len_bytes = pv_data->fifo_depth;
 
+       /*
+        * Pixels are pulled from the HVS if the number of bytes is
+        * lower than the FIFO full level.
+        *
+        * The latency of the pixel fetch mechanism is 6 pixels, so we
+        * need to convert those 6 pixels in bytes, depending on the
+        * format, and then subtract that from the length of the FIFO
+        * to make sure we never end up in a situation where the FIFO
+        * is full.
+        */
        switch (format) {
        case PV_CONTROL_FORMAT_DSIV_16:
        case PV_CONTROL_FORMAT_DSIC_16:
@@ -202,10 +231,30 @@ static u32 vc4_get_fifo_full_level(u32 format)
        case PV_CONTROL_FORMAT_24:
        case PV_CONTROL_FORMAT_DSIV_24:
        default:
+               /*
+                * For some reason, the pixelvalve4 doesn't work with
+                * the usual formula and will only work with 32.
+                */
+               if (crtc_data->hvs_output == 5)
+                       return 32;
+
                return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX;
        }
 }
 
+static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
+                                            u32 format)
+{
+       u32 level = vc4_get_fifo_full_level(vc4_crtc, format);
+       u32 ret = 0;
+
+       ret |= VC4_SET_FIELD((level >> 6),
+                            PV5_CONTROL_FIFO_LEVEL_HIGH);
+
+       return ret | VC4_SET_FIELD(level & 0x3f,
+                                  PV_CONTROL_FIFO_LEVEL);
+}
+
 /*
  * Returns the encoder attached to the CRTC.
  *
@@ -230,11 +279,23 @@ static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)
        return NULL;
 }
 
+static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
+{
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+       /* The PV needs to be disabled before it can be flushed */
+       CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) & ~PV_CONTROL_EN);
+       CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR);
+}
+
 static void vc4_crtc_config_pv(struct drm_crtc *crtc)
 {
+       struct drm_device *dev = crtc->dev;
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
        struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
        struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
        struct drm_crtc_state *state = crtc->state;
        struct drm_display_mode *mode = &state->adjusted_mode;
        bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -242,24 +303,29 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc)
        bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
                       vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
        u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
+       u8 ppc = pv_data->pixels_per_clock;
+       bool debug_dump_regs = false;
 
-       /* Reset the PV fifo. */
-       CRTC_WRITE(PV_CONTROL, 0);
-       CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | PV_CONTROL_EN);
-       CRTC_WRITE(PV_CONTROL, 0);
+       if (debug_dump_regs) {
+               struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev);
+               dev_info(&vc4_crtc->pdev->dev, "CRTC %d regs before:\n",
+                        drm_crtc_index(crtc));
+               drm_print_regset32(&p, &vc4_crtc->regset);
+       }
+
+       vc4_crtc_pixelvalve_reset(crtc);
 
        CRTC_WRITE(PV_HORZA,
-                  VC4_SET_FIELD((mode->htotal -
-                                 mode->hsync_end) * pixel_rep,
+                  VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc,
                                 PV_HORZA_HBP) |
-                  VC4_SET_FIELD((mode->hsync_end -
-                                 mode->hsync_start) * pixel_rep,
+                  VC4_SET_FIELD((mode->hsync_end - mode->hsync_start) * pixel_rep / ppc,
                                 PV_HORZA_HSYNC));
+
        CRTC_WRITE(PV_HORZB,
-                  VC4_SET_FIELD((mode->hsync_start -
-                                 mode->hdisplay) * pixel_rep,
+                  VC4_SET_FIELD((mode->hsync_start - mode->hdisplay) * pixel_rep / ppc,
                                 PV_HORZB_HFP) |
-                  VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE));
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
+                                PV_HORZB_HACTIVE));
 
        CRTC_WRITE(PV_VERTA,
                   VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
@@ -306,35 +372,20 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc)
        if (is_dsi)
                CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
 
-       CRTC_WRITE(PV_CONTROL,
+       if (vc4->hvs->hvs5)
+               CRTC_WRITE(PV_MUX_CFG,
+                          VC4_SET_FIELD(PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP,
+                                        PV_MUX_CFG_RGB_PIXEL_MUX_MODE));
+
+       CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR |
+                  vc4_crtc_get_fifo_full_level_bits(vc4_crtc, format) |
                   VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
-                  VC4_SET_FIELD(vc4_get_fifo_full_level(format),
-                                PV_CONTROL_FIFO_LEVEL) |
                   VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) |
                   PV_CONTROL_CLR_AT_START |
                   PV_CONTROL_TRIGGER_UNDERFLOW |
                   PV_CONTROL_WAIT_HSTART |
                   VC4_SET_FIELD(vc4_encoder->clock_select,
-                                PV_CONTROL_CLK_SELECT) |
-                  PV_CONTROL_FIFO_CLR |
-                  PV_CONTROL_EN);
-}
-
-static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
-{
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-       bool debug_dump_regs = false;
-
-       if (debug_dump_regs) {
-               struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev);
-               dev_info(&vc4_crtc->pdev->dev, "CRTC %d regs before:\n",
-                        drm_crtc_index(crtc));
-               drm_print_regset32(&p, &vc4_crtc->regset);
-       }
-
-       vc4_crtc_config_pv(crtc);
-
-       vc4_hvs_mode_set_nofb(crtc);
+                                PV_CONTROL_CLK_SELECT));
 
        if (debug_dump_regs) {
                struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev);
@@ -352,24 +403,86 @@ static void require_hvs_enabled(struct drm_device *dev)
                     SCALER_DISPCTRL_ENABLE);
 }
 
+static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel)
+{
+       struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
+       struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       int ret;
+
+       CRTC_WRITE(PV_V_CONTROL,
+                  CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
+       ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
+       WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n");
+
+       /*
+        * This delay is needed to avoid to get a pixel stuck in an
+        * unflushable FIFO between the pixelvalve and the HDMI
+        * controllers on the BCM2711.
+        *
+        * Timing is fairly sensitive here, so mdelay is the safest
+        * approach.
+        *
+        * If it was to be reworked, the stuck pixel happens on a
+        * BCM2711 when changing mode with a good probability, so a
+        * script that changes mode on a regular basis should trigger
+        * the bug after less than 10 attempts. It manifests itself with
+        * every pixels being shifted by one to the right, and thus the
+        * last pixel of a line actually being displayed as the first
+        * pixel on the next line.
+        */
+       mdelay(20);
+
+       if (vc4_encoder && vc4_encoder->post_crtc_disable)
+               vc4_encoder->post_crtc_disable(encoder);
+
+       vc4_crtc_pixelvalve_reset(crtc);
+       vc4_hvs_stop_channel(dev, channel);
+
+       if (vc4_encoder && vc4_encoder->post_crtc_powerdown)
+               vc4_encoder->post_crtc_powerdown(encoder);
+
+       return 0;
+}
+
+int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
+{
+       struct drm_device *drm = crtc->dev;
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       int channel;
+
+       if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
+                                     "brcm,bcm2711-pixelvalve2") ||
+             of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
+                                     "brcm,bcm2711-pixelvalve4")))
+               return 0;
+
+       if (!(CRTC_READ(PV_CONTROL) & PV_CONTROL_EN))
+               return 0;
+
+       if (!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN))
+               return 0;
+
+       channel = vc4_hvs_get_fifo_from_output(drm, vc4_crtc->data->hvs_output);
+       if (channel < 0)
+               return 0;
+
+       return vc4_crtc_disable(crtc, channel);
+}
+
 static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_state)
 {
+       struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
        struct drm_device *dev = crtc->dev;
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-       int ret;
 
        require_hvs_enabled(dev);
 
        /* Disable vblank irq handling before crtc is disabled. */
        drm_crtc_vblank_off(crtc);
 
-       CRTC_WRITE(PV_V_CONTROL,
-                  CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
-       ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
-       WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n");
-
-       vc4_hvs_atomic_disable(crtc, old_state);
+       vc4_crtc_disable(crtc, old_vc4_state->assigned_channel);
 
        /*
         * Make sure we issue a vblank event after disabling the CRTC if
@@ -390,6 +503,8 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
+       struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
 
        require_hvs_enabled(dev);
 
@@ -400,11 +515,24 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
 
        vc4_hvs_atomic_enable(crtc, old_state);
 
+       if (vc4_encoder->pre_crtc_configure)
+               vc4_encoder->pre_crtc_configure(encoder);
+
+       vc4_crtc_config_pv(crtc);
+
+       CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN);
+
+       if (vc4_encoder->pre_crtc_enable)
+               vc4_encoder->pre_crtc_enable(encoder);
+
        /* When feeding the transposer block the pixelvalve is unneeded and
         * should not be enabled.
         */
        CRTC_WRITE(PV_V_CONTROL,
                   CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
+
+       if (vc4_encoder->post_crtc_enable)
+               vc4_encoder->post_crtc_enable(encoder);
 }
 
 static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc,
@@ -499,7 +627,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
-       u32 chan = vc4_crtc->channel;
+       u32 chan = vc4_state->assigned_channel;
        unsigned long flags;
 
        spin_lock_irqsave(&dev->event_lock, flags);
@@ -516,7 +644,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
                 * the CRTC and encoder already reconfigured, leading to
                 * underruns. This can be seen when reconfiguring the CRTC.
                 */
-               vc4_hvs_unmask_underrun(dev, vc4_crtc->channel);
+               vc4_hvs_unmask_underrun(dev, chan);
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
@@ -698,6 +826,7 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
        old_vc4_state = to_vc4_crtc_state(crtc->state);
        vc4_state->feed_txp = old_vc4_state->feed_txp;
        vc4_state->margins = old_vc4_state->margins;
+       vc4_state->assigned_channel = old_vc4_state->assigned_channel;
 
        __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
        return &vc4_state->base;
@@ -747,7 +876,6 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
 };
 
 static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
-       .mode_set_nofb = vc4_crtc_mode_set_nofb,
        .mode_valid = vc4_crtc_mode_valid,
        .atomic_check = vc4_crtc_atomic_check,
        .atomic_flush = vc4_hvs_atomic_flush,
@@ -758,9 +886,12 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
 
 static const struct vc4_pv_data bcm2835_pv0_data = {
        .base = {
-               .hvs_channel = 0,
+               .hvs_available_channels = BIT(0),
+               .hvs_output = 0,
        },
        .debugfs_name = "crtc0_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 1,
        .encoder_types = {
                [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
                [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
@@ -769,9 +900,12 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
 
 static const struct vc4_pv_data bcm2835_pv1_data = {
        .base = {
-               .hvs_channel = 2,
+               .hvs_available_channels = BIT(2),
+               .hvs_output = 2,
        },
        .debugfs_name = "crtc1_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 1,
        .encoder_types = {
                [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
                [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
@@ -780,19 +914,94 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
 
 static const struct vc4_pv_data bcm2835_pv2_data = {
        .base = {
-               .hvs_channel = 1,
+               .hvs_available_channels = BIT(1),
+               .hvs_output = 1,
        },
        .debugfs_name = "crtc2_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 1,
        .encoder_types = {
-               [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
+               [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0,
                [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
        },
 };
 
+static const struct vc4_pv_data bcm2711_pv0_data = {
+       .base = {
+               .hvs_available_channels = BIT(0),
+               .hvs_output = 0,
+       },
+       .debugfs_name = "crtc0_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 1,
+       .encoder_types = {
+               [0] = VC4_ENCODER_TYPE_DSI0,
+               [1] = VC4_ENCODER_TYPE_DPI,
+       },
+};
+
+static const struct vc4_pv_data bcm2711_pv1_data = {
+       .base = {
+               .hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
+               .hvs_output = 3,
+       },
+       .debugfs_name = "crtc1_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 1,
+       .encoder_types = {
+               [0] = VC4_ENCODER_TYPE_DSI1,
+               [1] = VC4_ENCODER_TYPE_SMI,
+       },
+};
+
+static const struct vc4_pv_data bcm2711_pv2_data = {
+       .base = {
+               .hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
+               .hvs_output = 4,
+       },
+       .debugfs_name = "crtc2_regs",
+       .fifo_depth = 256,
+       .pixels_per_clock = 2,
+       .encoder_types = {
+               [0] = VC4_ENCODER_TYPE_HDMI0,
+       },
+};
+
+static const struct vc4_pv_data bcm2711_pv3_data = {
+       .base = {
+               .hvs_available_channels = BIT(1),
+               .hvs_output = 1,
+       },
+       .debugfs_name = "crtc3_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 1,
+       .encoder_types = {
+               [0] = VC4_ENCODER_TYPE_VEC,
+       },
+};
+
+static const struct vc4_pv_data bcm2711_pv4_data = {
+       .base = {
+               .hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
+               .hvs_output = 5,
+       },
+       .debugfs_name = "crtc4_regs",
+       .fifo_depth = 64,
+       .pixels_per_clock = 2,
+       .encoder_types = {
+               [0] = VC4_ENCODER_TYPE_HDMI1,
+       },
+};
+
 static const struct of_device_id vc4_crtc_dt_match[] = {
        { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data },
        { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data },
        { .compatible = "brcm,bcm2835-pixelvalve2", .data = &bcm2835_pv2_data },
+       { .compatible = "brcm,bcm2711-pixelvalve0", .data = &bcm2711_pv0_data },
+       { .compatible = "brcm,bcm2711-pixelvalve1", .data = &bcm2711_pv1_data },
+       { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data },
+       { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data },
+       { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data },
        {}
 };
 
@@ -819,26 +1028,11 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
        }
 }
 
-static void
-vc4_crtc_get_cob_allocation(struct vc4_crtc *vc4_crtc)
-{
-       struct drm_device *drm = vc4_crtc->base.dev;
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
-       u32 dispbase = HVS_READ(SCALER_DISPBASEX(vc4_crtc->channel));
-       /* Top/base are supposed to be 4-pixel aligned, but the
-        * Raspberry Pi firmware fills the low bits (which are
-        * presumably ignored).
-        */
-       u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
-       u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
-
-       vc4_crtc->cob_size = top - base + 4;
-}
-
 int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
                  const struct drm_crtc_funcs *crtc_funcs,
                  const struct drm_crtc_helper_funcs *crtc_helper_funcs)
 {
+       struct vc4_dev *vc4 = to_vc4_dev(drm);
        struct drm_crtc *crtc = &vc4_crtc->base;
        struct drm_plane *primary_plane;
        unsigned int i;
@@ -858,15 +1052,17 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
        drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
                                  crtc_funcs, NULL);
        drm_crtc_helper_add(crtc, crtc_helper_funcs);
-       vc4_crtc->channel = vc4_crtc->data->hvs_channel;
-       drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
-       drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
 
-       /* We support CTM, but only for one CRTC at a time. It's therefore
-        * implemented as private driver state in vc4_kms, not here.
-        */
-       drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
-       vc4_crtc_get_cob_allocation(vc4_crtc);
+       if (!vc4->hvs->hvs5) {
+               drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
+
+               drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
+
+               /* We support CTM, but only for one CRTC at a time. It's therefore
+                * implemented as private driver state in vc4_kms, not here.
+                */
+               drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
+       }
 
        for (i = 0; i < crtc->gamma_size; i++) {
                vc4_crtc->lut_r[i] = i;
@@ -915,7 +1111,9 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
        CRTC_WRITE(PV_INTEN, 0);
        CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START);
        ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-                              vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc);
+                              vc4_crtc_irq_handler,
+                              IRQF_SHARED,
+                              "vc4 crtc", vc4_crtc);
        if (ret)
                goto err_destroy_planes;
 
index 38343d2fb4fb4753ba13cd3a20653bffcb21cdc3..f1a5fd5dab6f5caf103a98764449fa79bfaf374f 100644 (file)
@@ -252,6 +252,7 @@ static int vc4_drm_bind(struct device *dev)
        struct drm_device *drm;
        struct vc4_dev *vc4;
        struct device_node *node;
+       struct drm_crtc *crtc;
        int ret = 0;
 
        dev->coherent_dma_mask = DMA_BIT_MASK(32);
@@ -298,6 +299,9 @@ static int vc4_drm_bind(struct device *dev)
        if (ret < 0)
                goto unbind_all;
 
+       drm_for_each_crtc(crtc, drm)
+               vc4_crtc_disable_at_boot(crtc);
+
        ret = drm_dev_register(drm, 0);
        if (ret < 0)
                goto unbind_all;
@@ -368,6 +372,7 @@ static int vc4_platform_drm_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id vc4_of_match[] = {
+       { .compatible = "brcm,bcm2711-vc5", },
        { .compatible = "brcm,bcm2835-vc4", },
        { .compatible = "brcm,cygnus-vc4", },
        {},
index fa19160c801f8e8e48d8d3a3e6aba1629f63902b..8c8d96b6289f40cd89e73b0516258ebebad4c482 100644 (file)
@@ -73,7 +73,6 @@ struct vc4_perfmon {
 struct vc4_dev {
        struct drm_device *dev;
 
-       struct vc4_hdmi *hdmi;
        struct vc4_hvs *hvs;
        struct vc4_v3d *v3d;
        struct vc4_dpi *dpi;
@@ -201,6 +200,9 @@ struct vc4_dev {
 
        int power_refcount;
 
+       /* Set to true when the load tracker is supported. */
+       bool load_tracker_available;
+
        /* Set to true when the load tracker is active. */
        bool load_tracker_enabled;
 
@@ -320,6 +322,8 @@ struct vc4_hvs {
        void __iomem *regs;
        u32 __iomem *dlist;
 
+       struct clk *core_clk;
+
        /* Memory manager for CRTCs to allocate space in the display
         * list.  Units are dwords.
         */
@@ -329,7 +333,11 @@ struct vc4_hvs {
        spinlock_t mm_lock;
 
        struct drm_mm_node mitchell_netravali_filter;
+
        struct debugfs_regset32 regset;
+
+       /* HVS version 5 flag, therefore requires updated dlist structures */
+       bool hvs5;
 };
 
 struct vc4_plane {
@@ -420,7 +428,8 @@ to_vc4_plane_state(struct drm_plane_state *state)
 
 enum vc4_encoder_type {
        VC4_ENCODER_TYPE_NONE,
-       VC4_ENCODER_TYPE_HDMI,
+       VC4_ENCODER_TYPE_HDMI0,
+       VC4_ENCODER_TYPE_HDMI1,
        VC4_ENCODER_TYPE_VEC,
        VC4_ENCODER_TYPE_DSI0,
        VC4_ENCODER_TYPE_DSI1,
@@ -432,6 +441,13 @@ struct vc4_encoder {
        struct drm_encoder base;
        enum vc4_encoder_type type;
        u32 clock_select;
+
+       void (*pre_crtc_configure)(struct drm_encoder *encoder);
+       void (*pre_crtc_enable)(struct drm_encoder *encoder);
+       void (*post_crtc_enable)(struct drm_encoder *encoder);
+
+       void (*post_crtc_disable)(struct drm_encoder *encoder);
+       void (*post_crtc_powerdown)(struct drm_encoder *encoder);
 };
 
 static inline struct vc4_encoder *
@@ -441,13 +457,22 @@ to_vc4_encoder(struct drm_encoder *encoder)
 }
 
 struct vc4_crtc_data {
-       /* Which channel of the HVS this pixelvalve sources from. */
-       int hvs_channel;
+       /* Bitmask of channels (FIFOs) of the HVS that the output can source from */
+       unsigned int hvs_available_channels;
+
+       /* Which output of the HVS this pixelvalve sources from. */
+       int hvs_output;
 };
 
 struct vc4_pv_data {
        struct vc4_crtc_data    base;
 
+       /* Depth of the PixelValve FIFO in bytes */
+       unsigned int fifo_depth;
+
+       /* Number of pixels output per clock period */
+       u8 pixels_per_clock;
+
        enum vc4_encoder_type encoder_types[4];
        const char *debugfs_name;
 
@@ -462,14 +487,9 @@ struct vc4_crtc {
        /* Timestamp at start of vblank irq - unaffected by lock delays. */
        ktime_t t_vblank;
 
-       /* Which HVS channel we're using for our CRTC. */
-       int channel;
-
        u8 lut_r[256];
        u8 lut_g[256];
        u8 lut_b[256];
-       /* Size in pixels of the COB memory allocated to this CRTC. */
-       u32 cob_size;
 
        struct drm_pending_vblank_event *event;
 
@@ -502,6 +522,7 @@ struct vc4_crtc_state {
        struct drm_mm_node mm;
        bool feed_txp;
        bool txp_armed;
+       unsigned int assigned_channel;
 
        struct {
                unsigned int left;
@@ -794,6 +815,7 @@ void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo);
 
 /* vc4_crtc.c */
 extern struct platform_driver vc4_crtc_driver;
+int vc4_crtc_disable_at_boot(struct drm_crtc *crtc);
 int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
                  const struct drm_crtc_funcs *crtc_funcs,
                  const struct drm_crtc_helper_funcs *crtc_helper_funcs);
@@ -888,11 +910,12 @@ void vc4_irq_reset(struct drm_device *dev);
 
 /* vc4_hvs.c */
 extern struct platform_driver vc4_hvs_driver;
+void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output);
+int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output);
 int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state);
 void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
 void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state);
 void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *state);
-void vc4_hvs_mode_set_nofb(struct drm_crtc *crtc);
 void vc4_hvs_dump_state(struct drm_device *dev);
 void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel);
 void vc4_hvs_mask_underrun(struct drm_device *dev, int channel);
index 15a11cd4de256a94cb528cc5a4d2770b7726af0b..03825596a3085f66883f26e47157bf31de5690d6 100644 (file)
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 #include <linux/rational.h>
+#include <linux/reset.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm_drm_eld.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include "media/cec.h"
 #include "vc4_drv.h"
+#include "vc4_hdmi.h"
+#include "vc4_hdmi_regs.h"
 #include "vc4_regs.h"
 
-#define HSM_CLOCK_FREQ 163682864
-#define CEC_CLOCK_FREQ 40000
-#define CEC_CLOCK_DIV  (HSM_CLOCK_FREQ / CEC_CLOCK_FREQ)
-
-/* HDMI audio information */
-struct vc4_hdmi_audio {
-       struct snd_soc_card card;
-       struct snd_soc_dai_link link;
-       struct snd_soc_dai_link_component cpu;
-       struct snd_soc_dai_link_component codec;
-       struct snd_soc_dai_link_component platform;
-       int samplerate;
-       int channels;
-       struct snd_dmaengine_dai_dma_data dma_data;
-       struct snd_pcm_substream *substream;
-};
+#define VC5_HDMI_HORZA_HFP_SHIFT               16
+#define VC5_HDMI_HORZA_HFP_MASK                        VC4_MASK(28, 16)
+#define VC5_HDMI_HORZA_VPOS                    BIT(15)
+#define VC5_HDMI_HORZA_HPOS                    BIT(14)
+#define VC5_HDMI_HORZA_HAP_SHIFT               0
+#define VC5_HDMI_HORZA_HAP_MASK                        VC4_MASK(13, 0)
 
-/* General HDMI hardware state. */
-struct vc4_hdmi {
-       struct platform_device *pdev;
-
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
+#define VC5_HDMI_HORZB_HBP_SHIFT               16
+#define VC5_HDMI_HORZB_HBP_MASK                        VC4_MASK(26, 16)
+#define VC5_HDMI_HORZB_HSP_SHIFT               0
+#define VC5_HDMI_HORZB_HSP_MASK                        VC4_MASK(10, 0)
 
-       struct vc4_hdmi_audio audio;
+#define VC5_HDMI_VERTA_VSP_SHIFT               24
+#define VC5_HDMI_VERTA_VSP_MASK                        VC4_MASK(28, 24)
+#define VC5_HDMI_VERTA_VFP_SHIFT               16
+#define VC5_HDMI_VERTA_VFP_MASK                        VC4_MASK(22, 16)
+#define VC5_HDMI_VERTA_VAL_SHIFT               0
+#define VC5_HDMI_VERTA_VAL_MASK                        VC4_MASK(12, 0)
 
-       struct i2c_adapter *ddc;
-       void __iomem *hdmicore_regs;
-       void __iomem *hd_regs;
-       int hpd_gpio;
-       bool hpd_active_low;
+#define VC5_HDMI_VERTB_VSPO_SHIFT              16
+#define VC5_HDMI_VERTB_VSPO_MASK               VC4_MASK(29, 16)
 
-       struct cec_adapter *cec_adap;
-       struct cec_msg cec_rx_msg;
-       bool cec_tx_ok;
-       bool cec_irq_was_rx;
+# define VC4_HD_M_SW_RST                       BIT(2)
+# define VC4_HD_M_ENABLE                       BIT(0)
 
-       struct clk *pixel_clock;
-       struct clk *hsm_clock;
+#define CEC_CLOCK_FREQ 40000
+#define VC4_HSM_MID_CLOCK 149985000
 
-       struct debugfs_regset32 hdmi_regset;
-       struct debugfs_regset32 hd_regset;
-};
+static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct vc4_hdmi *vc4_hdmi = node->info_ent->data;
+       struct drm_printer p = drm_seq_file_printer(m);
 
-#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset)
-#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset)
-#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset)
-#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset)
+       drm_print_regset32(&p, &vc4_hdmi->hdmi_regset);
+       drm_print_regset32(&p, &vc4_hdmi->hd_regset);
 
-/* VC4 HDMI encoder KMS struct */
-struct vc4_hdmi_encoder {
-       struct vc4_encoder base;
-       bool hdmi_monitor;
-       bool limited_rgb_range;
-};
+       return 0;
+}
 
-static inline struct vc4_hdmi_encoder *
-to_vc4_hdmi_encoder(struct drm_encoder *encoder)
+static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
 {
-       return container_of(encoder, struct vc4_hdmi_encoder, base.base);
-}
+       HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST);
+       udelay(1);
+       HDMI_WRITE(HDMI_M_CTL, 0);
 
-/* VC4 HDMI connector KMS struct */
-struct vc4_hdmi_connector {
-       struct drm_connector base;
+       HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_ENABLE);
 
-       /* Since the connector is attached to just the one encoder,
-        * this is the reference to it so we can do the best_encoder()
-        * hook.
-        */
-       struct drm_encoder *encoder;
-};
+       HDMI_WRITE(HDMI_SW_RESET_CONTROL,
+                  VC4_HDMI_SW_RESET_HDMI |
+                  VC4_HDMI_SW_RESET_FORMAT_DETECT);
 
-static inline struct vc4_hdmi_connector *
-to_vc4_hdmi_connector(struct drm_connector *connector)
-{
-       return container_of(connector, struct vc4_hdmi_connector, base);
+       HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
 }
 
-static const struct debugfs_reg32 hdmi_regs[] = {
-       VC4_REG32(VC4_HDMI_CORE_REV),
-       VC4_REG32(VC4_HDMI_SW_RESET_CONTROL),
-       VC4_REG32(VC4_HDMI_HOTPLUG_INT),
-       VC4_REG32(VC4_HDMI_HOTPLUG),
-       VC4_REG32(VC4_HDMI_MAI_CHANNEL_MAP),
-       VC4_REG32(VC4_HDMI_MAI_CONFIG),
-       VC4_REG32(VC4_HDMI_MAI_FORMAT),
-       VC4_REG32(VC4_HDMI_AUDIO_PACKET_CONFIG),
-       VC4_REG32(VC4_HDMI_RAM_PACKET_CONFIG),
-       VC4_REG32(VC4_HDMI_HORZA),
-       VC4_REG32(VC4_HDMI_HORZB),
-       VC4_REG32(VC4_HDMI_FIFO_CTL),
-       VC4_REG32(VC4_HDMI_SCHEDULER_CONTROL),
-       VC4_REG32(VC4_HDMI_VERTA0),
-       VC4_REG32(VC4_HDMI_VERTA1),
-       VC4_REG32(VC4_HDMI_VERTB0),
-       VC4_REG32(VC4_HDMI_VERTB1),
-       VC4_REG32(VC4_HDMI_TX_PHY_RESET_CTL),
-       VC4_REG32(VC4_HDMI_TX_PHY_CTL0),
-
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_1),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_2),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_3),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_4),
-       VC4_REG32(VC4_HDMI_CEC_CNTRL_5),
-       VC4_REG32(VC4_HDMI_CPU_STATUS),
-       VC4_REG32(VC4_HDMI_CPU_MASK_STATUS),
-
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_1),
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_2),
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_3),
-       VC4_REG32(VC4_HDMI_CEC_RX_DATA_4),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_1),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_2),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_3),
-       VC4_REG32(VC4_HDMI_CEC_TX_DATA_4),
-};
-
-static const struct debugfs_reg32 hd_regs[] = {
-       VC4_REG32(VC4_HD_M_CTL),
-       VC4_REG32(VC4_HD_MAI_CTL),
-       VC4_REG32(VC4_HD_MAI_THR),
-       VC4_REG32(VC4_HD_MAI_FMT),
-       VC4_REG32(VC4_HD_MAI_SMP),
-       VC4_REG32(VC4_HD_VID_CTL),
-       VC4_REG32(VC4_HD_CSC_CTL),
-       VC4_REG32(VC4_HD_FRAME_COUNT),
-};
-
-static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
+static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
 {
-       struct drm_info_node *node = (struct drm_info_node *)m->private;
-       struct drm_device *dev = node->minor->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_hdmi *hdmi = vc4->hdmi;
-       struct drm_printer p = drm_seq_file_printer(m);
+       reset_control_reset(vc4_hdmi->reset);
 
-       drm_print_regset32(&p, &hdmi->hdmi_regset);
-       drm_print_regset32(&p, &hdmi->hd_regset);
+       HDMI_WRITE(HDMI_DVP_CTL, 0);
 
-       return 0;
+       HDMI_WRITE(HDMI_CLOCK_STOP,
+                  HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL);
 }
 
 static enum drm_connector_status
 vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
 {
-       struct drm_device *dev = connector->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
 
-       if (vc4->hdmi->hpd_gpio) {
-               if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
-                   vc4->hdmi->hpd_active_low)
+       if (vc4_hdmi->hpd_gpio) {
+               if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^
+                   vc4_hdmi->hpd_active_low)
                        return connector_status_connected;
-               cec_phys_addr_invalidate(vc4->hdmi->cec_adap);
+               cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
                return connector_status_disconnected;
        }
 
-       if (drm_probe_ddc(vc4->hdmi->ddc))
+       if (drm_probe_ddc(vc4_hdmi->ddc))
                return connector_status_connected;
 
-       if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
+       if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
                return connector_status_connected;
-       cec_phys_addr_invalidate(vc4->hdmi->cec_adap);
+       cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
        return connector_status_disconnected;
 }
 
@@ -225,17 +149,13 @@ static void vc4_hdmi_connector_destroy(struct drm_connector *connector)
 
 static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
 {
-       struct vc4_hdmi_connector *vc4_connector =
-               to_vc4_hdmi_connector(connector);
-       struct drm_encoder *encoder = vc4_connector->encoder;
-       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
-       struct drm_device *dev = connector->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+       struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder;
        int ret = 0;
        struct edid *edid;
 
-       edid = drm_get_edid(connector, vc4->hdmi->ddc);
-       cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
+       edid = drm_get_edid(connector, vc4_hdmi->ddc);
+       cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
        if (!edid)
                return -ENODEV;
 
@@ -267,32 +187,23 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs =
        .get_modes = vc4_hdmi_connector_get_modes,
 };
 
-static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
-                                                    struct drm_encoder *encoder,
-                                                    struct i2c_adapter *ddc)
+static int vc4_hdmi_connector_init(struct drm_device *dev,
+                                  struct vc4_hdmi *vc4_hdmi)
 {
-       struct drm_connector *connector;
-       struct vc4_hdmi_connector *hdmi_connector;
+       struct drm_connector *connector = &vc4_hdmi->connector;
+       struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
        int ret;
 
-       hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector),
-                                     GFP_KERNEL);
-       if (!hdmi_connector)
-               return ERR_PTR(-ENOMEM);
-       connector = &hdmi_connector->base;
-
-       hdmi_connector->encoder = encoder;
-
        drm_connector_init_with_ddc(dev, connector,
                                    &vc4_hdmi_connector_funcs,
                                    DRM_MODE_CONNECTOR_HDMIA,
-                                   ddc);
+                                   vc4_hdmi->ddc);
        drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
 
        /* Create and attach TV margin props to this connector. */
        ret = drm_mode_create_tv_margin_properties(dev);
        if (ret)
-               return ERR_PTR(ret);
+               return ret;
 
        drm_connector_attach_tv_margin_properties(connector);
 
@@ -304,35 +215,37 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
 
        drm_connector_attach_encoder(connector, encoder);
 
-       return connector;
+       return 0;
 }
 
 static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type)
 {
-       struct drm_device *dev = encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        u32 packet_id = type - 0x80;
 
-       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
-                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
 
-       return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+       return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) &
                          BIT(packet_id)), 100);
 }
 
 static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
                                     union hdmi_infoframe *frame)
 {
-       struct drm_device *dev = encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        u32 packet_id = frame->any.type - 0x80;
-       u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id);
+       const struct vc4_hdmi_register *ram_packet_start =
+               &vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START];
+       u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id;
+       void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
+                                                      ram_packet_start->reg);
        uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
        ssize_t len, i;
        int ret;
 
-       WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+       WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
                    VC4_HDMI_RAM_PACKET_ENABLE),
                  "Packet RAM has to be on to store the packet.");
 
@@ -347,23 +260,23 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
        }
 
        for (i = 0; i < len; i += 7) {
-               HDMI_WRITE(packet_reg,
-                          buffer[i + 0] << 0 |
-                          buffer[i + 1] << 8 |
-                          buffer[i + 2] << 16);
+               writel(buffer[i + 0] << 0 |
+                      buffer[i + 1] << 8 |
+                      buffer[i + 2] << 16,
+                      base + packet_reg);
                packet_reg += 4;
 
-               HDMI_WRITE(packet_reg,
-                          buffer[i + 3] << 0 |
-                          buffer[i + 4] << 8 |
-                          buffer[i + 5] << 16 |
-                          buffer[i + 6] << 24);
+               writel(buffer[i + 3] << 0 |
+                      buffer[i + 4] << 8 |
+                      buffer[i + 5] << 16 |
+                      buffer[i + 6] << 24,
+                      base + packet_reg);
                packet_reg += 4;
        }
 
-       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
-                  HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
-       ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
+                  HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
+       ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
                        BIT(packet_id)), 100);
        if (ret)
                DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
@@ -371,24 +284,24 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
 
 static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
 {
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
-       struct vc4_dev *vc4 = encoder->dev->dev_private;
-       struct vc4_hdmi *hdmi = vc4->hdmi;
-       struct drm_connector_state *cstate = hdmi->connector->state;
+       struct drm_connector *connector = &vc4_hdmi->connector;
+       struct drm_connector_state *cstate = connector->state;
        struct drm_crtc *crtc = encoder->crtc;
        const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
        union hdmi_infoframe frame;
        int ret;
 
        ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-                                                      hdmi->connector, mode);
+                                                      connector, mode);
        if (ret < 0) {
                DRM_ERROR("couldn't fill AVI infoframe\n");
                return;
        }
 
        drm_hdmi_avi_infoframe_quant_range(&frame.avi,
-                                          hdmi->connector, mode,
+                                          connector, mode,
                                           vc4_encoder->limited_rgb_range ?
                                           HDMI_QUANTIZATION_RANGE_LIMITED :
                                           HDMI_QUANTIZATION_RANGE_FULL);
@@ -416,9 +329,7 @@ static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
 
 static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
 {
-       struct drm_device *drm = encoder->dev;
-       struct vc4_dev *vc4 = drm->dev_private;
-       struct vc4_hdmi *hdmi = vc4->hdmi;
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        union hdmi_infoframe frame;
        int ret;
 
@@ -427,45 +338,139 @@ static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
        frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
        frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
        frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
-       frame.audio.channels = hdmi->audio.channels;
+       frame.audio.channels = vc4_hdmi->audio.channels;
 
        vc4_hdmi_write_infoframe(encoder, &frame);
 }
 
 static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
 {
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+
        vc4_hdmi_set_avi_infoframe(encoder);
        vc4_hdmi_set_spd_infoframe(encoder);
+       /*
+        * If audio was streaming, then we need to reenabled the audio
+        * infoframe here during encoder_enable.
+        */
+       if (vc4_hdmi->audio.streaming)
+               vc4_hdmi_set_audio_infoframe(encoder);
 }
 
-static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_hdmi *hdmi = vc4->hdmi;
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
+
+       HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) |
+                  VC4_HD_VID_CTL_CLRRGB | VC4_HD_VID_CTL_CLRSYNC);
+
+       HDMI_WRITE(HDMI_VID_CTL,
+                  HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
+}
+
+static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder)
+{
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        int ret;
 
-       HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
+       if (vc4_hdmi->variant->phy_disable)
+               vc4_hdmi->variant->phy_disable(vc4_hdmi);
 
-       HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
-       HD_WRITE(VC4_HD_VID_CTL,
-                HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
+       HDMI_WRITE(HDMI_VID_CTL,
+                  HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
 
-       clk_disable_unprepare(hdmi->pixel_clock);
+       clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
+       clk_disable_unprepare(vc4_hdmi->hsm_clock);
+       clk_disable_unprepare(vc4_hdmi->pixel_clock);
 
-       ret = pm_runtime_put(&hdmi->pdev->dev);
+       ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
        if (ret < 0)
                DRM_ERROR("Failed to release power domain: %d\n", ret);
 }
 
-static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
+{
+       u32 csc_ctl;
+
+       csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
+                               VC4_HD_CSC_CTL_ORDER);
+
+       if (enable) {
+               /* CEA VICs other than #1 requre limited range RGB
+                * output unless overridden by an AVI infoframe.
+                * Apply a colorspace conversion to squash 0-255 down
+                * to 16-235.  The matrix here is:
+                *
+                * [ 0      0      0.8594 16]
+                * [ 0      0.8594 0      16]
+                * [ 0.8594 0      0      16]
+                * [ 0      0      0       1]
+                */
+               csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
+               csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
+               csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
+                                        VC4_HD_CSC_CTL_MODE);
+
+               HDMI_WRITE(HDMI_CSC_12_11, (0x000 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_14_13, (0x100 << 16) | 0x6e0);
+               HDMI_WRITE(HDMI_CSC_22_21, (0x6e0 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_24_23, (0x100 << 16) | 0x000);
+               HDMI_WRITE(HDMI_CSC_32_31, (0x000 << 16) | 0x6e0);
+               HDMI_WRITE(HDMI_CSC_34_33, (0x100 << 16) | 0x000);
+       }
+
+       /* The RGB order applies even when CSC is disabled. */
+       HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
+}
+
+static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
+{
+       u32 csc_ctl;
+
+       csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */
+
+       if (enable) {
+               /* CEA VICs other than #1 requre limited range RGB
+                * output unless overridden by an AVI infoframe.
+                * Apply a colorspace conversion to squash 0-255 down
+                * to 16-235.  The matrix here is:
+                *
+                * [ 0.8594 0      0      16]
+                * [ 0      0.8594 0      16]
+                * [ 0      0      0.8594 16]
+                * [ 0      0      0       1]
+                * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+                */
+               HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80);
+               HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80);
+       } else {
+               /* Still use the matrix for full range, but make it unity.
+                * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
+                */
+               HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000);
+               HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000);
+               HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000);
+       }
+
+       HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
+}
+
+static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
+                                struct drm_display_mode *mode)
 {
-       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
-       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_hdmi *hdmi = vc4->hdmi;
-       bool debug_dump_regs = false;
        bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
        bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
        bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -483,213 +488,285 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
                                        mode->crtc_vsync_end -
                                        interlaced,
                                        VC4_HDMI_VERTB_VBP));
-       u32 csc_ctl;
+
+       HDMI_WRITE(HDMI_HORZA,
+                  (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
+                  (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) |
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep,
+                                VC4_HDMI_HORZA_HAP));
+
+       HDMI_WRITE(HDMI_HORZB,
+                  VC4_SET_FIELD((mode->htotal -
+                                 mode->hsync_end) * pixel_rep,
+                                VC4_HDMI_HORZB_HBP) |
+                  VC4_SET_FIELD((mode->hsync_end -
+                                 mode->hsync_start) * pixel_rep,
+                                VC4_HDMI_HORZB_HSP) |
+                  VC4_SET_FIELD((mode->hsync_start -
+                                 mode->hdisplay) * pixel_rep,
+                                VC4_HDMI_HORZB_HFP));
+
+       HDMI_WRITE(HDMI_VERTA0, verta);
+       HDMI_WRITE(HDMI_VERTA1, verta);
+
+       HDMI_WRITE(HDMI_VERTB0, vertb_even);
+       HDMI_WRITE(HDMI_VERTB1, vertb);
+}
+static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
+                                struct drm_display_mode *mode)
+{
+       bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
+       bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+       bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
+       u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
+       u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
+                                  VC5_HDMI_VERTA_VSP) |
+                    VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
+                                  VC5_HDMI_VERTA_VFP) |
+                    VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
+       u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
+                    VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
+                                  VC4_HDMI_VERTB_VBP));
+       u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
+                         VC4_SET_FIELD(mode->crtc_vtotal -
+                                       mode->crtc_vsync_end -
+                                       interlaced,
+                                       VC4_HDMI_VERTB_VBP));
+
+       HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
+       HDMI_WRITE(HDMI_HORZA,
+                  (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) |
+                  (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) |
+                  VC4_SET_FIELD(mode->hdisplay * pixel_rep,
+                                VC5_HDMI_HORZA_HAP) |
+                  VC4_SET_FIELD((mode->hsync_start -
+                                 mode->hdisplay) * pixel_rep,
+                                VC5_HDMI_HORZA_HFP));
+
+       HDMI_WRITE(HDMI_HORZB,
+                  VC4_SET_FIELD((mode->htotal -
+                                 mode->hsync_end) * pixel_rep,
+                                VC5_HDMI_HORZB_HBP) |
+                  VC4_SET_FIELD((mode->hsync_end -
+                                 mode->hsync_start) * pixel_rep,
+                                VC5_HDMI_HORZB_HSP));
+
+       HDMI_WRITE(HDMI_VERTA0, verta);
+       HDMI_WRITE(HDMI_VERTA1, verta);
+
+       HDMI_WRITE(HDMI_VERTB0, vertb_even);
+       HDMI_WRITE(HDMI_VERTB1, vertb);
+
+       HDMI_WRITE(HDMI_CLOCK_STOP, 0);
+}
+
+static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
+{
+       u32 drift;
+       int ret;
+
+       drift = HDMI_READ(HDMI_FIFO_CTL);
+       drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
+
+       HDMI_WRITE(HDMI_FIFO_CTL,
+                  drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
+       HDMI_WRITE(HDMI_FIFO_CTL,
+                  drift | VC4_HDMI_FIFO_CTL_RECENTER);
+       usleep_range(1000, 1100);
+       HDMI_WRITE(HDMI_FIFO_CTL,
+                  drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
+       HDMI_WRITE(HDMI_FIFO_CTL,
+                  drift | VC4_HDMI_FIFO_CTL_RECENTER);
+
+       ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) &
+                      VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
+       WARN_ONCE(ret, "Timeout waiting for "
+                 "VC4_HDMI_FIFO_CTL_RECENTER_DONE");
+}
+
+static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder)
+{
+       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+       unsigned long pixel_rate, hsm_rate;
        int ret;
 
-       ret = pm_runtime_get_sync(&hdmi->pdev->dev);
+       ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev);
        if (ret < 0) {
                DRM_ERROR("Failed to retain power domain: %d\n", ret);
                return;
        }
 
-       ret = clk_set_rate(hdmi->pixel_clock,
-                          mode->clock * 1000 *
-                          ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1));
+       pixel_rate = mode->clock * 1000 * ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1);
+       ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
        if (ret) {
                DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
                return;
        }
 
-       ret = clk_prepare_enable(hdmi->pixel_clock);
+       ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
        if (ret) {
                DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
                return;
        }
 
-       HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL,
-                  VC4_HDMI_SW_RESET_HDMI |
-                  VC4_HDMI_SW_RESET_FORMAT_DETECT);
-
-       HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0);
-
-       /* PHY should be in reset, like
-        * vc4_hdmi_encoder_disable() does.
+       /*
+        * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
+        * be faster than pixel clock, infinitesimally faster, tested in
+        * simulation. Otherwise, exact value is unimportant for HDMI
+        * operation." This conflicts with bcm2835's vc4 documentation, which
+        * states HSM's clock has to be at least 108% of the pixel clock.
+        *
+        * Real life tests reveal that vc4's firmware statement holds up, and
+        * users are able to use pixel clocks closer to HSM's, namely for
+        * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
+        * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
+        * 162MHz.
+        *
+        * Additionally, the AXI clock needs to be at least 25% of
+        * pixel clock, but HSM ends up being the limiting factor.
         */
-       HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
+       hsm_rate = max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
+       ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate);
+       if (ret) {
+               DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
+               return;
+       }
 
-       HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0);
+       ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
+       if (ret) {
+               DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
+               clk_disable_unprepare(vc4_hdmi->pixel_clock);
+               return;
+       }
 
-       if (debug_dump_regs) {
-               struct drm_printer p = drm_info_printer(&hdmi->pdev->dev);
+       /*
+        * FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup
+        * at 300MHz.
+        */
+       ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock,
+                              (hsm_rate > VC4_HSM_MID_CLOCK ? 150000000 : 75000000));
+       if (ret) {
+               DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
+               clk_disable_unprepare(vc4_hdmi->hsm_clock);
+               clk_disable_unprepare(vc4_hdmi->pixel_clock);
+               return;
+       }
 
-               dev_info(&hdmi->pdev->dev, "HDMI regs before:\n");
-               drm_print_regset32(&p, &hdmi->hdmi_regset);
-               drm_print_regset32(&p, &hdmi->hd_regset);
+       ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
+       if (ret) {
+               DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
+               clk_disable_unprepare(vc4_hdmi->hsm_clock);
+               clk_disable_unprepare(vc4_hdmi->pixel_clock);
+               return;
        }
 
-       HD_WRITE(VC4_HD_VID_CTL, 0);
+       if (vc4_hdmi->variant->reset)
+               vc4_hdmi->variant->reset(vc4_hdmi);
 
-       HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                  HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
+       if (vc4_hdmi->variant->phy_init)
+               vc4_hdmi->variant->phy_init(vc4_hdmi, mode);
+
+       HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                  HDMI_READ(HDMI_SCHEDULER_CONTROL) |
                   VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT |
                   VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
 
-       HDMI_WRITE(VC4_HDMI_HORZA,
-                  (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
-                  (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) |
-                  VC4_SET_FIELD(mode->hdisplay * pixel_rep,
-                                VC4_HDMI_HORZA_HAP));
-
-       HDMI_WRITE(VC4_HDMI_HORZB,
-                  VC4_SET_FIELD((mode->htotal -
-                                 mode->hsync_end) * pixel_rep,
-                                VC4_HDMI_HORZB_HBP) |
-                  VC4_SET_FIELD((mode->hsync_end -
-                                 mode->hsync_start) * pixel_rep,
-                                VC4_HDMI_HORZB_HSP) |
-                  VC4_SET_FIELD((mode->hsync_start -
-                                 mode->hdisplay) * pixel_rep,
-                                VC4_HDMI_HORZB_HFP));
-
-       HDMI_WRITE(VC4_HDMI_VERTA0, verta);
-       HDMI_WRITE(VC4_HDMI_VERTA1, verta);
-
-       HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even);
-       HDMI_WRITE(VC4_HDMI_VERTB1, vertb);
-
-       HD_WRITE(VC4_HD_VID_CTL,
-                (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
-                (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
+       if (vc4_hdmi->variant->set_timings)
+               vc4_hdmi->variant->set_timings(vc4_hdmi, mode);
+}
 
-       csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
-                               VC4_HD_CSC_CTL_ORDER);
+static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder)
+{
+       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 
        if (vc4_encoder->hdmi_monitor &&
-           drm_default_rgb_quant_range(mode) ==
-           HDMI_QUANTIZATION_RANGE_LIMITED) {
-               /* CEA VICs other than #1 requre limited range RGB
-                * output unless overridden by an AVI infoframe.
-                * Apply a colorspace conversion to squash 0-255 down
-                * to 16-235.  The matrix here is:
-                *
-                * [ 0      0      0.8594 16]
-                * [ 0      0.8594 0      16]
-                * [ 0.8594 0      0      16]
-                * [ 0      0      0       1]
-                */
-               csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
-               csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
-               csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
-                                        VC4_HD_CSC_CTL_MODE);
+           drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
+               if (vc4_hdmi->variant->csc_setup)
+                       vc4_hdmi->variant->csc_setup(vc4_hdmi, true);
 
-               HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
-               HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
-               HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
-               HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
-               HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
-               HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
                vc4_encoder->limited_rgb_range = true;
        } else {
+               if (vc4_hdmi->variant->csc_setup)
+                       vc4_hdmi->variant->csc_setup(vc4_hdmi, false);
+
                vc4_encoder->limited_rgb_range = false;
        }
 
-       /* The RGB order applies even when CSC is disabled. */
-       HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
-
-       HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
+       HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
+}
 
-       if (debug_dump_regs) {
-               struct drm_printer p = drm_info_printer(&hdmi->pdev->dev);
+static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder)
+{
+       struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+       bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
+       bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+       int ret;
 
-               dev_info(&hdmi->pdev->dev, "HDMI regs after:\n");
-               drm_print_regset32(&p, &hdmi->hdmi_regset);
-               drm_print_regset32(&p, &hdmi->hd_regset);
-       }
+       HDMI_WRITE(HDMI_VID_CTL,
+                  VC4_HD_VID_CTL_ENABLE |
+                  VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
+                  VC4_HD_VID_CTL_FRAME_COUNTER_RESET |
+                  (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
+                  (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
 
-       HD_WRITE(VC4_HD_VID_CTL,
-                HD_READ(VC4_HD_VID_CTL) |
-                VC4_HD_VID_CTL_ENABLE |
-                VC4_HD_VID_CTL_UNDERFLOW_ENABLE |
-                VC4_HD_VID_CTL_FRAME_COUNTER_RESET);
+       HDMI_WRITE(HDMI_VID_CTL,
+                  HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_BLANKPIX);
 
        if (vc4_encoder->hdmi_monitor) {
-               HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                          HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
+               HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                          HDMI_READ(HDMI_SCHEDULER_CONTROL) |
                           VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
-               ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                               VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        } else {
-               HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
-                          HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+               HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
+                          HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
                           ~(VC4_HDMI_RAM_PACKET_ENABLE));
-               HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                          HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                          HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                           ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
 
-               ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                                 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
                WARN_ONCE(ret, "Timeout waiting for "
                          "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        }
 
        if (vc4_encoder->hdmi_monitor) {
-               u32 drift;
-
-               WARN_ON(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
+               WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                          VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
-               HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL,
-                          HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
+               HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
+                          HDMI_READ(HDMI_SCHEDULER_CONTROL) |
                           VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
 
-               HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
+               HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
                           VC4_HDMI_RAM_PACKET_ENABLE);
 
                vc4_hdmi_set_infoframes(encoder);
-
-               drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
-               drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
-
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
-                          drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
-                          drift | VC4_HDMI_FIFO_CTL_RECENTER);
-               usleep_range(1000, 1100);
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
-                          drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
-               HDMI_WRITE(VC4_HDMI_FIFO_CTL,
-                          drift | VC4_HDMI_FIFO_CTL_RECENTER);
-
-               ret = wait_for(HDMI_READ(VC4_HDMI_FIFO_CTL) &
-                              VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
-               WARN_ONCE(ret, "Timeout waiting for "
-                         "VC4_HDMI_FIFO_CTL_RECENTER_DONE");
        }
+
+       vc4_hdmi_recenter_fifo(vc4_hdmi);
+}
+
+static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
 }
 
 static enum drm_mode_status
-vc4_hdmi_encoder_mode_valid(struct drm_encoder *crtc,
+vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
                            const struct drm_display_mode *mode)
 {
-       /*
-        * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
-        * be faster than pixel clock, infinitesimally faster, tested in
-        * simulation. Otherwise, exact value is unimportant for HDMI
-        * operation." This conflicts with bcm2835's vc4 documentation, which
-        * states HSM's clock has to be at least 108% of the pixel clock.
-        *
-        * Real life tests reveal that vc4's firmware statement holds up, and
-        * users are able to use pixel clocks closer to HSM's, namely for
-        * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
-        * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
-        * 162MHz.
-        *
-        * Additionally, the AXI clock needs to be at least 25% of
-        * pixel clock, but HSM ends up being the limiting factor.
-        */
-       if (mode->clock > HSM_CLOCK_FREQ / (1000 * 101 / 100))
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+
+       if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock)
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
@@ -701,34 +778,54 @@ static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
        .enable = vc4_hdmi_encoder_enable,
 };
 
+static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
+{
+       int i;
+       u32 channel_map = 0;
+
+       for (i = 0; i < 8; i++) {
+               if (channel_mask & BIT(i))
+                       channel_map |= i << (3 * i);
+       }
+       return channel_map;
+}
+
+static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
+{
+       int i;
+       u32 channel_map = 0;
+
+       for (i = 0; i < 8; i++) {
+               if (channel_mask & BIT(i))
+                       channel_map |= i << (4 * i);
+       }
+       return channel_map;
+}
+
 /* HDMI audio codec callbacks */
-static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *hdmi)
+static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi)
 {
-       struct drm_device *drm = hdmi->encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
-       u32 hsm_clock = clk_get_rate(hdmi->hsm_clock);
+       u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock);
        unsigned long n, m;
 
-       rational_best_approximation(hsm_clock, hdmi->audio.samplerate,
+       rational_best_approximation(hsm_clock, vc4_hdmi->audio.samplerate,
                                    VC4_HD_MAI_SMP_N_MASK >>
                                    VC4_HD_MAI_SMP_N_SHIFT,
                                    (VC4_HD_MAI_SMP_M_MASK >>
                                     VC4_HD_MAI_SMP_M_SHIFT) + 1,
                                    &n, &m);
 
-       HD_WRITE(VC4_HD_MAI_SMP,
-                VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
-                VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
+       HDMI_WRITE(HDMI_MAI_SMP,
+                  VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
+                  VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
 }
 
-static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi)
+static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi)
 {
-       struct drm_encoder *encoder = hdmi->encoder;
+       struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
        struct drm_crtc *crtc = encoder->crtc;
-       struct drm_device *drm = encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
        const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-       u32 samplerate = hdmi->audio.samplerate;
+       u32 samplerate = vc4_hdmi->audio.samplerate;
        u32 n, cts;
        u64 tmp;
 
@@ -737,7 +834,7 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi)
        do_div(tmp, 128 * samplerate);
        cts = tmp;
 
-       HDMI_WRITE(VC4_HDMI_CRP_CFG,
+       HDMI_WRITE(HDMI_CRP_CFG,
                   VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN |
                   VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N));
 
@@ -746,8 +843,8 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi)
         * providing a CTS_1 value.  The two CTS values are alternated
         * between based on the period fields
         */
-       HDMI_WRITE(VC4_HDMI_CTS_0, cts);
-       HDMI_WRITE(VC4_HDMI_CTS_1, cts);
+       HDMI_WRITE(HDMI_CTS_0, cts);
+       HDMI_WRITE(HDMI_CTS_1, cts);
 }
 
 static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
@@ -760,26 +857,25 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
 static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
-       struct vc4_hdmi *hdmi = dai_to_hdmi(dai);
-       struct drm_encoder *encoder = hdmi->encoder;
-       struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
+       struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
+       struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
+       struct drm_connector *connector = &vc4_hdmi->connector;
        int ret;
 
-       if (hdmi->audio.substream && hdmi->audio.substream != substream)
+       if (vc4_hdmi->audio.substream && vc4_hdmi->audio.substream != substream)
                return -EINVAL;
 
-       hdmi->audio.substream = substream;
+       vc4_hdmi->audio.substream = substream;
 
        /*
         * If the HDMI encoder hasn't probed, or the encoder is
         * currently in DVI mode, treat the codec dai as missing.
         */
-       if (!encoder->crtc || !(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
+       if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
                                VC4_HDMI_RAM_PACKET_ENABLE))
                return -ENODEV;
 
-       ret = snd_pcm_hw_constraint_eld(substream->runtime,
-                                       hdmi->connector->eld);
+       ret = snd_pcm_hw_constraint_eld(substream->runtime, connector->eld);
        if (ret)
                return ret;
 
@@ -791,34 +887,33 @@ static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static void vc4_hdmi_audio_reset(struct vc4_hdmi *hdmi)
+static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
 {
-       struct drm_encoder *encoder = hdmi->encoder;
-       struct drm_device *drm = encoder->dev;
-       struct device *dev = &hdmi->pdev->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
+       struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
+       struct device *dev = &vc4_hdmi->pdev->dev;
        int ret;
 
+       vc4_hdmi->audio.streaming = false;
        ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO);
        if (ret)
                dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
 
-       HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_RESET);
-       HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
-       HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
+       HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET);
+       HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
+       HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
 }
 
 static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream,
                                    struct snd_soc_dai *dai)
 {
-       struct vc4_hdmi *hdmi = dai_to_hdmi(dai);
+       struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
 
-       if (substream != hdmi->audio.substream)
+       if (substream != vc4_hdmi->audio.substream)
                return;
 
-       vc4_hdmi_audio_reset(hdmi);
+       vc4_hdmi_audio_reset(vc4_hdmi);
 
-       hdmi->audio.substream = NULL;
+       vc4_hdmi->audio.substream = NULL;
 }
 
 /* HDMI audio codec callbacks */
@@ -826,72 +921,65 @@ static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *dai)
 {
-       struct vc4_hdmi *hdmi = dai_to_hdmi(dai);
-       struct drm_encoder *encoder = hdmi->encoder;
-       struct drm_device *drm = encoder->dev;
-       struct device *dev = &hdmi->pdev->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
+       struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
+       struct device *dev = &vc4_hdmi->pdev->dev;
        u32 audio_packet_config, channel_mask;
-       u32 channel_map, i;
+       u32 channel_map;
 
-       if (substream != hdmi->audio.substream)
+       if (substream != vc4_hdmi->audio.substream)
                return -EINVAL;
 
        dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
                params_rate(params), params_width(params),
                params_channels(params));
 
-       hdmi->audio.channels = params_channels(params);
-       hdmi->audio.samplerate = params_rate(params);
+       vc4_hdmi->audio.channels = params_channels(params);
+       vc4_hdmi->audio.samplerate = params_rate(params);
 
-       HD_WRITE(VC4_HD_MAI_CTL,
-                VC4_HD_MAI_CTL_RESET |
-                VC4_HD_MAI_CTL_FLUSH |
-                VC4_HD_MAI_CTL_DLATE |
-                VC4_HD_MAI_CTL_ERRORE |
-                VC4_HD_MAI_CTL_ERRORF);
+       HDMI_WRITE(HDMI_MAI_CTL,
+                  VC4_HD_MAI_CTL_RESET |
+                  VC4_HD_MAI_CTL_FLUSH |
+                  VC4_HD_MAI_CTL_DLATE |
+                  VC4_HD_MAI_CTL_ERRORE |
+                  VC4_HD_MAI_CTL_ERRORF);
 
-       vc4_hdmi_audio_set_mai_clock(hdmi);
+       vc4_hdmi_audio_set_mai_clock(vc4_hdmi);
 
+       /* The B frame identifier should match the value used by alsa-lib (8) */
        audio_packet_config =
                VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT |
                VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS |
-               VC4_SET_FIELD(0xf, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER);
+               VC4_SET_FIELD(0x8, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER);
 
-       channel_mask = GENMASK(hdmi->audio.channels - 1, 0);
+       channel_mask = GENMASK(vc4_hdmi->audio.channels - 1, 0);
        audio_packet_config |= VC4_SET_FIELD(channel_mask,
                                             VC4_HDMI_AUDIO_PACKET_CEA_MASK);
 
        /* Set the MAI threshold.  This logic mimics the firmware's. */
-       if (hdmi->audio.samplerate > 96000) {
-               HD_WRITE(VC4_HD_MAI_THR,
-                        VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) |
-                        VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
-       } else if (hdmi->audio.samplerate > 48000) {
-               HD_WRITE(VC4_HD_MAI_THR,
-                        VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) |
-                        VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
+       if (vc4_hdmi->audio.samplerate > 96000) {
+               HDMI_WRITE(HDMI_MAI_THR,
+                          VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) |
+                          VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
+       } else if (vc4_hdmi->audio.samplerate > 48000) {
+               HDMI_WRITE(HDMI_MAI_THR,
+                          VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) |
+                          VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW));
        } else {
-               HD_WRITE(VC4_HD_MAI_THR,
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
-                        VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
+               HDMI_WRITE(HDMI_MAI_THR,
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
+                          VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
        }
 
-       HDMI_WRITE(VC4_HDMI_MAI_CONFIG,
+       HDMI_WRITE(HDMI_MAI_CONFIG,
                   VC4_HDMI_MAI_CONFIG_BIT_REVERSE |
                   VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK));
 
-       channel_map = 0;
-       for (i = 0; i < 8; i++) {
-               if (channel_mask & BIT(i))
-                       channel_map |= i << (3 * i);
-       }
-
-       HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map);
-       HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
-       vc4_hdmi_set_n_cts(hdmi);
+       channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask);
+       HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
+       HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
+       vc4_hdmi_set_n_cts(vc4_hdmi);
 
        return 0;
 }
@@ -899,30 +987,33 @@ static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
 static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
                                  struct snd_soc_dai *dai)
 {
-       struct vc4_hdmi *hdmi = dai_to_hdmi(dai);
-       struct drm_encoder *encoder = hdmi->encoder;
-       struct drm_device *drm = encoder->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
+       struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
+       struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                vc4_hdmi_set_audio_infoframe(encoder);
-               HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0,
-                          HDMI_READ(VC4_HDMI_TX_PHY_CTL0) &
-                          ~VC4_HDMI_TX_PHY_RNG_PWRDN);
-               HD_WRITE(VC4_HD_MAI_CTL,
-                        VC4_SET_FIELD(hdmi->audio.channels,
-                                      VC4_HD_MAI_CTL_CHNUM) |
-                        VC4_HD_MAI_CTL_ENABLE);
+               vc4_hdmi->audio.streaming = true;
+
+               if (vc4_hdmi->variant->phy_rng_enable)
+                       vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
+
+               HDMI_WRITE(HDMI_MAI_CTL,
+                          VC4_SET_FIELD(vc4_hdmi->audio.channels,
+                                        VC4_HD_MAI_CTL_CHNUM) |
+                          VC4_HD_MAI_CTL_ENABLE);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               HD_WRITE(VC4_HD_MAI_CTL,
-                        VC4_HD_MAI_CTL_DLATE |
-                        VC4_HD_MAI_CTL_ERRORE |
-                        VC4_HD_MAI_CTL_ERRORF);
-               HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0,
-                          HDMI_READ(VC4_HDMI_TX_PHY_CTL0) |
-                          VC4_HDMI_TX_PHY_RNG_PWRDN);
+               HDMI_WRITE(HDMI_MAI_CTL,
+                          VC4_HD_MAI_CTL_DLATE |
+                          VC4_HD_MAI_CTL_ERRORE |
+                          VC4_HD_MAI_CTL_ERRORF);
+
+               if (vc4_hdmi->variant->phy_rng_disable)
+                       vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
+
+               vc4_hdmi->audio.streaming = false;
+
                break;
        default:
                break;
@@ -943,10 +1034,11 @@ static int vc4_hdmi_audio_eld_ctl_info(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
        struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-       struct vc4_hdmi *hdmi = snd_component_to_hdmi(component);
+       struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component);
+       struct drm_connector *connector = &vc4_hdmi->connector;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-       uinfo->count = sizeof(hdmi->connector->eld);
+       uinfo->count = sizeof(connector->eld);
 
        return 0;
 }
@@ -955,10 +1047,11 @@ static int vc4_hdmi_audio_eld_ctl_get(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-       struct vc4_hdmi *hdmi = snd_component_to_hdmi(component);
+       struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component);
+       struct drm_connector *connector = &vc4_hdmi->connector;
 
-       memcpy(ucontrol->value.bytes.data, hdmi->connector->eld,
-              sizeof(hdmi->connector->eld));
+       memcpy(ucontrol->value.bytes.data, connector->eld,
+              sizeof(connector->eld));
 
        return 0;
 }
@@ -1023,9 +1116,9 @@ static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = {
 
 static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai)
 {
-       struct vc4_hdmi *hdmi = dai_to_hdmi(dai);
+       struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai);
 
-       snd_soc_dai_init_dma_data(dai, &hdmi->audio.dma_data, NULL);
+       snd_soc_dai_init_dma_data(dai, &vc4_hdmi->audio.dma_data, NULL);
 
        return 0;
 }
@@ -1051,12 +1144,15 @@ static const struct snd_dmaengine_pcm_config pcm_conf = {
        .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
 };
 
-static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
+static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
 {
-       struct snd_soc_dai_link *dai_link = &hdmi->audio.link;
-       struct snd_soc_card *card = &hdmi->audio.card;
-       struct device *dev = &hdmi->pdev->dev;
+       const struct vc4_hdmi_register *mai_data =
+               &vc4_hdmi->variant->registers[HDMI_MAI_DATA];
+       struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link;
+       struct snd_soc_card *card = &vc4_hdmi->audio.card;
+       struct device *dev = &vc4_hdmi->pdev->dev;
        const __be32 *addr;
+       int index;
        int ret;
 
        if (!of_find_property(dev->of_node, "dmas", NULL)) {
@@ -1065,6 +1161,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
                return 0;
        }
 
+       if (mai_data->reg != VC4_HD) {
+               WARN_ONCE(true, "MAI isn't in the HD block\n");
+               return -EINVAL;
+       }
+
        /*
         * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve
         * the bus address specified in the DT, because the physical address
@@ -1072,10 +1173,16 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
         * for DMA transfers.
         * This VC/MMU should probably be exposed to avoid this kind of hacks.
         */
-       addr = of_get_address(dev->of_node, 1, NULL, NULL);
-       hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA;
-       hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       hdmi->audio.dma_data.maxburst = 2;
+       index = of_property_match_string(dev->of_node, "reg-names", "hd");
+       /* Before BCM2711, we don't have a named register range */
+       if (index < 0)
+               index = 1;
+
+       addr = of_get_address(dev->of_node, index, NULL, NULL);
+
+       vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset;
+       vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       vc4_hdmi->audio.dma_data.maxburst = 2;
 
        ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0);
        if (ret) {
@@ -1098,9 +1205,9 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
                return ret;
        }
 
-       dai_link->cpus          = &hdmi->audio.cpu;
-       dai_link->codecs        = &hdmi->audio.codec;
-       dai_link->platforms     = &hdmi->audio.platform;
+       dai_link->cpus          = &vc4_hdmi->audio.cpu;
+       dai_link->codecs        = &vc4_hdmi->audio.codec;
+       dai_link->platforms     = &vc4_hdmi->audio.platform;
 
        dai_link->num_cpus      = 1;
        dai_link->num_codecs    = 1;
@@ -1115,7 +1222,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
 
        card->dai_link = dai_link;
        card->num_links = 1;
-       card->name = "vc4-hdmi";
+       card->name = vc4_hdmi->variant->card_name;
        card->dev = dev;
 
        /*
@@ -1125,7 +1232,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
         * now stored in card->drvdata and should be retrieved with
         * snd_soc_card_get_drvdata() if needed.
         */
-       snd_soc_card_set_drvdata(card, hdmi);
+       snd_soc_card_set_drvdata(card, vc4_hdmi);
        ret = devm_snd_soc_register_card(dev, card);
        if (ret)
                dev_err(dev, "Could not register sound card: %d\n", ret);
@@ -1137,35 +1244,35 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
 #ifdef CONFIG_DRM_VC4_HDMI_CEC
 static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
 {
-       struct vc4_dev *vc4 = priv;
-       struct vc4_hdmi *hdmi = vc4->hdmi;
-
-       if (hdmi->cec_irq_was_rx) {
-               if (hdmi->cec_rx_msg.len)
-                       cec_received_msg(hdmi->cec_adap, &hdmi->cec_rx_msg);
-       } else if (hdmi->cec_tx_ok) {
-               cec_transmit_done(hdmi->cec_adap, CEC_TX_STATUS_OK,
+       struct vc4_hdmi *vc4_hdmi = priv;
+
+       if (vc4_hdmi->cec_irq_was_rx) {
+               if (vc4_hdmi->cec_rx_msg.len)
+                       cec_received_msg(vc4_hdmi->cec_adap,
+                                        &vc4_hdmi->cec_rx_msg);
+       } else if (vc4_hdmi->cec_tx_ok) {
+               cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK,
                                  0, 0, 0, 0);
        } else {
                /*
                 * This CEC implementation makes 1 retry, so if we
                 * get a NACK, then that means it made 2 attempts.
                 */
-               cec_transmit_done(hdmi->cec_adap, CEC_TX_STATUS_NACK,
+               cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_NACK,
                                  0, 2, 0, 0);
        }
        return IRQ_HANDLED;
 }
 
-static void vc4_cec_read_msg(struct vc4_dev *vc4, u32 cntrl1)
+static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
 {
-       struct cec_msg *msg = &vc4->hdmi->cec_rx_msg;
+       struct cec_msg *msg = &vc4_hdmi->cec_rx_msg;
        unsigned int i;
 
        msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
                                        VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
        for (i = 0; i < msg->len; i += 4) {
-               u32 val = HDMI_READ(VC4_HDMI_CEC_RX_DATA_1 + i);
+               u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + i);
 
                msg->msg[i] = val & 0xff;
                msg->msg[i + 1] = (val >> 8) & 0xff;
@@ -1176,38 +1283,37 @@ static void vc4_cec_read_msg(struct vc4_dev *vc4, u32 cntrl1)
 
 static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
 {
-       struct vc4_dev *vc4 = priv;
-       struct vc4_hdmi *hdmi = vc4->hdmi;
-       u32 stat = HDMI_READ(VC4_HDMI_CPU_STATUS);
+       struct vc4_hdmi *vc4_hdmi = priv;
+       u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS);
        u32 cntrl1, cntrl5;
 
        if (!(stat & VC4_HDMI_CPU_CEC))
                return IRQ_NONE;
-       hdmi->cec_rx_msg.len = 0;
-       cntrl1 = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
-       cntrl5 = HDMI_READ(VC4_HDMI_CEC_CNTRL_5);
-       hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
-       if (hdmi->cec_irq_was_rx) {
-               vc4_cec_read_msg(vc4, cntrl1);
+       vc4_hdmi->cec_rx_msg.len = 0;
+       cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
+       cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
+       vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
+       if (vc4_hdmi->cec_irq_was_rx) {
+               vc4_cec_read_msg(vc4_hdmi, cntrl1);
                cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1);
+               HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
                cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
        } else {
-               hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
+               vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
                cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
        }
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1);
-       HDMI_WRITE(VC4_HDMI_CPU_CLEAR, VC4_HDMI_CPU_CEC);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
+       HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
 
        return IRQ_WAKE_THREAD;
 }
 
 static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
-       struct vc4_dev *vc4 = cec_get_drvdata(adap);
+       struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
        /* clock period in microseconds */
        const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
-       u32 val = HDMI_READ(VC4_HDMI_CEC_CNTRL_5);
+       u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
 
        val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
                 VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
@@ -1216,30 +1322,30 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
               ((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);
 
        if (enable) {
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val |
+               HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
                           VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val);
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_2,
-                        ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
-                        ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
-                        ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
-                        ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
-                        ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_3,
-                        ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
-                        ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
-                        ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
-                        ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_4,
-                        ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
-                        ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
-                        ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
-                        ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
-
-               HDMI_WRITE(VC4_HDMI_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
+               HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
+               HDMI_WRITE(HDMI_CEC_CNTRL_2,
+                          ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
+                          ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
+                          ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
+                          ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
+                          ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
+               HDMI_WRITE(HDMI_CEC_CNTRL_3,
+                          ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
+                          ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
+                          ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
+                          ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
+               HDMI_WRITE(HDMI_CEC_CNTRL_4,
+                          ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
+                          ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
+                          ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
+                          ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
+
+               HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
        } else {
-               HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
-               HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val |
+               HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
+               HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
                           VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
        }
        return 0;
@@ -1247,10 +1353,10 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
 
 static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
 {
-       struct vc4_dev *vc4 = cec_get_drvdata(adap);
+       struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
 
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1,
-                  (HDMI_READ(VC4_HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
+       HDMI_WRITE(HDMI_CEC_CNTRL_1,
+                  (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
                   (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
        return 0;
 }
@@ -1258,25 +1364,25 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
 static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
                                      u32 signal_free_time, struct cec_msg *msg)
 {
-       struct vc4_dev *vc4 = cec_get_drvdata(adap);
+       struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
        u32 val;
        unsigned int i;
 
        for (i = 0; i < msg->len; i += 4)
-               HDMI_WRITE(VC4_HDMI_CEC_TX_DATA_1 + i,
+               HDMI_WRITE(HDMI_CEC_TX_DATA_1 + i,
                           (msg->msg[i]) |
                           (msg->msg[i + 1] << 8) |
                           (msg->msg[i + 2] << 16) |
                           (msg->msg[i + 3] << 24));
 
-       val = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
+       val = HDMI_READ(HDMI_CEC_CNTRL_1);
        val &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
        val &= ~VC4_HDMI_CEC_MESSAGE_LENGTH_MASK;
        val |= (msg->len - 1) << VC4_HDMI_CEC_MESSAGE_LENGTH_SHIFT;
        val |= VC4_HDMI_CEC_START_XMIT_BEGIN;
 
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
        return 0;
 }
 
@@ -1285,61 +1391,275 @@ static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = {
        .adap_log_addr = vc4_hdmi_cec_adap_log_addr,
        .adap_transmit = vc4_hdmi_cec_adap_transmit,
 };
-#endif
 
-static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
+static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
 {
-#ifdef CONFIG_DRM_VC4_HDMI_CEC
        struct cec_connector_info conn_info;
-#endif
-       struct platform_device *pdev = to_platform_device(dev);
-       struct drm_device *drm = dev_get_drvdata(master);
-       struct vc4_dev *vc4 = drm->dev_private;
-       struct vc4_hdmi *hdmi;
-       struct vc4_hdmi_encoder *vc4_hdmi_encoder;
-       struct device_node *ddc_node;
+       struct platform_device *pdev = vc4_hdmi->pdev;
        u32 value;
        int ret;
 
-       hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
-       if (!hdmi)
+       if (!vc4_hdmi->variant->cec_available)
+               return 0;
+
+       vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
+                                                 vc4_hdmi, "vc4",
+                                                 CEC_CAP_DEFAULTS |
+                                                 CEC_CAP_CONNECTOR_INFO, 1);
+       ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap);
+       if (ret < 0)
+               return ret;
+
+       cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
+       cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
+
+       HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
+       value = HDMI_READ(HDMI_CEC_CNTRL_1);
+       value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
+       /*
+        * Set the logical address to Unregistered and set the clock
+        * divider: the hsm_clock rate and this divider setting will
+        * give a 40 kHz CEC clock.
+        */
+       value |= VC4_HDMI_CEC_ADDR_MASK |
+                (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT);
+       HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
+       ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
+                                       vc4_cec_irq_handler,
+                                       vc4_cec_irq_handler_thread, 0,
+                                       "vc4 hdmi cec", vc4_hdmi);
+       if (ret)
+               goto err_delete_cec_adap;
+
+       ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
+       if (ret < 0)
+               goto err_delete_cec_adap;
+
+       return 0;
+
+err_delete_cec_adap:
+       cec_delete_adapter(vc4_hdmi->cec_adap);
+
+       return ret;
+}
+
+static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
+{
+       cec_unregister_adapter(vc4_hdmi->cec_adap);
+}
+#else
+static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
+{
+       return 0;
+}
+
+static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {};
+
+#endif
+
+static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi,
+                                struct debugfs_regset32 *regset,
+                                enum vc4_hdmi_regs reg)
+{
+       const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
+       struct debugfs_reg32 *regs, *new_regs;
+       unsigned int count = 0;
+       unsigned int i;
+
+       regs = kcalloc(variant->num_registers, sizeof(*regs),
+                      GFP_KERNEL);
+       if (!regs)
                return -ENOMEM;
 
-       vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder),
-                                       GFP_KERNEL);
-       if (!vc4_hdmi_encoder)
+       for (i = 0; i < variant->num_registers; i++) {
+               const struct vc4_hdmi_register *field = &variant->registers[i];
+
+               if (field->reg != reg)
+                       continue;
+
+               regs[count].name = field->name;
+               regs[count].offset = field->offset;
+               count++;
+       }
+
+       new_regs = krealloc(regs, count * sizeof(*regs), GFP_KERNEL);
+       if (!new_regs)
                return -ENOMEM;
-       vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI;
-       hdmi->encoder = &vc4_hdmi_encoder->base.base;
-
-       hdmi->pdev = pdev;
-       hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0);
-       if (IS_ERR(hdmi->hdmicore_regs))
-               return PTR_ERR(hdmi->hdmicore_regs);
-
-       hdmi->hd_regs = vc4_ioremap_regs(pdev, 1);
-       if (IS_ERR(hdmi->hd_regs))
-               return PTR_ERR(hdmi->hd_regs);
-
-       hdmi->hdmi_regset.base = hdmi->hdmicore_regs;
-       hdmi->hdmi_regset.regs = hdmi_regs;
-       hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs);
-       hdmi->hd_regset.base = hdmi->hd_regs;
-       hdmi->hd_regset.regs = hd_regs;
-       hdmi->hd_regset.nregs = ARRAY_SIZE(hd_regs);
-
-       hdmi->pixel_clock = devm_clk_get(dev, "pixel");
-       if (IS_ERR(hdmi->pixel_clock)) {
-               ret = PTR_ERR(hdmi->pixel_clock);
+
+       regset->base = __vc4_hdmi_get_field_base(vc4_hdmi, reg);
+       regset->regs = new_regs;
+       regset->nregs = count;
+
+       return 0;
+}
+
+static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
+{
+       struct platform_device *pdev = vc4_hdmi->pdev;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       vc4_hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0);
+       if (IS_ERR(vc4_hdmi->hdmicore_regs))
+               return PTR_ERR(vc4_hdmi->hdmicore_regs);
+
+       vc4_hdmi->hd_regs = vc4_ioremap_regs(pdev, 1);
+       if (IS_ERR(vc4_hdmi->hd_regs))
+               return PTR_ERR(vc4_hdmi->hd_regs);
+
+       ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD);
+       if (ret)
+               return ret;
+
+       ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI);
+       if (ret)
+               return ret;
+
+       vc4_hdmi->pixel_clock = devm_clk_get(dev, "pixel");
+       if (IS_ERR(vc4_hdmi->pixel_clock)) {
+               ret = PTR_ERR(vc4_hdmi->pixel_clock);
                if (ret != -EPROBE_DEFER)
                        DRM_ERROR("Failed to get pixel clock\n");
                return ret;
        }
-       hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
-       if (IS_ERR(hdmi->hsm_clock)) {
+
+       vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
+       if (IS_ERR(vc4_hdmi->hsm_clock)) {
                DRM_ERROR("Failed to get HDMI state machine clock\n");
-               return PTR_ERR(hdmi->hsm_clock);
+               return PTR_ERR(vc4_hdmi->hsm_clock);
        }
+       vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock;
+
+       return 0;
+}
+
+static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
+{
+       struct platform_device *pdev = vc4_hdmi->pdev;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->hdmicore_regs = devm_ioremap(dev, res->start,
+                                              resource_size(res));
+       if (!vc4_hdmi->hdmicore_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hd");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->hd_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->hd_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cec");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->cec_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->cec_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csc");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->csc_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->csc_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvp");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->dvp_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->dvp_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->phy_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->phy_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "packet");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->ram_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->ram_regs)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rm");
+       if (!res)
+               return -ENODEV;
+
+       vc4_hdmi->rm_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!vc4_hdmi->rm_regs)
+               return -ENOMEM;
+
+       vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
+       if (IS_ERR(vc4_hdmi->hsm_clock)) {
+               DRM_ERROR("Failed to get HDMI state machine clock\n");
+               return PTR_ERR(vc4_hdmi->hsm_clock);
+       }
+
+       vc4_hdmi->pixel_bvb_clock = devm_clk_get(dev, "bvb");
+       if (IS_ERR(vc4_hdmi->pixel_bvb_clock)) {
+               DRM_ERROR("Failed to get pixel bvb clock\n");
+               return PTR_ERR(vc4_hdmi->pixel_bvb_clock);
+       }
+
+       vc4_hdmi->audio_clock = devm_clk_get(dev, "audio");
+       if (IS_ERR(vc4_hdmi->audio_clock)) {
+               DRM_ERROR("Failed to get audio clock\n");
+               return PTR_ERR(vc4_hdmi->audio_clock);
+       }
+
+       vc4_hdmi->reset = devm_reset_control_get(dev, NULL);
+       if (IS_ERR(vc4_hdmi->reset)) {
+               DRM_ERROR("Failed to get HDMI reset line\n");
+               return PTR_ERR(vc4_hdmi->reset);
+       }
+
+       return 0;
+}
+
+static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
+{
+       const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct drm_device *drm = dev_get_drvdata(master);
+       struct vc4_hdmi *vc4_hdmi;
+       struct drm_encoder *encoder;
+       struct device_node *ddc_node;
+       u32 value;
+       int ret;
+
+       vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
+       if (!vc4_hdmi)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, vc4_hdmi);
+       encoder = &vc4_hdmi->encoder.base.base;
+       vc4_hdmi->encoder.base.type = variant->encoder_type;
+       vc4_hdmi->encoder.base.pre_crtc_configure = vc4_hdmi_encoder_pre_crtc_configure;
+       vc4_hdmi->encoder.base.pre_crtc_enable = vc4_hdmi_encoder_pre_crtc_enable;
+       vc4_hdmi->encoder.base.post_crtc_enable = vc4_hdmi_encoder_post_crtc_enable;
+       vc4_hdmi->encoder.base.post_crtc_disable = vc4_hdmi_encoder_post_crtc_disable;
+       vc4_hdmi->encoder.base.post_crtc_powerdown = vc4_hdmi_encoder_post_crtc_powerdown;
+       vc4_hdmi->pdev = pdev;
+       vc4_hdmi->variant = variant;
+
+       ret = variant->init_resources(vc4_hdmi);
+       if (ret)
+               return ret;
 
        ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
        if (!ddc_node) {
@@ -1347,123 +1667,62 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
                return -ENODEV;
        }
 
-       hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
+       vc4_hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
        of_node_put(ddc_node);
-       if (!hdmi->ddc) {
+       if (!vc4_hdmi->ddc) {
                DRM_DEBUG("Failed to get ddc i2c adapter by node\n");
                return -EPROBE_DEFER;
        }
 
-       /* This is the rate that is set by the firmware.  The number
-        * needs to be a bit higher than the pixel clock rate
-        * (generally 148.5Mhz).
-        */
-       ret = clk_set_rate(hdmi->hsm_clock, HSM_CLOCK_FREQ);
-       if (ret) {
-               DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
-               goto err_put_i2c;
-       }
-
-       ret = clk_prepare_enable(hdmi->hsm_clock);
-       if (ret) {
-               DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n",
-                         ret);
-               goto err_put_i2c;
-       }
-
        /* Only use the GPIO HPD pin if present in the DT, otherwise
         * we'll use the HDMI core's register.
         */
        if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
                enum of_gpio_flags hpd_gpio_flags;
 
-               hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
-                                                        "hpd-gpios", 0,
-                                                        &hpd_gpio_flags);
-               if (hdmi->hpd_gpio < 0) {
-                       ret = hdmi->hpd_gpio;
+               vc4_hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
+                                                            "hpd-gpios", 0,
+                                                            &hpd_gpio_flags);
+               if (vc4_hdmi->hpd_gpio < 0) {
+                       ret = vc4_hdmi->hpd_gpio;
                        goto err_unprepare_hsm;
                }
 
-               hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
+               vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
        }
 
-       vc4->hdmi = hdmi;
-
-       /* HDMI core must be enabled. */
-       if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) {
-               HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST);
-               udelay(1);
-               HD_WRITE(VC4_HD_M_CTL, 0);
-
-               HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE);
-       }
        pm_runtime_enable(dev);
 
-       drm_simple_encoder_init(drm, hdmi->encoder, DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs);
+       drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+       drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs);
 
-       hdmi->connector =
-               vc4_hdmi_connector_init(drm, hdmi->encoder, hdmi->ddc);
-       if (IS_ERR(hdmi->connector)) {
-               ret = PTR_ERR(hdmi->connector);
+       ret = vc4_hdmi_connector_init(drm, vc4_hdmi);
+       if (ret)
                goto err_destroy_encoder;
-       }
-#ifdef CONFIG_DRM_VC4_HDMI_CEC
-       hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
-                                             vc4, "vc4",
-                                             CEC_CAP_DEFAULTS |
-                                             CEC_CAP_CONNECTOR_INFO, 1);
-       ret = PTR_ERR_OR_ZERO(hdmi->cec_adap);
-       if (ret < 0)
-               goto err_destroy_conn;
 
-       cec_fill_conn_info_from_drm(&conn_info, hdmi->connector);
-       cec_s_conn_info(hdmi->cec_adap, &conn_info);
-
-       HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff);
-       value = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
-       value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
-       /*
-        * Set the logical address to Unregistered and set the clock
-        * divider: the hsm_clock rate and this divider setting will
-        * give a 40 kHz CEC clock.
-        */
-       value |= VC4_HDMI_CEC_ADDR_MASK |
-                (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT);
-       HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, value);
-       ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
-                                       vc4_cec_irq_handler,
-                                       vc4_cec_irq_handler_thread, 0,
-                                       "vc4 hdmi cec", vc4);
+       ret = vc4_hdmi_cec_init(vc4_hdmi);
        if (ret)
-               goto err_delete_cec_adap;
-       ret = cec_register_adapter(hdmi->cec_adap, dev);
-       if (ret < 0)
-               goto err_delete_cec_adap;
-#endif
+               goto err_destroy_conn;
 
-       ret = vc4_hdmi_audio_init(hdmi);
+       ret = vc4_hdmi_audio_init(vc4_hdmi);
        if (ret)
-               goto err_destroy_encoder;
+               goto err_free_cec;
 
-       vc4_debugfs_add_file(drm, "hdmi_regs", vc4_hdmi_debugfs_regs, hdmi);
+       vc4_debugfs_add_file(drm, variant->debugfs_name,
+                            vc4_hdmi_debugfs_regs,
+                            vc4_hdmi);
 
        return 0;
 
-#ifdef CONFIG_DRM_VC4_HDMI_CEC
-err_delete_cec_adap:
-       cec_delete_adapter(hdmi->cec_adap);
+err_free_cec:
+       vc4_hdmi_cec_exit(vc4_hdmi);
 err_destroy_conn:
-       vc4_hdmi_connector_destroy(hdmi->connector);
-#endif
+       vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
 err_destroy_encoder:
-       drm_encoder_cleanup(hdmi->encoder);
+       drm_encoder_cleanup(encoder);
 err_unprepare_hsm:
-       clk_disable_unprepare(hdmi->hsm_clock);
        pm_runtime_disable(dev);
-err_put_i2c:
-       put_device(&hdmi->ddc->dev);
+       put_device(&vc4_hdmi->ddc->dev);
 
        return ret;
 }
@@ -1471,20 +1730,39 @@ err_put_i2c:
 static void vc4_hdmi_unbind(struct device *dev, struct device *master,
                            void *data)
 {
-       struct drm_device *drm = dev_get_drvdata(master);
-       struct vc4_dev *vc4 = drm->dev_private;
-       struct vc4_hdmi *hdmi = vc4->hdmi;
+       struct vc4_hdmi *vc4_hdmi;
 
-       cec_unregister_adapter(hdmi->cec_adap);
-       vc4_hdmi_connector_destroy(hdmi->connector);
-       drm_encoder_cleanup(hdmi->encoder);
+       /*
+        * ASoC makes it a bit hard to retrieve a pointer to the
+        * vc4_hdmi structure. Registering the card will overwrite our
+        * device drvdata with a pointer to the snd_soc_card structure,
+        * which can then be used to retrieve whatever drvdata we want
+        * to associate.
+        *
+        * However, that doesn't fly in the case where we wouldn't
+        * register an ASoC card (because of an old DT that is missing
+        * the dmas properties for example), then the card isn't
+        * registered and the device drvdata wouldn't be set.
+        *
+        * We can deal with both cases by making sure a snd_soc_card
+        * pointer and a vc4_hdmi structure are pointing to the same
+        * memory address, so we can treat them indistinctly without any
+        * issue.
+        */
+       BUILD_BUG_ON(offsetof(struct vc4_hdmi_audio, card) != 0);
+       BUILD_BUG_ON(offsetof(struct vc4_hdmi, audio) != 0);
+       vc4_hdmi = dev_get_drvdata(dev);
 
-       clk_disable_unprepare(hdmi->hsm_clock);
-       pm_runtime_disable(dev);
+       kfree(vc4_hdmi->hdmi_regset.regs);
+       kfree(vc4_hdmi->hd_regset.regs);
 
-       put_device(&hdmi->ddc->dev);
+       vc4_hdmi_cec_exit(vc4_hdmi);
+       vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
+       drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);
+
+       pm_runtime_disable(dev);
 
-       vc4->hdmi = NULL;
+       put_device(&vc4_hdmi->ddc->dev);
 }
 
 static const struct component_ops vc4_hdmi_ops = {
@@ -1503,8 +1781,80 @@ static int vc4_hdmi_dev_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct vc4_hdmi_variant bcm2835_variant = {
+       .encoder_type           = VC4_ENCODER_TYPE_HDMI0,
+       .debugfs_name           = "hdmi_regs",
+       .card_name              = "vc4-hdmi",
+       .max_pixel_clock        = 162000000,
+       .cec_available          = true,
+       .registers              = vc4_hdmi_fields,
+       .num_registers          = ARRAY_SIZE(vc4_hdmi_fields),
+
+       .init_resources         = vc4_hdmi_init_resources,
+       .csc_setup              = vc4_hdmi_csc_setup,
+       .reset                  = vc4_hdmi_reset,
+       .set_timings            = vc4_hdmi_set_timings,
+       .phy_init               = vc4_hdmi_phy_init,
+       .phy_disable            = vc4_hdmi_phy_disable,
+       .phy_rng_enable         = vc4_hdmi_phy_rng_enable,
+       .phy_rng_disable        = vc4_hdmi_phy_rng_disable,
+       .channel_map            = vc4_hdmi_channel_map,
+};
+
+static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
+       .encoder_type           = VC4_ENCODER_TYPE_HDMI0,
+       .debugfs_name           = "hdmi0_regs",
+       .card_name              = "vc4-hdmi-0",
+       .max_pixel_clock        = 297000000,
+       .registers              = vc5_hdmi_hdmi0_fields,
+       .num_registers          = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
+       .phy_lane_mapping       = {
+               PHY_LANE_0,
+               PHY_LANE_1,
+               PHY_LANE_2,
+               PHY_LANE_CK,
+       },
+
+       .init_resources         = vc5_hdmi_init_resources,
+       .csc_setup              = vc5_hdmi_csc_setup,
+       .reset                  = vc5_hdmi_reset,
+       .set_timings            = vc5_hdmi_set_timings,
+       .phy_init               = vc5_hdmi_phy_init,
+       .phy_disable            = vc5_hdmi_phy_disable,
+       .phy_rng_enable         = vc5_hdmi_phy_rng_enable,
+       .phy_rng_disable        = vc5_hdmi_phy_rng_disable,
+       .channel_map            = vc5_hdmi_channel_map,
+};
+
+static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
+       .encoder_type           = VC4_ENCODER_TYPE_HDMI1,
+       .debugfs_name           = "hdmi1_regs",
+       .card_name              = "vc4-hdmi-1",
+       .max_pixel_clock        = 297000000,
+       .registers              = vc5_hdmi_hdmi1_fields,
+       .num_registers          = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
+       .phy_lane_mapping       = {
+               PHY_LANE_1,
+               PHY_LANE_0,
+               PHY_LANE_CK,
+               PHY_LANE_2,
+       },
+
+       .init_resources         = vc5_hdmi_init_resources,
+       .csc_setup              = vc5_hdmi_csc_setup,
+       .reset                  = vc5_hdmi_reset,
+       .set_timings            = vc5_hdmi_set_timings,
+       .phy_init               = vc5_hdmi_phy_init,
+       .phy_disable            = vc5_hdmi_phy_disable,
+       .phy_rng_enable         = vc5_hdmi_phy_rng_enable,
+       .phy_rng_disable        = vc5_hdmi_phy_rng_disable,
+       .channel_map            = vc5_hdmi_channel_map,
+};
+
 static const struct of_device_id vc4_hdmi_dt_match[] = {
-       { .compatible = "brcm,bcm2835-hdmi" },
+       { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant },
+       { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant },
+       { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant },
        {}
 };
 
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
new file mode 100644 (file)
index 0000000..63c6f8b
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef _VC4_HDMI_H_
+#define _VC4_HDMI_H_
+
+#include <drm/drm_connector.h>
+#include <media/cec.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+
+#include "vc4_drv.h"
+
+/* VC4 HDMI encoder KMS struct */
+struct vc4_hdmi_encoder {
+       struct vc4_encoder base;
+       bool hdmi_monitor;
+       bool limited_rgb_range;
+};
+
+static inline struct vc4_hdmi_encoder *
+to_vc4_hdmi_encoder(struct drm_encoder *encoder)
+{
+       return container_of(encoder, struct vc4_hdmi_encoder, base.base);
+}
+
+struct drm_display_mode;
+
+struct vc4_hdmi;
+struct vc4_hdmi_register;
+
+enum vc4_hdmi_phy_channel {
+       PHY_LANE_0 = 0,
+       PHY_LANE_1,
+       PHY_LANE_2,
+       PHY_LANE_CK,
+};
+
+struct vc4_hdmi_variant {
+       /* Encoder Type for that controller */
+       enum vc4_encoder_type encoder_type;
+
+       /* ALSA card name */
+       const char *card_name;
+
+       /* Filename to expose the registers in debugfs */
+       const char *debugfs_name;
+
+       /* Set to true when the CEC support is available */
+       bool cec_available;
+
+       /* Maximum pixel clock supported by the controller (in Hz) */
+       unsigned long long max_pixel_clock;
+
+       /* List of the registers available on that variant */
+       const struct vc4_hdmi_register *registers;
+
+       /* Number of registers on that variant */
+       unsigned int num_registers;
+
+       /* BCM2711 Only.
+        * The variants don't map the lane in the same order in the
+        * PHY, so this is an array mapping the HDMI channel (index)
+        * to the PHY lane (value).
+        */
+       enum vc4_hdmi_phy_channel phy_lane_mapping[4];
+
+       /* Callback to get the resources (memory region, interrupts,
+        * clocks, etc) for that variant.
+        */
+       int (*init_resources)(struct vc4_hdmi *vc4_hdmi);
+
+       /* Callback to reset the HDMI block */
+       void (*reset)(struct vc4_hdmi *vc4_hdmi);
+
+       /* Callback to enable / disable the CSC */
+       void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable);
+
+       /* Callback to configure the video timings in the HDMI block */
+       void (*set_timings)(struct vc4_hdmi *vc4_hdmi,
+                           struct drm_display_mode *mode);
+
+       /* Callback to initialize the PHY according to the mode */
+       void (*phy_init)(struct vc4_hdmi *vc4_hdmi,
+                        struct drm_display_mode *mode);
+
+       /* Callback to disable the PHY */
+       void (*phy_disable)(struct vc4_hdmi *vc4_hdmi);
+
+       /* Callback to enable the RNG in the PHY */
+       void (*phy_rng_enable)(struct vc4_hdmi *vc4_hdmi);
+
+       /* Callback to disable the RNG in the PHY */
+       void (*phy_rng_disable)(struct vc4_hdmi *vc4_hdmi);
+
+       /* Callback to get channel map */
+       u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
+};
+
+/* HDMI audio information */
+struct vc4_hdmi_audio {
+       struct snd_soc_card card;
+       struct snd_soc_dai_link link;
+       struct snd_soc_dai_link_component cpu;
+       struct snd_soc_dai_link_component codec;
+       struct snd_soc_dai_link_component platform;
+       int samplerate;
+       int channels;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       struct snd_pcm_substream *substream;
+
+       bool streaming;
+};
+
+/* General HDMI hardware state. */
+struct vc4_hdmi {
+       struct vc4_hdmi_audio audio;
+
+       struct platform_device *pdev;
+       const struct vc4_hdmi_variant *variant;
+
+       struct vc4_hdmi_encoder encoder;
+       struct drm_connector connector;
+
+       struct i2c_adapter *ddc;
+       void __iomem *hdmicore_regs;
+       void __iomem *hd_regs;
+
+       /* VC5 Only */
+       void __iomem *cec_regs;
+       /* VC5 Only */
+       void __iomem *csc_regs;
+       /* VC5 Only */
+       void __iomem *dvp_regs;
+       /* VC5 Only */
+       void __iomem *phy_regs;
+       /* VC5 Only */
+       void __iomem *ram_regs;
+       /* VC5 Only */
+       void __iomem *rm_regs;
+
+       int hpd_gpio;
+       bool hpd_active_low;
+
+       struct cec_adapter *cec_adap;
+       struct cec_msg cec_rx_msg;
+       bool cec_tx_ok;
+       bool cec_irq_was_rx;
+
+       struct clk *pixel_clock;
+       struct clk *hsm_clock;
+       struct clk *audio_clock;
+       struct clk *pixel_bvb_clock;
+
+       struct reset_control *reset;
+
+       struct debugfs_regset32 hdmi_regset;
+       struct debugfs_regset32 hd_regset;
+};
+
+static inline struct vc4_hdmi *
+connector_to_vc4_hdmi(struct drm_connector *connector)
+{
+       return container_of(connector, struct vc4_hdmi, connector);
+}
+
+static inline struct vc4_hdmi *
+encoder_to_vc4_hdmi(struct drm_encoder *encoder)
+{
+       struct vc4_hdmi_encoder *_encoder = to_vc4_hdmi_encoder(encoder);
+
+       return container_of(_encoder, struct vc4_hdmi, encoder);
+}
+
+void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
+                      struct drm_display_mode *mode);
+void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi);
+void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi);
+void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi);
+
+void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
+                      struct drm_display_mode *mode);
+void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi);
+void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi);
+void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi);
+
+#endif /* _VC4_HDMI_H_ */
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
new file mode 100644 (file)
index 0000000..057796b
--- /dev/null
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015 Broadcom
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ */
+
+#include "vc4_hdmi.h"
+#include "vc4_regs.h"
+#include "vc4_hdmi_regs.h"
+
+#define VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB   BIT(5)
+#define VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB        BIT(4)
+#define VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET  BIT(3)
+#define VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET   BIT(2)
+#define VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET   BIT(1)
+#define VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET   BIT(0)
+
+#define VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN     BIT(4)
+
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_SHIFT    29
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_MASK     VC4_MASK(31, 29)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_SHIFT   24
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_MASK    VC4_MASK(28, 24)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_SHIFT    21
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_MASK     VC4_MASK(23, 21)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_SHIFT   16
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_MASK    VC4_MASK(20, 16)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_SHIFT    13
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_MASK     VC4_MASK(15, 13)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_SHIFT   8
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_MASK    VC4_MASK(12, 8)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_SHIFT   5
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_MASK    VC4_MASK(7, 5)
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_SHIFT  0
+#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_MASK   VC4_MASK(4, 0)
+
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_SHIFT      15
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_MASK       VC4_MASK(19, 15)
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_SHIFT      10
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_MASK       VC4_MASK(14, 10)
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_SHIFT      5
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_MASK       VC4_MASK(9, 5)
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_SHIFT         0
+#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_MASK          VC4_MASK(4, 0)
+
+#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_SHIFT           16
+#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_MASK            VC4_MASK(19, 16)
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_SHIFT  12
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_MASK   VC4_MASK(15, 12)
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_SHIFT  8
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_MASK   VC4_MASK(11, 8)
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_SHIFT  4
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_MASK   VC4_MASK(7, 4)
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_SHIFT     0
+#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_MASK      VC4_MASK(3, 0)
+
+#define VC4_HDMI_TX_PHY_CTL_3_RP_SHIFT                 17
+#define VC4_HDMI_TX_PHY_CTL_3_RP_MASK                  VC4_MASK(19, 17)
+#define VC4_HDMI_TX_PHY_CTL_3_RZ_SHIFT                 12
+#define VC4_HDMI_TX_PHY_CTL_3_RZ_MASK                  VC4_MASK(16, 12)
+#define VC4_HDMI_TX_PHY_CTL_3_CP1_SHIFT                        10
+#define VC4_HDMI_TX_PHY_CTL_3_CP1_MASK                 VC4_MASK(11, 10)
+#define VC4_HDMI_TX_PHY_CTL_3_CP_SHIFT                 8
+#define VC4_HDMI_TX_PHY_CTL_3_CP_MASK                  VC4_MASK(9, 8)
+#define VC4_HDMI_TX_PHY_CTL_3_CZ_SHIFT                 6
+#define VC4_HDMI_TX_PHY_CTL_3_CZ_MASK                  VC4_MASK(7, 6)
+#define VC4_HDMI_TX_PHY_CTL_3_ICP_SHIFT                        0
+#define VC4_HDMI_TX_PHY_CTL_3_ICP_MASK                 VC4_MASK(5, 0)
+
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE          BIT(13)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_VC_RANGE_EN          BIT(12)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_LOW       BIT(11)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_HIGH      BIT(10)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_SHIFT                9
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_MASK         VC4_MASK(9, 9)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_FB_DIV2          BIT(8)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_POST_DIV2                BIT(7)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN          BIT(6)
+#define VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK          BIT(5)
+
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_SHIFT                    16
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_MASK                     VC4_MASK(27, 16)
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_SHIFT     14
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_MASK      VC4_MASK(15, 14)
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE          BIT(13)
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_SHIFT           11
+#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_MASK            VC4_MASK(12, 11)
+
+#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_SHIFT              8
+#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_MASK               VC4_MASK(15, 8)
+
+#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_SHIFT             0
+#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_MASK              VC4_MASK(3, 0)
+
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_MASK VC4_MASK(13, 12)
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_SHIFT        12
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_MASK  VC4_MASK(9, 8)
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_SHIFT 8
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_MASK  VC4_MASK(5, 4)
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_SHIFT 4
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_MASK  VC4_MASK(1, 0)
+#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_SHIFT 0
+
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK                VC4_MASK(27, 0)
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_SHIFT       0
+
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK                VC4_MASK(27, 0)
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_SHIFT       0
+
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_MASK VC4_MASK(31, 16)
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_SHIFT        16
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_MASK   VC4_MASK(15, 0)
+#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_SHIFT  0
+
+#define VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS         BIT(19)
+#define VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR         BIT(17)
+#define VC4_HDMI_RM_CONTROL_FREE_RUN                   BIT(4)
+
+#define VC4_HDMI_RM_OFFSET_ONLY                                BIT(31)
+#define VC4_HDMI_RM_OFFSET_OFFSET_SHIFT                        0
+#define VC4_HDMI_RM_OFFSET_OFFSET_MASK                 VC4_MASK(30, 0)
+
+#define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT                 24
+#define VC4_HDMI_RM_FORMAT_SHIFT_MASK                  VC4_MASK(25, 24)
+
+#define OSCILLATOR_FREQUENCY   54000000
+
+void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode)
+{
+       /* PHY should be in reset, like
+        * vc4_hdmi_encoder_disable() does.
+        */
+
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0);
+}
+
+void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
+{
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
+}
+
+void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
+{
+       HDMI_WRITE(HDMI_TX_PHY_CTL_0,
+                  HDMI_READ(HDMI_TX_PHY_CTL_0) &
+                  ~VC4_HDMI_TX_PHY_RNG_PWRDN);
+}
+
+void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
+{
+       HDMI_WRITE(HDMI_TX_PHY_CTL_0,
+                  HDMI_READ(HDMI_TX_PHY_CTL_0) |
+                  VC4_HDMI_TX_PHY_RNG_PWRDN);
+}
+
+static unsigned long long
+phy_get_vco_freq(unsigned long long clock, u8 *vco_sel, u8 *vco_div)
+{
+       unsigned long long vco_freq = clock;
+       unsigned int _vco_div = 0;
+       unsigned int _vco_sel = 0;
+
+       while (vco_freq < 3000000000ULL) {
+               _vco_div++;
+               vco_freq = clock * _vco_div * 10;
+       }
+
+       if (vco_freq > 4500000000ULL)
+               _vco_sel = 1;
+
+       *vco_sel = _vco_sel;
+       *vco_div = _vco_div;
+
+       return vco_freq;
+}
+
+static u8 phy_get_cp_current(unsigned long vco_freq)
+{
+       if (vco_freq < 3700000000ULL)
+               return 0x1c;
+
+       return 0x18;
+}
+
+static u32 phy_get_rm_offset(unsigned long long vco_freq)
+{
+       unsigned long long fref = OSCILLATOR_FREQUENCY;
+       u64 offset = 0;
+
+       /* RM offset is stored as 9.22 format */
+       offset = vco_freq * 2;
+       offset = offset << 22;
+       do_div(offset, fref);
+       offset >>= 2;
+
+       return offset;
+}
+
+static u8 phy_get_vco_gain(unsigned long long vco_freq)
+{
+       if (vco_freq < 3350000000ULL)
+               return 0xf;
+
+       if (vco_freq < 3700000000ULL)
+               return 0xc;
+
+       if (vco_freq < 4050000000ULL)
+               return 0x6;
+
+       if (vco_freq < 4800000000ULL)
+               return 0x5;
+
+       if (vco_freq < 5200000000ULL)
+               return 0x7;
+
+       return 0x2;
+}
+
+struct phy_lane_settings {
+       struct {
+               u8 preemphasis;
+               u8 main_driver;
+       } amplitude;
+
+       u8 res_sel_data;
+       u8 term_res_sel_data;
+};
+
+struct phy_settings {
+       unsigned long long min_rate;
+       unsigned long long max_rate;
+       struct phy_lane_settings channel[3];
+       struct phy_lane_settings clock;
+};
+
+static const struct phy_settings vc5_hdmi_phy_settings[] = {
+       {
+               0, 50000000,
+               {
+                       {{0x0, 0x0A}, 0x12, 0x0},
+                       {{0x0, 0x0A}, 0x12, 0x0},
+                       {{0x0, 0x0A}, 0x12, 0x0}
+               },
+               {{0x0, 0x0A}, 0x18, 0x0},
+       },
+       {
+               50000001, 75000000,
+               {
+                       {{0x0, 0x09}, 0x12, 0x0},
+                       {{0x0, 0x09}, 0x12, 0x0},
+                       {{0x0, 0x09}, 0x12, 0x0}
+               },
+               {{0x0, 0x0C}, 0x18, 0x3},
+       },
+       {
+               75000001,   165000000,
+               {
+                       {{0x0, 0x09}, 0x12, 0x0},
+                       {{0x0, 0x09}, 0x12, 0x0},
+                       {{0x0, 0x09}, 0x12, 0x0}
+               },
+               {{0x0, 0x0C}, 0x18, 0x3},
+       },
+       {
+               165000001,  250000000,
+               {
+                       {{0x0, 0x0F}, 0x12, 0x1},
+                       {{0x0, 0x0F}, 0x12, 0x1},
+                       {{0x0, 0x0F}, 0x12, 0x1}
+               },
+               {{0x0, 0x0C}, 0x18, 0x3},
+       },
+       {
+               250000001,  340000000,
+               {
+                       {{0x2, 0x0D}, 0x12, 0x1},
+                       {{0x2, 0x0D}, 0x12, 0x1},
+                       {{0x2, 0x0D}, 0x12, 0x1}
+               },
+               {{0x0, 0x0C}, 0x18, 0xF},
+       },
+       {
+               340000001,  450000000,
+               {
+                       {{0x0, 0x1B}, 0x12, 0xF},
+                       {{0x0, 0x1B}, 0x12, 0xF},
+                       {{0x0, 0x1B}, 0x12, 0xF}
+               },
+               {{0x0, 0x0A}, 0x12, 0xF},
+       },
+       {
+               450000001,  600000000,
+               {
+                       {{0x0, 0x1C}, 0x12, 0xF},
+                       {{0x0, 0x1C}, 0x12, 0xF},
+                       {{0x0, 0x1C}, 0x12, 0xF}
+               },
+               {{0x0, 0x0B}, 0x13, 0xF},
+       },
+};
+
+static const struct phy_settings *phy_get_settings(unsigned long long tmds_rate)
+{
+       unsigned int count = ARRAY_SIZE(vc5_hdmi_phy_settings);
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               const struct phy_settings *s = &vc5_hdmi_phy_settings[i];
+
+               if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate)
+                       return s;
+       }
+
+       /*
+        * If the pixel clock exceeds our max setting, try the max
+        * setting anyway.
+        */
+       return &vc5_hdmi_phy_settings[count - 1];
+}
+
+static const struct phy_lane_settings *
+phy_get_channel_settings(enum vc4_hdmi_phy_channel chan,
+                        unsigned long long tmds_rate)
+{
+       const struct phy_settings *settings = phy_get_settings(tmds_rate);
+
+       if (chan == PHY_LANE_CK)
+               return &settings->clock;
+
+       return &settings->channel[chan];
+}
+
+static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi)
+{
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f);
+       HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10));
+}
+
+void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode)
+{
+       const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings;
+       const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
+       unsigned long long pixel_freq = mode->clock * 1000;
+       unsigned long long vco_freq;
+       unsigned char word_sel;
+       u8 vco_sel, vco_div;
+
+       vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div);
+
+       vc5_hdmi_reset_phy(vc4_hdmi);
+
+       HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
+                  VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
+
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL,
+                  HDMI_READ(HDMI_TX_PHY_RESET_CTL) &
+                  ~VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET &
+                  ~VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET &
+                  ~VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET &
+                  ~VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET);
+
+       HDMI_WRITE(HDMI_RM_CONTROL,
+                  HDMI_READ(HDMI_RM_CONTROL) |
+                  VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS |
+                  VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR |
+                  VC4_HDMI_RM_CONTROL_FREE_RUN);
+
+       HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1,
+                  (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1) &
+                   ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK) |
+                  VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT));
+
+       HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2,
+                  (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2) &
+                   ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK) |
+                  VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT));
+
+       HDMI_WRITE(HDMI_RM_OFFSET,
+                  VC4_SET_FIELD(phy_get_rm_offset(vco_freq),
+                                VC4_HDMI_RM_OFFSET_OFFSET) |
+                  VC4_HDMI_RM_OFFSET_ONLY);
+
+       HDMI_WRITE(HDMI_TX_PHY_CLK_DIV,
+                  VC4_SET_FIELD(vco_div, VC4_HDMI_TX_PHY_CLK_DIV_VCO));
+
+       HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4,
+                  VC4_SET_FIELD(0xe147, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD) |
+                  VC4_SET_FIELD(0xe14, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD));
+
+       HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_0,
+                  VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK |
+                  VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN |
+                  VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE |
+                  VC4_SET_FIELD(vco_sel, VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL));
+
+       HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_1,
+                  HDMI_READ(HDMI_TX_PHY_PLL_CTL_1) |
+                  VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE |
+                  VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL) |
+                  VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY) |
+                  VC4_SET_FIELD(0x8a, VC4_HDMI_TX_PHY_PLL_CTL_1_CPP));
+
+       HDMI_WRITE(HDMI_RM_FORMAT,
+                  HDMI_READ(HDMI_RM_FORMAT) |
+                  VC4_SET_FIELD(2, VC4_HDMI_RM_FORMAT_SHIFT));
+
+       HDMI_WRITE(HDMI_TX_PHY_PLL_CFG,
+                  HDMI_READ(HDMI_TX_PHY_PLL_CFG) |
+                  VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CFG_PDIV));
+
+       if (pixel_freq >= 340000000)
+               word_sel = 3;
+       else
+               word_sel = 0;
+       HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel);
+
+       HDMI_WRITE(HDMI_TX_PHY_CTL_3,
+                  VC4_SET_FIELD(phy_get_cp_current(vco_freq),
+                                VC4_HDMI_TX_PHY_CTL_3_ICP) |
+                  VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP) |
+                  VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP1) |
+                  VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_CTL_3_CZ) |
+                  VC4_SET_FIELD(4, VC4_HDMI_TX_PHY_CTL_3_RP) |
+                  VC4_SET_FIELD(6, VC4_HDMI_TX_PHY_CTL_3_RZ));
+
+       chan0_settings =
+               phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_0],
+                                        pixel_freq);
+       chan1_settings =
+               phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_1],
+                                        pixel_freq);
+       chan2_settings =
+               phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_2],
+                                        pixel_freq);
+       clock_settings =
+               phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_CK],
+                                        pixel_freq);
+
+       HDMI_WRITE(HDMI_TX_PHY_CTL_0,
+                  VC4_SET_FIELD(chan0_settings->amplitude.preemphasis,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP) |
+                  VC4_SET_FIELD(chan0_settings->amplitude.main_driver,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV) |
+                  VC4_SET_FIELD(chan1_settings->amplitude.preemphasis,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP) |
+                  VC4_SET_FIELD(chan1_settings->amplitude.main_driver,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV) |
+                  VC4_SET_FIELD(chan2_settings->amplitude.preemphasis,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP) |
+                  VC4_SET_FIELD(chan2_settings->amplitude.main_driver,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV) |
+                  VC4_SET_FIELD(clock_settings->amplitude.preemphasis,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP) |
+                  VC4_SET_FIELD(clock_settings->amplitude.main_driver,
+                                VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV));
+
+       HDMI_WRITE(HDMI_TX_PHY_CTL_1,
+                  HDMI_READ(HDMI_TX_PHY_CTL_1) |
+                  VC4_SET_FIELD(chan0_settings->res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0) |
+                  VC4_SET_FIELD(chan1_settings->res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1) |
+                  VC4_SET_FIELD(chan2_settings->res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2) |
+                  VC4_SET_FIELD(clock_settings->res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK));
+
+       HDMI_WRITE(HDMI_TX_PHY_CTL_2,
+                  VC4_SET_FIELD(chan0_settings->term_res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0) |
+                  VC4_SET_FIELD(chan1_settings->term_res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1) |
+                  VC4_SET_FIELD(chan2_settings->term_res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2) |
+                  VC4_SET_FIELD(clock_settings->term_res_sel_data,
+                                VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK) |
+                  VC4_SET_FIELD(phy_get_vco_gain(vco_freq),
+                                VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN));
+
+       HDMI_WRITE(HDMI_TX_PHY_CHANNEL_SWAP,
+                  VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_0],
+                                VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL) |
+                  VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_1],
+                                VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL) |
+                  VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_2],
+                                VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL) |
+                  VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_CK],
+                                VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL));
+
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL,
+                  HDMI_READ(HDMI_TX_PHY_RESET_CTL) &
+                  ~(VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
+                    VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB));
+
+       HDMI_WRITE(HDMI_TX_PHY_RESET_CTL,
+                  HDMI_READ(HDMI_TX_PHY_RESET_CTL) |
+                  VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
+                  VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB);
+}
+
+void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
+{
+       vc5_hdmi_reset_phy(vc4_hdmi);
+}
+
+void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
+{
+       HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
+                  HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) &
+                  ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
+}
+
+void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
+{
+       HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
+                  HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) |
+                  VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
+}
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
new file mode 100644 (file)
index 0000000..7c6b481
--- /dev/null
@@ -0,0 +1,442 @@
+#ifndef _VC4_HDMI_REGS_H_
+#define _VC4_HDMI_REGS_H_
+
+#include "vc4_hdmi.h"
+
+#define VC4_HDMI_PACKET_STRIDE                 0x24
+
+enum vc4_hdmi_regs {
+       VC4_INVALID = 0,
+       VC4_HDMI,
+       VC4_HD,
+       VC5_CEC,
+       VC5_CSC,
+       VC5_DVP,
+       VC5_PHY,
+       VC5_RAM,
+       VC5_RM,
+};
+
+enum vc4_hdmi_field {
+       HDMI_AUDIO_PACKET_CONFIG,
+       HDMI_CEC_CNTRL_1,
+       HDMI_CEC_CNTRL_2,
+       HDMI_CEC_CNTRL_3,
+       HDMI_CEC_CNTRL_4,
+       HDMI_CEC_CNTRL_5,
+       HDMI_CEC_CPU_CLEAR,
+       HDMI_CEC_CPU_MASK_CLEAR,
+       HDMI_CEC_CPU_MASK_SET,
+       HDMI_CEC_CPU_MASK_STATUS,
+       HDMI_CEC_CPU_STATUS,
+
+       /*
+        * Transmit data, first byte is low byte of the 32-bit reg.
+        * MSB of each byte transmitted first.
+        */
+       HDMI_CEC_RX_DATA_1,
+       HDMI_CEC_RX_DATA_2,
+       HDMI_CEC_RX_DATA_3,
+       HDMI_CEC_RX_DATA_4,
+       HDMI_CEC_TX_DATA_1,
+       HDMI_CEC_TX_DATA_2,
+       HDMI_CEC_TX_DATA_3,
+       HDMI_CEC_TX_DATA_4,
+       HDMI_CLOCK_STOP,
+       HDMI_CORE_REV,
+       HDMI_CRP_CFG,
+       HDMI_CSC_12_11,
+       HDMI_CSC_14_13,
+       HDMI_CSC_22_21,
+       HDMI_CSC_24_23,
+       HDMI_CSC_32_31,
+       HDMI_CSC_34_33,
+       HDMI_CSC_CTL,
+
+       /*
+        * 20-bit fields containing CTS values to be transmitted if
+        * !EXTERNAL_CTS_EN
+        */
+       HDMI_CTS_0,
+       HDMI_CTS_1,
+       HDMI_DVP_CTL,
+       HDMI_FIFO_CTL,
+       HDMI_FRAME_COUNT,
+       HDMI_HORZA,
+       HDMI_HORZB,
+       HDMI_HOTPLUG,
+       HDMI_HOTPLUG_INT,
+
+       /*
+        * 3 bits per field, where each field maps from that
+        * corresponding MAI bus channel to the given HDMI channel.
+        */
+       HDMI_MAI_CHANNEL_MAP,
+       HDMI_MAI_CONFIG,
+       HDMI_MAI_CTL,
+
+       /*
+        * Register for DMAing in audio data to be transported over
+        * the MAI bus to the Falcon core.
+        */
+       HDMI_MAI_DATA,
+
+       /* Format header to be placed on the MAI data. Unused. */
+       HDMI_MAI_FMT,
+
+       /* Last received format word on the MAI bus. */
+       HDMI_MAI_FORMAT,
+       HDMI_MAI_SMP,
+       HDMI_MAI_THR,
+       HDMI_M_CTL,
+       HDMI_RAM_PACKET_CONFIG,
+       HDMI_RAM_PACKET_START,
+       HDMI_RAM_PACKET_STATUS,
+       HDMI_RM_CONTROL,
+       HDMI_RM_FORMAT,
+       HDMI_RM_OFFSET,
+       HDMI_SCHEDULER_CONTROL,
+       HDMI_SW_RESET_CONTROL,
+       HDMI_TX_PHY_CHANNEL_SWAP,
+       HDMI_TX_PHY_CLK_DIV,
+       HDMI_TX_PHY_CTL_0,
+       HDMI_TX_PHY_CTL_1,
+       HDMI_TX_PHY_CTL_2,
+       HDMI_TX_PHY_CTL_3,
+       HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1,
+       HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2,
+       HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4,
+       HDMI_TX_PHY_PLL_CFG,
+       HDMI_TX_PHY_PLL_CTL_0,
+       HDMI_TX_PHY_PLL_CTL_1,
+       HDMI_TX_PHY_POWERDOWN_CTL,
+       HDMI_TX_PHY_RESET_CTL,
+       HDMI_TX_PHY_TMDS_CLK_WORD_SEL,
+       HDMI_VEC_INTERFACE_XBAR,
+       HDMI_VERTA0,
+       HDMI_VERTA1,
+       HDMI_VERTB0,
+       HDMI_VERTB1,
+       HDMI_VID_CTL,
+};
+
+struct vc4_hdmi_register {
+       char *name;
+       enum vc4_hdmi_regs reg;
+       unsigned int offset;
+};
+
+#define _VC4_REG(_base, _reg, _offset) \
+       [_reg] = {                              \
+               .name = #_reg,                  \
+               .reg = _base,                   \
+               .offset = _offset,              \
+       }
+
+#define VC4_HD_REG(reg, offset)                _VC4_REG(VC4_HD, reg, offset)
+#define VC4_HDMI_REG(reg, offset)      _VC4_REG(VC4_HDMI, reg, offset)
+#define VC5_CEC_REG(reg, offset)       _VC4_REG(VC5_CEC, reg, offset)
+#define VC5_CSC_REG(reg, offset)       _VC4_REG(VC5_CSC, reg, offset)
+#define VC5_DVP_REG(reg, offset)       _VC4_REG(VC5_DVP, reg, offset)
+#define VC5_PHY_REG(reg, offset)       _VC4_REG(VC5_PHY, reg, offset)
+#define VC5_RAM_REG(reg, offset)       _VC4_REG(VC5_RAM, reg, offset)
+#define VC5_RM_REG(reg, offset)                _VC4_REG(VC5_RM, reg, offset)
+
+static const struct vc4_hdmi_register vc4_hdmi_fields[] = {
+       VC4_HD_REG(HDMI_M_CTL, 0x000c),
+       VC4_HD_REG(HDMI_MAI_CTL, 0x0014),
+       VC4_HD_REG(HDMI_MAI_THR, 0x0018),
+       VC4_HD_REG(HDMI_MAI_FMT, 0x001c),
+       VC4_HD_REG(HDMI_MAI_DATA, 0x0020),
+       VC4_HD_REG(HDMI_MAI_SMP, 0x002c),
+       VC4_HD_REG(HDMI_VID_CTL, 0x0038),
+       VC4_HD_REG(HDMI_CSC_CTL, 0x0040),
+       VC4_HD_REG(HDMI_CSC_12_11, 0x0044),
+       VC4_HD_REG(HDMI_CSC_14_13, 0x0048),
+       VC4_HD_REG(HDMI_CSC_22_21, 0x004c),
+       VC4_HD_REG(HDMI_CSC_24_23, 0x0050),
+       VC4_HD_REG(HDMI_CSC_32_31, 0x0054),
+       VC4_HD_REG(HDMI_CSC_34_33, 0x0058),
+       VC4_HD_REG(HDMI_FRAME_COUNT, 0x0068),
+
+       VC4_HDMI_REG(HDMI_CORE_REV, 0x0000),
+       VC4_HDMI_REG(HDMI_SW_RESET_CONTROL, 0x0004),
+       VC4_HDMI_REG(HDMI_HOTPLUG_INT, 0x0008),
+       VC4_HDMI_REG(HDMI_HOTPLUG, 0x000c),
+       VC4_HDMI_REG(HDMI_FIFO_CTL, 0x005c),
+       VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0090),
+       VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0094),
+       VC4_HDMI_REG(HDMI_MAI_FORMAT, 0x0098),
+       VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x009c),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x00a0),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x00a4),
+       VC4_HDMI_REG(HDMI_CRP_CFG, 0x00a8),
+       VC4_HDMI_REG(HDMI_CTS_0, 0x00ac),
+       VC4_HDMI_REG(HDMI_CTS_1, 0x00b0),
+       VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x00c0),
+       VC4_HDMI_REG(HDMI_HORZA, 0x00c4),
+       VC4_HDMI_REG(HDMI_HORZB, 0x00c8),
+       VC4_HDMI_REG(HDMI_VERTA0, 0x00cc),
+       VC4_HDMI_REG(HDMI_VERTB0, 0x00d0),
+       VC4_HDMI_REG(HDMI_VERTA1, 0x00d4),
+       VC4_HDMI_REG(HDMI_VERTB1, 0x00d8),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_1, 0x00e8),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_2, 0x00ec),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_3, 0x00f0),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_4, 0x00f4),
+       VC4_HDMI_REG(HDMI_CEC_CNTRL_5, 0x00f8),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_1, 0x00fc),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_2, 0x0100),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_3, 0x0104),
+       VC4_HDMI_REG(HDMI_CEC_TX_DATA_4, 0x0108),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_1, 0x010c),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_2, 0x0110),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_3, 0x0114),
+       VC4_HDMI_REG(HDMI_CEC_RX_DATA_4, 0x0118),
+       VC4_HDMI_REG(HDMI_TX_PHY_RESET_CTL, 0x02c0),
+       VC4_HDMI_REG(HDMI_TX_PHY_CTL_0, 0x02c4),
+       VC4_HDMI_REG(HDMI_CEC_CPU_STATUS, 0x0340),
+       VC4_HDMI_REG(HDMI_CEC_CPU_CLEAR, 0x0348),
+       VC4_HDMI_REG(HDMI_CEC_CPU_MASK_STATUS, 0x034c),
+       VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x034c),
+       VC4_HDMI_REG(HDMI_CEC_CPU_MASK_CLEAR, 0x0354),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400),
+};
+
+static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = {
+       VC4_HD_REG(HDMI_DVP_CTL, 0x0000),
+       VC4_HD_REG(HDMI_MAI_CTL, 0x0010),
+       VC4_HD_REG(HDMI_MAI_THR, 0x0014),
+       VC4_HD_REG(HDMI_MAI_FMT, 0x0018),
+       VC4_HD_REG(HDMI_MAI_DATA, 0x001c),
+       VC4_HD_REG(HDMI_MAI_SMP, 0x0020),
+       VC4_HD_REG(HDMI_VID_CTL, 0x0044),
+       VC4_HD_REG(HDMI_FRAME_COUNT, 0x0060),
+
+       VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074),
+       VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4),
+       VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8),
+       VC4_HDMI_REG(HDMI_CTS_0, 0x0cc),
+       VC4_HDMI_REG(HDMI_CTS_1, 0x0d0),
+       VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0),
+       VC4_HDMI_REG(HDMI_HORZA, 0x0e4),
+       VC4_HDMI_REG(HDMI_HORZB, 0x0e8),
+       VC4_HDMI_REG(HDMI_VERTA0, 0x0ec),
+       VC4_HDMI_REG(HDMI_VERTB0, 0x0f0),
+       VC4_HDMI_REG(HDMI_VERTA1, 0x0f4),
+       VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
+       VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
+       VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
+       VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
+
+       VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+       VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
+
+       VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
+       VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020),
+       VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034),
+       VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044),
+       VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c),
+
+       VC5_RM_REG(HDMI_RM_CONTROL, 0x000),
+       VC5_RM_REG(HDMI_RM_OFFSET, 0x018),
+       VC5_RM_REG(HDMI_RM_FORMAT, 0x01c),
+
+       VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000),
+
+       VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044),
+
+       VC5_CSC_REG(HDMI_CSC_CTL, 0x000),
+       VC5_CSC_REG(HDMI_CSC_12_11, 0x004),
+       VC5_CSC_REG(HDMI_CSC_14_13, 0x008),
+       VC5_CSC_REG(HDMI_CSC_22_21, 0x00c),
+       VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
+       VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
+       VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
+};
+
+static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = {
+       VC4_HD_REG(HDMI_DVP_CTL, 0x0000),
+       VC4_HD_REG(HDMI_MAI_CTL, 0x0030),
+       VC4_HD_REG(HDMI_MAI_THR, 0x0034),
+       VC4_HD_REG(HDMI_MAI_FMT, 0x0038),
+       VC4_HD_REG(HDMI_MAI_DATA, 0x003c),
+       VC4_HD_REG(HDMI_MAI_SMP, 0x0040),
+       VC4_HD_REG(HDMI_VID_CTL, 0x0048),
+       VC4_HD_REG(HDMI_FRAME_COUNT, 0x0064),
+
+       VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074),
+       VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc),
+       VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4),
+       VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8),
+       VC4_HDMI_REG(HDMI_CTS_0, 0x0cc),
+       VC4_HDMI_REG(HDMI_CTS_1, 0x0d0),
+       VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0),
+       VC4_HDMI_REG(HDMI_HORZA, 0x0e4),
+       VC4_HDMI_REG(HDMI_HORZB, 0x0e8),
+       VC4_HDMI_REG(HDMI_VERTA0, 0x0ec),
+       VC4_HDMI_REG(HDMI_VERTB0, 0x0f0),
+       VC4_HDMI_REG(HDMI_VERTA1, 0x0f4),
+       VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
+       VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
+       VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
+       VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
+
+       VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+       VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
+
+       VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
+       VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010),
+       VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020),
+       VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034),
+       VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c),
+       VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054),
+       VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c),
+
+       VC5_RM_REG(HDMI_RM_CONTROL, 0x000),
+       VC5_RM_REG(HDMI_RM_OFFSET, 0x018),
+       VC5_RM_REG(HDMI_RM_FORMAT, 0x01c),
+
+       VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000),
+
+       VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c),
+       VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030),
+       VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040),
+       VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044),
+
+       VC5_CSC_REG(HDMI_CSC_CTL, 0x000),
+       VC5_CSC_REG(HDMI_CSC_12_11, 0x004),
+       VC5_CSC_REG(HDMI_CSC_14_13, 0x008),
+       VC5_CSC_REG(HDMI_CSC_22_21, 0x00c),
+       VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
+       VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
+       VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
+};
+
+static inline
+void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi,
+                                       enum vc4_hdmi_regs reg)
+{
+       switch (reg) {
+       case VC4_HD:
+               return hdmi->hd_regs;
+
+       case VC4_HDMI:
+               return hdmi->hdmicore_regs;
+
+       case VC5_CSC:
+               return hdmi->csc_regs;
+
+       case VC5_CEC:
+               return hdmi->cec_regs;
+
+       case VC5_DVP:
+               return hdmi->dvp_regs;
+
+       case VC5_PHY:
+               return hdmi->phy_regs;
+
+       case VC5_RAM:
+               return hdmi->ram_regs;
+
+       case VC5_RM:
+               return hdmi->rm_regs;
+
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
+static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
+                               enum vc4_hdmi_field reg)
+{
+       const struct vc4_hdmi_register *field;
+       const struct vc4_hdmi_variant *variant = hdmi->variant;
+       void __iomem *base;
+
+       if (reg >= variant->num_registers) {
+               dev_warn(&hdmi->pdev->dev,
+                        "Invalid register ID %u\n", reg);
+               return 0;
+       }
+
+       field = &variant->registers[reg];
+       base = __vc4_hdmi_get_field_base(hdmi, field->reg);
+       if (!base) {
+               dev_warn(&hdmi->pdev->dev,
+                        "Unknown register ID %u\n", reg);
+               return 0;
+       }
+
+       return readl(base + field->offset);
+}
+#define HDMI_READ(reg)         vc4_hdmi_read(vc4_hdmi, reg)
+
+static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
+                                 enum vc4_hdmi_field reg,
+                                 u32 value)
+{
+       const struct vc4_hdmi_register *field;
+       const struct vc4_hdmi_variant *variant = hdmi->variant;
+       void __iomem *base;
+
+       if (reg >= variant->num_registers) {
+               dev_warn(&hdmi->pdev->dev,
+                        "Invalid register ID %u\n", reg);
+               return;
+       }
+
+       field = &variant->registers[reg];
+       base = __vc4_hdmi_get_field_base(hdmi, field->reg);
+       if (!base)
+               return;
+
+       writel(value, base + field->offset);
+}
+#define HDMI_WRITE(reg, val)   vc4_hdmi_write(vc4_hdmi, reg, val)
+
+#endif /* _VC4_HDMI_REGS_H_ */
index 2d2bf59c05032bd4fbffb07644e461342e6786a1..4d0a833366cee10eb6fca2644433738b78985eeb 100644 (file)
@@ -19,6 +19,8 @@
  * each CRTC.
  */
 
+#include <linux/bitfield.h>
+#include <linux/clk.h>
 #include <linux/component.h>
 #include <linux/platform_device.h>
 
@@ -160,6 +162,7 @@ static void vc4_hvs_lut_load(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+       struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
        u32 i;
 
        /* The LUT memory is laid out with each HVS channel in order,
@@ -168,7 +171,7 @@ static void vc4_hvs_lut_load(struct drm_crtc *crtc)
         */
        HVS_WRITE(SCALER_GAMADDR,
                  SCALER_GAMADDR_AUTOINC |
-                 (vc4_crtc->channel * 3 * crtc->gamma_size));
+                 (vc4_state->assigned_channel * 3 * crtc->gamma_size));
 
        for (i = 0; i < crtc->gamma_size; i++)
                HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]);
@@ -194,6 +197,135 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
        vc4_hvs_lut_load(crtc);
 }
 
+int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
+{
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+       u32 reg;
+       int ret;
+
+       if (!vc4->hvs->hvs5)
+               return output;
+
+       switch (output) {
+       case 0:
+               return 0;
+
+       case 1:
+               return 1;
+
+       case 2:
+               reg = HVS_READ(SCALER_DISPECTRL);
+               ret = FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg);
+               if (ret == 0)
+                       return 2;
+
+               return 0;
+
+       case 3:
+               reg = HVS_READ(SCALER_DISPCTRL);
+               ret = FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg);
+               if (ret == 3)
+                       return -EPIPE;
+
+               return ret;
+
+       case 4:
+               reg = HVS_READ(SCALER_DISPEOLN);
+               ret = FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg);
+               if (ret == 3)
+                       return -EPIPE;
+
+               return ret;
+
+       case 5:
+               reg = HVS_READ(SCALER_DISPDITHER);
+               ret = FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg);
+               if (ret == 3)
+                       return -EPIPE;
+
+               return ret;
+
+       default:
+               return -EPIPE;
+       }
+}
+
+static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
+                               struct drm_display_mode *mode, bool oneshot)
+{
+       struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
+       unsigned int chan = vc4_crtc_state->assigned_channel;
+       bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
+       u32 dispbkgndx;
+       u32 dispctrl;
+
+       HVS_WRITE(SCALER_DISPCTRLX(chan), 0);
+       HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET);
+       HVS_WRITE(SCALER_DISPCTRLX(chan), 0);
+
+       /* Turn on the scaler, which will wait for vstart to start
+        * compositing.
+        * When feeding the transposer, we should operate in oneshot
+        * mode.
+        */
+       dispctrl = SCALER_DISPCTRLX_ENABLE;
+
+       if (!vc4->hvs->hvs5)
+               dispctrl |= VC4_SET_FIELD(mode->hdisplay,
+                                         SCALER_DISPCTRLX_WIDTH) |
+                           VC4_SET_FIELD(mode->vdisplay,
+                                         SCALER_DISPCTRLX_HEIGHT) |
+                           (oneshot ? SCALER_DISPCTRLX_ONESHOT : 0);
+       else
+               dispctrl |= VC4_SET_FIELD(mode->hdisplay,
+                                         SCALER5_DISPCTRLX_WIDTH) |
+                           VC4_SET_FIELD(mode->vdisplay,
+                                         SCALER5_DISPCTRLX_HEIGHT) |
+                           (oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0);
+
+       HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl);
+
+       dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
+       dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
+       dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
+
+       HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
+                 SCALER_DISPBKGND_AUTOHS |
+                 ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) |
+                 (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
+
+       /* Reload the LUT, since the SRAMs would have been disabled if
+        * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
+        */
+       vc4_hvs_lut_load(crtc);
+
+       return 0;
+}
+
+void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan)
+{
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
+
+       if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE)
+               return;
+
+       HVS_WRITE(SCALER_DISPCTRLX(chan),
+                 HVS_READ(SCALER_DISPCTRLX(chan)) | SCALER_DISPCTRLX_RESET);
+       HVS_WRITE(SCALER_DISPCTRLX(chan),
+                 HVS_READ(SCALER_DISPCTRLX(chan)) & ~SCALER_DISPCTRLX_ENABLE);
+
+       /* Once we leave, the scaler should be disabled and its fifo empty. */
+       WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET);
+
+       WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)),
+                                  SCALER_DISPSTATX_MODE) !=
+                    SCALER_DISPSTATX_MODE_DISABLED);
+
+       WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) &
+                     (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) !=
+                    SCALER_DISPSTATX_EMPTY);
+}
+
 int vc4_hvs_atomic_check(struct drm_crtc *crtc,
                         struct drm_crtc_state *state)
 {
@@ -248,12 +380,12 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
                        crtc->state->event = NULL;
                }
 
-               HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
+               HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
                          vc4_state->mm.start);
 
                spin_unlock_irqrestore(&dev->event_lock, flags);
        } else {
-               HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
+               HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
                          vc4_state->mm.start);
        }
 }
@@ -263,59 +395,22 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
        struct drm_display_mode *mode = &crtc->state->adjusted_mode;
        bool oneshot = vc4_state->feed_txp;
-       u32 dispctrl;
 
        vc4_hvs_update_dlist(crtc);
-
-       /* Turn on the scaler, which will wait for vstart to start
-        * compositing.
-        * When feeding the transposer, we should operate in oneshot
-        * mode.
-        */
-       dispctrl = SCALER_DISPCTRLX_ENABLE;
-       dispctrl |= VC4_SET_FIELD(mode->hdisplay,
-                                 SCALER_DISPCTRLX_WIDTH) |
-                   VC4_SET_FIELD(mode->vdisplay,
-                                 SCALER_DISPCTRLX_HEIGHT) |
-                   (oneshot ? SCALER_DISPCTRLX_ONESHOT : 0);
-
-       HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), dispctrl);
+       vc4_hvs_init_channel(vc4, crtc, mode, oneshot);
 }
 
 void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
                            struct drm_crtc_state *old_state)
 {
        struct drm_device *dev = crtc->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-       u32 chan = vc4_crtc->channel;
+       struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(old_state);
+       unsigned int chan = vc4_state->assigned_channel;
 
-       if (HVS_READ(SCALER_DISPCTRLX(chan)) &
-           SCALER_DISPCTRLX_ENABLE) {
-               HVS_WRITE(SCALER_DISPCTRLX(chan),
-                         SCALER_DISPCTRLX_RESET);
-
-               /* While the docs say that reset is self-clearing, it
-                * seems it doesn't actually.
-                */
-               HVS_WRITE(SCALER_DISPCTRLX(chan), 0);
-       }
-
-       /* Once we leave, the scaler should be disabled and its fifo empty. */
-
-       WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET);
-
-       WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)),
-                                  SCALER_DISPSTATX_MODE) !=
-                    SCALER_DISPSTATX_MODE_DISABLED);
-
-       WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) &
-                     (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) !=
-                    SCALER_DISPSTATX_EMPTY);
+       vc4_hvs_stop_channel(dev, chan);
 }
 
 void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
@@ -323,7 +418,6 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
        struct drm_plane *plane;
        struct vc4_plane_state *vc4_plane_state;
@@ -365,8 +459,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
                /* This sets a black background color fill, as is the case
                 * with other DRM drivers.
                 */
-               HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
-                         HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) |
+               HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
+                         HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)) |
                          SCALER_DISPBKGND_FILL);
 
        /* Only update DISPLIST if the CRTC was already running and is not
@@ -380,7 +474,7 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
                vc4_hvs_update_dlist(crtc);
 
        if (crtc->state->color_mgmt_changed) {
-               u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel));
+               u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
 
                if (crtc->state->gamma_lut) {
                        vc4_hvs_update_gamma_lut(crtc);
@@ -392,7 +486,7 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
                         */
                        dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
                }
-               HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), dispbkgndx);
+               HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx);
        }
 
        if (debug_dump_regs) {
@@ -401,50 +495,6 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
        }
 }
 
-void vc4_hvs_mode_set_nofb(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-       struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
-       struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-       bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
-
-       if (vc4_crtc->data->hvs_channel == 2) {
-               u32 dispctrl;
-               u32 dsp3_mux;
-
-               /*
-                * SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to
-                * FIFO X'.
-                * SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'.
-                *
-                * DSP3 is connected to FIFO2 unless the transposer is
-                * enabled. In this case, FIFO 2 is directly accessed by the
-                * TXP IP, and we need to disable the FIFO2 -> pixelvalve1
-                * route.
-                */
-               if (vc4_state->feed_txp)
-                       dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX);
-               else
-                       dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
-
-               dispctrl = HVS_READ(SCALER_DISPCTRL) &
-                          ~SCALER_DISPCTRL_DSP3_MUX_MASK;
-               HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux);
-       }
-
-       HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
-                 SCALER_DISPBKGND_AUTOHS |
-                 SCALER_DISPBKGND_GAMMA |
-                 (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
-
-       /* Reload the LUT, since the SRAMs would have been disabled if
-        * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
-        */
-       vc4_hvs_lut_load(crtc);
-}
-
 void vc4_hvs_mask_underrun(struct drm_device *dev, int channel)
 {
        struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -521,6 +571,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
 
        hvs->pdev = pdev;
 
+       if (of_device_is_compatible(pdev->dev.of_node, "brcm,bcm2711-hvs"))
+               hvs->hvs5 = true;
+
        hvs->regs = vc4_ioremap_regs(pdev, 0);
        if (IS_ERR(hvs->regs))
                return PTR_ERR(hvs->regs);
@@ -529,7 +582,24 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
        hvs->regset.regs = hvs_regs;
        hvs->regset.nregs = ARRAY_SIZE(hvs_regs);
 
-       hvs->dlist = hvs->regs + SCALER_DLIST_START;
+       if (hvs->hvs5) {
+               hvs->core_clk = devm_clk_get(&pdev->dev, NULL);
+               if (IS_ERR(hvs->core_clk)) {
+                       dev_err(&pdev->dev, "Couldn't get core clock\n");
+                       return PTR_ERR(hvs->core_clk);
+               }
+
+               ret = clk_prepare_enable(hvs->core_clk);
+               if (ret) {
+                       dev_err(&pdev->dev, "Couldn't enable the core clock\n");
+                       return ret;
+               }
+       }
+
+       if (!hvs->hvs5)
+               hvs->dlist = hvs->regs + SCALER_DLIST_START;
+       else
+               hvs->dlist = hvs->regs + SCALER5_DLIST_START;
 
        spin_lock_init(&hvs->mm_lock);
 
@@ -547,7 +617,12 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
         * between planes when they don't overlap on the screen, but
         * for now we just allocate globally.
         */
-       drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
+       if (!hvs->hvs5)
+               /* 96kB */
+               drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
+       else
+               /* 70k words */
+               drm_mm_init(&hvs->lbm_mm, 0, 70 * 2 * 1024);
 
        /* Upload filter kernels.  We only have the one for now, so we
         * keep it around for the lifetime of the driver.
@@ -605,6 +680,7 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
 {
        struct drm_device *drm = dev_get_drvdata(master);
        struct vc4_dev *vc4 = drm->dev_private;
+       struct vc4_hvs *hvs = vc4->hvs;
 
        if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter))
                drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
@@ -612,6 +688,8 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
        drm_mm_takedown(&vc4->hvs->dlist_mm);
        drm_mm_takedown(&vc4->hvs->lbm_mm);
 
+       clk_disable_unprepare(hvs->core_clk);
+
        vc4->hvs = NULL;
 }
 
@@ -632,6 +710,7 @@ static int vc4_hvs_dev_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id vc4_hvs_dt_match[] = {
+       { .compatible = "brcm,bcm2711-hvs" },
        { .compatible = "brcm,bcm2835-hvs" },
        {}
 };
index 08318e69061be37c7995e311289eb58d7c9f1ee5..16e233e1406e9f06f6ec944e59cac52a05225ca4 100644 (file)
@@ -11,6 +11,8 @@
  * crtc, HDMI encoder).
  */
 
+#include <linux/clk.h>
+
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
@@ -144,22 +146,130 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
                  VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO));
 }
 
+static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
+                                    struct drm_atomic_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       unsigned int i;
+
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+               struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
+               u32 dispctrl;
+               u32 dsp3_mux;
+
+               if (!crtc_state->active)
+                       continue;
+
+               if (vc4_state->assigned_channel != 2)
+                       continue;
+
+               /*
+                * SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to
+                * FIFO X'.
+                * SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'.
+                *
+                * DSP3 is connected to FIFO2 unless the transposer is
+                * enabled. In this case, FIFO 2 is directly accessed by the
+                * TXP IP, and we need to disable the FIFO2 -> pixelvalve1
+                * route.
+                */
+               if (vc4_state->feed_txp)
+                       dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX);
+               else
+                       dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
+
+               dispctrl = HVS_READ(SCALER_DISPCTRL) &
+                          ~SCALER_DISPCTRL_DSP3_MUX_MASK;
+               HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux);
+       }
+}
+
+static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4,
+                                    struct drm_atomic_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       unsigned char dsp2_mux = 0;
+       unsigned char dsp3_mux = 3;
+       unsigned char dsp4_mux = 3;
+       unsigned char dsp5_mux = 3;
+       unsigned int i;
+       u32 reg;
+
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+               struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
+               struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+               if (!crtc_state->active)
+                       continue;
+
+               switch (vc4_crtc->data->hvs_output) {
+               case 2:
+                       dsp2_mux = (vc4_state->assigned_channel == 2) ? 0 : 1;
+                       break;
+
+               case 3:
+                       dsp3_mux = vc4_state->assigned_channel;
+                       break;
+
+               case 4:
+                       dsp4_mux = vc4_state->assigned_channel;
+                       break;
+
+               case 5:
+                       dsp5_mux = vc4_state->assigned_channel;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       reg = HVS_READ(SCALER_DISPECTRL);
+       HVS_WRITE(SCALER_DISPECTRL,
+                 (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) |
+                 VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX));
+
+       reg = HVS_READ(SCALER_DISPCTRL);
+       HVS_WRITE(SCALER_DISPCTRL,
+                 (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) |
+                 VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX));
+
+       reg = HVS_READ(SCALER_DISPEOLN);
+       HVS_WRITE(SCALER_DISPEOLN,
+                 (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) |
+                 VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX));
+
+       reg = HVS_READ(SCALER_DISPDITHER);
+       HVS_WRITE(SCALER_DISPDITHER,
+                 (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) |
+                 VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX));
+}
+
 static void
 vc4_atomic_complete_commit(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc;
+       struct vc4_hvs *hvs = vc4->hvs;
+       struct drm_crtc_state *new_crtc_state;
+       struct drm_crtc *crtc;
        int i;
 
-       for (i = 0; i < dev->mode_config.num_crtc; i++) {
-               if (!state->crtcs[i].ptr || !state->crtcs[i].commit)
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+               struct vc4_crtc_state *vc4_crtc_state;
+
+               if (!new_crtc_state->commit)
                        continue;
 
-               vc4_crtc = to_vc4_crtc(state->crtcs[i].ptr);
-               vc4_hvs_mask_underrun(dev, vc4_crtc->channel);
+               vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
+               vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
        }
 
+       if (vc4->hvs->hvs5)
+               clk_set_min_rate(hvs->core_clk, 500000000);
+
        drm_atomic_helper_wait_for_fences(dev, state, false);
 
        drm_atomic_helper_wait_for_dependencies(state);
@@ -168,6 +278,11 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state)
 
        vc4_ctm_commit(vc4, state);
 
+       if (vc4->hvs->hvs5)
+               vc5_hvs_pv_muxing_commit(vc4, state);
+       else
+               vc4_hvs_pv_muxing_commit(vc4, state);
+
        drm_atomic_helper_commit_planes(dev, state, 0);
 
        drm_atomic_helper_commit_modeset_enables(dev, state);
@@ -182,6 +297,9 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state)
 
        drm_atomic_helper_commit_cleanup_done(state);
 
+       if (vc4->hvs->hvs5)
+               clk_set_min_rate(hvs->core_clk, 0);
+
        drm_atomic_state_put(state);
 
        up(&vc4->async_modeset);
@@ -374,8 +492,11 @@ vc4_ctm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 
                /* CTM is being enabled or the matrix changed. */
                if (new_crtc_state->ctm) {
+                       struct vc4_crtc_state *vc4_crtc_state =
+                               to_vc4_crtc_state(new_crtc_state);
+
                        /* fifo is 1-based since 0 disables CTM. */
-                       int fifo = to_vc4_crtc(crtc)->channel + 1;
+                       int fifo = vc4_crtc_state->assigned_channel + 1;
 
                        /* Check userland isn't trying to turn on CTM for more
                         * than one CRTC at a time.
@@ -415,6 +536,9 @@ static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state)
        struct drm_plane *plane;
        int i;
 
+       if (!vc4->load_tracker_available)
+               return 0;
+
        priv_state = drm_atomic_get_private_obj_state(state,
                                                      &vc4->load_tracker);
        if (IS_ERR(priv_state))
@@ -485,10 +609,60 @@ static const struct drm_private_state_funcs vc4_load_tracker_state_funcs = {
        .atomic_destroy_state = vc4_load_tracker_destroy_state,
 };
 
+#define NUM_OUTPUTS  6
+#define NUM_CHANNELS 3
+
 static int
 vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
-       int ret;
+       unsigned long unassigned_channels = GENMASK(NUM_CHANNELS - 1, 0);
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       int i, ret;
+
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+               struct vc4_crtc_state *vc4_crtc_state =
+                       to_vc4_crtc_state(crtc_state);
+               struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+               unsigned int matching_channels;
+
+               if (!crtc_state->active)
+                       continue;
+
+               /*
+                * The problem we have to solve here is that we have
+                * up to 7 encoders, connected to up to 6 CRTCs.
+                *
+                * Those CRTCs, depending on the instance, can be
+                * routed to 1, 2 or 3 HVS FIFOs, and we need to set
+                * the change the muxing between FIFOs and outputs in
+                * the HVS accordingly.
+                *
+                * It would be pretty hard to come up with an
+                * algorithm that would generically solve
+                * this. However, the current routing trees we support
+                * allow us to simplify a bit the problem.
+                *
+                * Indeed, with the current supported layouts, if we
+                * try to assign in the ascending crtc index order the
+                * FIFOs, we can't fall into the situation where an
+                * earlier CRTC that had multiple routes is assigned
+                * one that was the only option for a later CRTC.
+                *
+                * If the layout changes and doesn't give us that in
+                * the future, we will need to have something smarter,
+                * but it works so far.
+                */
+               matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels;
+               if (matching_channels) {
+                       unsigned int channel = ffs(matching_channels) - 1;
+
+                       vc4_crtc_state->assigned_channel = channel;
+                       unassigned_channels &= ~BIT(channel);
+               } else {
+                       return -EINVAL;
+               }
+       }
 
        ret = vc4_ctm_atomic_check(dev, state);
        if (ret < 0)
@@ -512,12 +686,18 @@ int vc4_kms_load(struct drm_device *dev)
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct vc4_ctm_state *ctm_state;
        struct vc4_load_tracker_state *load_state;
+       bool is_vc5 = of_device_is_compatible(dev->dev->of_node,
+                                             "brcm,bcm2711-vc5");
        int ret;
 
-       /* Start with the load tracker enabled. Can be disabled through the
-        * debugfs load_tracker file.
-        */
-       vc4->load_tracker_enabled = true;
+       if (!is_vc5) {
+               vc4->load_tracker_available = true;
+
+               /* Start with the load tracker enabled. Can be
+                * disabled through the debugfs load_tracker file.
+                */
+               vc4->load_tracker_enabled = true;
+       }
 
        sema_init(&vc4->async_modeset, 1);
 
@@ -531,8 +711,14 @@ int vc4_kms_load(struct drm_device *dev)
                return ret;
        }
 
-       dev->mode_config.max_width = 2048;
-       dev->mode_config.max_height = 2048;
+       if (is_vc5) {
+               dev->mode_config.max_width = 7680;
+               dev->mode_config.max_height = 7680;
+       } else {
+               dev->mode_config.max_width = 2048;
+               dev->mode_config.max_height = 2048;
+       }
+
        dev->mode_config.funcs = &vc4_mode_funcs;
        dev->mode_config.preferred_depth = 24;
        dev->mode_config.async_page_flip = true;
@@ -547,14 +733,17 @@ int vc4_kms_load(struct drm_device *dev)
        drm_atomic_private_obj_init(dev, &vc4->ctm_manager, &ctm_state->base,
                                    &vc4_ctm_state_funcs);
 
-       load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
-       if (!load_state) {
-               drm_atomic_private_obj_fini(&vc4->ctm_manager);
-               return -ENOMEM;
-       }
+       if (vc4->load_tracker_available) {
+               load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
+               if (!load_state) {
+                       drm_atomic_private_obj_fini(&vc4->ctm_manager);
+                       return -ENOMEM;
+               }
 
-       drm_atomic_private_obj_init(dev, &vc4->load_tracker, &load_state->base,
-                                   &vc4_load_tracker_state_funcs);
+               drm_atomic_private_obj_init(dev, &vc4->load_tracker,
+                                           &load_state->base,
+                                           &vc4_load_tracker_state_funcs);
+       }
 
        drm_mode_config_reset(dev);
 
index d040d9f12c6d769bd633f076236a5c769bc58a26..89543fa8ca4de2ad6bc2641a003763c91bdfb3b6 100644 (file)
@@ -32,45 +32,60 @@ static const struct hvs_format {
        u32 drm; /* DRM_FORMAT_* */
        u32 hvs; /* HVS_FORMAT_* */
        u32 pixel_order;
+       u32 pixel_order_hvs5;
 } hvs_formats[] = {
        {
-               .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_XRGB8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
        },
        {
-               .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_ARGB8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
        },
        {
-               .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_ABGR8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ARGB,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
+               .drm = DRM_FORMAT_XBGR8888,
+               .hvs = HVS_PIXEL_FORMAT_RGBA8888,
                .pixel_order = HVS_PIXEL_ORDER_ARGB,
+               .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
+               .drm = DRM_FORMAT_RGB565,
+               .hvs = HVS_PIXEL_FORMAT_RGB565,
                .pixel_order = HVS_PIXEL_ORDER_XRGB,
        },
        {
-               .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
+               .drm = DRM_FORMAT_BGR565,
+               .hvs = HVS_PIXEL_FORMAT_RGB565,
                .pixel_order = HVS_PIXEL_ORDER_XBGR,
        },
        {
-               .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
+               .drm = DRM_FORMAT_ARGB1555,
+               .hvs = HVS_PIXEL_FORMAT_RGBA5551,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
+               .drm = DRM_FORMAT_XRGB1555,
+               .hvs = HVS_PIXEL_FORMAT_RGBA5551,
                .pixel_order = HVS_PIXEL_ORDER_ABGR,
        },
        {
-               .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
+               .drm = DRM_FORMAT_RGB888,
+               .hvs = HVS_PIXEL_FORMAT_RGB888,
                .pixel_order = HVS_PIXEL_ORDER_XRGB,
        },
        {
-               .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888,
+               .drm = DRM_FORMAT_BGR888,
+               .hvs = HVS_PIXEL_FORMAT_RGB888,
                .pixel_order = HVS_PIXEL_ORDER_XBGR,
        },
        {
@@ -422,10 +437,7 @@ static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
 static u32 vc4_lbm_size(struct drm_plane_state *state)
 {
        struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
-       /* This is the worst case number.  One of the two sizes will
-        * be used depending on the scaling configuration.
-        */
-       u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w);
+       u32 pix_per_line;
        u32 lbm;
 
        /* LBM is not needed when there's no vertical scaling. */
@@ -433,6 +445,18 @@ static u32 vc4_lbm_size(struct drm_plane_state *state)
            vc4_state->y_scaling[1] == VC4_SCALING_NONE)
                return 0;
 
+       /*
+        * This can be further optimized in the RGB/YUV444 case if the PPF
+        * decimation factor is between 0.5 and 1.0 by using crtc_w.
+        *
+        * It's not an issue though, since in that case since src_w[0] is going
+        * to be greater than or equal to crtc_w.
+        */
+       if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ)
+               pix_per_line = vc4_state->crtc_w;
+       else
+               pix_per_line = vc4_state->src_w[0];
+
        if (!vc4_state->is_yuv) {
                if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
                        lbm = pix_per_line * 8;
@@ -492,6 +516,11 @@ static void vc4_plane_calc_load(struct drm_plane_state *state)
        struct vc4_plane_state *vc4_state;
        struct drm_crtc_state *crtc_state;
        unsigned int vscale_factor;
+       struct vc4_dev *vc4;
+
+       vc4 = to_vc4_dev(state->plane->dev);
+       if (!vc4->load_tracker_available)
+               return;
 
        vc4_state = to_vc4_plane_state(state);
        crtc_state = drm_atomic_get_existing_crtc_state(state->state,
@@ -563,7 +592,9 @@ static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
                spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
                ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
                                                 &vc4_state->lbm,
-                                                lbm_size, 32, 0, 0);
+                                                lbm_size,
+                                                vc4->hvs->hvs5 ? 64 : 32,
+                                                0, 0);
                spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
 
                if (ret)
@@ -776,35 +807,6 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                return -EINVAL;
        }
 
-       /* Control word */
-       vc4_dlist_write(vc4_state,
-                       SCALER_CTL0_VALID |
-                       (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
-                       (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
-                       VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
-                       (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
-                       (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
-                       VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
-                       (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
-                       VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
-                       VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
-
-       /* Position Word 0: Image Positions and Alpha Value */
-       vc4_state->pos0_offset = vc4_state->dlist_count;
-       vc4_dlist_write(vc4_state,
-                       VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
-                       VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
-                       VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
-
-       /* Position Word 1: Scaled Image Dimensions. */
-       if (!vc4_state->is_unity) {
-               vc4_dlist_write(vc4_state,
-                               VC4_SET_FIELD(vc4_state->crtc_w,
-                                             SCALER_POS1_SCL_WIDTH) |
-                               VC4_SET_FIELD(vc4_state->crtc_h,
-                                             SCALER_POS1_SCL_HEIGHT));
-       }
-
        /* Don't waste cycles mixing with plane alpha if the set alpha
         * is opaque or there is no per-pixel alpha information.
         * In any case we use the alpha property value as the fixed alpha.
@@ -812,20 +814,120 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
                          fb->format->has_alpha;
 
-       /* Position Word 2: Source Image Size, Alpha */
-       vc4_state->pos2_offset = vc4_state->dlist_count;
-       vc4_dlist_write(vc4_state,
-                       VC4_SET_FIELD(fb->format->has_alpha ?
-                                     SCALER_POS2_ALPHA_MODE_PIPELINE :
-                                     SCALER_POS2_ALPHA_MODE_FIXED,
-                                     SCALER_POS2_ALPHA_MODE) |
-                       (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
-                       (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
-                       VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
-                       VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
+       if (!vc4->hvs->hvs5) {
+       /* Control word */
+               vc4_dlist_write(vc4_state,
+                               SCALER_CTL0_VALID |
+                               (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
+                               (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
+                               VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
+                               (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+                               (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+                               VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
+                               (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
+                               VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
+                               VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
+
+               /* Position Word 0: Image Positions and Alpha Value */
+               vc4_state->pos0_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
+                               VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
+                               VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
 
-       /* Position Word 3: Context.  Written by the HVS. */
-       vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+               /* Position Word 1: Scaled Image Dimensions. */
+               if (!vc4_state->is_unity) {
+                       vc4_dlist_write(vc4_state,
+                                       VC4_SET_FIELD(vc4_state->crtc_w,
+                                                     SCALER_POS1_SCL_WIDTH) |
+                                       VC4_SET_FIELD(vc4_state->crtc_h,
+                                                     SCALER_POS1_SCL_HEIGHT));
+               }
+
+               /* Position Word 2: Source Image Size, Alpha */
+               vc4_state->pos2_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(fb->format->has_alpha ?
+                                             SCALER_POS2_ALPHA_MODE_PIPELINE :
+                                             SCALER_POS2_ALPHA_MODE_FIXED,
+                                             SCALER_POS2_ALPHA_MODE) |
+                               (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
+                               (fb->format->has_alpha ?
+                                               SCALER_POS2_ALPHA_PREMULT : 0) |
+                               VC4_SET_FIELD(vc4_state->src_w[0],
+                                             SCALER_POS2_WIDTH) |
+                               VC4_SET_FIELD(vc4_state->src_h[0],
+                                             SCALER_POS2_HEIGHT));
+
+               /* Position Word 3: Context.  Written by the HVS. */
+               vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+
+       } else {
+               u32 hvs_pixel_order = format->pixel_order;
+
+               if (format->pixel_order_hvs5)
+                       hvs_pixel_order = format->pixel_order_hvs5;
+
+               /* Control word */
+               vc4_dlist_write(vc4_state,
+                               SCALER_CTL0_VALID |
+                               (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+                               (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+                               VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
+                               (vc4_state->is_unity ?
+                                               SCALER5_CTL0_UNITY : 0) |
+                               VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
+                               VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
+                               SCALER5_CTL0_ALPHA_EXPAND |
+                               SCALER5_CTL0_RGB_EXPAND);
+
+               /* Position Word 0: Image Positions and Alpha Value */
+               vc4_state->pos0_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               (rotation & DRM_MODE_REFLECT_Y ?
+                                               SCALER5_POS0_VFLIP : 0) |
+                               VC4_SET_FIELD(vc4_state->crtc_x,
+                                             SCALER_POS0_START_X) |
+                               (rotation & DRM_MODE_REFLECT_X ?
+                                             SCALER5_POS0_HFLIP : 0) |
+                               VC4_SET_FIELD(vc4_state->crtc_y,
+                                             SCALER5_POS0_START_Y)
+                              );
+
+               /* Control Word 2 */
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(state->alpha >> 4,
+                                             SCALER5_CTL2_ALPHA) |
+                               (fb->format->has_alpha ?
+                                       SCALER5_CTL2_ALPHA_PREMULT : 0) |
+                               (mix_plane_alpha ?
+                                       SCALER5_CTL2_ALPHA_MIX : 0) |
+                               VC4_SET_FIELD(fb->format->has_alpha ?
+                                     SCALER5_CTL2_ALPHA_MODE_PIPELINE :
+                                     SCALER5_CTL2_ALPHA_MODE_FIXED,
+                                     SCALER5_CTL2_ALPHA_MODE)
+                              );
+
+               /* Position Word 1: Scaled Image Dimensions. */
+               if (!vc4_state->is_unity) {
+                       vc4_dlist_write(vc4_state,
+                                       VC4_SET_FIELD(vc4_state->crtc_w,
+                                                     SCALER_POS1_SCL_WIDTH) |
+                                       VC4_SET_FIELD(vc4_state->crtc_h,
+                                                     SCALER_POS1_SCL_HEIGHT));
+               }
+
+               /* Position Word 2: Source Image Size */
+               vc4_state->pos2_offset = vc4_state->dlist_count;
+               vc4_dlist_write(vc4_state,
+                               VC4_SET_FIELD(vc4_state->src_w[0],
+                                             SCALER5_POS2_WIDTH) |
+                               VC4_SET_FIELD(vc4_state->src_h[0],
+                                             SCALER5_POS2_HEIGHT));
+
+               /* Position Word 3: Context.  Written by the HVS. */
+               vc4_dlist_write(vc4_state, 0xc0c0c0c0);
+       }
 
 
        /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
@@ -1203,6 +1305,10 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
                default:
                        return false;
                }
+       case DRM_FORMAT_RGBX1010102:
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_BGRA1010102:
        case DRM_FORMAT_YUV422:
        case DRM_FORMAT_YVU422:
        case DRM_FORMAT_YUV420:
@@ -1283,7 +1389,7 @@ int vc4_plane_create_additional_planes(struct drm_device *drm)
         * modest number of planes to expose, that should hopefully
         * still cover any sane usecase.
         */
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 16; i++) {
                struct drm_plane *plane =
                        vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY);
 
index 324462cc9cd416191ce16a911aa390e21ec40ea3..be2c32a519b31d503d39ca722f44347dc449f35d 100644 (file)
 #define V3D_ERRSTAT  0x00f20
 
 #define PV_CONTROL                             0x00
+# define PV5_CONTROL_FIFO_LEVEL_HIGH_MASK      VC4_MASK(26, 25)
+# define PV5_CONTROL_FIFO_LEVEL_HIGH_SHIFT     25
 # define PV_CONTROL_FORMAT_MASK                        VC4_MASK(23, 21)
 # define PV_CONTROL_FORMAT_SHIFT               21
 # define PV_CONTROL_FORMAT_24                  0
 
 #define PV_HACT_ACT                            0x30
 
+#define PV_MUX_CFG                             0x34
+# define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_MASK    VC4_MASK(5, 2)
+# define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_SHIFT   2
+# define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP 8
+
 #define SCALER_CHANNELS_COUNT                  3
 
 #define SCALER_DISPCTRL                         0x00000000
 
 #define SCALER_DISPID                           0x00000008
 #define SCALER_DISPECTRL                        0x0000000c
+# define SCALER_DISPECTRL_DSP2_MUX_SHIFT       31
+# define SCALER_DISPECTRL_DSP2_MUX_MASK                VC4_MASK(31, 31)
+
 #define SCALER_DISPPROF                         0x00000010
+
 #define SCALER_DISPDITHER                       0x00000014
+# define SCALER_DISPDITHER_DSP5_MUX_SHIFT      30
+# define SCALER_DISPDITHER_DSP5_MUX_MASK       VC4_MASK(31, 30)
+
 #define SCALER_DISPEOLN                         0x00000018
+# define SCALER_DISPEOLN_DSP4_MUX_SHIFT                30
+# define SCALER_DISPEOLN_DSP4_MUX_MASK         VC4_MASK(31, 30)
+
 #define SCALER_DISPLIST0                        0x00000020
 #define SCALER_DISPLIST1                        0x00000024
 #define SCALER_DISPLIST2                        0x00000028
 # define SCALER_DISPCTRLX_HEIGHT_MASK          VC4_MASK(11, 0)
 # define SCALER_DISPCTRLX_HEIGHT_SHIFT         0
 
+# define SCALER5_DISPCTRLX_WIDTH_MASK          VC4_MASK(28, 16)
+# define SCALER5_DISPCTRLX_WIDTH_SHIFT         16
+/* Generates a single frame when VSTART is seen and stops at the last
+ * pixel read from the FIFO.
+ */
+# define SCALER5_DISPCTRLX_ONESHOT             BIT(15)
+/* Processes a single context in the dlist and then task switch,
+ * instead of an entire line.
+ */
+# define SCALER5_DISPCTRLX_ONECTX_MASK         VC4_MASK(14, 13)
+# define SCALER5_DISPCTRLX_ONECTX_SHIFT                13
+# define SCALER5_DISPCTRLX_HEIGHT_MASK         VC4_MASK(12, 0)
+# define SCALER5_DISPCTRLX_HEIGHT_SHIFT                0
+
 #define SCALER_DISPBKGND0                       0x00000044
 # define SCALER_DISPBKGND_AUTOHS               BIT(31)
 # define SCALER_DISPBKGND_INTERLACE            BIT(30)
 #define SCALER_DLIST_START                      0x00002000
 #define SCALER_DLIST_SIZE                       0x00004000
 
-#define VC4_HDMI_CORE_REV                      0x000
+#define SCALER5_DLIST_START                    0x00004000
 
-#define VC4_HDMI_SW_RESET_CONTROL              0x004
 # define VC4_HDMI_SW_RESET_FORMAT_DETECT       BIT(1)
 # define VC4_HDMI_SW_RESET_HDMI                        BIT(0)
 
-#define VC4_HDMI_HOTPLUG_INT                   0x008
-
-#define VC4_HDMI_HOTPLUG                       0x00c
 # define VC4_HDMI_HOTPLUG_CONNECTED            BIT(0)
 
-/* 3 bits per field, where each field maps from that corresponding MAI
- * bus channel to the given HDMI channel.
- */
-#define VC4_HDMI_MAI_CHANNEL_MAP               0x090
-
-#define VC4_HDMI_MAI_CONFIG                    0x094
 # define VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE            BIT(27)
 # define VC4_HDMI_MAI_CONFIG_BIT_REVERSE               BIT(26)
 # define VC4_HDMI_MAI_CHANNEL_MASK_MASK                        VC4_MASK(15, 0)
 # define VC4_HDMI_MAI_CHANNEL_MASK_SHIFT               0
 
-/* Last received format word on the MAI bus. */
-#define VC4_HDMI_MAI_FORMAT                    0x098
-
-#define VC4_HDMI_AUDIO_PACKET_CONFIG           0x09c
 # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT                BIT(29)
 # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS  BIT(24)
 # define VC4_HDMI_AUDIO_PACKET_FORCE_SAMPLE_PRESENT            BIT(19)
 # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK                   VC4_MASK(7, 0)
 # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT                  0
 
-#define VC4_HDMI_RAM_PACKET_CONFIG             0x0a0
 # define VC4_HDMI_RAM_PACKET_ENABLE            BIT(16)
 
-#define VC4_HDMI_RAM_PACKET_STATUS             0x0a4
-
-#define VC4_HDMI_CRP_CFG                       0x0a8
 /* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead
  * of pixel clock.
  */
 # define VC4_HDMI_CRP_CFG_N_MASK               VC4_MASK(19, 0)
 # define VC4_HDMI_CRP_CFG_N_SHIFT              0
 
-/* 20-bit fields containing CTS values to be transmitted if !EXTERNAL_CTS_EN */
-#define VC4_HDMI_CTS_0                         0x0ac
-#define VC4_HDMI_CTS_1                         0x0b0
-/* 20-bit fields containing number of clocks to send CTS0/1 before
- * switching to the other one.
- */
-#define VC4_HDMI_CTS_PERIOD_0                  0x0b4
-#define VC4_HDMI_CTS_PERIOD_1                  0x0b8
-
-#define VC4_HDMI_HORZA                         0x0c4
 # define VC4_HDMI_HORZA_VPOS                   BIT(14)
 # define VC4_HDMI_HORZA_HPOS                   BIT(13)
 /* Horizontal active pixels (hdisplay). */
 # define VC4_HDMI_HORZA_HAP_MASK               VC4_MASK(12, 0)
 # define VC4_HDMI_HORZA_HAP_SHIFT              0
 
-#define VC4_HDMI_HORZB                         0x0c8
 /* Horizontal pack porch (htotal - hsync_end). */
 # define VC4_HDMI_HORZB_HBP_MASK               VC4_MASK(29, 20)
 # define VC4_HDMI_HORZB_HBP_SHIFT              20
 # define VC4_HDMI_HORZB_HFP_MASK               VC4_MASK(9, 0)
 # define VC4_HDMI_HORZB_HFP_SHIFT              0
 
-#define VC4_HDMI_FIFO_CTL                      0x05c
 # define VC4_HDMI_FIFO_CTL_RECENTER_DONE       BIT(14)
 # define VC4_HDMI_FIFO_CTL_USE_EMPTY           BIT(13)
 # define VC4_HDMI_FIFO_CTL_ON_VB               BIT(7)
 # define VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N      BIT(0)
 # define VC4_HDMI_FIFO_VALID_WRITE_MASK                0xefff
 
-#define VC4_HDMI_SCHEDULER_CONTROL             0x0c0
 # define VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT BIT(15)
 # define VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS BIT(5)
 # define VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT        BIT(3)
 # define VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE        BIT(1)
 # define VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI  BIT(0)
 
-#define VC4_HDMI_VERTA0                                0x0cc
-#define VC4_HDMI_VERTA1                                0x0d4
 /* Vertical sync pulse (vsync_end - vsync_start). */
 # define VC4_HDMI_VERTA_VSP_MASK               VC4_MASK(24, 20)
 # define VC4_HDMI_VERTA_VSP_SHIFT              20
 # define VC4_HDMI_VERTA_VAL_MASK               VC4_MASK(12, 0)
 # define VC4_HDMI_VERTA_VAL_SHIFT              0
 
-#define VC4_HDMI_VERTB0                                0x0d0
-#define VC4_HDMI_VERTB1                                0x0d8
 /* Vertical sync pulse offset (for interlaced) */
 # define VC4_HDMI_VERTB_VSPO_MASK              VC4_MASK(21, 9)
 # define VC4_HDMI_VERTB_VSPO_SHIFT             9
 # define VC4_HDMI_VERTB_VBP_MASK               VC4_MASK(8, 0)
 # define VC4_HDMI_VERTB_VBP_SHIFT              0
 
-#define VC4_HDMI_CEC_CNTRL_1                   0x0e8
 /* Set when the transmission has ended. */
 # define VC4_HDMI_CEC_TX_EOM                   BIT(31)
 /* If set, transmission was acked on the 1st or 2nd attempt (only one
 /* Set these fields to how many bit clock cycles get to that many
  * microseconds.
  */
-#define VC4_HDMI_CEC_CNTRL_2                   0x0ec
 # define VC4_HDMI_CEC_CNT_TO_1500_US_MASK      VC4_MASK(30, 24)
 # define VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT     24
 # define VC4_HDMI_CEC_CNT_TO_1300_US_MASK      VC4_MASK(23, 17)
 # define VC4_HDMI_CEC_CNT_TO_400_US_MASK       VC4_MASK(4, 0)
 # define VC4_HDMI_CEC_CNT_TO_400_US_SHIFT      0
 
-#define VC4_HDMI_CEC_CNTRL_3                   0x0f0
 # define VC4_HDMI_CEC_CNT_TO_2750_US_MASK      VC4_MASK(31, 24)
 # define VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT     24
 # define VC4_HDMI_CEC_CNT_TO_2400_US_MASK      VC4_MASK(23, 16)
 # define VC4_HDMI_CEC_CNT_TO_1700_US_MASK      VC4_MASK(7, 0)
 # define VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT     0
 
-#define VC4_HDMI_CEC_CNTRL_4                   0x0f4
 # define VC4_HDMI_CEC_CNT_TO_4300_US_MASK      VC4_MASK(31, 24)
 # define VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT     24
 # define VC4_HDMI_CEC_CNT_TO_3900_US_MASK      VC4_MASK(23, 16)
 # define VC4_HDMI_CEC_CNT_TO_3500_US_MASK      VC4_MASK(7, 0)
 # define VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT     0
 
-#define VC4_HDMI_CEC_CNTRL_5                   0x0f8
 # define VC4_HDMI_CEC_TX_SW_RESET              BIT(27)
 # define VC4_HDMI_CEC_RX_SW_RESET              BIT(26)
 # define VC4_HDMI_CEC_PAD_SW_RESET             BIT(25)
 # define VC4_HDMI_CEC_CNT_TO_4500_US_MASK      VC4_MASK(7, 0)
 # define VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT     0
 
-/* Transmit data, first byte is low byte of the 32-bit reg.  MSB of
- * each byte transmitted first.
- */
-#define VC4_HDMI_CEC_TX_DATA_1                 0x0fc
-#define VC4_HDMI_CEC_TX_DATA_2                 0x100
-#define VC4_HDMI_CEC_TX_DATA_3                 0x104
-#define VC4_HDMI_CEC_TX_DATA_4                 0x108
-#define VC4_HDMI_CEC_RX_DATA_1                 0x10c
-#define VC4_HDMI_CEC_RX_DATA_2                 0x110
-#define VC4_HDMI_CEC_RX_DATA_3                 0x114
-#define VC4_HDMI_CEC_RX_DATA_4                 0x118
-
-#define VC4_HDMI_TX_PHY_RESET_CTL              0x2c0
-
-#define VC4_HDMI_TX_PHY_CTL0                   0x2c4
 # define VC4_HDMI_TX_PHY_RNG_PWRDN             BIT(25)
 
-/* Interrupt status bits */
-#define VC4_HDMI_CPU_STATUS                    0x340
-#define VC4_HDMI_CPU_SET                       0x344
-#define VC4_HDMI_CPU_CLEAR                     0x348
 # define VC4_HDMI_CPU_CEC                      BIT(6)
 # define VC4_HDMI_CPU_HOTPLUG                  BIT(0)
 
-#define VC4_HDMI_CPU_MASK_STATUS               0x34c
-#define VC4_HDMI_CPU_MASK_SET                  0x350
-#define VC4_HDMI_CPU_MASK_CLEAR                        0x354
-
-#define VC4_HDMI_GCP(x)                                (0x400 + ((x) * 0x4))
-#define VC4_HDMI_RAM_PACKET(x)                 (0x400 + ((x) * 0x24))
-#define VC4_HDMI_PACKET_STRIDE                 0x24
-
-#define VC4_HD_M_CTL                           0x00c
 /* Debug: Current receive value on the CEC pad. */
 # define VC4_HD_CECRXD                         BIT(9)
 /* Debug: Override CEC output to 0. */
 # define VC4_HD_M_SW_RST                       BIT(2)
 # define VC4_HD_M_ENABLE                       BIT(0)
 
-#define VC4_HD_MAI_CTL                         0x014
 /* Set when audio stream is received at a slower rate than the
  * sampling period, so MAI fifo goes empty.  Write 1 to clear.
  */
 /* Single-shot reset bit.  Read value is undefined. */
 # define VC4_HD_MAI_CTL_RESET                  BIT(0)
 
-#define VC4_HD_MAI_THR                         0x018
 # define VC4_HD_MAI_THR_PANICHIGH_MASK         VC4_MASK(29, 24)
 # define VC4_HD_MAI_THR_PANICHIGH_SHIFT                24
 # define VC4_HD_MAI_THR_PANICLOW_MASK          VC4_MASK(21, 16)
 # define VC4_HD_MAI_THR_DREQLOW_MASK           VC4_MASK(5, 0)
 # define VC4_HD_MAI_THR_DREQLOW_SHIFT          0
 
-/* Format header to be placed on the MAI data. Unused. */
-#define VC4_HD_MAI_FMT                         0x01c
-
-/* Register for DMAing in audio data to be transported over the MAI
- * bus to the Falcon core.
- */
-#define VC4_HD_MAI_DATA                                0x020
-
 /* Divider from HDMI HSM clock to MAI serial clock.  Sampling period
  * converges to N / (M + 1) cycles.
  */
-#define VC4_HD_MAI_SMP                         0x02c
 # define VC4_HD_MAI_SMP_N_MASK                 VC4_MASK(31, 8)
 # define VC4_HD_MAI_SMP_N_SHIFT                        8
 # define VC4_HD_MAI_SMP_M_MASK                 VC4_MASK(7, 0)
 # define VC4_HD_MAI_SMP_M_SHIFT                        0
 
-#define VC4_HD_VID_CTL                         0x038
 # define VC4_HD_VID_CTL_ENABLE                 BIT(31)
 # define VC4_HD_VID_CTL_UNDERFLOW_ENABLE       BIT(30)
 # define VC4_HD_VID_CTL_FRAME_COUNTER_RESET    BIT(29)
 # define VC4_HD_VID_CTL_VSYNC_LOW              BIT(28)
 # define VC4_HD_VID_CTL_HSYNC_LOW              BIT(27)
+# define VC4_HD_VID_CTL_CLRSYNC                        BIT(24)
+# define VC4_HD_VID_CTL_CLRRGB                 BIT(23)
+# define VC4_HD_VID_CTL_BLANKPIX               BIT(18)
 
-#define VC4_HD_CSC_CTL                         0x040
 # define VC4_HD_CSC_CTL_ORDER_MASK             VC4_MASK(7, 5)
 # define VC4_HD_CSC_CTL_ORDER_SHIFT            5
 # define VC4_HD_CSC_CTL_ORDER_RGB              0
 # define VC4_HD_CSC_CTL_RGB2YCC                        BIT(1)
 # define VC4_HD_CSC_CTL_ENABLE                 BIT(0)
 
-#define VC4_HD_CSC_12_11                       0x044
-#define VC4_HD_CSC_14_13                       0x048
-#define VC4_HD_CSC_22_21                       0x04c
-#define VC4_HD_CSC_24_23                       0x050
-#define VC4_HD_CSC_32_31                       0x054
-#define VC4_HD_CSC_34_33                       0x058
-
-#define VC4_HD_FRAME_COUNT                     0x068
+# define VC4_DVP_HT_CLOCK_STOP_PIXEL           BIT(1)
 
 /* HVS display list information. */
 #define HVS_BOOTLOADER_DLIST_END                32
@@ -825,6 +771,8 @@ enum hvs_pixel_format {
        HVS_PIXEL_FORMAT_PALETTE = 13,
        HVS_PIXEL_FORMAT_YUV444_RGB = 14,
        HVS_PIXEL_FORMAT_AYUV444_RGB = 15,
+       HVS_PIXEL_FORMAT_RGBA1010102 = 16,
+       HVS_PIXEL_FORMAT_YCBCR_10BIT = 17,
 };
 
 /* Note: the LSB is the rightmost character shown.  Only valid for
@@ -879,6 +827,10 @@ enum hvs_pixel_format {
 #define SCALER_CTL0_RGBA_EXPAND_MSB            2
 #define SCALER_CTL0_RGBA_EXPAND_ROUND          3
 
+#define SCALER5_CTL0_ALPHA_EXPAND              BIT(12)
+
+#define SCALER5_CTL0_RGB_EXPAND                        BIT(11)
+
 #define SCALER_CTL0_SCL1_MASK                  VC4_MASK(10, 8)
 #define SCALER_CTL0_SCL1_SHIFT                 8
 
@@ -896,10 +848,13 @@ enum hvs_pixel_format {
 
 /* Set to indicate no scaling. */
 #define SCALER_CTL0_UNITY                      BIT(4)
+#define SCALER5_CTL0_UNITY                     BIT(15)
 
 #define SCALER_CTL0_PIXEL_FORMAT_MASK          VC4_MASK(3, 0)
 #define SCALER_CTL0_PIXEL_FORMAT_SHIFT         0
 
+#define SCALER5_CTL0_PIXEL_FORMAT_MASK         VC4_MASK(4, 0)
+
 #define SCALER_POS0_FIXED_ALPHA_MASK           VC4_MASK(31, 24)
 #define SCALER_POS0_FIXED_ALPHA_SHIFT          24
 
@@ -909,12 +864,48 @@ enum hvs_pixel_format {
 #define SCALER_POS0_START_X_MASK               VC4_MASK(11, 0)
 #define SCALER_POS0_START_X_SHIFT              0
 
+#define SCALER5_POS0_START_Y_MASK              VC4_MASK(27, 16)
+#define SCALER5_POS0_START_Y_SHIFT             16
+
+#define SCALER5_POS0_START_X_MASK              VC4_MASK(13, 0)
+#define SCALER5_POS0_START_X_SHIFT             0
+
+#define SCALER5_POS0_VFLIP                     BIT(31)
+#define SCALER5_POS0_HFLIP                     BIT(15)
+
+#define SCALER5_CTL2_ALPHA_MODE_MASK           VC4_MASK(31, 30)
+#define SCALER5_CTL2_ALPHA_MODE_SHIFT          30
+#define SCALER5_CTL2_ALPHA_MODE_PIPELINE               0
+#define SCALER5_CTL2_ALPHA_MODE_FIXED          1
+#define SCALER5_CTL2_ALPHA_MODE_FIXED_NONZERO  2
+#define SCALER5_CTL2_ALPHA_MODE_FIXED_OVER_0x07        3
+
+#define SCALER5_CTL2_ALPHA_PREMULT             BIT(29)
+
+#define SCALER5_CTL2_ALPHA_MIX                 BIT(28)
+
+#define SCALER5_CTL2_ALPHA_LOC                 BIT(25)
+
+#define SCALER5_CTL2_MAP_SEL_MASK              VC4_MASK(18, 17)
+#define SCALER5_CTL2_MAP_SEL_SHIFT             17
+
+#define SCALER5_CTL2_GAMMA                     BIT(16)
+
+#define SCALER5_CTL2_ALPHA_MASK                        VC4_MASK(15, 4)
+#define SCALER5_CTL2_ALPHA_SHIFT               4
+
 #define SCALER_POS1_SCL_HEIGHT_MASK            VC4_MASK(27, 16)
 #define SCALER_POS1_SCL_HEIGHT_SHIFT           16
 
 #define SCALER_POS1_SCL_WIDTH_MASK             VC4_MASK(11, 0)
 #define SCALER_POS1_SCL_WIDTH_SHIFT            0
 
+#define SCALER5_POS1_SCL_HEIGHT_MASK           VC4_MASK(28, 16)
+#define SCALER5_POS1_SCL_HEIGHT_SHIFT          16
+
+#define SCALER5_POS1_SCL_WIDTH_MASK            VC4_MASK(12, 0)
+#define SCALER5_POS1_SCL_WIDTH_SHIFT           0
+
 #define SCALER_POS2_ALPHA_MODE_MASK            VC4_MASK(31, 30)
 #define SCALER_POS2_ALPHA_MODE_SHIFT           30
 #define SCALER_POS2_ALPHA_MODE_PIPELINE                0
@@ -930,6 +921,12 @@ enum hvs_pixel_format {
 #define SCALER_POS2_WIDTH_MASK                 VC4_MASK(11, 0)
 #define SCALER_POS2_WIDTH_SHIFT                        0
 
+#define SCALER5_POS2_HEIGHT_MASK               VC4_MASK(28, 16)
+#define SCALER5_POS2_HEIGHT_SHIFT              16
+
+#define SCALER5_POS2_WIDTH_MASK                        VC4_MASK(12, 0)
+#define SCALER5_POS2_WIDTH_SHIFT               0
+
 /* Color Space Conversion words.  Some values are S2.8 signed
  * integers, except that the 2 integer bits map as {0x0: 0, 0x1: 1,
  * 0x2: 2, 0x3: -1}
index a7c3af0005a0aa0908ff0c46a0d312b95eeb6a96..849dcafbfff17d127531595a43acef379b7dcc9b 100644 (file)
@@ -436,7 +436,6 @@ static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = {
        .atomic_flush   = vc4_hvs_atomic_flush,
        .atomic_enable  = vc4_txp_atomic_enable,
        .atomic_disable = vc4_txp_atomic_disable,
-       .mode_set_nofb  = vc4_hvs_mode_set_nofb,
 };
 
 static irqreturn_t vc4_txp_interrupt(int irq, void *data)
@@ -452,7 +451,8 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
 }
 
 static const struct vc4_crtc_data vc4_txp_crtc_data = {
-       .hvs_channel = 2,
+       .hvs_available_channels = BIT(2),
+       .hvs_output = 2,
 };
 
 static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
index 313339bbff90114e926e2c5152fe43f8f26b1be8..cb884c89006541d57d9408db4e5af1ece34e61e8 100644 (file)
@@ -321,7 +321,7 @@ static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj)
 {
        struct drm_vgem_gem_object *bo = to_vgem_bo(obj);
 
-       return drm_prime_pages_to_sg(bo->pages, bo->base.size >> PAGE_SHIFT);
+       return drm_prime_pages_to_sg(obj->dev, bo->pages, bo->base.size >> PAGE_SHIFT);
 }
 
 static struct drm_gem_object* vgem_prime_import(struct drm_device *dev,
@@ -401,16 +401,8 @@ static int vgem_prime_mmap(struct drm_gem_object *obj,
        return 0;
 }
 
-static void vgem_release(struct drm_device *dev)
-{
-       struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm);
-
-       platform_device_unregister(vgem->platform);
-}
-
 static struct drm_driver vgem_driver = {
        .driver_features                = DRIVER_GEM | DRIVER_RENDER,
-       .release                        = vgem_release,
        .open                           = vgem_open,
        .postclose                      = vgem_postclose,
        .gem_free_object_unlocked       = vgem_gem_free_object,
@@ -442,48 +434,49 @@ static struct drm_driver vgem_driver = {
 static int __init vgem_init(void)
 {
        int ret;
+       struct platform_device *pdev;
 
-       vgem_device = kzalloc(sizeof(*vgem_device), GFP_KERNEL);
-       if (!vgem_device)
-               return -ENOMEM;
+       pdev = platform_device_register_simple("vgem", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
 
-       vgem_device->platform =
-               platform_device_register_simple("vgem", -1, NULL, 0);
-       if (IS_ERR(vgem_device->platform)) {
-               ret = PTR_ERR(vgem_device->platform);
-               goto out_free;
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto out_unregister;
        }
 
-       dma_coerce_mask_and_coherent(&vgem_device->platform->dev,
+       dma_coerce_mask_and_coherent(&pdev->dev,
                                     DMA_BIT_MASK(64));
-       ret = drm_dev_init(&vgem_device->drm, &vgem_driver,
-                          &vgem_device->platform->dev);
-       if (ret)
-               goto out_unregister;
-       drmm_add_final_kfree(&vgem_device->drm, vgem_device);
+
+       vgem_device = devm_drm_dev_alloc(&pdev->dev, &vgem_driver,
+                                        struct vgem_device, drm);
+       if (IS_ERR(vgem_device)) {
+               ret = PTR_ERR(vgem_device);
+               goto out_devres;
+       }
+       vgem_device->platform = pdev;
 
        /* Final step: expose the device/driver to userspace */
        ret = drm_dev_register(&vgem_device->drm, 0);
        if (ret)
-               goto out_put;
+               goto out_devres;
 
        return 0;
 
-out_put:
-       drm_dev_put(&vgem_device->drm);
-       platform_device_unregister(vgem_device->platform);
-       return ret;
+out_devres:
+       devres_release_group(&pdev->dev, NULL);
 out_unregister:
-       platform_device_unregister(vgem_device->platform);
-out_free:
-       kfree(vgem_device);
+       platform_device_unregister(pdev);
        return ret;
 }
 
 static void __exit vgem_exit(void)
 {
+       struct platform_device *pdev = vgem_device->platform;
+
        drm_dev_unregister(&vgem_device->drm);
-       drm_dev_put(&vgem_device->drm);
+       devres_release_group(&pdev->dev, NULL);
+       platform_device_unregister(pdev);
 }
 
 module_init(vgem_init);
index 3221520f61f0cc2ecb3f8030532e64ce2564ff04..d5b0c543bd6d72b0fc55a3b873e227b1d8466f24 100644 (file)
@@ -48,6 +48,7 @@ static int virtio_gpu_features(struct seq_file *m, void *data)
        virtio_add_bool(m, "virgl", vgdev->has_virgl_3d);
        virtio_add_bool(m, "edid", vgdev->has_edid);
        virtio_add_bool(m, "indirect", vgdev->has_indirect);
+       virtio_add_bool(m, "resource uuid", vgdev->has_resource_assign_uuid);
        virtio_add_int(m, "cap sets", vgdev->num_capsets);
        virtio_add_int(m, "scanouts", vgdev->num_scanouts);
        return 0;
index 75d0dc2f6d2852ffe7a7e17b8b81fbd00b601bcb..06af537b0091d27814a5871bc22dbde292c9e50f 100644 (file)
@@ -80,8 +80,10 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev,
                                         vgdev->capsets[i].id > 0, 5 * HZ);
                if (ret == 0) {
                        DRM_ERROR("timed out waiting for cap set %d\n", i);
+                       spin_lock(&vgdev->display_info_lock);
                        kfree(vgdev->capsets);
                        vgdev->capsets = NULL;
+                       spin_unlock(&vgdev->display_info_lock);
                        return;
                }
                DRM_INFO("cap set %d: id %d, max-version %d, max-size %d\n",
@@ -103,7 +105,7 @@ int virtio_gpu_init(struct drm_device *dev)
        /* this will expand later */
        struct virtqueue *vqs[2];
        u32 num_scanouts, num_capsets;
-       int ret;
+       int ret = 0;
 
        if (!virtio_has_feature(dev_to_virtio(dev->dev), VIRTIO_F_VERSION_1))
                return -ENODEV;
index c93c2db35aaf318d601ee90f23ee42fbf82b647a..7436705ba5a229114cf6db72d0fbe003f31c9bc7 100644 (file)
@@ -684,9 +684,13 @@ static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
        int i = le32_to_cpu(cmd->capset_index);
 
        spin_lock(&vgdev->display_info_lock);
-       vgdev->capsets[i].id = le32_to_cpu(resp->capset_id);
-       vgdev->capsets[i].max_version = le32_to_cpu(resp->capset_max_version);
-       vgdev->capsets[i].max_size = le32_to_cpu(resp->capset_max_size);
+       if (vgdev->capsets) {
+               vgdev->capsets[i].id = le32_to_cpu(resp->capset_id);
+               vgdev->capsets[i].max_version = le32_to_cpu(resp->capset_max_version);
+               vgdev->capsets[i].max_size = le32_to_cpu(resp->capset_max_size);
+       } else {
+               DRM_ERROR("invalid capset memory.");
+       }
        spin_unlock(&vgdev->display_info_lock);
        wake_up(&vgdev->resp_wq);
 }
index 0b767d7efa24b2235ef1bc663fff51ddf065dd01..333d3cead0e38dd78192cfb676abb7f4dd471fec 100644 (file)
@@ -1,4 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
-vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o vkms_composer.o
+vkms-y := \
+       vkms_drv.o \
+       vkms_plane.o \
+       vkms_output.o \
+       vkms_crtc.o \
+       vkms_gem.o \
+       vkms_composer.o \
+       vkms_writeback.o
 
 obj-$(CONFIG_DRM_VKMS) += vkms.o
index eaecc5a6c5dba165b5839f26986892adc9141ab4..33c031f27c2c11848a54e3039f82339ca2fc393a 100644 (file)
@@ -9,31 +9,41 @@
 
 #include "vkms_drv.h"
 
+static u32 get_pixel_from_buffer(int x, int y, const u8 *buffer,
+                                const struct vkms_composer *composer)
+{
+       u32 pixel;
+       int src_offset = composer->offset + (y * composer->pitch)
+                                     + (x * composer->cpp);
+
+       pixel = *(u32 *)&buffer[src_offset];
+
+       return pixel;
+}
+
 /**
  * compute_crc - Compute CRC value on output frame
  *
- * @vaddr_out: address to final framebuffer
+ * @vaddr: address to final framebuffer
  * @composer: framebuffer's metadata
  *
  * returns CRC value computed using crc32 on the visible portion of
  * the final framebuffer at vaddr_out
  */
-static uint32_t compute_crc(void *vaddr_out, struct vkms_composer *composer)
+static uint32_t compute_crc(const u8 *vaddr,
+                           const struct vkms_composer *composer)
 {
-       int i, j, src_offset;
+       int x, y;
+       u32 crc = 0, pixel = 0;
        int x_src = composer->src.x1 >> 16;
        int y_src = composer->src.y1 >> 16;
        int h_src = drm_rect_height(&composer->src) >> 16;
        int w_src = drm_rect_width(&composer->src) >> 16;
-       u32 crc = 0;
-
-       for (i = y_src; i < y_src + h_src; ++i) {
-               for (j = x_src; j < x_src + w_src; ++j) {
-                       src_offset = composer->offset
-                                    + (i * composer->pitch)
-                                    + (j * composer->cpp);
-                       crc = crc32_le(crc, vaddr_out + src_offset,
-                                      sizeof(u32));
+
+       for (y = y_src; y < y_src + h_src; ++y) {
+               for (x = x_src; x < x_src + w_src; ++x) {
+                       pixel = get_pixel_from_buffer(x, y, vaddr, composer);
+                       crc = crc32_le(crc, (void *)&pixel, sizeof(u32));
                }
        }
 
@@ -131,35 +141,31 @@ static void compose_cursor(struct vkms_composer *cursor_composer,
              primary_composer, cursor_composer);
 }
 
-static uint32_t _vkms_get_crc(struct vkms_composer *primary_composer,
-                             struct vkms_composer *cursor_composer)
+static int compose_planes(void **vaddr_out,
+                         struct vkms_composer *primary_composer,
+                         struct vkms_composer *cursor_composer)
 {
        struct drm_framebuffer *fb = &primary_composer->fb;
        struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
        struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj);
-       void *vaddr_out = kzalloc(vkms_obj->gem.size, GFP_KERNEL);
-       u32 crc = 0;
 
-       if (!vaddr_out) {
-               DRM_ERROR("Failed to allocate memory for output frame.");
-               return 0;
+       if (!*vaddr_out) {
+               *vaddr_out = kzalloc(vkms_obj->gem.size, GFP_KERNEL);
+               if (!*vaddr_out) {
+                       DRM_ERROR("Cannot allocate memory for output frame.");
+                       return -ENOMEM;
+               }
        }
 
-       if (WARN_ON(!vkms_obj->vaddr)) {
-               kfree(vaddr_out);
-               return crc;
-       }
+       if (WARN_ON(!vkms_obj->vaddr))
+               return -EINVAL;
 
-       memcpy(vaddr_out, vkms_obj->vaddr, vkms_obj->gem.size);
+       memcpy(*vaddr_out, vkms_obj->vaddr, vkms_obj->gem.size);
 
        if (cursor_composer)
-               compose_cursor(cursor_composer, primary_composer, vaddr_out);
-
-       crc = compute_crc(vaddr_out, primary_composer);
-
-       kfree(vaddr_out);
+               compose_cursor(cursor_composer, primary_composer, *vaddr_out);
 
-       return crc;
+       return 0;
 }
 
 /**
@@ -180,14 +186,17 @@ void vkms_composer_worker(struct work_struct *work)
        struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
        struct vkms_composer *primary_composer = NULL;
        struct vkms_composer *cursor_composer = NULL;
+       bool crc_pending, wb_pending;
+       void *vaddr_out = NULL;
        u32 crc32 = 0;
        u64 frame_start, frame_end;
-       bool crc_pending;
+       int ret;
 
        spin_lock_irq(&out->composer_lock);
        frame_start = crtc_state->frame_start;
        frame_end = crtc_state->frame_end;
        crc_pending = crtc_state->crc_pending;
+       wb_pending = crtc_state->wb_pending;
        crtc_state->frame_start = 0;
        crtc_state->frame_end = 0;
        crtc_state->crc_pending = false;
@@ -206,8 +215,29 @@ void vkms_composer_worker(struct work_struct *work)
        if (crtc_state->num_active_planes == 2)
                cursor_composer = crtc_state->active_planes[1]->composer;
 
-       if (primary_composer)
-               crc32 = _vkms_get_crc(primary_composer, cursor_composer);
+       if (!primary_composer)
+               return;
+
+       if (wb_pending)
+               vaddr_out = crtc_state->active_writeback;
+
+       ret = compose_planes(&vaddr_out, primary_composer, cursor_composer);
+       if (ret) {
+               if (ret == -EINVAL && !wb_pending)
+                       kfree(vaddr_out);
+               return;
+       }
+
+       crc32 = compute_crc(vaddr_out, primary_composer);
+
+       if (wb_pending) {
+               drm_writeback_signal_completion(&out->wb_connector, 0);
+               spin_lock_irq(&out->composer_lock);
+               crtc_state->wb_pending = false;
+               spin_unlock_irq(&out->composer_lock);
+       } else {
+               kfree(vaddr_out);
+       }
 
        /*
         * The worker can fall behind the vblank hrtimer, make sure we catch up.
@@ -256,7 +286,7 @@ 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)
+void vkms_set_composer(struct vkms_output *out, bool enabled)
 {
        bool old_enabled;
 
index 83dd5567de8b562cd5567acee7e47010a77ac21a..cb0b6230c22cefbfbc1488fb839304ae4f7b260a 100644 (file)
@@ -61,9 +61,6 @@ static void vkms_release(struct drm_device *dev)
 {
        struct vkms_device *vkms = container_of(dev, struct vkms_device, drm);
 
-       platform_device_unregister(vkms->platform);
-       drm_atomic_helper_shutdown(&vkms->drm);
-       drm_mode_config_cleanup(&vkms->drm);
        destroy_workqueue(vkms->output.composer_workq);
 }
 
@@ -144,30 +141,31 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev)
 static int __init vkms_init(void)
 {
        int ret;
+       struct platform_device *pdev;
 
-       vkms_device = kzalloc(sizeof(*vkms_device), GFP_KERNEL);
-       if (!vkms_device)
-               return -ENOMEM;
+       pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
 
-       vkms_device->platform =
-               platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(vkms_device->platform)) {
-               ret = PTR_ERR(vkms_device->platform);
-               goto out_free;
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto out_unregister;
        }
 
-       ret = drm_dev_init(&vkms_device->drm, &vkms_driver,
-                          &vkms_device->platform->dev);
-       if (ret)
-               goto out_unregister;
-       drmm_add_final_kfree(&vkms_device->drm, vkms_device);
+       vkms_device = devm_drm_dev_alloc(&pdev->dev, &vkms_driver,
+                                        struct vkms_device, drm);
+       if (IS_ERR(vkms_device)) {
+               ret = PTR_ERR(vkms_device);
+               goto out_devres;
+       }
+       vkms_device->platform = pdev;
 
        ret = dma_coerce_mask_and_coherent(vkms_device->drm.dev,
                                           DMA_BIT_MASK(64));
 
        if (ret) {
                DRM_ERROR("Could not initialize DMA support\n");
-               goto out_put;
+               goto out_devres;
        }
 
        vkms_device->drm.irq_enabled = true;
@@ -175,39 +173,41 @@ static int __init vkms_init(void)
        ret = drm_vblank_init(&vkms_device->drm, 1);
        if (ret) {
                DRM_ERROR("Failed to vblank\n");
-               goto out_put;
+               goto out_devres;
        }
 
        ret = vkms_modeset_init(vkms_device);
        if (ret)
-               goto out_put;
+               goto out_devres;
 
        ret = drm_dev_register(&vkms_device->drm, 0);
        if (ret)
-               goto out_put;
+               goto out_devres;
 
        return 0;
 
-out_put:
-       drm_dev_put(&vkms_device->drm);
-       platform_device_unregister(vkms_device->platform);
-       return ret;
+out_devres:
+       devres_release_group(&pdev->dev, NULL);
 out_unregister:
-       platform_device_unregister(vkms_device->platform);
-out_free:
-       kfree(vkms_device);
+       platform_device_unregister(pdev);
        return ret;
 }
 
 static void __exit vkms_exit(void)
 {
+       struct platform_device *pdev;
+
        if (!vkms_device) {
                DRM_INFO("vkms_device is NULL.\n");
                return;
        }
 
+       pdev = vkms_device->platform;
+
        drm_dev_unregister(&vkms_device->drm);
-       drm_dev_put(&vkms_device->drm);
+       drm_atomic_helper_shutdown(&vkms_device->drm);
+       devres_release_group(&pdev->dev, NULL);
+       platform_device_unregister(pdev);
 }
 
 module_init(vkms_init);
index f4036bb0b9a89a51c05acdb1df2c0041af47a4ff..380a8f27e15603455530e3389c67ee6d36927f25 100644 (file)
@@ -8,6 +8,7 @@
 #include <drm/drm.h>
 #include <drm/drm_gem.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_writeback.h>
 
 #define XRES_MIN    20
 #define YRES_MIN    20
@@ -52,9 +53,11 @@ struct vkms_crtc_state {
        int num_active_planes;
        /* stack of active planes for crc computation, should be in z order */
        struct vkms_plane_state **active_planes;
+       void *active_writeback;
 
-       /* below three are protected by vkms_output.composer_lock */
+       /* below four are protected by vkms_output.composer_lock */
        bool crc_pending;
+       bool wb_pending;
        u64 frame_start;
        u64 frame_end;
 };
@@ -63,6 +66,7 @@ struct vkms_output {
        struct drm_crtc crtc;
        struct drm_encoder encoder;
        struct drm_connector connector;
+       struct drm_writeback_connector wb_connector;
        struct hrtimer vblank_hrtimer;
        ktime_t period_ns;
        struct drm_pending_vblank_event *event;
@@ -143,5 +147,9 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
 
 /* Composer Support */
 void vkms_composer_worker(struct work_struct *work);
+void vkms_set_composer(struct vkms_output *out, bool enabled);
+
+/* Writeback */
+int vkms_enable_writeback_connector(struct vkms_device *vkmsdev);
 
 #endif /* _VKMS_DRV_H_ */
index 85afb77e97f0e6a6d9bfd8ee985c29e1b1b845eb..4a1848b0318fb2ca2af2918d7e967dabe8fdda0b 100644 (file)
@@ -80,6 +80,10 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
                goto err_attach;
        }
 
+       ret = vkms_enable_writeback_connector(vkmsdev);
+       if (ret)
+               DRM_ERROR("Failed to init writeback connector\n");
+
        drm_mode_config_reset(dev);
 
        return 0;
diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c
new file mode 100644 (file)
index 0000000..094fa4a
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "vkms_drv.h"
+#include <drm/drm_fourcc.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+static const u32 vkms_wb_formats[] = {
+       DRM_FORMAT_XRGB8888,
+};
+
+static const struct drm_connector_funcs vkms_wb_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 vkms_wb_encoder_atomic_check(struct drm_encoder *encoder,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state)
+{
+       struct drm_framebuffer *fb;
+       const struct drm_display_mode *mode = &crtc_state->mode;
+
+       if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
+               return 0;
+
+       fb = conn_state->writeback_job->fb;
+       if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) {
+               DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n",
+                             fb->width, fb->height);
+               return -EINVAL;
+       }
+
+       if (fb->format->format != vkms_wb_formats[0]) {
+               struct drm_format_name_buf format_name;
+
+               DRM_DEBUG_KMS("Invalid pixel format %s\n",
+                             drm_get_format_name(fb->format->format,
+                                                 &format_name));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct drm_encoder_helper_funcs vkms_wb_encoder_helper_funcs = {
+       .atomic_check = vkms_wb_encoder_atomic_check,
+};
+
+static int vkms_wb_connector_get_modes(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+
+       return drm_add_modes_noedid(connector, dev->mode_config.max_width,
+                                   dev->mode_config.max_height);
+}
+
+static int vkms_wb_prepare_job(struct drm_writeback_connector *wb_connector,
+                              struct drm_writeback_job *job)
+{
+       struct vkms_gem_object *vkms_obj;
+       struct drm_gem_object *gem_obj;
+       int ret;
+
+       if (!job->fb)
+               return 0;
+
+       gem_obj = drm_gem_fb_get_obj(job->fb, 0);
+       ret = vkms_gem_vmap(gem_obj);
+       if (ret) {
+               DRM_ERROR("vmap failed: %d\n", ret);
+               return ret;
+       }
+
+       vkms_obj = drm_gem_to_vkms_gem(gem_obj);
+       job->priv = vkms_obj->vaddr;
+
+       return 0;
+}
+
+static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector,
+                               struct drm_writeback_job *job)
+{
+       struct drm_gem_object *gem_obj;
+       struct vkms_device *vkmsdev;
+
+       if (!job->fb)
+               return;
+
+       gem_obj = drm_gem_fb_get_obj(job->fb, 0);
+       vkms_gem_vunmap(gem_obj);
+
+       vkmsdev = drm_device_to_vkms_device(gem_obj->dev);
+       vkms_set_composer(&vkmsdev->output, false);
+}
+
+static void vkms_wb_atomic_commit(struct drm_connector *conn,
+                                 struct drm_connector_state *state)
+{
+       struct vkms_device *vkmsdev = drm_device_to_vkms_device(conn->dev);
+       struct vkms_output *output = &vkmsdev->output;
+       struct drm_writeback_connector *wb_conn = &output->wb_connector;
+       struct drm_connector_state *conn_state = wb_conn->base.state;
+       struct vkms_crtc_state *crtc_state = output->composer_state;
+
+       if (!conn_state)
+               return;
+
+       vkms_set_composer(&vkmsdev->output, true);
+
+       spin_lock_irq(&output->composer_lock);
+       crtc_state->active_writeback = conn_state->writeback_job->priv;
+       crtc_state->wb_pending = true;
+       spin_unlock_irq(&output->composer_lock);
+       drm_writeback_queue_job(wb_conn, state);
+}
+
+static const struct drm_connector_helper_funcs vkms_wb_conn_helper_funcs = {
+       .get_modes = vkms_wb_connector_get_modes,
+       .prepare_writeback_job = vkms_wb_prepare_job,
+       .cleanup_writeback_job = vkms_wb_cleanup_job,
+       .atomic_commit = vkms_wb_atomic_commit,
+};
+
+int vkms_enable_writeback_connector(struct vkms_device *vkmsdev)
+{
+       struct drm_writeback_connector *wb = &vkmsdev->output.wb_connector;
+
+       vkmsdev->output.wb_connector.encoder.possible_crtcs = 1;
+       drm_connector_helper_add(&wb->base, &vkms_wb_conn_helper_funcs);
+
+       return drm_writeback_connector_init(&vkmsdev->drm, wb,
+                                           &vkms_wb_connector_funcs,
+                                           &vkms_wb_encoder_helper_funcs,
+                                           vkms_wb_formats,
+                                           ARRAY_SIZE(vkms_wb_formats));
+}
index 1629427d5734a481be82330293eb735706c96132..0cd21590ded9e58eea521b8e4e1643e2f264e245 100644 (file)
@@ -465,13 +465,13 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst,
                dma_resv_assert_held(src->base.resv);
 
        if (dst->ttm->state == tt_unpopulated) {
-               ret = dst->ttm->bdev->driver->ttm_tt_populate(dst->ttm, &ctx);
+               ret = dst->bdev->driver->ttm_tt_populate(dst->bdev, dst->ttm, &ctx);
                if (ret)
                        return ret;
        }
 
        if (src->ttm->state == tt_unpopulated) {
-               ret = src->ttm->bdev->driver->ttm_tt_populate(src->ttm, &ctx);
+               ret = src->bdev->driver->ttm_tt_populate(src->bdev, src->ttm, &ctx);
                if (ret)
                        return ret;
        }
index 3229451d07062cdaf50e799db5cbe1e4de7578d3..813f1b14809415fa78eae62128677dc2832ca485 100644 (file)
@@ -354,10 +354,12 @@ void vmw_bo_pin_reserved(struct vmw_buffer_object *vbo, bool pin)
 
        pl.fpfn = 0;
        pl.lpfn = 0;
-       pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB
-               | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED;
+       pl.mem_type = bo->mem.mem_type;
+       pl.flags = bo->mem.placement;
        if (pin)
                pl.flags |= TTM_PL_FLAG_NO_EVICT;
+       else
+               pl.flags &= ~TTM_PL_FLAG_NO_EVICT;
 
        memset(&placement, 0, sizeof(placement));
        placement.num_placement = 1;
index 871ad738dadbdb90ba5a63f98c6455e343771cc3..1523b51a7284c03928195c67063db5ab96762f8d 100644 (file)
@@ -82,9 +82,7 @@
                        VMWGFX_NUM_GB_SCREEN_TARGET)
 
 #define VMW_PL_GMR (TTM_PL_PRIV + 0)
-#define VMW_PL_FLAG_GMR (TTM_PL_FLAG_PRIV << 0)
 #define VMW_PL_MOB (TTM_PL_PRIV + 1)
-#define VMW_PL_FLAG_MOB (TTM_PL_FLAG_PRIV << 1)
 
 #define VMW_RES_CONTEXT ttm_driver_type0
 #define VMW_RES_SURFACE ttm_driver_type1
index c7f10b2c93d22da2d41d31c243fb5ec22f10e088..03aa0fc5e753c0c27b3040e8eb00edc9e349e1ef 100644 (file)
 static const struct ttm_place vram_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+       .mem_type = TTM_PL_VRAM,
+       .flags = TTM_PL_FLAG_CACHED
 };
 
 static const struct ttm_place vram_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+       .mem_type = TTM_PL_VRAM,
+       .flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
 static const struct ttm_place sys_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED
+       .mem_type = TTM_PL_SYSTEM,
+       .flags = TTM_PL_FLAG_CACHED
 };
 
 static const struct ttm_place sys_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+       .mem_type = TTM_PL_SYSTEM,
+       .flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
 static const struct ttm_place gmr_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+       .mem_type = VMW_PL_GMR,
+       .flags = TTM_PL_FLAG_CACHED
 };
 
 static const struct ttm_place gmr_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+       .mem_type = VMW_PL_GMR,
+       .flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
 static const struct ttm_place mob_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
+       .mem_type = VMW_PL_MOB,
+       .flags = TTM_PL_FLAG_CACHED
 };
 
 static const struct ttm_place mob_ne_placement_flags = {
        .fpfn = 0,
        .lpfn = 0,
-       .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
+       .mem_type = VMW_PL_MOB,
+       .flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
 };
 
 struct ttm_placement vmw_vram_placement = {
@@ -89,11 +97,13 @@ static const struct ttm_place vram_gmr_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+               .mem_type = TTM_PL_VRAM,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+               .mem_type = VMW_PL_GMR,
+               .flags = TTM_PL_FLAG_CACHED
        }
 };
 
@@ -101,11 +111,13 @@ static const struct ttm_place gmr_vram_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+               .mem_type = VMW_PL_GMR,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+               .mem_type = TTM_PL_VRAM,
+               .flags = TTM_PL_FLAG_CACHED
        }
 };
 
@@ -120,12 +132,14 @@ static const struct ttm_place vram_gmr_ne_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED |
+               .mem_type = TTM_PL_VRAM,
+               .flags = TTM_PL_FLAG_CACHED |
                         TTM_PL_FLAG_NO_EVICT
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED |
+               .mem_type = VMW_PL_GMR,
+               .flags = TTM_PL_FLAG_CACHED |
                         TTM_PL_FLAG_NO_EVICT
        }
 };
@@ -169,19 +183,23 @@ static const struct ttm_place evictable_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED
+               .mem_type = TTM_PL_SYSTEM,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
+               .mem_type = TTM_PL_VRAM,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+               .mem_type = VMW_PL_GMR,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
+               .mem_type = VMW_PL_MOB,
+               .flags = TTM_PL_FLAG_CACHED
        }
 };
 
@@ -189,15 +207,18 @@ static const struct ttm_place nonfixed_placement_flags[] = {
        {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED
+               .mem_type = TTM_PL_SYSTEM,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+               .mem_type = VMW_PL_GMR,
+               .flags = TTM_PL_FLAG_CACHED
        }, {
                .fpfn = 0,
                .lpfn = 0,
-               .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
+               .mem_type = VMW_PL_MOB,
+               .flags = TTM_PL_FLAG_CACHED
        }
 };
 
@@ -539,7 +560,8 @@ 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_resource *bo_mem)
+static int vmw_ttm_bind(struct ttm_bo_device *bdev,
+                       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);
@@ -573,7 +595,8 @@ static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem)
        return 0;
 }
 
-static void vmw_ttm_unbind(struct ttm_tt *ttm)
+static void vmw_ttm_unbind(struct ttm_bo_device *bdev,
+                          struct ttm_tt *ttm)
 {
        struct vmw_ttm_tt *vmw_be =
                container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
@@ -594,7 +617,7 @@ static void vmw_ttm_unbind(struct ttm_tt *ttm)
 }
 
 
-static void vmw_ttm_destroy(struct ttm_tt *ttm)
+static void vmw_ttm_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
 {
        struct vmw_ttm_tt *vmw_be =
                container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
@@ -612,7 +635,8 @@ static void vmw_ttm_destroy(struct ttm_tt *ttm)
 }
 
 
-static int vmw_ttm_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
+static int vmw_ttm_populate(struct ttm_bo_device *bdev,
+                           struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
 {
        struct vmw_ttm_tt *vmw_tt =
                container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
@@ -640,7 +664,8 @@ static int vmw_ttm_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
        return ret;
 }
 
-static void vmw_ttm_unpopulate(struct ttm_tt *ttm)
+static void vmw_ttm_unpopulate(struct ttm_bo_device *bdev,
+                              struct ttm_tt *ttm)
 {
        struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
                                                 dma_ttm.ttm);
@@ -664,12 +689,6 @@ static void vmw_ttm_unpopulate(struct ttm_tt *ttm)
                ttm_pool_unpopulate(ttm);
 }
 
-static struct ttm_backend_func vmw_ttm_func = {
-       .bind = vmw_ttm_bind,
-       .unbind = vmw_ttm_unbind,
-       .destroy = vmw_ttm_destroy,
-};
-
 static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
                                        uint32_t page_flags)
 {
@@ -680,7 +699,6 @@ static struct ttm_tt *vmw_ttm_tt_create(struct ttm_buffer_object *bo,
        if (!vmw_be)
                return NULL;
 
-       vmw_be->dma_ttm.ttm.func = &vmw_ttm_func;
        vmw_be->dev_priv = container_of(bo->bdev, struct vmw_private, bdev);
        vmw_be->mob = NULL;
 
@@ -721,8 +739,8 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resourc
        case VMW_PL_MOB:
                return 0;
        case TTM_PL_VRAM:
-               mem->bus.offset = mem->start << PAGE_SHIFT;
-               mem->bus.base = dev_priv->vram_start;
+               mem->bus.offset = (mem->start << PAGE_SHIFT) +
+                       dev_priv->vram_start;
                mem->bus.is_iomem = true;
                break;
        default:
@@ -766,6 +784,9 @@ 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,
+       .ttm_tt_bind = &vmw_ttm_bind,
+       .ttm_tt_unbind = &vmw_ttm_unbind,
+       .ttm_tt_destroy = &vmw_ttm_destroy,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = vmw_evict_flags,
        .move = NULL,
@@ -796,7 +817,7 @@ int vmw_bo_create_and_populate(struct vmw_private *dev_priv,
 
        ret = ttm_bo_reserve(bo, false, true, NULL);
        BUG_ON(ret != 0);
-       ret = vmw_ttm_populate(bo->ttm, &ctx);
+       ret = vmw_ttm_populate(bo->bdev, bo->ttm, &ctx);
        if (likely(ret == 0)) {
                struct vmw_ttm_tt *vmw_tt =
                        container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
index 534daf37c97ed8bbb133b13f27a91908c83001bc..a8aefaa38bd360c3969212b93be11a8b072666ff 100644 (file)
@@ -180,7 +180,8 @@ struct sg_table *xen_drm_front_gem_get_sg_table(struct drm_gem_object *gem_obj)
        if (!xen_obj->pages)
                return ERR_PTR(-ENOMEM);
 
-       return drm_prime_pages_to_sg(xen_obj->pages, xen_obj->num_pages);
+       return drm_prime_pages_to_sg(gem_obj->dev,
+                                    xen_obj->pages, xen_obj->num_pages);
 }
 
 struct drm_gem_object *
index a455cfc1bee53ff0ba2b0c353c5538c28c7bd59f..98bd48f13fd11461953c397ad7db2a8142bd0cb9 100644 (file)
@@ -242,12 +242,6 @@ static const u32 scaling_factors_565[] = {
        ZYNQMP_DISP_AV_BUF_5BIT_SF,
 };
 
-static const u32 scaling_factors_666[] = {
-       ZYNQMP_DISP_AV_BUF_6BIT_SF,
-       ZYNQMP_DISP_AV_BUF_6BIT_SF,
-       ZYNQMP_DISP_AV_BUF_6BIT_SF,
-};
-
 static const u32 scaling_factors_888[] = {
        ZYNQMP_DISP_AV_BUF_8BIT_SF,
        ZYNQMP_DISP_AV_BUF_8BIT_SF,
index 26328c76305be1796cc496940b8a39237a037bd5..8e69303aad3f72cbf1d358f1277e277ad177864e 100644 (file)
@@ -111,7 +111,7 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
        /* Initialize mode config, vblank and the KMS poll helper. */
        ret = drmm_mode_config_init(drm);
        if (ret < 0)
-               goto err_dev_put;
+               return ret;
 
        drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs;
        drm->mode_config.min_width = 0;
@@ -121,7 +121,7 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
 
        ret = drm_vblank_init(drm, 1);
        if (ret)
-               goto err_dev_put;
+               return ret;
 
        drm->irq_enabled = 1;
 
@@ -154,8 +154,6 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
 
 err_poll_fini:
        drm_kms_helper_poll_fini(drm);
-err_dev_put:
-       drm_dev_put(drm);
        return ret;
 }
 
@@ -208,27 +206,16 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev)
        int ret;
 
        /* Allocate private data. */
-       dpsub = kzalloc(sizeof(*dpsub), GFP_KERNEL);
-       if (!dpsub)
-               return -ENOMEM;
+       dpsub = devm_drm_dev_alloc(&pdev->dev, &zynqmp_dpsub_drm_driver,
+                                  struct zynqmp_dpsub, drm);
+       if (IS_ERR(dpsub))
+               return PTR_ERR(dpsub);
 
        dpsub->dev = &pdev->dev;
        platform_set_drvdata(pdev, dpsub);
 
        dma_set_mask(dpsub->dev, DMA_BIT_MASK(ZYNQMP_DISP_MAX_DMA_BIT));
 
-       /*
-        * Initialize the DRM device early, as the DRM core mandates usage of
-        * the managed memory helpers tied to the DRM device.
-        */
-       ret = drm_dev_init(&dpsub->drm, &zynqmp_dpsub_drm_driver, &pdev->dev);
-       if (ret < 0) {
-               kfree(dpsub);
-               return ret;
-       }
-
-       drmm_add_final_kfree(&dpsub->drm, dpsub);
-
        /* Try the reserved memory. Proceed if there's none. */
        of_reserved_mem_device_init(&pdev->dev);
 
@@ -286,8 +273,6 @@ static int zynqmp_dpsub_remove(struct platform_device *pdev)
        clk_disable_unprepare(dpsub->apb_clk);
        of_reserved_mem_device_release(&pdev->dev);
 
-       drm_dev_put(drm);
-
        return 0;
 }
 
index b2c9dd4f0cb5eb77862572da7a863180d8fc2a53..e36578258b5bbcc235540b01542e14ad044b62cb 100644 (file)
@@ -1775,25 +1775,6 @@ config PXA3XX_GCU
 
          If you compile this as a module, it will be called pxa3xx_gcu.
 
-config FB_MBX
-       tristate "2700G LCD framebuffer support"
-       depends on FB && ARCH_PXA
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       help
-         Framebuffer driver for the Intel 2700G (Marathon) Graphics
-         Accelerator
-
-config FB_MBX_DEBUG
-       bool "Enable debugging info via debugfs"
-       depends on FB_MBX && DEBUG_FS
-       help
-         Enable this if you want debugging information using the debug
-         filesystem (debugfs)
-
-         If unsure, say N.
-
 config FB_FSL_DIU
        tristate "Freescale DIU framebuffer support"
        depends on FB && FSL_SOC
index cad4fb64442a185300124023aeef9fca0b980773..2ff8849ffde61892ccb3d2482db465b2c4ee4237 100644 (file)
@@ -31,7 +31,6 @@ obj-$(CONFIG_FB_VIA)            += via/
 obj-$(CONFIG_FB_KYRO)             += kyro/
 obj-$(CONFIG_FB_SAVAGE)                  += savage/
 obj-$(CONFIG_FB_GEODE)           += geode/
-obj-$(CONFIG_FB_MBX)             += mbx/
 obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
index 11ab9a15386081e8cb4cc8863bf4c746ce3bbac8..edf169d0816e6290f823729cad218642debb5b2b 100644 (file)
@@ -1085,12 +1085,11 @@ static void ark_pci_remove(struct pci_dev *dev)
 }
 
 
-#ifdef CONFIG_PM
 /* PCI suspend */
 
-static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
+static int __maybe_unused ark_pci_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct arkfb_info *par = info->par;
 
        dev_info(info->device, "suspend\n");
@@ -1098,7 +1097,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
        console_lock();
        mutex_lock(&(par->open_lock));
 
-       if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+       if (par->ref_count == 0) {
                mutex_unlock(&(par->open_lock));
                console_unlock();
                return 0;
@@ -1106,10 +1105,6 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
 
        fb_set_suspend(info, 1);
 
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-
        mutex_unlock(&(par->open_lock));
        console_unlock();
 
@@ -1119,9 +1114,9 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
 
 /* PCI resume */
 
-static int ark_pci_resume (struct pci_dev* dev)
+static int __maybe_unused ark_pci_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct arkfb_info *par = info->par;
 
        dev_info(info->device, "resume\n");
@@ -1132,14 +1127,6 @@ static int ark_pci_resume (struct pci_dev* dev)
        if (par->ref_count == 0)
                goto fail;
 
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-
-       if (pci_enable_device(dev))
-               goto fail;
-
-       pci_set_master(dev);
-
        arkfb_set_par(info);
        fb_set_suspend(info, 0);
 
@@ -1148,10 +1135,17 @@ fail:
        console_unlock();
        return 0;
 }
-#else
-#define ark_pci_suspend NULL
-#define ark_pci_resume NULL
-#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops ark_pci_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = ark_pci_suspend,
+       .resume         = ark_pci_resume,
+       .freeze         = NULL,
+       .thaw           = ark_pci_resume,
+       .poweroff       = ark_pci_suspend,
+       .restore        = ark_pci_resume,
+#endif
+};
 
 /* List of boards that we are trying to support */
 
@@ -1168,8 +1162,7 @@ static struct pci_driver arkfb_pci_driver = {
        .id_table       = ark_devices,
        .probe          = ark_pci_probe,
        .remove         = ark_pci_remove,
-       .suspend        = ark_pci_suspend,
-       .resume         = ark_pci_resume,
+       .driver.pm      = &ark_pci_pm_ops,
 };
 
 /* Cleanup */
index 6fae6ad6cb77b825658953626ceb04bee0d15f5d..e6a48689c2949395162b0b43e42fdec754f14415 100644 (file)
@@ -162,10 +162,22 @@ static char * const r128_family[] = {
 static int aty128_probe(struct pci_dev *pdev,
                                const struct pci_device_id *ent);
 static void aty128_remove(struct pci_dev *pdev);
-static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state);
-static int aty128_pci_resume(struct pci_dev *pdev);
+static int aty128_pci_suspend_late(struct device *dev, pm_message_t state);
+static int __maybe_unused aty128_pci_suspend(struct device *dev);
+static int __maybe_unused aty128_pci_hibernate(struct device *dev);
+static int __maybe_unused aty128_pci_freeze(struct device *dev);
+static int __maybe_unused aty128_pci_resume(struct device *dev);
 static int aty128_do_resume(struct pci_dev *pdev);
 
+static const struct dev_pm_ops aty128_pci_pm_ops = {
+       .suspend        = aty128_pci_suspend,
+       .resume         = aty128_pci_resume,
+       .freeze         = aty128_pci_freeze,
+       .thaw           = aty128_pci_resume,
+       .poweroff       = aty128_pci_hibernate,
+       .restore        = aty128_pci_resume,
+};
+
 /* supported Rage128 chipsets */
 static const struct pci_device_id aty128_pci_tbl[] = {
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
@@ -272,8 +284,7 @@ static struct pci_driver aty128fb_driver = {
        .id_table       = aty128_pci_tbl,
        .probe          = aty128_probe,
        .remove         = aty128_remove,
-       .suspend        = aty128_pci_suspend,
-       .resume         = aty128_pci_resume,
+       .driver.pm      = &aty128_pci_pm_ops,
 };
 
 /* packed BIOS settings */
@@ -2316,7 +2327,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
 {
        u32     pmgt;
-       struct pci_dev *pdev = par->pdev;
 
        if (!par->pdev->pm_cap)
                return;
@@ -2343,23 +2353,15 @@ static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
                aty_st_le32(BUS_CNTL1, 0x00000010);
                aty_st_le32(MEM_POWER_MISC, 0x0c830000);
                msleep(100);
-
-               /* Switch PCI power management to D2 */
-               pci_set_power_state(pdev, PCI_D2);
        }
 }
 
-static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int aty128_pci_suspend_late(struct device *dev, pm_message_t state)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct fb_info *info = pci_get_drvdata(pdev);
        struct aty128fb_par *par = info->par;
 
-       /* Because we may change PCI D state ourselves, we need to
-        * first save the config space content so the core can
-        * restore it properly on resume.
-        */
-       pci_save_state(pdev);
-
        /* We don't do anything but D2, for now we return 0, but
         * we may want to change that. How do we know if the BIOS
         * can properly take care of D3 ? Also, with swsusp, we
@@ -2418,6 +2420,21 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
+static int __maybe_unused aty128_pci_suspend(struct device *dev)
+{
+       return aty128_pci_suspend_late(dev, PMSG_SUSPEND);
+}
+
+static int __maybe_unused aty128_pci_hibernate(struct device *dev)
+{
+       return aty128_pci_suspend_late(dev, PMSG_HIBERNATE);
+}
+
+static int __maybe_unused aty128_pci_freeze(struct device *dev)
+{
+       return aty128_pci_suspend_late(dev, PMSG_FREEZE);
+}
+
 static int aty128_do_resume(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
@@ -2464,12 +2481,12 @@ static int aty128_do_resume(struct pci_dev *pdev)
        return 0;
 }
 
-static int aty128_pci_resume(struct pci_dev *pdev)
+static int __maybe_unused aty128_pci_resume(struct device *dev)
 {
        int rc;
 
        console_lock();
-       rc = aty128_do_resume(pdev);
+       rc = aty128_do_resume(to_pci_dev(dev));
        console_unlock();
 
        return rc;
index ad9cfe34c9ffac5bf70a682ca3966926160071a9..c8feff0ee8da99716013ad19fb22c587e7cf3167 100644 (file)
 #define PRINTKI(fmt, args...)  printk(KERN_INFO "atyfb: " fmt, ## args)
 #define PRINTKE(fmt, args...)  printk(KERN_ERR "atyfb: " fmt, ## args)
 
-#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \
-defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_FB_ATY_BACKLIGHT)
+#if defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_GENERIC_LCD) || \
+defined(CONFIG_FB_ATY_BACKLIGHT)
 static const u32 lt_lcd_regs[] = {
        CNFG_PANEL_LG,
        LCD_GEN_CNTL_LG,
@@ -175,7 +175,7 @@ u32 aty_ld_lcd(int index, const struct atyfb_par *par)
                return aty_ld_le32(LCD_DATA, par);
        }
 }
-#endif /* defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
+#endif /* defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
 
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 /*
@@ -1989,7 +1989,7 @@ static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 
 
 
-#if defined(CONFIG_PM) && defined(CONFIG_PCI)
+#if defined(CONFIG_PCI)
 
 #ifdef CONFIG_PPC_PMAC
 /* Power management routines. Those are used for PowerBook sleep.
@@ -2050,8 +2050,9 @@ static int aty_power_mgmt(int sleep, struct atyfb_par *par)
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int atyfb_pci_suspend_late(struct device *dev, pm_message_t state)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct fb_info *info = pci_get_drvdata(pdev);
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
@@ -2077,7 +2078,6 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
         * first save the config space content so the core can
         * restore it properly on resume.
         */
-       pci_save_state(pdev);
 
 #ifdef CONFIG_PPC_PMAC
        /* Set chip to "suspend" mode */
@@ -2089,8 +2089,6 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
                console_unlock();
                return -EIO;
        }
-#else
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
 #endif
 
        console_unlock();
@@ -2100,6 +2098,21 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
+static int __maybe_unused atyfb_pci_suspend(struct device *dev)
+{
+       return atyfb_pci_suspend_late(dev, PMSG_SUSPEND);
+}
+
+static int __maybe_unused atyfb_pci_hibernate(struct device *dev)
+{
+       return atyfb_pci_suspend_late(dev, PMSG_HIBERNATE);
+}
+
+static int __maybe_unused atyfb_pci_freeze(struct device *dev)
+{
+       return atyfb_pci_suspend_late(dev, PMSG_FREEZE);
+}
+
 static void aty_resume_chip(struct fb_info *info)
 {
        struct atyfb_par *par = info->par;
@@ -2114,8 +2127,9 @@ static void aty_resume_chip(struct fb_info *info)
                        aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
 }
 
-static int atyfb_pci_resume(struct pci_dev *pdev)
+static int __maybe_unused atyfb_pci_resume(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct fb_info *info = pci_get_drvdata(pdev);
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
@@ -2157,7 +2171,18 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
        return 0;
 }
 
-#endif /*  defined(CONFIG_PM) && defined(CONFIG_PCI) */
+static const struct dev_pm_ops atyfb_pci_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = atyfb_pci_suspend,
+       .resume         = atyfb_pci_resume,
+       .freeze         = atyfb_pci_freeze,
+       .thaw           = atyfb_pci_resume,
+       .poweroff       = atyfb_pci_hibernate,
+       .restore        = atyfb_pci_resume,
+#endif /* CONFIG_PM_SLEEP */
+};
+
+#endif /*  defined(CONFIG_PCI) */
 
 /* Backlight */
 #ifdef CONFIG_FB_ATY_BACKLIGHT
@@ -3796,10 +3821,7 @@ static struct pci_driver atyfb_driver = {
        .id_table       = atyfb_pci_tbl,
        .probe          = atyfb_pci_probe,
        .remove         = atyfb_pci_remove,
-#ifdef CONFIG_PM
-       .suspend        = atyfb_pci_suspend,
-       .resume         = atyfb_pci_resume,
-#endif /* CONFIG_PM */
+       .driver.pm      = &atyfb_pci_pm_ops,
 };
 
 #endif /* CONFIG_PCI */
index 3fe509cb9b874c90268b98fe385ee5859f9f92e9..2fe69015042064277cdef8919079abbec318ae22 100644 (file)
@@ -2307,7 +2307,7 @@ static int radeonfb_pci_register(struct pci_dev *pdev,
 
        ret = radeon_kick_out_firmware_fb(pdev);
        if (ret)
-               return ret;
+               goto err_release_fb;
 
        /* request the mem regions */
        ret = pci_request_region(pdev, 0, "radeonfb framebuffer");
@@ -2555,16 +2555,18 @@ static void radeonfb_pci_unregister(struct pci_dev *pdev)
         framebuffer_release(info);
 }
 
+#ifdef CONFIG_PM
+#define RADEONFB_PCI_PM_OPS (&radeonfb_pci_pm_ops)
+#else
+#define RADEONFB_PCI_PM_OPS NULL
+#endif
 
 static struct pci_driver radeonfb_driver = {
        .name           = "radeonfb",
        .id_table       = radeonfb_pci_table,
        .probe          = radeonfb_pci_register,
        .remove         = radeonfb_pci_unregister,
-#ifdef CONFIG_PM
-       .suspend        = radeonfb_pci_suspend,
-       .resume         = radeonfb_pci_resume,
-#endif /* CONFIG_PM */
+       .driver.pm      = RADEONFB_PCI_PM_OPS,
 };
 
 #ifndef MODULE
index f3d8123d7f363930586acc93039e87a9293ca3f3..b5fbd5329652865b573f85fa9b71f190490a6502 100644 (file)
@@ -1431,7 +1431,6 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
        mdelay( 15);
 }
 
-#if defined(CONFIG_PM)
 #if defined(CONFIG_X86) || defined(CONFIG_PPC_PMAC)
 static void radeon_pm_reset_pad_ctlr_strength(struct radeonfb_info *rinfo)
 {
@@ -2210,7 +2209,6 @@ static void radeon_reinitialize_M9P(struct radeonfb_info *rinfo)
        radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
 }
 #endif
-#endif
 
 #if 0 /* Not ready yet */
 static void radeon_reinitialize_QW(struct radeonfb_info *rinfo)
@@ -2613,8 +2611,9 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
        }
 }
 
-int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+static int radeonfb_pci_suspend_late(struct device *dev, pm_message_t mesg)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
 
@@ -2662,11 +2661,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
        pmac_suspend_agp_for_card(pdev);
 #endif /* CONFIG_PPC_PMAC */
 
-       /* It's unclear whether or when the generic code will do that, so let's
-        * do it ourselves. We save state before we do any power management
-        */
-       pci_save_state(pdev);
-
        /* If we support wakeup from poweroff, we save all regs we can including cfg
         * space
         */
@@ -2691,7 +2685,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
                        msleep(20);
                        OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON));
                }
-               pci_disable_device(pdev);
        }
        /* If we support D2, we go to it (should be fixed later with a flag forcing
         * D3 only for some laptops)
@@ -2707,6 +2700,21 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
        return 0;
 }
 
+static int radeonfb_pci_suspend(struct device *dev)
+{
+       return radeonfb_pci_suspend_late(dev, PMSG_SUSPEND);
+}
+
+static int radeonfb_pci_hibernate(struct device *dev)
+{
+       return radeonfb_pci_suspend_late(dev, PMSG_HIBERNATE);
+}
+
+static int radeonfb_pci_freeze(struct device *dev)
+{
+       return radeonfb_pci_suspend_late(dev, PMSG_FREEZE);
+}
+
 static int radeon_check_power_loss(struct radeonfb_info *rinfo)
 {
        return rinfo->save_regs[4] != INPLL(CLK_PIN_CNTL) ||
@@ -2714,8 +2722,9 @@ static int radeon_check_power_loss(struct radeonfb_info *rinfo)
               rinfo->save_regs[3] != INPLL(SCLK_CNTL);
 }
 
-int radeonfb_pci_resume(struct pci_dev *pdev)
+static int radeonfb_pci_resume(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
        int rc = 0;
@@ -2797,6 +2806,15 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
        return rc;
 }
 
+const struct dev_pm_ops radeonfb_pci_pm_ops = {
+       .suspend        = radeonfb_pci_suspend,
+       .resume         = radeonfb_pci_resume,
+       .freeze         = radeonfb_pci_freeze,
+       .thaw           = radeonfb_pci_resume,
+       .poweroff       = radeonfb_pci_hibernate,
+       .restore        = radeonfb_pci_resume,
+};
+
 #ifdef CONFIG_PPC__disabled
 static void radeonfb_early_resume(void *data)
 {
index 131b34dd65af61b2ee3e4dbbb3590d628b0d8799..93f403cbb41507963a34f293fbd564f3d5694fe8 100644 (file)
@@ -483,8 +483,7 @@ extern void radeon_delete_i2c_busses(struct radeonfb_info *rinfo);
 extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid);
 
 /* PM Functions */
-extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
-extern int radeonfb_pci_resume(struct pci_dev *pdev);
+extern const struct dev_pm_ops radeonfb_pci_pm_ops;
 extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep);
 extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
 
index cc69649dce95edd17de6e5944522c05dec62ee45..8268bbee8cae1132ac26470c156c77081eed25e4 100644 (file)
@@ -1006,6 +1006,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
                return 0;
        }
 
+       /* bitfill_aligned() assumes that it's at least 8x8 */
+       if (var->xres < 8 || var->yres < 8)
+               return -EINVAL;
+
        ret = info->fbops->fb_check_var(var, info);
 
        if (ret)
index 42d37bed518afdc4be2b7b0c9bda4a2b5a00f3a4..d45355b9a58ca3aae87833054fef2386d7a7da85 100644 (file)
@@ -1810,7 +1810,7 @@ static void cyberpro_pci_remove(struct pci_dev *dev)
        }
 }
 
-static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state)
+static int __maybe_unused cyberpro_pci_suspend(struct device *dev)
 {
        return 0;
 }
@@ -1818,9 +1818,9 @@ static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state)
 /*
  * Re-initialise the CyberPro hardware
  */
-static int cyberpro_pci_resume(struct pci_dev *dev)
+static int __maybe_unused cyberpro_pci_resume(struct device *dev)
 {
-       struct cfb_info *cfb = pci_get_drvdata(dev);
+       struct cfb_info *cfb = dev_get_drvdata(dev);
 
        if (cfb) {
                cyberpro_pci_enable_mmio(cfb);
@@ -1846,12 +1846,15 @@ static struct pci_device_id cyberpro_pci_table[] = {
 
 MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
 
+static SIMPLE_DEV_PM_OPS(cyberpro_pci_pm_ops,
+                        cyberpro_pci_suspend,
+                        cyberpro_pci_resume);
+
 static struct pci_driver cyberpro_driver = {
        .name           = "CyberPro",
        .probe          = cyberpro_pci_probe,
        .remove         = cyberpro_pci_remove,
-       .suspend        = cyberpro_pci_suspend,
-       .resume         = cyberpro_pci_resume,
+       .driver.pm      = &cyberpro_pci_pm_ops,
        .id_table       = cyberpro_pci_table
 };
 
index d2e9c5c8e29400ea457c71d1db8f998a46338844..792c111c21e4058a4af5e9ea10497994689c7a79 100644 (file)
@@ -21,7 +21,6 @@ struct gxfb_par {
        void __iomem *dc_regs;
        void __iomem *vid_regs;
        void __iomem *gp_regs;
-#ifdef CONFIG_PM
        int powered_down;
 
        /* register state, for power management functionality */
@@ -36,7 +35,6 @@ struct gxfb_par {
        uint64_t fp[FP_REG_COUNT];
 
        uint32_t pal[DC_PAL_COUNT];
-#endif
 };
 
 unsigned int gx_frame_buffer_size(void);
@@ -49,11 +47,8 @@ void gx_set_dclk_frequency(struct fb_info *info);
 void gx_configure_display(struct fb_info *info);
 int gx_blank_display(struct fb_info *info, int blank_mode);
 
-#ifdef CONFIG_PM
 int gx_powerdown(struct fb_info *info);
 int gx_powerup(struct fb_info *info);
-#endif
-
 
 /* Graphics Processor registers (table 6-23 from the data book) */
 enum gp_registers {
index d38a148d4746ff19d740f9cd1f0cd81851099778..44089b331f91db542467db2c6fc232f9eeb3e503 100644 (file)
@@ -322,17 +322,14 @@ static struct fb_info *gxfb_init_fbinfo(struct device *dev)
        return info;
 }
 
-#ifdef CONFIG_PM
-static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused gxfb_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(pdev);
+       struct fb_info *info = dev_get_drvdata(dev);
 
-       if (state.event == PM_EVENT_SUSPEND) {
-               console_lock();
-               gx_powerdown(info);
-               fb_set_suspend(info, 1);
-               console_unlock();
-       }
+       console_lock();
+       gx_powerdown(info);
+       fb_set_suspend(info, 1);
+       console_unlock();
 
        /* there's no point in setting PCI states; we emulate PCI, so
         * we don't end up getting power savings anyways */
@@ -340,9 +337,9 @@ static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int gxfb_resume(struct pci_dev *pdev)
+static int __maybe_unused gxfb_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(pdev);
+       struct fb_info *info = dev_get_drvdata(dev);
        int ret;
 
        console_lock();
@@ -356,7 +353,6 @@ static int gxfb_resume(struct pci_dev *pdev)
        console_unlock();
        return 0;
 }
-#endif
 
 static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -467,15 +463,23 @@ static const struct pci_device_id gxfb_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, gxfb_id_table);
 
+static const struct dev_pm_ops gxfb_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = gxfb_suspend,
+       .resume         = gxfb_resume,
+       .freeze         = NULL,
+       .thaw           = gxfb_resume,
+       .poweroff       = NULL,
+       .restore        = gxfb_resume,
+#endif
+};
+
 static struct pci_driver gxfb_driver = {
        .name           = "gxfb",
        .id_table       = gxfb_id_table,
        .probe          = gxfb_probe,
        .remove         = gxfb_remove,
-#ifdef CONFIG_PM
-       .suspend        = gxfb_suspend,
-       .resume         = gxfb_resume,
-#endif
+       .driver.pm      = &gxfb_pm_ops,
 };
 
 #ifndef MODULE
index ef24bf6d49dc9bf2886b165957c8e7a39135084e..d37b32dbcd686f06954cbad8d37c097f2094ea79 100644 (file)
@@ -29,7 +29,6 @@ struct lxfb_par {
        void __iomem *gp_regs;
        void __iomem *dc_regs;
        void __iomem *vp_regs;
-#ifdef CONFIG_PM
        int powered_down;
 
        /* register state, for power mgmt functionality */
@@ -50,7 +49,6 @@ struct lxfb_par {
        uint32_t hcoeff[DC_HFILT_COUNT * 2];
        uint32_t vcoeff[DC_VFILT_COUNT];
        uint32_t vp_coeff[VP_COEFF_SIZE / 4];
-#endif
 };
 
 static inline unsigned int lx_get_pitch(unsigned int xres, int bpp)
@@ -64,11 +62,8 @@ int lx_blank_display(struct fb_info *, int);
 void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
                        unsigned int, unsigned int);
 
-#ifdef CONFIG_PM
 int lx_powerdown(struct fb_info *info);
 int lx_powerup(struct fb_info *info);
-#endif
-
 
 /* Graphics Processor registers (table 6-29 from the data book) */
 enum gp_registers {
index adc2d9c2395e307affb849ea889b7c05a18ff33a..66c81262d18f873645810dc28dd52efa12314b47 100644 (file)
@@ -443,17 +443,14 @@ static struct fb_info *lxfb_init_fbinfo(struct device *dev)
        return info;
 }
 
-#ifdef CONFIG_PM
-static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused lxfb_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(pdev);
+       struct fb_info *info = dev_get_drvdata(dev);
 
-       if (state.event == PM_EVENT_SUSPEND) {
-               console_lock();
-               lx_powerdown(info);
-               fb_set_suspend(info, 1);
-               console_unlock();
-       }
+       console_lock();
+       lx_powerdown(info);
+       fb_set_suspend(info, 1);
+       console_unlock();
 
        /* there's no point in setting PCI states; we emulate PCI, so
         * we don't end up getting power savings anyways */
@@ -461,9 +458,9 @@ static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int lxfb_resume(struct pci_dev *pdev)
+static int __maybe_unused lxfb_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(pdev);
+       struct fb_info *info = dev_get_drvdata(dev);
        int ret;
 
        console_lock();
@@ -477,10 +474,6 @@ static int lxfb_resume(struct pci_dev *pdev)
        console_unlock();
        return 0;
 }
-#else
-#define lxfb_suspend NULL
-#define lxfb_resume NULL
-#endif
 
 static int lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -600,13 +593,23 @@ static struct pci_device_id lxfb_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, lxfb_id_table);
 
+static const struct dev_pm_ops lxfb_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = lxfb_suspend,
+       .resume         = lxfb_resume,
+       .freeze         = NULL,
+       .thaw           = lxfb_resume,
+       .poweroff       = NULL,
+       .restore        = lxfb_resume,
+#endif
+};
+
 static struct pci_driver lxfb_driver = {
        .name           = "lxfb",
        .id_table       = lxfb_id_table,
        .probe          = lxfb_probe,
        .remove         = lxfb_remove,
-       .suspend        = lxfb_suspend,
-       .resume         = lxfb_resume,
+       .driver.pm      = &lxfb_pm_ops,
 };
 
 #ifndef MODULE
index 5be8bc62844c2a397299bf9421b52950f000380b..b3a041fce570d93fc519e5a00c3728753de8ba23 100644 (file)
@@ -580,8 +580,6 @@ int lx_blank_display(struct fb_info *info, int blank_mode)
        return 0;
 }
 
-#ifdef CONFIG_PM
-
 static void lx_save_regs(struct lxfb_par *par)
 {
        uint32_t filt;
@@ -837,5 +835,3 @@ int lx_powerup(struct fb_info *info)
        par->powered_down = 0;
        return 0;
 }
-
-#endif
index 1110a527c35c5132ff98f0e8bbab28f7eccdd47b..8c49d4e98772253b6602ea295b8804369251c147 100644 (file)
@@ -11,8 +11,6 @@
 
 #include "gxfb.h"
 
-#ifdef CONFIG_PM
-
 static void gx_save_regs(struct gxfb_par *par)
 {
        int i;
@@ -259,5 +257,3 @@ int gx_powerup(struct fb_info *info)
        par->powered_down  = 0;
        return 0;
 }
-
-#endif
index e6f35f8feefcb529f54204c3800b58018705afc1..52cce0db8bd344a87d01ed0d9433916e955d9555 100644 (file)
@@ -1175,16 +1175,11 @@ static void i740fb_remove(struct pci_dev *dev)
        }
 }
 
-#ifdef CONFIG_PM
-static int i740fb_suspend(struct pci_dev *dev, pm_message_t state)
+static int __maybe_unused i740fb_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct i740fb_par *par = info->par;
 
-       /* don't disable console during hibernation and wakeup from it */
-       if (state.event == PM_EVENT_FREEZE || state.event == PM_EVENT_PRETHAW)
-               return 0;
-
        console_lock();
        mutex_lock(&(par->open_lock));
 
@@ -1197,19 +1192,15 @@ static int i740fb_suspend(struct pci_dev *dev, pm_message_t state)
 
        fb_set_suspend(info, 1);
 
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-
        mutex_unlock(&(par->open_lock));
        console_unlock();
 
        return 0;
 }
 
-static int i740fb_resume(struct pci_dev *dev)
+static int __maybe_unused i740fb_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct i740fb_par *par = info->par;
 
        console_lock();
@@ -1218,11 +1209,6 @@ static int i740fb_resume(struct pci_dev *dev)
        if (par->ref_count == 0)
                goto fail;
 
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-       if (pci_enable_device(dev))
-               goto fail;
-
        i740fb_set_par(info);
        fb_set_suspend(info, 0);
 
@@ -1231,10 +1217,17 @@ fail:
        console_unlock();
        return 0;
 }
-#else
-#define i740fb_suspend NULL
-#define i740fb_resume NULL
-#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops i740fb_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = i740fb_suspend,
+       .resume         = i740fb_resume,
+       .freeze         = NULL,
+       .thaw           = i740fb_resume,
+       .poweroff       = i740fb_suspend,
+       .restore        = i740fb_resume,
+#endif /* CONFIG_PM_SLEEP */
+};
 
 #define I740_ID_PCI 0x00d1
 #define I740_ID_AGP 0x7800
@@ -1251,8 +1244,7 @@ static struct pci_driver i740fb_driver = {
        .id_table       = i740fb_id_table,
        .probe          = i740fb_probe,
        .remove         = i740fb_remove,
-       .suspend        = i740fb_suspend,
-       .resume         = i740fb_resume,
+       .driver.pm      = &i740fb_pm_ops,
 };
 
 #ifndef MODULE
index 1d3f2080aa6f4ab8ba8eb1fda6bcfc0fae1317f5..21875d3c2dc207e143286b78052215672514cb2f 100644 (file)
@@ -120,7 +120,7 @@ u32 ProgramClock(u32 refClock,
 {
        u32 R = 0, F = 0, OD = 0, ODIndex = 0;
        u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0;
-       u32 ulBestVCO = 0, ulBestClk = 0, ulBestScore = 0;
+       u32 ulBestClk = 0, ulBestScore = 0;
        u32 ulScore, ulPhaseScore, ulVcoScore;
        u32 ulTmp = 0, ulVCO;
        u32 ulScaleClockReq, ulMinClock, ulMaxClock;
@@ -189,7 +189,6 @@ u32 ProgramClock(u32 refClock,
                                                ulScore = ulPhaseScore + ulVcoScore;
 
                                                if (!ulBestScore) {
-                                                       ulBestVCO = ulVCO;
                                                        ulBestOD = OD;
                                                        ulBestF = F;
                                                        ulBestR = R;
@@ -206,7 +205,6 @@ u32 ProgramClock(u32 refClock,
                           but we shall keep this code in case new restrictions come into play
                           --------------------------------------------------------------------------*/
                                                if ((ulScore >= ulBestScore) && (OD > 0)) {
-                                                       ulBestVCO = ulVCO;
                                                        ulBestOD = OD;
                                                        ulBestF = F;
                                                        ulBestR = R;
@@ -244,7 +242,6 @@ int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
 {
        u32 F, R, P;
        u16 core_pll = 0, sub;
-       u32 ulCoreClock;
        u32 tmp;
        u32 ulChipSpeed;
 
@@ -282,7 +279,7 @@ int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
        if (ulChipSpeed == 0)
                return -EINVAL;
 
-       ulCoreClock = ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P);
+       ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P);
 
        core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11));
 
diff --git a/drivers/video/fbdev/mbx/Makefile b/drivers/video/fbdev/mbx/Makefile
deleted file mode 100644 (file)
index 3e8e7ff..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-# Makefile for the 2700G controller driver.
-
-obj-y                  += mbxfb.o
diff --git a/drivers/video/fbdev/mbx/mbxdebugfs.c b/drivers/video/fbdev/mbx/mbxdebugfs.c
deleted file mode 100644 (file)
index 09af721..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-
-#define BIG_BUFFER_SIZE        (1024)
-
-static char big_buffer[BIG_BUFFER_SIZE];
-
-struct mbxfb_debugfs_data {
-       struct dentry *dir;
-       struct dentry *sysconf;
-       struct dentry *clock;
-       struct dentry *display;
-       struct dentry *gsctl;
-       struct dentry *sdram;
-       struct dentry *misc;
-};
-
-static ssize_t write_file_dummy(struct file *file, const char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       return count;
-}
-
-static ssize_t sysconf_read_file(struct file *file, char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       char * s = big_buffer;
-
-       s += sprintf(s, "SYSCFG = %08x\n", readl(SYSCFG));
-       s += sprintf(s, "PFBASE = %08x\n", readl(PFBASE));
-       s += sprintf(s, "PFCEIL = %08x\n", readl(PFCEIL));
-       s += sprintf(s, "POLLFLAG = %08x\n", readl(POLLFLAG));
-       s += sprintf(s, "SYSRST = %08x\n", readl(SYSRST));
-
-       return  simple_read_from_buffer(userbuf, count, ppos,
-                                       big_buffer, s-big_buffer);
-}
-
-
-static ssize_t gsctl_read_file(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       char * s = big_buffer;
-
-       s += sprintf(s, "GSCTRL = %08x\n", readl(GSCTRL));
-       s += sprintf(s, "VSCTRL = %08x\n", readl(VSCTRL));
-       s += sprintf(s, "GBBASE = %08x\n", readl(GBBASE));
-       s += sprintf(s, "VBBASE = %08x\n", readl(VBBASE));
-       s += sprintf(s, "GDRCTRL = %08x\n", readl(GDRCTRL));
-       s += sprintf(s, "VCMSK = %08x\n", readl(VCMSK));
-       s += sprintf(s, "GSCADR = %08x\n", readl(GSCADR));
-       s += sprintf(s, "VSCADR = %08x\n", readl(VSCADR));
-       s += sprintf(s, "VUBASE = %08x\n", readl(VUBASE));
-       s += sprintf(s, "VVBASE = %08x\n", readl(VVBASE));
-       s += sprintf(s, "GSADR = %08x\n", readl(GSADR));
-       s += sprintf(s, "VSADR = %08x\n", readl(VSADR));
-       s += sprintf(s, "HCCTRL = %08x\n", readl(HCCTRL));
-       s += sprintf(s, "HCSIZE = %08x\n", readl(HCSIZE));
-       s += sprintf(s, "HCPOS = %08x\n", readl(HCPOS));
-       s += sprintf(s, "HCBADR = %08x\n", readl(HCBADR));
-       s += sprintf(s, "HCCKMSK = %08x\n", readl(HCCKMSK));
-       s += sprintf(s, "GPLUT = %08x\n", readl(GPLUT));
-
-       return  simple_read_from_buffer(userbuf, count, ppos,
-                                       big_buffer, s-big_buffer);
-}
-
-static ssize_t display_read_file(struct file *file, char __user *userbuf,
-                                size_t count, loff_t *ppos)
-{
-       char * s = big_buffer;
-
-       s += sprintf(s, "DSCTRL = %08x\n", readl(DSCTRL));
-       s += sprintf(s, "DHT01 = %08x\n", readl(DHT01));
-       s += sprintf(s, "DHT02 = %08x\n", readl(DHT02));
-       s += sprintf(s, "DHT03 = %08x\n", readl(DHT03));
-       s += sprintf(s, "DVT01 = %08x\n", readl(DVT01));
-       s += sprintf(s, "DVT02 = %08x\n", readl(DVT02));
-       s += sprintf(s, "DVT03 = %08x\n", readl(DVT03));
-       s += sprintf(s, "DBCOL = %08x\n", readl(DBCOL));
-       s += sprintf(s, "BGCOLOR = %08x\n", readl(BGCOLOR));
-       s += sprintf(s, "DINTRS = %08x\n", readl(DINTRS));
-       s += sprintf(s, "DINTRE = %08x\n", readl(DINTRE));
-       s += sprintf(s, "DINTRCNT = %08x\n", readl(DINTRCNT));
-       s += sprintf(s, "DSIG = %08x\n", readl(DSIG));
-       s += sprintf(s, "DMCTRL = %08x\n", readl(DMCTRL));
-       s += sprintf(s, "CLIPCTRL = %08x\n", readl(CLIPCTRL));
-       s += sprintf(s, "SPOCTRL = %08x\n", readl(SPOCTRL));
-       s += sprintf(s, "SVCTRL = %08x\n", readl(SVCTRL));
-       s += sprintf(s, "DLSTS = %08x\n", readl(DLSTS));
-       s += sprintf(s, "DLLCTRL = %08x\n", readl(DLLCTRL));
-       s += sprintf(s, "DVLNUM = %08x\n", readl(DVLNUM));
-       s += sprintf(s, "DUCTRL = %08x\n", readl(DUCTRL));
-       s += sprintf(s, "DVECTRL = %08x\n", readl(DVECTRL));
-       s += sprintf(s, "DHDET = %08x\n", readl(DHDET));
-       s += sprintf(s, "DVDET = %08x\n", readl(DVDET));
-       s += sprintf(s, "DODMSK = %08x\n", readl(DODMSK));
-       s += sprintf(s, "CSC01 = %08x\n", readl(CSC01));
-       s += sprintf(s, "CSC02 = %08x\n", readl(CSC02));
-       s += sprintf(s, "CSC03 = %08x\n", readl(CSC03));
-       s += sprintf(s, "CSC04 = %08x\n", readl(CSC04));
-       s += sprintf(s, "CSC05 = %08x\n", readl(CSC05));
-
-       return  simple_read_from_buffer(userbuf, count, ppos,
-                                       big_buffer, s-big_buffer);
-}
-
-static ssize_t clock_read_file(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       char * s = big_buffer;
-
-       s += sprintf(s, "SYSCLKSRC = %08x\n", readl(SYSCLKSRC));
-       s += sprintf(s, "PIXCLKSRC = %08x\n", readl(PIXCLKSRC));
-       s += sprintf(s, "CLKSLEEP = %08x\n", readl(CLKSLEEP));
-       s += sprintf(s, "COREPLL = %08x\n", readl(COREPLL));
-       s += sprintf(s, "DISPPLL = %08x\n", readl(DISPPLL));
-       s += sprintf(s, "PLLSTAT = %08x\n", readl(PLLSTAT));
-       s += sprintf(s, "VOVRCLK = %08x\n", readl(VOVRCLK));
-       s += sprintf(s, "PIXCLK = %08x\n", readl(PIXCLK));
-       s += sprintf(s, "MEMCLK = %08x\n", readl(MEMCLK));
-       s += sprintf(s, "M24CLK = %08x\n", readl(M24CLK));
-       s += sprintf(s, "MBXCLK = %08x\n", readl(MBXCLK));
-       s += sprintf(s, "SDCLK = %08x\n", readl(SDCLK));
-       s += sprintf(s, "PIXCLKDIV = %08x\n", readl(PIXCLKDIV));
-
-       return  simple_read_from_buffer(userbuf, count, ppos,
-                                       big_buffer, s-big_buffer);
-}
-
-static ssize_t sdram_read_file(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       char * s = big_buffer;
-
-       s += sprintf(s, "LMRST = %08x\n", readl(LMRST));
-       s += sprintf(s, "LMCFG = %08x\n", readl(LMCFG));
-       s += sprintf(s, "LMPWR = %08x\n", readl(LMPWR));
-       s += sprintf(s, "LMPWRSTAT = %08x\n", readl(LMPWRSTAT));
-       s += sprintf(s, "LMCEMR = %08x\n", readl(LMCEMR));
-       s += sprintf(s, "LMTYPE = %08x\n", readl(LMTYPE));
-       s += sprintf(s, "LMTIM = %08x\n", readl(LMTIM));
-       s += sprintf(s, "LMREFRESH = %08x\n", readl(LMREFRESH));
-       s += sprintf(s, "LMPROTMIN = %08x\n", readl(LMPROTMIN));
-       s += sprintf(s, "LMPROTMAX = %08x\n", readl(LMPROTMAX));
-       s += sprintf(s, "LMPROTCFG = %08x\n", readl(LMPROTCFG));
-       s += sprintf(s, "LMPROTERR = %08x\n", readl(LMPROTERR));
-
-       return  simple_read_from_buffer(userbuf, count, ppos,
-                                       big_buffer, s-big_buffer);
-}
-
-static ssize_t misc_read_file(struct file *file, char __user *userbuf,
-                              size_t count, loff_t *ppos)
-{
-       char * s = big_buffer;
-
-       s += sprintf(s, "LCD_CONFIG = %08x\n", readl(LCD_CONFIG));
-       s += sprintf(s, "ODFBPWR = %08x\n", readl(ODFBPWR));
-       s += sprintf(s, "ODFBSTAT = %08x\n", readl(ODFBSTAT));
-       s += sprintf(s, "ID = %08x\n", readl(ID));
-
-       return  simple_read_from_buffer(userbuf, count, ppos,
-                                       big_buffer, s-big_buffer);
-}
-
-
-static const struct file_operations sysconf_fops = {
-       .read = sysconf_read_file,
-       .write = write_file_dummy,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static const struct file_operations clock_fops = {
-       .read = clock_read_file,
-       .write = write_file_dummy,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static const struct file_operations display_fops = {
-       .read = display_read_file,
-       .write = write_file_dummy,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static const struct file_operations gsctl_fops = {
-       .read = gsctl_read_file,
-       .write = write_file_dummy,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static const struct file_operations sdram_fops = {
-       .read = sdram_read_file,
-       .write = write_file_dummy,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static const struct file_operations misc_fops = {
-       .read = misc_read_file,
-       .write = write_file_dummy,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static void mbxfb_debugfs_init(struct fb_info *fbi)
-{
-       struct mbxfb_info *mfbi = fbi->par;
-       struct dentry *dir;
-
-       dir = debugfs_create_dir("mbxfb", NULL);
-       mfbi->debugfs_dir = dir;
-
-       debugfs_create_file("sysconf", 0444, dir, fbi, &sysconf_fops);
-       debugfs_create_file("clock", 0444, dir, fbi, &clock_fops);
-       debugfs_create_file("display", 0444, dir, fbi, &display_fops);
-       debugfs_create_file("gsctl", 0444, dir, fbi, &gsctl_fops);
-       debugfs_create_file("sdram", 0444, dir, fbi, &sdram_fops);
-       debugfs_create_file("misc", 0444, dir, fbi, &misc_fops);
-}
-
-static void mbxfb_debugfs_remove(struct fb_info *fbi)
-{
-       struct mbxfb_info *mfbi = fbi->par;
-
-       debugfs_remove_recursive(mfbi->debugfs_dir);
-}
diff --git a/drivers/video/fbdev/mbx/mbxfb.c b/drivers/video/fbdev/mbx/mbxfb.c
deleted file mode 100644 (file)
index 6dc287c..0000000
+++ /dev/null
@@ -1,1053 +0,0 @@
-/*
- *  linux/drivers/video/mbx/mbxfb.c
- *
- *  Copyright (C) 2006-2007 8D Technologies inc
- *  Raphael Assenat <raph@8d.com>
- *     - Added video overlay support
- *     - Various improvements
- *
- *  Copyright (C) 2006 Compulab, Ltd.
- *  Mike Rapoport <mike@compulab.co.il>
- *     - Creation of driver
- *
- *   Based on pxafb.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive for
- * more details.
- *
- *   Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
- *
- */
-
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-
-#include <video/mbxfb.h>
-
-#include "regs.h"
-#include "reg_bits.h"
-
-static void __iomem *virt_base_2700;
-
-#define write_reg(val, reg) do { writel((val), (reg)); } while(0)
-
-/* Without this delay, the graphics appears somehow scaled and
- * there is a lot of jitter in scanlines. This delay is probably
- * needed only after setting some specific register(s) somewhere,
- * not all over the place... */
-#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
-
-#define MIN_XRES       16
-#define MIN_YRES       16
-#define MAX_XRES       2048
-#define MAX_YRES       2048
-
-#define MAX_PALETTES   16
-
-/* FIXME: take care of different chip revisions with different sizes
-   of ODFB */
-#define MEMORY_OFFSET  0x60000
-
-struct mbxfb_info {
-       struct device *dev;
-
-       struct resource *fb_res;
-       struct resource *fb_req;
-
-       struct resource *reg_res;
-       struct resource *reg_req;
-
-       void __iomem *fb_virt_addr;
-       unsigned long fb_phys_addr;
-
-       void __iomem *reg_virt_addr;
-       unsigned long reg_phys_addr;
-
-       int (*platform_probe) (struct fb_info * fb);
-       int (*platform_remove) (struct fb_info * fb);
-
-       u32 pseudo_palette[MAX_PALETTES];
-#ifdef CONFIG_FB_MBX_DEBUG
-       struct dentry *debugfs_dir;
-#endif
-
-};
-
-static const struct fb_var_screeninfo mbxfb_default = {
-       .xres = 640,
-       .yres = 480,
-       .xres_virtual = 640,
-       .yres_virtual = 480,
-       .bits_per_pixel = 16,
-       .red = {11, 5, 0},
-       .green = {5, 6, 0},
-       .blue = {0, 5, 0},
-       .activate = FB_ACTIVATE_TEST,
-       .height = -1,
-       .width = -1,
-       .pixclock = 40000,
-       .left_margin = 48,
-       .right_margin = 16,
-       .upper_margin = 33,
-       .lower_margin = 10,
-       .hsync_len = 96,
-       .vsync_len = 2,
-       .vmode = FB_VMODE_NONINTERLACED,
-       .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-};
-
-static const struct fb_fix_screeninfo mbxfb_fix = {
-       .id = "MBX",
-       .type = FB_TYPE_PACKED_PIXELS,
-       .visual = FB_VISUAL_TRUECOLOR,
-       .xpanstep = 0,
-       .ypanstep = 0,
-       .ywrapstep = 0,
-       .accel = FB_ACCEL_NONE,
-};
-
-struct pixclock_div {
-       u8 m;
-       u8 n;
-       u8 p;
-};
-
-static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
-                                      struct pixclock_div *div)
-{
-       u8 m, n, p;
-       unsigned int err = 0;
-       unsigned int min_err = ~0x0;
-       unsigned int clk;
-       unsigned int best_clk = 0;
-       unsigned int ref_clk = 13000;   /* FIXME: take from platform data */
-       unsigned int pixclock;
-
-       /* convert pixclock to KHz */
-       pixclock = PICOS2KHZ(pixclock_ps);
-
-       /* PLL output freq = (ref_clk * M) / (N * 2^P)
-        *
-        * M: 1 to 63
-        * N: 1 to 7
-        * P: 0 to 7
-        */
-
-       /* RAPH: When N==1, the resulting pixel clock appears to
-        * get divided by 2. Preventing N=1 by starting the following
-        * loop at 2 prevents this. Is this a bug with my chip
-        * revision or something I dont understand? */
-       for (m = 1; m < 64; m++) {
-               for (n = 2; n < 8; n++) {
-                       for (p = 0; p < 8; p++) {
-                               clk = (ref_clk * m) / (n * (1 << p));
-                               err = (clk > pixclock) ? (clk - pixclock) :
-                                       (pixclock - clk);
-                               if (err < min_err) {
-                                       min_err = err;
-                                       best_clk = clk;
-                                       div->m = m;
-                                       div->n = n;
-                                       div->p = p;
-                               }
-                       }
-               }
-       }
-       return KHZ2PICOS(best_clk);
-}
-
-static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                          u_int trans, struct fb_info *info)
-{
-       u32 val, ret = 1;
-
-       if (regno < MAX_PALETTES) {
-               u32 *pal = info->pseudo_palette;
-
-               val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
-                       ((blue & 0xf800) >> 11);
-               pal[regno] = val;
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-       struct pixclock_div div;
-
-       var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
-
-       if (var->xres < MIN_XRES)
-               var->xres = MIN_XRES;
-       if (var->yres < MIN_YRES)
-               var->yres = MIN_YRES;
-       if (var->xres > MAX_XRES)
-               return -EINVAL;
-       if (var->yres > MAX_YRES)
-               return -EINVAL;
-       var->xres_virtual = max(var->xres_virtual, var->xres);
-       var->yres_virtual = max(var->yres_virtual, var->yres);
-
-       switch (var->bits_per_pixel) {
-               /* 8 bits-per-pixel is not supported yet */
-       case 8:
-               return -EINVAL;
-       case 16:
-               var->green.length = (var->green.length == 5) ? 5 : 6;
-               var->red.length = 5;
-               var->blue.length = 5;
-               var->transp.length = 6 - var->green.length;
-               var->blue.offset = 0;
-               var->green.offset = 5;
-               var->red.offset = 5 + var->green.length;
-               var->transp.offset = (5 + var->red.offset) & 15;
-               break;
-       case 24:                /* RGB 888   */
-       case 32:                /* RGBA 8888 */
-               var->red.offset = 16;
-               var->red.length = 8;
-               var->green.offset = 8;
-               var->green.length = 8;
-               var->blue.offset = 0;
-               var->blue.length = 8;
-               var->transp.length = var->bits_per_pixel - 24;
-               var->transp.offset = (var->transp.length) ? 24 : 0;
-               break;
-       }
-       var->red.msb_right = 0;
-       var->green.msb_right = 0;
-       var->blue.msb_right = 0;
-       var->transp.msb_right = 0;
-
-       return 0;
-}
-
-static int mbxfb_set_par(struct fb_info *info)
-{
-       struct fb_var_screeninfo *var = &info->var;
-       struct pixclock_div div;
-       ushort hbps, ht, hfps, has;
-       ushort vbps, vt, vfps, vas;
-       u32 gsctrl = readl(GSCTRL);
-       u32 gsadr = readl(GSADR);
-
-       info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
-
-       /* setup color mode */
-       gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
-       /* FIXME: add *WORKING* support for 8-bits per color */
-       if (info->var.bits_per_pixel == 8) {
-               return -EINVAL;
-       } else {
-               fb_dealloc_cmap(&info->cmap);
-               gsctrl &= ~GSCTRL_LUT_EN;
-
-               info->fix.visual = FB_VISUAL_TRUECOLOR;
-               switch (info->var.bits_per_pixel) {
-               case 16:
-                       if (info->var.green.length == 5)
-                               gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
-                       else
-                               gsctrl |= GSCTRL_GPIXFMT_RGB565;
-                       break;
-               case 24:
-                       gsctrl |= GSCTRL_GPIXFMT_RGB888;
-                       break;
-               case 32:
-                       gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
-                       break;
-               }
-       }
-
-       /* setup resolution */
-       gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
-       gsctrl |= Gsctrl_Width(info->var.xres) |
-               Gsctrl_Height(info->var.yres);
-       write_reg_dly(gsctrl, GSCTRL);
-
-       gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
-       gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
-                                (8 * 16) - 1);
-       write_reg_dly(gsadr, GSADR);
-
-       /* setup timings */
-       var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
-
-       write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
-               Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
-
-       hbps = var->hsync_len;
-       has = hbps + var->left_margin;
-       hfps = has + var->xres;
-       ht = hfps + var->right_margin;
-
-       vbps = var->vsync_len;
-       vas = vbps + var->upper_margin;
-       vfps = vas + var->yres;
-       vt = vfps + var->lower_margin;
-
-       write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
-       write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
-       write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
-       write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
-
-       write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
-       write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
-       write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
-       write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
-       write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
-
-       write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
-
-       write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
-
-       return 0;
-}
-
-static int mbxfb_blank(int blank, struct fb_info *info)
-{
-       switch (blank) {
-       case FB_BLANK_POWERDOWN:
-       case FB_BLANK_VSYNC_SUSPEND:
-       case FB_BLANK_HSYNC_SUSPEND:
-       case FB_BLANK_NORMAL:
-               write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
-               write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
-               write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
-               break;
-       case FB_BLANK_UNBLANK:
-               write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
-               write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
-               break;
-       }
-       return 0;
-}
-
-static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
-{
-       u32 vsctrl, vscadr, vsadr;
-       u32 sssize, spoctrl, shctrl;
-       u32 vubase, vvbase;
-       u32 vovrclk;
-
-       if (set->scaled_width==0 || set->scaled_height==0)
-               return -EINVAL;
-
-       /* read registers which have reserved bits
-        * so we can write them back as-is. */
-       vovrclk = readl(VOVRCLK);
-       vsctrl = readl(VSCTRL);
-       vscadr = readl(VSCADR);
-       vubase = readl(VUBASE);
-       vvbase = readl(VVBASE);
-       shctrl = readl(SHCTRL);
-
-       spoctrl = readl(SPOCTRL);
-       sssize = readl(SSSIZE);
-
-       vsctrl &= ~(    FMsk(VSCTRL_VSWIDTH) |
-                                       FMsk(VSCTRL_VSHEIGHT) |
-                                       FMsk(VSCTRL_VPIXFMT) |
-                                       VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
-                                       VSCTRL_COSITED );
-       vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
-                               VSCTRL_CSC_EN;
-
-       vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) );
-       vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
-       vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
-
-       switch (set->fmt) {
-       case MBXFB_FMT_YUV16:
-               vsctrl |= VSCTRL_VPIXFMT_YUV12;
-
-               set->Y_stride = ((set->width) + 0xf ) & ~0xf;
-               break;
-       case MBXFB_FMT_YUV12:
-               vsctrl |= VSCTRL_VPIXFMT_YUV12;
-
-               set->Y_stride = ((set->width) + 0xf ) & ~0xf;
-               vubase |= VUBASE_UVHALFSTR;
-
-               break;
-       case MBXFB_FMT_UY0VY1:
-               vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
-               set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
-               break;
-       case MBXFB_FMT_VY0UY1:
-               vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
-               set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
-               break;
-       case MBXFB_FMT_Y0UY1V:
-               vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
-               set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
-               break;
-       case MBXFB_FMT_Y0VY1U:
-               vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
-               set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
-                       break;
-       default:
-               return -EINVAL;
-       }
-
-       /* VSCTRL has the bits which sets the Video Pixel Format.
-        * When passing from a packed to planar format,
-        * if we write VSCTRL first, VVBASE and VUBASE would
-        * be zero if we would not set them here. (And then,
-        * the chips hangs and only a reset seems to fix it).
-        *
-        * If course, the values calculated here have no meaning
-        * for packed formats.
-        */
-       set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
-               set->U_offset = set->height * set->Y_stride;
-               set->V_offset = set->U_offset +
-                                               set->height * set->UV_stride;
-       vubase |= Vubase_Ubase_Adr(
-                       (0x60000 + set->mem_offset + set->U_offset)>>3);
-       vvbase |= Vvbase_Vbase_Adr(
-                       (0x60000 + set->mem_offset + set->V_offset)>>3);
-
-
-       vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
-
-       if (set->enable)
-               vscadr |= VSCADR_STR_EN;
-
-
-       vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
-               Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
-
-       sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
-       sssize = Sssize_Sc_Width(set->scaled_width-1) |
-                       Sssize_Sc_Height(set->scaled_height-1);
-
-       spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
-                       SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
-                       FMsk(SPOCTRL_VPITCH));
-       spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height);
-
-       /* Bypass horiz/vert scaler when same size */
-       if (set->scaled_width == set->width)
-               spoctrl |= SPOCTRL_H_SC_BP;
-       if (set->scaled_height == set->height)
-               spoctrl |= SPOCTRL_V_SC_BP;
-
-       shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM);
-       shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width);
-
-       /* Video plane registers */
-       write_reg(vsctrl, VSCTRL);
-       write_reg(vscadr, VSCADR);
-       write_reg(vubase, VUBASE);
-       write_reg(vvbase, VVBASE);
-       write_reg(vsadr, VSADR);
-
-       /* Video scaler registers */
-       write_reg(sssize, SSSIZE);
-       write_reg(spoctrl, SPOCTRL);
-       write_reg(shctrl, SHCTRL);
-
-       /* Clock */
-       if (set->enable)
-               vovrclk |= 1;
-       else
-               vovrclk &= ~1;
-
-       write_reg(vovrclk, VOVRCLK);
-
-       return 0;
-}
-
-static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder)
-{
-       unsigned long gscadr, vscadr;
-
-       if (porder->bottom == porder->top)
-               return -EINVAL;
-
-       gscadr = readl(GSCADR);
-       vscadr = readl(VSCADR);
-
-       gscadr &= ~(FMsk(GSCADR_BLEND_POS));
-       vscadr &= ~(FMsk(VSCADR_BLEND_POS));
-
-       switch (porder->bottom) {
-       case MBXFB_PLANE_GRAPHICS:
-               gscadr |= GSCADR_BLEND_GFX;
-               break;
-       case MBXFB_PLANE_VIDEO:
-               vscadr |= VSCADR_BLEND_GFX;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (porder->top) {
-       case MBXFB_PLANE_GRAPHICS:
-               gscadr |= GSCADR_BLEND_VID;
-               break;
-       case MBXFB_PLANE_VIDEO:
-               vscadr |= GSCADR_BLEND_VID;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       write_reg_dly(vscadr, VSCADR);
-       write_reg_dly(gscadr, GSCADR);
-
-       return 0;
-
-}
-
-static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha)
-{
-       unsigned long vscadr, vbbase, vcmsk;
-       unsigned long gscadr, gbbase, gdrctrl;
-
-       vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) |
-                               Vbbase_Colkey(alpha->overlay_colorkey);
-
-       gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) |
-                               Gbbase_Colkey(alpha->graphics_colorkey);
-
-       vcmsk = readl(VCMSK);
-       vcmsk &= ~(FMsk(VCMSK_COLKEY_M));
-       vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask);
-
-       gdrctrl = readl(GDRCTRL);
-       gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM));
-       gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask);
-
-       vscadr = readl(VSCADR);
-       vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN);
-
-       gscadr = readl(GSCADR);
-       gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC);
-
-       switch (alpha->overlay_colorkey_mode) {
-       case MBXFB_COLORKEY_DISABLED:
-               break;
-       case MBXFB_COLORKEY_PREVIOUS:
-               vscadr |= VSCADR_COLKEY_EN;
-               break;
-       case MBXFB_COLORKEY_CURRENT:
-               vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (alpha->overlay_blend_mode) {
-       case MBXFB_ALPHABLEND_NONE:
-               vscadr |= VSCADR_BLEND_NONE;
-               break;
-       case MBXFB_ALPHABLEND_GLOBAL:
-               vscadr |= VSCADR_BLEND_GLOB;
-               break;
-       case MBXFB_ALPHABLEND_PIXEL:
-               vscadr |= VSCADR_BLEND_PIX;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (alpha->graphics_colorkey_mode) {
-       case MBXFB_COLORKEY_DISABLED:
-               break;
-       case MBXFB_COLORKEY_PREVIOUS:
-               gscadr |= GSCADR_COLKEY_EN;
-               break;
-       case MBXFB_COLORKEY_CURRENT:
-               gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (alpha->graphics_blend_mode) {
-       case MBXFB_ALPHABLEND_NONE:
-               gscadr |= GSCADR_BLEND_NONE;
-               break;
-       case MBXFB_ALPHABLEND_GLOBAL:
-               gscadr |= GSCADR_BLEND_GLOB;
-               break;
-       case MBXFB_ALPHABLEND_PIXEL:
-               gscadr |= GSCADR_BLEND_PIX;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       write_reg_dly(vbbase, VBBASE);
-       write_reg_dly(gbbase, GBBASE);
-       write_reg_dly(vcmsk, VCMSK);
-       write_reg_dly(gdrctrl, GDRCTRL);
-       write_reg_dly(gscadr, GSCADR);
-       write_reg_dly(vscadr, VSCADR);
-
-       return 0;
-}
-
-static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct mbxfb_overlaySetup       setup;
-       struct mbxfb_planeorder         porder;
-       struct mbxfb_alphaCtl           alpha;
-       struct mbxfb_reg                        reg;
-       int res;
-       __u32 tmp;
-
-       switch (cmd)
-       {
-               case MBXFB_IOCX_OVERLAY:
-                       if (copy_from_user(&setup, (void __user*)arg,
-                                               sizeof(struct mbxfb_overlaySetup)))
-                               return -EFAULT;
-
-                       res = mbxfb_setupOverlay(&setup);
-                       if (res)
-                               return res;
-
-                       if (copy_to_user((void __user*)arg, &setup,
-                                               sizeof(struct mbxfb_overlaySetup)))
-                               return -EFAULT;
-
-                       return 0;
-
-               case MBXFB_IOCS_PLANEORDER:
-                       if (copy_from_user(&porder, (void __user*)arg,
-                                       sizeof(struct mbxfb_planeorder)))
-                               return -EFAULT;
-
-                       return mbxfb_ioctl_planeorder(&porder);
-
-               case MBXFB_IOCS_ALPHA:
-                       if (copy_from_user(&alpha, (void __user*)arg,
-                                       sizeof(struct mbxfb_alphaCtl)))
-                               return -EFAULT;
-
-                       return mbxfb_ioctl_alphactl(&alpha);
-
-               case MBXFB_IOCS_REG:
-                       if (copy_from_user(&reg, (void __user*)arg,
-                                               sizeof(struct mbxfb_reg)))
-                               return -EFAULT;
-
-                       if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */
-                               return -EINVAL;
-
-                       tmp = readl(virt_base_2700 + reg.addr);
-                       tmp &= ~reg.mask;
-                       tmp |= reg.val & reg.mask;
-                       writel(tmp, virt_base_2700 + reg.addr);
-
-                       return 0;
-               case MBXFB_IOCX_REG:
-                       if (copy_from_user(&reg, (void __user*)arg,
-                                               sizeof(struct mbxfb_reg)))
-                               return -EFAULT;
-
-                       if (reg.addr >= 0x10000)        /* regs are from 0x3fe0000 to 0x3feffff */
-                               return -EINVAL;
-                       reg.val = readl(virt_base_2700 + reg.addr);
-
-                       if (copy_to_user((void __user*)arg, &reg,
-                                               sizeof(struct mbxfb_reg)))
-                               return -EFAULT;
-
-                       return 0;
-       }
-       return -EINVAL;
-}
-
-static const struct fb_ops mbxfb_ops = {
-       .owner = THIS_MODULE,
-       .fb_check_var = mbxfb_check_var,
-       .fb_set_par = mbxfb_set_par,
-       .fb_setcolreg = mbxfb_setcolreg,
-       .fb_fillrect = cfb_fillrect,
-       .fb_copyarea = cfb_copyarea,
-       .fb_imageblit = cfb_imageblit,
-       .fb_blank = mbxfb_blank,
-       .fb_ioctl = mbxfb_ioctl,
-};
-
-/*
-  Enable external SDRAM controller. Assume that all clocks are active
-  by now.
-*/
-static void setup_memc(struct fb_info *fbi)
-{
-       unsigned long tmp;
-       int i;
-
-       /* FIXME: use platform specific parameters */
-       /* setup SDRAM controller */
-       write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
-               LMCFG_LMA_TS),
-              LMCFG);
-
-       write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
-
-       /* setup SDRAM timings */
-       write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
-               Lmtim_Trc(9) | Lmtim_Tdpl(2)),
-              LMTIM);
-       /* setup SDRAM refresh rate */
-       write_reg_dly(0xc2b, LMREFRESH);
-       /* setup SDRAM type parameters */
-       write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
-               LMTYPE_COLSZ_8),
-              LMTYPE);
-       /* enable memory controller */
-       write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
-       /* perform dummy reads */
-       for ( i = 0; i < 16; i++ ) {
-               tmp = readl(fbi->screen_base);
-       }
-}
-
-static void enable_clocks(struct fb_info *fbi)
-{
-       /* enable clocks */
-       write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
-       write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
-       write_reg_dly(0x00000000, CLKSLEEP);
-
-       /* PLL output = (Frefclk * M) / (N * 2^P )
-        *
-        * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
-        * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
-        * */
-       write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
-               CORE_PLL_EN),
-              COREPLL);
-
-       write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
-               DISP_PLL_EN),
-              DISPPLL);
-
-       write_reg_dly(0x00000000, VOVRCLK);
-       write_reg_dly(PIXCLK_EN, PIXCLK);
-       write_reg_dly(MEMCLK_EN, MEMCLK);
-       write_reg_dly(0x00000001, M24CLK);
-       write_reg_dly(0x00000001, MBXCLK);
-       write_reg_dly(SDCLK_EN, SDCLK);
-       write_reg_dly(0x00000001, PIXCLKDIV);
-}
-
-static void setup_graphics(struct fb_info *fbi)
-{
-       unsigned long gsctrl;
-       unsigned long vscadr;
-
-       gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
-               Gsctrl_Height(fbi->var.yres);
-       switch (fbi->var.bits_per_pixel) {
-       case 16:
-               if (fbi->var.green.length == 5)
-                       gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
-               else
-                       gsctrl |= GSCTRL_GPIXFMT_RGB565;
-               break;
-       case 24:
-               gsctrl |= GSCTRL_GPIXFMT_RGB888;
-               break;
-       case 32:
-               gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
-               break;
-       }
-
-       write_reg_dly(gsctrl, GSCTRL);
-       write_reg_dly(0x00000000, GBBASE);
-       write_reg_dly(0x00ffffff, GDRCTRL);
-       write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
-       write_reg_dly(0x00000000, GPLUT);
-
-       vscadr = readl(VSCADR);
-       vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M));
-       vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE;
-       write_reg_dly(vscadr, VSCADR);
-}
-
-static void setup_display(struct fb_info *fbi)
-{
-       unsigned long dsctrl = 0;
-
-       dsctrl = DSCTRL_BLNK_POL;
-       if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
-               dsctrl |= DSCTRL_HS_POL;
-       if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
-               dsctrl |= DSCTRL_VS_POL;
-       write_reg_dly(dsctrl, DSCTRL);
-       write_reg_dly(0xd0303010, DMCTRL);
-       write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
-}
-
-static void enable_controller(struct fb_info *fbi)
-{
-       u32 svctrl, shctrl;
-
-       write_reg_dly(SYSRST_RST, SYSRST);
-
-       /* setup a timeout, raise drive strength */
-       write_reg_dly(0xffffff0c, SYSCFG);
-
-       enable_clocks(fbi);
-       setup_memc(fbi);
-       setup_graphics(fbi);
-       setup_display(fbi);
-
-       shctrl = readl(SHCTRL);
-       shctrl &= ~(FMsk(SHCTRL_HINITIAL));
-       shctrl |= Shctrl_Hinitial(4<<11);
-       writel(shctrl, SHCTRL);
-
-       svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
-       writel(svctrl, SVCTRL);
-
-       writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP
-                       , SPOCTRL);
-
-       /* Those coefficients are good for scaling up. For scaling
-        * down, the application has to calculate them. */
-       write_reg(0xff000100, VSCOEFF0);
-       write_reg(0xfdfcfdfe, VSCOEFF1);
-       write_reg(0x170d0500, VSCOEFF2);
-       write_reg(0x3d372d22, VSCOEFF3);
-       write_reg(0x00000040, VSCOEFF4);
-
-       write_reg(0xff010100, HSCOEFF0);
-       write_reg(0x00000000, HSCOEFF1);
-       write_reg(0x02010000, HSCOEFF2);
-       write_reg(0x01020302, HSCOEFF3);
-       write_reg(0xf9fbfe00, HSCOEFF4);
-       write_reg(0xfbf7f6f7, HSCOEFF5);
-       write_reg(0x1c110700, HSCOEFF6);
-       write_reg(0x3e393127, HSCOEFF7);
-       write_reg(0x00000040, HSCOEFF8);
-
-}
-
-#ifdef CONFIG_PM
-/*
- * Power management hooks.  Note that we won't be called from IRQ context,
- * unlike the blank functions above, so we may sleep.
- */
-static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
-{
-       /* make frame buffer memory enter self-refresh mode */
-       write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
-       while (readl(LMPWRSTAT) != LMPWRSTAT_MC_PWR_SRM)
-               ; /* empty statement */
-
-       /* reset the device, since it's initial state is 'mostly sleeping' */
-       write_reg_dly(SYSRST_RST, SYSRST);
-       return 0;
-}
-
-static int mbxfb_resume(struct platform_device *dev)
-{
-       struct fb_info *fbi = platform_get_drvdata(dev);
-
-       enable_clocks(fbi);
-/*     setup_graphics(fbi); */
-/*     setup_display(fbi); */
-
-       write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
-       return 0;
-}
-#else
-#define mbxfb_suspend  NULL
-#define mbxfb_resume   NULL
-#endif
-
-/* debugfs entries */
-#ifndef CONFIG_FB_MBX_DEBUG
-#define mbxfb_debugfs_init(x)  do {} while(0)
-#define mbxfb_debugfs_remove(x)        do {} while(0)
-#else
-#include "mbxdebugfs.c"
-#endif
-
-#define res_size(_r) (((_r)->end - (_r)->start) + 1)
-
-static int mbxfb_probe(struct platform_device *dev)
-{
-       int ret;
-       struct fb_info *fbi;
-       struct mbxfb_info *mfbi;
-       struct mbxfb_platform_data *pdata;
-
-       dev_dbg(&dev->dev, "mbxfb_probe\n");
-
-       pdata = dev_get_platdata(&dev->dev);
-       if (!pdata) {
-               dev_err(&dev->dev, "platform data is required\n");
-               return -EINVAL;
-       }
-
-       fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
-       if (!fbi)
-               return -ENOMEM;
-
-       mfbi = fbi->par;
-       fbi->pseudo_palette = mfbi->pseudo_palette;
-
-
-       if (pdata->probe)
-               mfbi->platform_probe = pdata->probe;
-       if (pdata->remove)
-               mfbi->platform_remove = pdata->remove;
-
-       mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
-
-       if (!mfbi->fb_res || !mfbi->reg_res) {
-               dev_err(&dev->dev, "no resources found\n");
-               ret = -ENODEV;
-               goto err1;
-       }
-
-       mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
-                                         res_size(mfbi->fb_res), dev->name);
-       if (mfbi->fb_req == NULL) {
-               dev_err(&dev->dev, "failed to claim framebuffer memory\n");
-               ret = -EINVAL;
-               goto err1;
-       }
-       mfbi->fb_phys_addr = mfbi->fb_res->start;
-
-       mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
-                                          res_size(mfbi->reg_res), dev->name);
-       if (mfbi->reg_req == NULL) {
-               dev_err(&dev->dev, "failed to claim Marathon registers\n");
-               ret = -EINVAL;
-               goto err2;
-       }
-       mfbi->reg_phys_addr = mfbi->reg_res->start;
-
-       mfbi->reg_virt_addr = devm_ioremap(&dev->dev,
-                                                  mfbi->reg_phys_addr,
-                                                  res_size(mfbi->reg_req));
-       if (!mfbi->reg_virt_addr) {
-               dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
-               ret = -EINVAL;
-               goto err3;
-       }
-       virt_base_2700 = mfbi->reg_virt_addr;
-
-       mfbi->fb_virt_addr = devm_ioremap(&dev->dev, mfbi->fb_phys_addr,
-                                                 res_size(mfbi->fb_req));
-       if (!mfbi->fb_virt_addr) {
-               dev_err(&dev->dev, "failed to ioremap frame buffer\n");
-               ret = -EINVAL;
-               goto err3;
-       }
-
-       fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
-       fbi->screen_size = pdata->memsize;
-       fbi->fbops = &mbxfb_ops;
-
-       fbi->var = mbxfb_default;
-       fbi->fix = mbxfb_fix;
-       fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
-       fbi->fix.smem_len = pdata->memsize;
-       fbi->fix.line_length = mbxfb_default.xres_virtual *
-                                       mbxfb_default.bits_per_pixel / 8;
-
-       ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
-       if (ret < 0) {
-               dev_err(&dev->dev, "fb_alloc_cmap failed\n");
-               ret = -EINVAL;
-               goto err3;
-       }
-
-       platform_set_drvdata(dev, fbi);
-
-       fb_info(fbi, "mbx frame buffer device\n");
-
-       if (mfbi->platform_probe)
-               mfbi->platform_probe(fbi);
-
-       enable_controller(fbi);
-
-       mbxfb_debugfs_init(fbi);
-
-       ret = register_framebuffer(fbi);
-       if (ret < 0) {
-               dev_err(&dev->dev, "register_framebuffer failed\n");
-               ret = -EINVAL;
-               goto err6;
-       }
-
-       return 0;
-
-err6:
-       fb_dealloc_cmap(&fbi->cmap);
-err3:
-       release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
-err2:
-       release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
-err1:
-       framebuffer_release(fbi);
-
-       return ret;
-}
-
-static int mbxfb_remove(struct platform_device *dev)
-{
-       struct fb_info *fbi = platform_get_drvdata(dev);
-
-       write_reg_dly(SYSRST_RST, SYSRST);
-
-       mbxfb_debugfs_remove(fbi);
-
-       if (fbi) {
-               struct mbxfb_info *mfbi = fbi->par;
-
-               unregister_framebuffer(fbi);
-               if (mfbi) {
-                       if (mfbi->platform_remove)
-                               mfbi->platform_remove(fbi);
-
-
-                       if (mfbi->reg_req)
-                               release_mem_region(mfbi->reg_req->start,
-                                                  res_size(mfbi->reg_req));
-                       if (mfbi->fb_req)
-                               release_mem_region(mfbi->fb_req->start,
-                                                  res_size(mfbi->fb_req));
-               }
-               framebuffer_release(fbi);
-       }
-
-       return 0;
-}
-
-static struct platform_driver mbxfb_driver = {
-       .probe = mbxfb_probe,
-       .remove = mbxfb_remove,
-       .suspend = mbxfb_suspend,
-       .resume = mbxfb_resume,
-       .driver = {
-               .name = "mbx-fb",
-       },
-};
-
-module_platform_driver(mbxfb_driver);
-
-MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
-MODULE_AUTHOR("Mike Rapoport, Compulab");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mbx/reg_bits.h b/drivers/video/fbdev/mbx/reg_bits.h
deleted file mode 100644 (file)
index 6607f35..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __REG_BITS_2700G_
-#define __REG_BITS_2700G_
-
-/* use defines from asm-arm/arch-pxa/bitfields.h for bit fields access */
-#define UData(Data)    ((unsigned long) (Data))
-#define Fld(Size, Shft)        (((Size) << 16) + (Shft))
-#define FSize(Field)   ((Field) >> 16)
-#define FShft(Field)   ((Field) & 0x0000FFFF)
-#define FMsk(Field)    (((UData (1) << FSize (Field)) - 1) << FShft (Field))
-#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1)
-#define F1stBit(Field) (UData (1) << FShft (Field))
-
-#define SYSRST_RST     (1 << 0)
-
-/* SYSCLKSRC - SYSCLK Source Control Register */
-#define SYSCLKSRC_SEL  Fld(2,0)
-#define SYSCLKSRC_REF  ((0x0) << FShft(SYSCLKSRC_SEL))
-#define SYSCLKSRC_PLL_1        ((0x1) << FShft(SYSCLKSRC_SEL))
-#define SYSCLKSRC_PLL_2        ((0x2) << FShft(SYSCLKSRC_SEL))
-
-/* PIXCLKSRC - PIXCLK Source Control Register */
-#define PIXCLKSRC_SEL  Fld(2,0)
-#define PIXCLKSRC_REF  ((0x0) << FShft(PIXCLKSRC_SEL))
-#define PIXCLKSRC_PLL_1        ((0x1) << FShft(PIXCLKSRC_SEL))
-#define PIXCLKSRC_PLL_2        ((0x2) << FShft(PIXCLKSRC_SEL))
-
-/* Clock Disable Register */
-#define CLKSLEEP_SLP   (1 << 0)
-
-/* Core PLL Control Register */
-#define CORE_PLL_M     Fld(6,7)
-#define Core_Pll_M(x)  ((x) << FShft(CORE_PLL_M))
-#define CORE_PLL_N     Fld(3,4)
-#define Core_Pll_N(x)  ((x) << FShft(CORE_PLL_N))
-#define CORE_PLL_P     Fld(3,1)
-#define Core_Pll_P(x)  ((x) << FShft(CORE_PLL_P))
-#define CORE_PLL_EN    (1 << 0)
-
-/* Display PLL Control Register */
-#define DISP_PLL_M     Fld(6,7)
-#define Disp_Pll_M(x)  ((x) << FShft(DISP_PLL_M))
-#define DISP_PLL_N     Fld(3,4)
-#define Disp_Pll_N(x)  ((x) << FShft(DISP_PLL_N))
-#define DISP_PLL_P     Fld(3,1)
-#define Disp_Pll_P(x)  ((x) << FShft(DISP_PLL_P))
-#define DISP_PLL_EN    (1 << 0)
-
-/* PLL status register */
-#define PLLSTAT_CORE_PLL_LOST_L        (1 << 3)
-#define PLLSTAT_CORE_PLL_LSTS  (1 << 2)
-#define PLLSTAT_DISP_PLL_LOST_L        (1 << 1)
-#define PLLSTAT_DISP_PLL_LSTS  (1 << 0)
-
-/* Video and scale clock control register */
-#define VOVRCLK_EN     (1 << 0)
-
-/* Pixel clock control register */
-#define PIXCLK_EN      (1 << 0)
-
-/* Memory clock control register */
-#define MEMCLK_EN      (1 << 0)
-
-/* MBX clock control register */
-#define MBXCLK_DIV     Fld(2,2)
-#define MBXCLK_DIV_1   ((0x0) << FShft(MBXCLK_DIV))
-#define MBXCLK_DIV_2   ((0x1) << FShft(MBXCLK_DIV))
-#define MBXCLK_DIV_3   ((0x2) << FShft(MBXCLK_DIV))
-#define MBXCLK_DIV_4   ((0x3) << FShft(MBXCLK_DIV))
-#define MBXCLK_EN      Fld(2,0)
-#define MBXCLK_EN_NONE ((0x0) << FShft(MBXCLK_EN))
-#define MBXCLK_EN_2D   ((0x1) << FShft(MBXCLK_EN))
-#define MBXCLK_EN_BOTH ((0x2) << FShft(MBXCLK_EN))
-
-/* M24 clock control register */
-#define M24CLK_DIV     Fld(2,1)
-#define M24CLK_DIV_1   ((0x0) << FShft(M24CLK_DIV))
-#define M24CLK_DIV_2   ((0x1) << FShft(M24CLK_DIV))
-#define M24CLK_DIV_3   ((0x2) << FShft(M24CLK_DIV))
-#define M24CLK_DIV_4   ((0x3) << FShft(M24CLK_DIV))
-#define M24CLK_EN      (1 << 0)
-
-/* SDRAM clock control register */
-#define SDCLK_EN       (1 << 0)
-
-/* PixClk Divisor Register */
-#define PIXCLKDIV_PD   Fld(9,0)
-#define Pixclkdiv_Pd(x)        ((x) << FShft(PIXCLKDIV_PD))
-
-/* LCD Config control register */
-#define LCDCFG_IN_FMT  Fld(3,28)
-#define Lcdcfg_In_Fmt(x)       ((x) << FShft(LCDCFG_IN_FMT))
-#define LCDCFG_LCD1DEN_POL     (1 << 27)
-#define LCDCFG_LCD1FCLK_POL    (1 << 26)
-#define LCDCFG_LCD1LCLK_POL    (1 << 25)
-#define LCDCFG_LCD1D_POL       (1 << 24)
-#define LCDCFG_LCD2DEN_POL     (1 << 23)
-#define LCDCFG_LCD2FCLK_POL    (1 << 22)
-#define LCDCFG_LCD2LCLK_POL    (1 << 21)
-#define LCDCFG_LCD2D_POL       (1 << 20)
-#define LCDCFG_LCD1_TS         (1 << 19)
-#define LCDCFG_LCD1D_DS                (1 << 18)
-#define LCDCFG_LCD1C_DS                (1 << 17)
-#define LCDCFG_LCD1_IS_IN      (1 << 16)
-#define LCDCFG_LCD2_TS         (1 << 3)
-#define LCDCFG_LCD2D_DS                (1 << 2)
-#define LCDCFG_LCD2C_DS                (1 << 1)
-#define LCDCFG_LCD2_IS_IN      (1 << 0)
-
-/* On-Die Frame Buffer Power Control Register */
-#define ODFBPWR_SLOW   (1 << 2)
-#define ODFBPWR_MODE   Fld(2,0)
-#define ODFBPWR_MODE_ACT       ((0x0) << FShft(ODFBPWR_MODE))
-#define ODFBPWR_MODE_ACT_LP    ((0x1) << FShft(ODFBPWR_MODE))
-#define ODFBPWR_MODE_SLEEP     ((0x2) << FShft(ODFBPWR_MODE))
-#define ODFBPWR_MODE_SHUTD     ((0x3) << FShft(ODFBPWR_MODE))
-
-/* On-Die Frame Buffer Power State Status Register */
-#define ODFBSTAT_ACT   (1 << 2)
-#define ODFBSTAT_SLP   (1 << 1)
-#define ODFBSTAT_SDN   (1 << 0)
-
-/* LMRST - Local Memory (SDRAM) Reset */
-#define LMRST_MC_RST   (1 << 0)
-
-/* LMCFG - Local Memory (SDRAM) Configuration Register */
-#define LMCFG_LMC_DS   (1 << 5)
-#define LMCFG_LMD_DS   (1 << 4)
-#define LMCFG_LMA_DS   (1 << 3)
-#define LMCFG_LMC_TS   (1 << 2)
-#define LMCFG_LMD_TS   (1 << 1)
-#define LMCFG_LMA_TS   (1 << 0)
-
-/* LMPWR - Local Memory (SDRAM) Power Control Register */
-#define LMPWR_MC_PWR_CNT       Fld(2,0)
-#define LMPWR_MC_PWR_ACT       ((0x0) << FShft(LMPWR_MC_PWR_CNT)) /* Active */
-#define LMPWR_MC_PWR_SRM       ((0x1) << FShft(LMPWR_MC_PWR_CNT)) /* Self-refresh */
-#define LMPWR_MC_PWR_DPD       ((0x3) << FShft(LMPWR_MC_PWR_CNT)) /* deep power down */
-
-/* LMPWRSTAT - Local Memory (SDRAM) Power Status Register */
-#define LMPWRSTAT_MC_PWR_CNT   Fld(2,0)
-#define LMPWRSTAT_MC_PWR_ACT   ((0x0) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Active */
-#define LMPWRSTAT_MC_PWR_SRM   ((0x1) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Self-refresh */
-#define LMPWRSTAT_MC_PWR_DPD   ((0x3) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* deep power down */
-
-/* LMTYPE - Local Memory (SDRAM) Type Register */
-#define LMTYPE_CASLAT  Fld(3,10)
-#define LMTYPE_CASLAT_1        ((0x1) << FShft(LMTYPE_CASLAT))
-#define LMTYPE_CASLAT_2        ((0x2) << FShft(LMTYPE_CASLAT))
-#define LMTYPE_CASLAT_3        ((0x3) << FShft(LMTYPE_CASLAT))
-#define LMTYPE_BKSZ    Fld(2,8)
-#define LMTYPE_BKSZ_1  ((0x1) << FShft(LMTYPE_BKSZ))
-#define LMTYPE_BKSZ_2  ((0x2) << FShft(LMTYPE_BKSZ))
-#define LMTYPE_ROWSZ   Fld(4,4)
-#define LMTYPE_ROWSZ_11        ((0xb) << FShft(LMTYPE_ROWSZ))
-#define LMTYPE_ROWSZ_12        ((0xc) << FShft(LMTYPE_ROWSZ))
-#define LMTYPE_ROWSZ_13        ((0xd) << FShft(LMTYPE_ROWSZ))
-#define LMTYPE_COLSZ   Fld(4,0)
-#define LMTYPE_COLSZ_7 ((0x7) << FShft(LMTYPE_COLSZ))
-#define LMTYPE_COLSZ_8 ((0x8) << FShft(LMTYPE_COLSZ))
-#define LMTYPE_COLSZ_9 ((0x9) << FShft(LMTYPE_COLSZ))
-#define LMTYPE_COLSZ_10        ((0xa) << FShft(LMTYPE_COLSZ))
-#define LMTYPE_COLSZ_11        ((0xb) << FShft(LMTYPE_COLSZ))
-#define LMTYPE_COLSZ_12        ((0xc) << FShft(LMTYPE_COLSZ))
-
-/* LMTIM - Local Memory (SDRAM) Timing Register */
-#define LMTIM_TRAS     Fld(4,16)
-#define Lmtim_Tras(x)  ((x) << FShft(LMTIM_TRAS))
-#define LMTIM_TRP      Fld(4,12)
-#define Lmtim_Trp(x)   ((x) << FShft(LMTIM_TRP))
-#define LMTIM_TRCD     Fld(4,8)
-#define Lmtim_Trcd(x)  ((x) << FShft(LMTIM_TRCD))
-#define LMTIM_TRC      Fld(4,4)
-#define Lmtim_Trc(x)   ((x) << FShft(LMTIM_TRC))
-#define LMTIM_TDPL     Fld(4,0)
-#define Lmtim_Tdpl(x)  ((x) << FShft(LMTIM_TDPL))
-
-/* LMREFRESH - Local Memory (SDRAM) tREF Control Register */
-#define LMREFRESH_TREF Fld(2,0)
-#define Lmrefresh_Tref(x)      ((x) << FShft(LMREFRESH_TREF))
-
-/* GSCTRL - Graphics surface control register */
-#define GSCTRL_LUT_EN  (1 << 31)
-#define GSCTRL_GPIXFMT Fld(4,27)
-#define GSCTRL_GPIXFMT_INDEXED ((0x0) << FShft(GSCTRL_GPIXFMT))
-#define GSCTRL_GPIXFMT_ARGB4444        ((0x4) << FShft(GSCTRL_GPIXFMT))
-#define GSCTRL_GPIXFMT_ARGB1555        ((0x5) << FShft(GSCTRL_GPIXFMT))
-#define GSCTRL_GPIXFMT_RGB888  ((0x6) << FShft(GSCTRL_GPIXFMT))
-#define GSCTRL_GPIXFMT_RGB565  ((0x7) << FShft(GSCTRL_GPIXFMT))
-#define GSCTRL_GPIXFMT_ARGB8888        ((0x8) << FShft(GSCTRL_GPIXFMT))
-#define GSCTRL_GAMMA_EN        (1 << 26)
-
-#define GSCTRL_GSWIDTH Fld(11,11)
-#define Gsctrl_Width(Pixel)    /* Display Width [1..2048 pix.]  */ \
-                        (((Pixel) - 1) << FShft(GSCTRL_GSWIDTH))
-
-#define GSCTRL_GSHEIGHT Fld(11,0)
-#define Gsctrl_Height(Pixel)   /* Display Height [1..2048 pix.]  */ \
-                        (((Pixel) - 1) << FShft(GSCTRL_GSHEIGHT))
-
-/* GBBASE fileds */
-#define GBBASE_GLALPHA Fld(8,24)
-#define Gbbase_Glalpha(x)      ((x) << FShft(GBBASE_GLALPHA))
-
-#define GBBASE_COLKEY Fld(24,0)
-#define Gbbase_Colkey(x)       ((x) << FShft(GBBASE_COLKEY))
-
-/* GDRCTRL fields */
-#define GDRCTRL_PIXDBL (1 << 31)
-#define GDRCTRL_PIXHLV (1 << 30)
-#define GDRCTRL_LNDBL  (1 << 29)
-#define GDRCTRL_LNHLV  (1 << 28)
-#define GDRCTRL_COLKEYM        Fld(24,0)
-#define Gdrctrl_Colkeym(x)     ((x) << FShft(GDRCTRL_COLKEYM))
-
-/* GSCADR graphics stream control address register fields */
-#define GSCADR_STR_EN  (1 << 31)
-#define GSCADR_COLKEY_EN       (1 << 30)
-#define GSCADR_COLKEYSRC       (1 << 29)
-#define GSCADR_BLEND_M Fld(2,27)
-#define GSCADR_BLEND_NONE      ((0x0) << FShft(GSCADR_BLEND_M))
-#define GSCADR_BLEND_INV       ((0x1) << FShft(GSCADR_BLEND_M))
-#define GSCADR_BLEND_GLOB      ((0x2) << FShft(GSCADR_BLEND_M))
-#define GSCADR_BLEND_PIX       ((0x3) << FShft(GSCADR_BLEND_M))
-#define GSCADR_BLEND_POS       Fld(2,24)
-#define GSCADR_BLEND_GFX       ((0x0) << FShft(GSCADR_BLEND_POS))
-#define GSCADR_BLEND_VID       ((0x1) << FShft(GSCADR_BLEND_POS))
-#define GSCADR_BLEND_CUR       ((0x2) << FShft(GSCADR_BLEND_POS))
-#define GSCADR_GBASE_ADR       Fld(23,0)
-#define Gscadr_Gbase_Adr(x)    ((x) << FShft(GSCADR_GBASE_ADR))
-
-/* GSADR graphics stride address register fields */
-#define GSADR_SRCSTRIDE        Fld(10,22)
-#define Gsadr_Srcstride(x)     ((x) << FShft(GSADR_SRCSTRIDE))
-#define GSADR_XSTART   Fld(11,11)
-#define Gsadr_Xstart(x)                ((x) << FShft(GSADR_XSTART))
-#define GSADR_YSTART   Fld(11,0)
-#define Gsadr_Ystart(y)                ((y) << FShft(GSADR_YSTART))
-
-/* GPLUT graphics palette register fields */
-#define GPLUT_LUTADR   Fld(8,24)
-#define Gplut_Lutadr(x)        ((x) << FShft(GPLUT_LUTADR))
-#define GPLUT_LUTDATA  Fld(24,0)
-#define Gplut_Lutdata(x)       ((x) << FShft(GPLUT_LUTDATA))
-
-/* VSCTRL - Video Surface Control Register */
-#define VSCTRL_VPIXFMT         Fld(4,27)
-#define VSCTRL_VPIXFMT_YUV12   ((0x9) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_UY0VY1  ((0xc) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_VY0UY1  ((0xd) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_Y0UY1V  ((0xe) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_Y0VY1U  ((0xf) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_GAMMA_EN                (1 << 26)
-#define VSCTRL_CSC_EN          (1 << 25)
-#define VSCTRL_COSITED         (1 << 22)
-#define VSCTRL_VSWIDTH         Fld(11,11)
-#define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \
-                       (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH))
-#define VSCTRL_VSHEIGHT                Fld(11,0)
-#define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \
-                       (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT))
-
-/* VBBASE - Video Blending Base Register */
-#define VBBASE_GLALPHA         Fld(8,24)
-#define Vbbase_Glalpha(x)      ((x) << FShft(VBBASE_GLALPHA))
-
-#define VBBASE_COLKEY          Fld(24,0)
-#define Vbbase_Colkey(x)       ((x) << FShft(VBBASE_COLKEY))
-
-/* VCMSK - Video Color Key Mask Register */
-#define VCMSK_COLKEY_M         Fld(24,0)
-#define Vcmsk_colkey_m(x)      ((x) << FShft(VCMSK_COLKEY_M))
-
-/* VSCADR - Video Stream Control Rddress Register */
-#define VSCADR_STR_EN          (1 << 31)
-#define VSCADR_COLKEY_EN       (1 << 30)
-#define VSCADR_COLKEYSRC       (1 << 29)
-#define VSCADR_BLEND_M         Fld(2,27)
-#define VSCADR_BLEND_NONE      ((0x0) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_INV       ((0x1) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_GLOB      ((0x2) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_PIX       ((0x3) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_POS       Fld(2,24)
-#define VSCADR_BLEND_GFX       ((0x0) << FShft(VSCADR_BLEND_POS))
-#define VSCADR_BLEND_VID       ((0x1) << FShft(VSCADR_BLEND_POS))
-#define VSCADR_BLEND_CUR       ((0x2) << FShft(VSCADR_BLEND_POS))
-#define VSCADR_VBASE_ADR       Fld(23,0)
-#define Vscadr_Vbase_Adr(x)    ((x) << FShft(VSCADR_VBASE_ADR))
-
-/* VUBASE - Video U Base Register */
-#define VUBASE_UVHALFSTR       (1 << 31)
-#define VUBASE_UBASE_ADR       Fld(24,0)
-#define Vubase_Ubase_Adr(x)    ((x) << FShft(VUBASE_UBASE_ADR))
-
-/* VVBASE - Video V Base Register */
-#define VVBASE_VBASE_ADR       Fld(24,0)
-#define Vvbase_Vbase_Adr(x)    ((x) << FShft(VVBASE_VBASE_ADR))
-
-/* VSADR - Video Stride Address Register */
-#define VSADR_SRCSTRIDE                Fld(10,22)
-#define Vsadr_Srcstride(x)     ((x) << FShft(VSADR_SRCSTRIDE))
-#define VSADR_XSTART           Fld(11,11)
-#define Vsadr_Xstart(x)                ((x) << FShft(VSADR_XSTART))
-#define VSADR_YSTART           Fld(11,0)
-#define Vsadr_Ystart(x)                ((x) << FShft(VSADR_YSTART))
-
-/* VSCTRL - Video Surface Control Register */
-#define VSCTRL_VPIXFMT         Fld(4,27)
-#define VSCTRL_VPIXFMT_YUV12   ((0x9) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_UY0VY1  ((0xc) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_VY0UY1  ((0xd) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_Y0UY1V  ((0xe) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_VPIXFMT_Y0VY1U  ((0xf) << FShft(VSCTRL_VPIXFMT))
-#define VSCTRL_GAMMA_EN                (1 << 26)
-#define VSCTRL_CSC_EN          (1 << 25)
-#define VSCTRL_COSITED         (1 << 22)
-#define VSCTRL_VSWIDTH         Fld(11,11)
-#define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \
-                       (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH))
-#define VSCTRL_VSHEIGHT                Fld(11,0)
-#define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \
-                       (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT))
-
-/* VBBASE - Video Blending Base Register */
-#define VBBASE_GLALPHA         Fld(8,24)
-#define Vbbase_Glalpha(x)      ((x) << FShft(VBBASE_GLALPHA))
-
-#define VBBASE_COLKEY          Fld(24,0)
-#define Vbbase_Colkey(x)       ((x) << FShft(VBBASE_COLKEY))
-
-/* VCMSK - Video Color Key Mask Register */
-#define VCMSK_COLKEY_M         Fld(24,0)
-#define Vcmsk_colkey_m(x)      ((x) << FShft(VCMSK_COLKEY_M))
-
-/* VSCADR - Video Stream Control Rddress Register */
-#define VSCADR_STR_EN          (1 << 31)
-#define VSCADR_COLKEY_EN       (1 << 30)
-#define VSCADR_COLKEYSRC       (1 << 29)
-#define VSCADR_BLEND_M         Fld(2,27)
-#define VSCADR_BLEND_NONE      ((0x0) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_INV       ((0x1) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_GLOB      ((0x2) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_PIX       ((0x3) << FShft(VSCADR_BLEND_M))
-#define VSCADR_BLEND_POS       Fld(2,24)
-#define VSCADR_BLEND_GFX       ((0x0) << FShft(VSCADR_BLEND_POS))
-#define VSCADR_BLEND_VID       ((0x1) << FShft(VSCADR_BLEND_POS))
-#define VSCADR_BLEND_CUR       ((0x2) << FShft(VSCADR_BLEND_POS))
-#define VSCADR_VBASE_ADR       Fld(23,0)
-#define Vscadr_Vbase_Adr(x)    ((x) << FShft(VSCADR_VBASE_ADR))
-
-/* VUBASE - Video U Base Register */
-#define VUBASE_UVHALFSTR       (1 << 31)
-#define VUBASE_UBASE_ADR       Fld(24,0)
-#define Vubase_Ubase_Adr(x)    ((x) << FShft(VUBASE_UBASE_ADR))
-
-/* VVBASE - Video V Base Register */
-#define VVBASE_VBASE_ADR       Fld(24,0)
-#define Vvbase_Vbase_Adr(x)    ((x) << FShft(VVBASE_VBASE_ADR))
-
-/* VSADR - Video Stride Address Register */
-#define VSADR_SRCSTRIDE                Fld(10,22)
-#define Vsadr_Srcstride(x)     ((x) << FShft(VSADR_SRCSTRIDE))
-#define VSADR_XSTART           Fld(11,11)
-#define Vsadr_Xstart(x)                ((x) << FShft(VSADR_XSTART))
-#define VSADR_YSTART           Fld(11,0)
-#define Vsadr_Ystart(x)                ((x) << FShft(VSADR_YSTART))
-
-/* HCCTRL - Hardware Cursor Register fields */
-#define HCCTRL_CUR_EN  (1 << 31)
-#define HCCTRL_COLKEY_EN       (1 << 29)
-#define HCCTRL_COLKEYSRC       (1 << 28)
-#define HCCTRL_BLEND_M Fld(2,26)
-#define HCCTRL_BLEND_NONE      ((0x0) << FShft(HCCTRL_BLEND_M))
-#define HCCTRL_BLEND_INV       ((0x1) << FShft(HCCTRL_BLEND_M))
-#define HCCTRL_BLEND_GLOB      ((0x2) << FShft(HCCTRL_BLEND_M))
-#define HCCTRL_BLEND_PIX       ((0x3) << FShft(HCCTRL_BLEND_M))
-#define HCCTRL_CPIXFMT Fld(3,23)
-#define HCCTRL_CPIXFMT_RGB332  ((0x3) << FShft(HCCTRL_CPIXFMT))
-#define HCCTRL_CPIXFMT_ARGB4444        ((0x4) << FShft(HCCTRL_CPIXFMT))
-#define HCCTRL_CPIXFMT_ARGB1555        ((0x5) << FShft(HCCTRL_CPIXFMT))
-#define HCCTRL_CBASE_ADR       Fld(23,0)
-#define Hcctrl_Cbase_Adr(x)    ((x) << FShft(HCCTRL_CBASE_ADR))
-
-/* HCSIZE Hardware Cursor Size Register fields */
-#define HCSIZE_BLEND_POS       Fld(2,29)
-#define HCSIZE_BLEND_GFX       ((0x0) << FShft(HCSIZE_BLEND_POS))
-#define HCSIZE_BLEND_VID       ((0x1) << FShft(HCSIZE_BLEND_POS))
-#define HCSIZE_BLEND_CUR       ((0x2) << FShft(HCSIZE_BLEND_POS))
-#define HCSIZE_CWIDTH  Fld(3,16)
-#define Hcsize_Cwidth(x)       ((x) << FShft(HCSIZE_CWIDTH))
-#define HCSIZE_CHEIGHT Fld(3,0)
-#define Hcsize_Cheight(x)      ((x) << FShft(HCSIZE_CHEIGHT))
-
-/* HCPOS Hardware Cursor Position Register fields */
-#define HCPOS_SWITCHSRC        (1 << 30)
-#define HCPOS_CURBLINK Fld(6,24)
-#define Hcpos_Curblink(x)      ((x) << FShft(HCPOS_CURBLINK))
-#define HCPOS_XSTART   Fld(12,12)
-#define Hcpos_Xstart(x)        ((x) << FShft(HCPOS_XSTART))
-#define HCPOS_YSTART   Fld(12,0)
-#define Hcpos_Ystart(y)        ((y) << FShft(HCPOS_YSTART))
-
-/* HCBADR Hardware Cursor Blend Address Register */
-#define HCBADR_GLALPHA Fld(8,24)
-#define Hcbadr_Glalpha(x)      ((x) << FShft(HCBADR_GLALPHA))
-#define HCBADR_COLKEY  Fld(24,0)
-#define Hcbadr_Colkey(x)       ((x) << FShft(HCBADR_COLKEY))
-
-/* HCCKMSK - Hardware Cursor Color Key Mask Register */
-#define HCCKMSK_COLKEY_M       Fld(24,0)
-#define Hcckmsk_Colkey_M(x)    ((x) << FShft(HCCKMSK_COLKEY_M))
-
-/* DSCTRL - Display sync control register */
-#define DSCTRL_SYNCGEN_EN      (1 << 31)
-#define DSCTRL_DPL_RST         (1 << 29)
-#define DSCTRL_PWRDN_M         (1 << 28)
-#define DSCTRL_UPDSYNCCNT      (1 << 26)
-#define DSCTRL_UPDINTCNT       (1 << 25)
-#define DSCTRL_UPDCNT          (1 << 24)
-#define DSCTRL_UPDWAIT Fld(4,16)
-#define Dsctrl_Updwait(x)      ((x) << FShft(DSCTRL_UPDWAIT))
-#define DSCTRL_CLKPOL          (1 << 11)
-#define DSCTRL_CSYNC_EN                (1 << 10)
-#define DSCTRL_VS_SLAVE                (1 << 7)
-#define DSCTRL_HS_SLAVE                (1 << 6)
-#define DSCTRL_BLNK_POL                (1 << 5)
-#define DSCTRL_BLNK_DIS                (1 << 4)
-#define DSCTRL_VS_POL          (1 << 3)
-#define DSCTRL_VS_DIS          (1 << 2)
-#define DSCTRL_HS_POL          (1 << 1)
-#define DSCTRL_HS_DIS          (1 << 0)
-
-/* DHT01 - Display horizontal timing register 01 */
-#define DHT01_HBPS     Fld(12,16)
-#define Dht01_Hbps(x)  ((x) << FShft(DHT01_HBPS))
-#define DHT01_HT       Fld(12,0)
-#define Dht01_Ht(x)    ((x) << FShft(DHT01_HT))
-
-/* DHT02 - Display horizontal timing register 02 */
-#define DHT02_HAS      Fld(12,16)
-#define Dht02_Has(x)   ((x) << FShft(DHT02_HAS))
-#define DHT02_HLBS     Fld(12,0)
-#define Dht02_Hlbs(x)  ((x) << FShft(DHT02_HLBS))
-
-/* DHT03 - Display horizontal timing register 03 */
-#define DHT03_HFPS     Fld(12,16)
-#define Dht03_Hfps(x)  ((x) << FShft(DHT03_HFPS))
-#define DHT03_HRBS     Fld(12,0)
-#define Dht03_Hrbs(x)  ((x) << FShft(DHT03_HRBS))
-
-/* DVT01 - Display vertical timing register 01 */
-#define DVT01_VBPS     Fld(12,16)
-#define Dvt01_Vbps(x)  ((x) << FShft(DVT01_VBPS))
-#define DVT01_VT       Fld(12,0)
-#define Dvt01_Vt(x)    ((x) << FShft(DVT01_VT))
-
-/* DVT02 - Display vertical timing register 02 */
-#define DVT02_VAS      Fld(12,16)
-#define Dvt02_Vas(x)   ((x) << FShft(DVT02_VAS))
-#define DVT02_VTBS     Fld(12,0)
-#define Dvt02_Vtbs(x)  ((x) << FShft(DVT02_VTBS))
-
-/* DVT03 - Display vertical timing register 03 */
-#define DVT03_VFPS     Fld(12,16)
-#define Dvt03_Vfps(x)  ((x) << FShft(DVT03_VFPS))
-#define DVT03_VBBS     Fld(12,0)
-#define Dvt03_Vbbs(x)  ((x) << FShft(DVT03_VBBS))
-
-/* DVECTRL - display vertical event control register */
-#define DVECTRL_VEVENT Fld(12,16)
-#define Dvectrl_Vevent(x)      ((x) << FShft(DVECTRL_VEVENT))
-#define DVECTRL_VFETCH Fld(12,0)
-#define Dvectrl_Vfetch(x)      ((x) << FShft(DVECTRL_VFETCH))
-
-/* DHDET - display horizontal DE timing register */
-#define DHDET_HDES     Fld(12,16)
-#define Dhdet_Hdes(x)  ((x) << FShft(DHDET_HDES))
-#define DHDET_HDEF     Fld(12,0)
-#define Dhdet_Hdef(x)  ((x) << FShft(DHDET_HDEF))
-
-/* DVDET - display vertical DE timing register */
-#define DVDET_VDES     Fld(12,16)
-#define Dvdet_Vdes(x)  ((x) << FShft(DVDET_VDES))
-#define DVDET_VDEF     Fld(12,0)
-#define Dvdet_Vdef(x)  ((x) << FShft(DVDET_VDEF))
-
-/* DODMSK - display output data mask register */
-#define DODMSK_MASK_LVL        (1 << 31)
-#define DODMSK_BLNK_LVL        (1 << 30)
-#define DODMSK_MASK_B  Fld(8,16)
-#define Dodmsk_Mask_B(x)       ((x) << FShft(DODMSK_MASK_B))
-#define DODMSK_MASK_G  Fld(8,8)
-#define Dodmsk_Mask_G(x)       ((x) << FShft(DODMSK_MASK_G))
-#define DODMSK_MASK_R  Fld(8,0)
-#define Dodmsk_Mask_R(x)       ((x) << FShft(DODMSK_MASK_R))
-
-/* DBCOL - display border color control register */
-#define DBCOL_BORDCOL  Fld(24,0)
-#define Dbcol_Bordcol(x)       ((x) << FShft(DBCOL_BORDCOL))
-
-/* DVLNUM - display vertical line number register */
-#define DVLNUM_VLINE   Fld(12,0)
-#define Dvlnum_Vline(x)        ((x) << FShft(DVLNUM_VLINE))
-
-/* DMCTRL - Display Memory Control Register */
-#define DMCTRL_MEM_REF Fld(2,30)
-#define DMCTRL_MEM_REF_ACT     ((0x0) << FShft(DMCTRL_MEM_REF))
-#define DMCTRL_MEM_REF_HB      ((0x1) << FShft(DMCTRL_MEM_REF))
-#define DMCTRL_MEM_REF_VB      ((0x2) << FShft(DMCTRL_MEM_REF))
-#define DMCTRL_MEM_REF_BOTH    ((0x3) << FShft(DMCTRL_MEM_REF))
-#define DMCTRL_UV_THRHLD       Fld(6,24)
-#define Dmctrl_Uv_Thrhld(x)    ((x) << FShft(DMCTRL_UV_THRHLD))
-#define DMCTRL_V_THRHLD                Fld(7,16)
-#define Dmctrl_V_Thrhld(x)     ((x) << FShft(DMCTRL_V_THRHLD))
-#define DMCTRL_D_THRHLD                Fld(7,8)
-#define Dmctrl_D_Thrhld(x)     ((x) << FShft(DMCTRL_D_THRHLD))
-#define DMCTRL_BURSTLEN        Fld(6,0)
-#define Dmctrl_Burstlen(x)     ((x) << FShft(DMCTRL_BURSTLEN))
-
-/* DINTRS - Display Interrupt Status Register */
-#define DINTRS_CUR_OR_S                (1 << 18)
-#define DINTRS_STR2_OR_S       (1 << 17)
-#define DINTRS_STR1_OR_S       (1 << 16)
-#define DINTRS_CUR_UR_S                (1 << 6)
-#define DINTRS_STR2_UR_S       (1 << 5)
-#define DINTRS_STR1_UR_S       (1 << 4)
-#define DINTRS_VEVENT1_S       (1 << 3)
-#define DINTRS_VEVENT0_S       (1 << 2)
-#define DINTRS_HBLNK1_S                (1 << 1)
-#define DINTRS_HBLNK0_S                (1 << 0)
-
-/* DINTRE - Display Interrupt Enable Register */
-#define DINTRE_CUR_OR_EN       (1 << 18)
-#define DINTRE_STR2_OR_EN      (1 << 17)
-#define DINTRE_STR1_OR_EN      (1 << 16)
-#define DINTRE_CUR_UR_EN       (1 << 6)
-#define DINTRE_STR2_UR_EN      (1 << 5)
-#define DINTRE_STR1_UR_EN      (1 << 4)
-#define DINTRE_VEVENT1_EN      (1 << 3)
-#define DINTRE_VEVENT0_EN      (1 << 2)
-#define DINTRE_HBLNK1_EN       (1 << 1)
-#define DINTRE_HBLNK0_EN       (1 << 0)
-
-/* DINTRS - Display Interrupt Status Register */
-#define DINTRS_CUR_OR_S                (1 << 18)
-#define DINTRS_STR2_OR_S       (1 << 17)
-#define DINTRS_STR1_OR_S       (1 << 16)
-#define DINTRS_CUR_UR_S                (1 << 6)
-#define DINTRS_STR2_UR_S       (1 << 5)
-#define DINTRS_STR1_UR_S       (1 << 4)
-#define DINTRS_VEVENT1_S       (1 << 3)
-#define DINTRS_VEVENT0_S       (1 << 2)
-#define DINTRS_HBLNK1_S                (1 << 1)
-#define DINTRS_HBLNK0_S                (1 << 0)
-
-/* DINTRE - Display Interrupt Enable Register */
-#define DINTRE_CUR_OR_EN       (1 << 18)
-#define DINTRE_STR2_OR_EN      (1 << 17)
-#define DINTRE_STR1_OR_EN      (1 << 16)
-#define DINTRE_CUR_UR_EN       (1 << 6)
-#define DINTRE_STR2_UR_EN      (1 << 5)
-#define DINTRE_STR1_UR_EN      (1 << 4)
-#define DINTRE_VEVENT1_EN      (1 << 3)
-#define DINTRE_VEVENT0_EN      (1 << 2)
-#define DINTRE_HBLNK1_EN       (1 << 1)
-#define DINTRE_HBLNK0_EN       (1 << 0)
-
-
-/* DLSTS - display load status register */
-#define DLSTS_RLD_ADONE        (1 << 23)
-/* #define DLSTS_RLD_ADOUT     Fld(23,0) */
-
-/* DLLCTRL - display list load control register */
-#define DLLCTRL_RLD_ADRLN      Fld(8,24)
-#define Dllctrl_Rld_Adrln(x)   ((x) << FShft(DLLCTRL_RLD_ADRLN))
-
-/* CLIPCTRL - Clipping Control Register */
-#define CLIPCTRL_HSKIP         Fld(11,16)
-#define Clipctrl_Hskip         ((x) << FShft(CLIPCTRL_HSKIP))
-#define CLIPCTRL_VSKIP         Fld(11,0)
-#define Clipctrl_Vskip         ((x) << FShft(CLIPCTRL_VSKIP))
-
-/* SPOCTRL - Scale Pitch/Order Control Register */
-#define SPOCTRL_H_SC_BP                (1 << 31)
-#define SPOCTRL_V_SC_BP                (1 << 30)
-#define SPOCTRL_HV_SC_OR       (1 << 29)
-#define SPOCTRL_VS_UR_C                (1 << 27)
-#define SPOCTRL_VORDER         Fld(2,16)
-#define SPOCTRL_VORDER_1TAP    ((0x0) << FShft(SPOCTRL_VORDER))
-#define SPOCTRL_VORDER_2TAP    ((0x1) << FShft(SPOCTRL_VORDER))
-#define SPOCTRL_VORDER_4TAP    ((0x3) << FShft(SPOCTRL_VORDER))
-#define SPOCTRL_VPITCH         Fld(16,0)
-#define Spoctrl_Vpitch(x)      ((x) << FShft(SPOCTRL_VPITCH))
-
-/* SVCTRL - Scale Vertical Control Register */
-#define SVCTRL_INITIAL1                Fld(16,16)
-#define Svctrl_Initial1(x)     ((x) << FShft(SVCTRL_INITIAL1))
-#define SVCTRL_INITIAL2                Fld(16,0)
-#define Svctrl_Initial2(x)     ((x) << FShft(SVCTRL_INITIAL2))
-
-/* SHCTRL - Scale Horizontal Control Register */
-#define SHCTRL_HINITIAL                Fld(16,16)
-#define Shctrl_Hinitial(x)     ((x) << FShft(SHCTRL_HINITIAL))
-#define SHCTRL_HDECIM          (1 << 15)
-#define SHCTRL_HPITCH          Fld(15,0)
-#define Shctrl_Hpitch(x)       ((x) << FShft(SHCTRL_HPITCH))
-
-/* SSSIZE - Scale Surface Size Register */
-#define SSSIZE_SC_WIDTH                Fld(11,16)
-#define Sssize_Sc_Width(x)     ((x) << FShft(SSSIZE_SC_WIDTH))
-#define SSSIZE_SC_HEIGHT       Fld(11,0)
-#define Sssize_Sc_Height(x)    ((x) << FShft(SSSIZE_SC_HEIGHT))
-
-#endif /* __REG_BITS_2700G_ */
diff --git a/drivers/video/fbdev/mbx/regs.h b/drivers/video/fbdev/mbx/regs.h
deleted file mode 100644 (file)
index 591fc9d..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __REGS_2700G_
-#define __REGS_2700G_
-
-/* extern unsigned long virt_base_2700; */
-/* #define __REG_2700G(x)      (*(volatile unsigned long*)((x)+virt_base_2700)) */
-#define __REG_2700G(x) ((x)+virt_base_2700)
-
-/* System Configuration Registers (0x0000_0000  0x0000_0010) */
-#define SYSCFG         __REG_2700G(0x00000000)
-#define PFBASE         __REG_2700G(0x00000004)
-#define PFCEIL         __REG_2700G(0x00000008)
-#define POLLFLAG       __REG_2700G(0x0000000c)
-#define SYSRST         __REG_2700G(0x00000010)
-
-/* Interrupt Control Registers (0x0000_0014  0x0000_002F) */
-#define NINTPW         __REG_2700G(0x00000014)
-#define MINTENABLE     __REG_2700G(0x00000018)
-#define MINTSTAT       __REG_2700G(0x0000001c)
-#define SINTENABLE     __REG_2700G(0x00000020)
-#define SINTSTAT       __REG_2700G(0x00000024)
-#define SINTCLR                __REG_2700G(0x00000028)
-
-/* Clock Control Registers (0x0000_002C  0x0000_005F) */
-#define SYSCLKSRC      __REG_2700G(0x0000002c)
-#define PIXCLKSRC      __REG_2700G(0x00000030)
-#define CLKSLEEP       __REG_2700G(0x00000034)
-#define COREPLL                __REG_2700G(0x00000038)
-#define DISPPLL                __REG_2700G(0x0000003c)
-#define PLLSTAT                __REG_2700G(0x00000040)
-#define VOVRCLK                __REG_2700G(0x00000044)
-#define PIXCLK         __REG_2700G(0x00000048)
-#define MEMCLK         __REG_2700G(0x0000004c)
-#define M24CLK         __REG_2700G(0x00000050)
-#define MBXCLK         __REG_2700G(0x00000054)
-#define SDCLK          __REG_2700G(0x00000058)
-#define PIXCLKDIV      __REG_2700G(0x0000005c)
-
-/* LCD Port Control Register (0x0000_0060  0x0000_006F) */
-#define LCD_CONFIG     __REG_2700G(0x00000060)
-
-/* On-Die Frame Buffer Registers (0x0000_0064  0x0000_006B) */
-#define ODFBPWR                __REG_2700G(0x00000064)
-#define ODFBSTAT       __REG_2700G(0x00000068)
-
-/* GPIO Registers (0x0000_006C  0x0000_007F) */
-#define GPIOCGF                __REG_2700G(0x0000006c)
-#define GPIOHI         __REG_2700G(0x00000070)
-#define GPIOLO         __REG_2700G(0x00000074)
-#define GPIOSTAT       __REG_2700G(0x00000078)
-
-/* Pulse Width Modulator (PWM) Registers (0x0000_0200  0x0000_02FF) */
-#define PWMRST         __REG_2700G(0x00000200)
-#define PWMCFG         __REG_2700G(0x00000204)
-#define PWM0DIV                __REG_2700G(0x00000210)
-#define PWM0DUTY       __REG_2700G(0x00000214)
-#define PWM0PER                __REG_2700G(0x00000218)
-#define PWM1DIV                __REG_2700G(0x00000220)
-#define PWM1DUTY       __REG_2700G(0x00000224)
-#define PWM1PER                __REG_2700G(0x00000228)
-
-/* Identification (ID) Registers (0x0000_0300  0x0000_0FFF) */
-#define ID             __REG_2700G(0x00000FF0)
-
-/* Local Memory (SDRAM) Interface Registers (0x0000_1000  0x0000_1FFF) */
-#define LMRST          __REG_2700G(0x00001000)
-#define LMCFG          __REG_2700G(0x00001004)
-#define LMPWR          __REG_2700G(0x00001008)
-#define LMPWRSTAT      __REG_2700G(0x0000100c)
-#define LMCEMR         __REG_2700G(0x00001010)
-#define LMTYPE         __REG_2700G(0x00001014)
-#define LMTIM          __REG_2700G(0x00001018)
-#define LMREFRESH      __REG_2700G(0x0000101c)
-#define LMPROTMIN      __REG_2700G(0x00001020)
-#define LMPROTMAX      __REG_2700G(0x00001024)
-#define LMPROTCFG      __REG_2700G(0x00001028)
-#define LMPROTERR      __REG_2700G(0x0000102c)
-
-/* Plane Controller Registers (0x0000_2000  0x0000_2FFF) */
-#define GSCTRL         __REG_2700G(0x00002000)
-#define VSCTRL         __REG_2700G(0x00002004)
-#define GBBASE         __REG_2700G(0x00002020)
-#define VBBASE         __REG_2700G(0x00002024)
-#define GDRCTRL                __REG_2700G(0x00002040)
-#define VCMSK          __REG_2700G(0x00002044)
-#define GSCADR         __REG_2700G(0x00002060)
-#define VSCADR         __REG_2700G(0x00002064)
-#define VUBASE         __REG_2700G(0x00002084)
-#define VVBASE         __REG_2700G(0x000020a4)
-#define GSADR          __REG_2700G(0x000020c0)
-#define VSADR          __REG_2700G(0x000020c4)
-#define HCCTRL         __REG_2700G(0x00002100)
-#define HCSIZE         __REG_2700G(0x00002110)
-#define HCPOS          __REG_2700G(0x00002120)
-#define HCBADR         __REG_2700G(0x00002130)
-#define HCCKMSK                __REG_2700G(0x00002140)
-#define GPLUT          __REG_2700G(0x00002150)
-#define DSCTRL         __REG_2700G(0x00002154)
-#define DHT01          __REG_2700G(0x00002158)
-#define DHT02          __REG_2700G(0x0000215c)
-#define DHT03          __REG_2700G(0x00002160)
-#define DVT01          __REG_2700G(0x00002164)
-#define DVT02          __REG_2700G(0x00002168)
-#define DVT03          __REG_2700G(0x0000216c)
-#define DBCOL          __REG_2700G(0x00002170)
-#define BGCOLOR                __REG_2700G(0x00002174)
-#define DINTRS         __REG_2700G(0x00002178)
-#define DINTRE         __REG_2700G(0x0000217c)
-#define DINTRCNT       __REG_2700G(0x00002180)
-#define DSIG           __REG_2700G(0x00002184)
-#define DMCTRL         __REG_2700G(0x00002188)
-#define CLIPCTRL       __REG_2700G(0x0000218c)
-#define SPOCTRL                __REG_2700G(0x00002190)
-#define SVCTRL         __REG_2700G(0x00002194)
-
-/* 0x0000_2198 */
-/* 0x0000_21A8 VSCOEFF[0:4] Video Scalar Vertical Coefficient [0:4] 4.14.5 */
-#define VSCOEFF0       __REG_2700G(0x00002198)
-#define VSCOEFF1       __REG_2700G(0x0000219c)
-#define VSCOEFF2       __REG_2700G(0x000021a0)
-#define VSCOEFF3       __REG_2700G(0x000021a4)
-#define VSCOEFF4       __REG_2700G(0x000021a8)
-
-#define SHCTRL         __REG_2700G(0x000021b0)
-
-/* 0x0000_21B4 */
-/* 0x0000_21D4 HSCOEFF[0:8] Video Scalar Horizontal Coefficient [0:8] 4.14.7 */
-#define HSCOEFF0       __REG_2700G(0x000021b4)
-#define HSCOEFF1       __REG_2700G(0x000021b8)
-#define HSCOEFF2       __REG_2700G(0x000021bc)
-#define HSCOEFF3       __REG_2700G(0x000021c0)
-#define HSCOEFF4       __REG_2700G(0x000021c4)
-#define HSCOEFF5       __REG_2700G(0x000021c8)
-#define HSCOEFF6       __REG_2700G(0x000021cc)
-#define HSCOEFF7       __REG_2700G(0x000021d0)
-#define HSCOEFF8       __REG_2700G(0x000021d4)
-
-#define SSSIZE         __REG_2700G(0x000021D8)
-
-/* 0x0000_2200 */
-/* 0x0000_2240 VIDGAM[0:16] Video Gamma LUT Index [0:16] 4.15.2 */
-#define VIDGAM0                __REG_2700G(0x00002200)
-#define VIDGAM1                __REG_2700G(0x00002204)
-#define VIDGAM2                __REG_2700G(0x00002208)
-#define VIDGAM3                __REG_2700G(0x0000220c)
-#define VIDGAM4                __REG_2700G(0x00002210)
-#define VIDGAM5                __REG_2700G(0x00002214)
-#define VIDGAM6                __REG_2700G(0x00002218)
-#define VIDGAM7                __REG_2700G(0x0000221c)
-#define VIDGAM8                __REG_2700G(0x00002220)
-#define VIDGAM9                __REG_2700G(0x00002224)
-#define VIDGAM10       __REG_2700G(0x00002228)
-#define VIDGAM11       __REG_2700G(0x0000222c)
-#define VIDGAM12       __REG_2700G(0x00002230)
-#define VIDGAM13       __REG_2700G(0x00002234)
-#define VIDGAM14       __REG_2700G(0x00002238)
-#define VIDGAM15       __REG_2700G(0x0000223c)
-#define VIDGAM16       __REG_2700G(0x00002240)
-
-/* 0x0000_2250 */
-/* 0x0000_2290 GFXGAM[0:16] Graphics Gamma LUT Index [0:16] 4.15.3 */
-#define GFXGAM0                __REG_2700G(0x00002250)
-#define GFXGAM1                __REG_2700G(0x00002254)
-#define GFXGAM2                __REG_2700G(0x00002258)
-#define GFXGAM3                __REG_2700G(0x0000225c)
-#define GFXGAM4                __REG_2700G(0x00002260)
-#define GFXGAM5                __REG_2700G(0x00002264)
-#define GFXGAM6                __REG_2700G(0x00002268)
-#define GFXGAM7                __REG_2700G(0x0000226c)
-#define GFXGAM8                __REG_2700G(0x00002270)
-#define GFXGAM9                __REG_2700G(0x00002274)
-#define GFXGAM10       __REG_2700G(0x00002278)
-#define GFXGAM11       __REG_2700G(0x0000227c)
-#define GFXGAM12       __REG_2700G(0x00002280)
-#define GFXGAM13       __REG_2700G(0x00002284)
-#define GFXGAM14       __REG_2700G(0x00002288)
-#define GFXGAM15       __REG_2700G(0x0000228c)
-#define GFXGAM16       __REG_2700G(0x00002290)
-
-#define DLSTS          __REG_2700G(0x00002300)
-#define DLLCTRL                __REG_2700G(0x00002304)
-#define DVLNUM         __REG_2700G(0x00002308)
-#define DUCTRL         __REG_2700G(0x0000230c)
-#define DVECTRL                __REG_2700G(0x00002310)
-#define DHDET          __REG_2700G(0x00002314)
-#define DVDET          __REG_2700G(0x00002318)
-#define DODMSK         __REG_2700G(0x0000231c)
-#define CSC01          __REG_2700G(0x00002330)
-#define CSC02          __REG_2700G(0x00002334)
-#define CSC03          __REG_2700G(0x00002338)
-#define CSC04          __REG_2700G(0x0000233c)
-#define CSC05          __REG_2700G(0x00002340)
-
-#define FB_MEMORY_START        __REG_2700G(0x00060000)
-
-#endif /* __REGS_2700G_ */
index c6820e21875d3569b704f4733bbc83d2c5e5012f..a372a183c1f0196d6ad74a22a1634ba52aa22edf 100644 (file)
@@ -1037,10 +1037,9 @@ static struct fb_ops nvidia_fb_ops = {
        .fb_sync        = nvidiafb_sync,
 };
 
-#ifdef CONFIG_PM
-static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
+static int nvidiafb_suspend_late(struct device *dev, pm_message_t mesg)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct nvidia_par *par = info->par;
 
        if (mesg.event == PM_EVENT_PRETHAW)
@@ -1052,46 +1051,54 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
                fb_set_suspend(info, 1);
                nvidiafb_blank(FB_BLANK_POWERDOWN, info);
                nvidia_write_regs(par, &par->SavedReg);
-               pci_save_state(dev);
-               pci_disable_device(dev);
-               pci_set_power_state(dev, pci_choose_state(dev, mesg));
        }
-       dev->dev.power.power_state = mesg;
+       dev->power.power_state = mesg;
 
        console_unlock();
        return 0;
 }
 
-static int nvidiafb_resume(struct pci_dev *dev)
+static int __maybe_unused nvidiafb_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
-       struct nvidia_par *par = info->par;
+       return nvidiafb_suspend_late(dev, PMSG_SUSPEND);
+}
 
-       console_lock();
-       pci_set_power_state(dev, PCI_D0);
+static int __maybe_unused nvidiafb_hibernate(struct device *dev)
+{
+       return nvidiafb_suspend_late(dev, PMSG_HIBERNATE);
+}
 
-       if (par->pm_state != PM_EVENT_FREEZE) {
-               pci_restore_state(dev);
+static int __maybe_unused nvidiafb_freeze(struct device *dev)
+{
+       return nvidiafb_suspend_late(dev, PMSG_FREEZE);
+}
 
-               if (pci_enable_device(dev))
-                       goto fail;
+static int __maybe_unused nvidiafb_resume(struct device *dev)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct nvidia_par *par = info->par;
 
-               pci_set_master(dev);
-       }
+       console_lock();
 
        par->pm_state = PM_EVENT_ON;
        nvidiafb_set_par(info);
        fb_set_suspend (info, 0);
        nvidiafb_blank(FB_BLANK_UNBLANK, info);
 
-fail:
        console_unlock();
        return 0;
 }
-#else
-#define nvidiafb_suspend NULL
-#define nvidiafb_resume NULL
-#endif
+
+static const struct dev_pm_ops nvidiafb_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = nvidiafb_suspend,
+       .resume         = nvidiafb_resume,
+       .freeze         = nvidiafb_freeze,
+       .thaw           = nvidiafb_resume,
+       .poweroff       = nvidiafb_hibernate,
+       .restore        = nvidiafb_resume,
+#endif /* CONFIG_PM_SLEEP */
+};
 
 static int nvidia_set_fbinfo(struct fb_info *info)
 {
@@ -1492,12 +1499,11 @@ static int nvidiafb_setup(char *options)
 #endif                         /* !MODULE */
 
 static struct pci_driver nvidiafb_driver = {
-       .name = "nvidiafb",
-       .id_table = nvidiafb_pci_tbl,
-       .probe    = nvidiafb_probe,
-       .suspend  = nvidiafb_suspend,
-       .resume   = nvidiafb_resume,
-       .remove   = nvidiafb_remove,
+       .name      = "nvidiafb",
+       .id_table  = nvidiafb_pci_tbl,
+       .probe     = nvidiafb_probe,
+       .driver.pm = &nvidiafb_pm_ops,
+       .remove    = nvidiafb_remove,
 };
 
 /* ------------------------------------------------------------------------- *
index 0b0ad20afd6305abfbb575ca630780602470f1bf..f560fa4d7786eb9219eec21851dad9508af6d4f8 100644 (file)
@@ -787,7 +787,7 @@ static int venc_probe_of(struct platform_device *pdev)
                venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
                break;
        default:
-               dev_err(&pdev->dev, "bad channel propert '%d'\n", channels);
+               dev_err(&pdev->dev, "bad channel property '%d'\n", channels);
                r = -EINVAL;
                goto err;
        }
index 60c424fae9883527425aa9675ed0c002cd6a6974..5c74253e7b2c03222febf7f46ae0e4de810db6f1 100644 (file)
@@ -1410,9 +1410,9 @@ static void s3_pci_remove(struct pci_dev *dev)
 
 /* PCI suspend */
 
-static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
+static int __maybe_unused s3_pci_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct s3fb_info *par = info->par;
 
        dev_info(info->device, "suspend\n");
@@ -1420,7 +1420,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
        console_lock();
        mutex_lock(&(par->open_lock));
 
-       if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+       if (par->ref_count == 0) {
                mutex_unlock(&(par->open_lock));
                console_unlock();
                return 0;
@@ -1428,10 +1428,6 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
        fb_set_suspend(info, 1);
 
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-
        mutex_unlock(&(par->open_lock));
        console_unlock();
 
@@ -1441,11 +1437,10 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
 /* PCI resume */
 
-static int s3_pci_resume(struct pci_dev* dev)
+static int __maybe_unused s3_pci_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct s3fb_info *par = info->par;
-       int err;
 
        dev_info(info->device, "resume\n");
 
@@ -1458,17 +1453,6 @@ static int s3_pci_resume(struct pci_dev* dev)
                return 0;
        }
 
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-       err = pci_enable_device(dev);
-       if (err) {
-               mutex_unlock(&(par->open_lock));
-               console_unlock();
-               dev_err(info->device, "error %d enabling device for resume\n", err);
-               return err;
-       }
-       pci_set_master(dev);
-
        s3fb_set_par(info);
        fb_set_suspend(info, 0);
 
@@ -1478,6 +1462,16 @@ static int s3_pci_resume(struct pci_dev* dev)
        return 0;
 }
 
+static const struct dev_pm_ops s3_pci_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = s3_pci_suspend,
+       .resume         = s3_pci_resume,
+       .freeze         = NULL,
+       .thaw           = s3_pci_resume,
+       .poweroff       = s3_pci_suspend,
+       .restore        = s3_pci_resume,
+#endif
+};
 
 /* List of boards that we are trying to support */
 
@@ -1510,8 +1504,7 @@ static struct pci_driver s3fb_pci_driver = {
        .id_table       = s3_devices,
        .probe          = s3_pci_probe,
        .remove         = s3_pci_remove,
-       .suspend        = s3_pci_suspend,
-       .resume         = s3_pci_resume,
+       .driver.pm      = &s3_pci_pm_ops,
 };
 
 /* Parse user specified options */
index 661398e40ff433c359899430d767abeaf1cffddc..0ac750cc5ea13686529bcfbc945c02cd3a38d77b 100644 (file)
@@ -2347,9 +2347,9 @@ static void savagefb_remove(struct pci_dev *dev)
        }
 }
 
-static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
+static int savagefb_suspend_late(struct device *dev, pm_message_t mesg)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct savagefb_par *par = info->par;
 
        DBG("savagefb_suspend");
@@ -2357,7 +2357,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
        if (mesg.event == PM_EVENT_PRETHAW)
                mesg.event = PM_EVENT_FREEZE;
        par->pm_state = mesg.event;
-       dev->dev.power.power_state = mesg;
+       dev->power.power_state = mesg;
 
        /*
         * For PM_EVENT_FREEZE, do not power down so the console
@@ -2375,17 +2375,29 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
        savagefb_blank(FB_BLANK_POWERDOWN, info);
        savage_set_default_par(par, &par->save);
        savage_disable_mmio(par);
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, mesg));
        console_unlock();
 
        return 0;
 }
 
-static int savagefb_resume(struct pci_dev* dev)
+static int __maybe_unused savagefb_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       return savagefb_suspend_late(dev, PMSG_SUSPEND);
+}
+
+static int __maybe_unused savagefb_hibernate(struct device *dev)
+{
+       return savagefb_suspend_late(dev, PMSG_HIBERNATE);
+}
+
+static int __maybe_unused savagefb_freeze(struct device *dev)
+{
+       return savagefb_suspend_late(dev, PMSG_FREEZE);
+}
+
+static int __maybe_unused savagefb_resume(struct device *dev)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
        struct savagefb_par *par = info->par;
        int cur_state = par->pm_state;
 
@@ -2397,20 +2409,11 @@ static int savagefb_resume(struct pci_dev* dev)
         * The adapter was not powered down coming back from a
         * PM_EVENT_FREEZE.
         */
-       if (cur_state == PM_EVENT_FREEZE) {
-               pci_set_power_state(dev, PCI_D0);
+       if (cur_state == PM_EVENT_FREEZE)
                return 0;
-       }
 
        console_lock();
 
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-
-       if (pci_enable_device(dev))
-               DBG("err");
-
-       pci_set_master(dev);
        savage_enable_mmio(par);
        savage_init_hw(par);
        savagefb_set_par(info);
@@ -2421,6 +2424,16 @@ static int savagefb_resume(struct pci_dev* dev)
        return 0;
 }
 
+static const struct dev_pm_ops savagefb_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = savagefb_suspend,
+       .resume         = savagefb_resume,
+       .freeze         = savagefb_freeze,
+       .thaw           = savagefb_resume,
+       .poweroff       = savagefb_hibernate,
+       .restore        = savagefb_resume,
+#endif
+};
 
 static const struct pci_device_id savagefb_devices[] = {
        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
@@ -2501,8 +2514,7 @@ static struct pci_driver savagefb_driver = {
        .name =     "savagefb",
        .id_table = savagefb_devices,
        .probe =    savagefb_probe,
-       .suspend =  savagefb_suspend,
-       .resume =   savagefb_resume,
+       .driver.pm = &savagefb_pm_ops,
        .remove =   savagefb_remove,
 };
 
index dfe3eb769638bd29dd76231f0cbc6f41f9b61566..fde27feae5d0c29bfd581939e66a475ddcc515e4 100644 (file)
@@ -2428,6 +2428,11 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
    i = 0;
 
+       if (SiS_Pr->ChipType == SIS_730)
+               queuedata = &FQBQData730[0];
+       else
+               queuedata = &FQBQData[0];
+
    if(ModeNo > 0x13) {
 
       /* Get VCLK  */
@@ -2445,12 +2450,6 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
       /* Get half colordepth */
       colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)];
 
-      if(SiS_Pr->ChipType == SIS_730) {
-        queuedata = &FQBQData730[0];
-      } else {
-        queuedata = &FQBQData[0];
-      }
-
       do {
         templ = SiS_CalcDelay2(SiS_Pr, queuedata[i]) * VCLK * colorth;
 
index bdbe9c68e2740484bfa769e4881c50183d9db333..0dbc6bf8268acf5fa0528f28f047372cbd4fd5e8 100644 (file)
@@ -1604,6 +1604,14 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
                sfb->fb->fix.mmio_start = mmio_base;
                sfb->fb->fix.mmio_len = 0x00200000;
                sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
+               if (!sfb->dp_regs) {
+                       dev_err(&pdev->dev,
+                               "%s: unable to map memory mapped IO!\n",
+                               sfb->fb->fix.id);
+                       err = -ENOMEM;
+                       goto failed_fb;
+               }
+
                sfb->lfb = sfb->dp_regs + 0x00200000;
                sfb->mmio = (smtc_regbaseaddress =
                    sfb->dp_regs + 0x000c0000);
index 09425ec317ba2cbcc37da7b80f216b63036fc7b2..eda448b7a0c9d8ceb0d8beb2eb394c06b1cbb57c 100644 (file)
@@ -74,6 +74,7 @@ struct ssd1307fb_par {
        struct fb_info *info;
        u8 lookup_table[4];
        u32 page_offset;
+       u32 col_offset;
        u32 prechargep1;
        u32 prechargep2;
        struct pwm_device *pwm;
@@ -458,11 +459,11 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
        if (ret < 0)
                return ret;
 
-       ret = ssd1307fb_write_cmd(par->client, 0x0);
+       ret = ssd1307fb_write_cmd(par->client, par->col_offset);
        if (ret < 0)
                return ret;
 
-       ret = ssd1307fb_write_cmd(par->client, par->width - 1);
+       ret = ssd1307fb_write_cmd(par->client, par->col_offset + par->width - 1);
        if (ret < 0)
                return ret;
 
@@ -626,6 +627,9 @@ static int ssd1307fb_probe(struct i2c_client *client)
        if (device_property_read_u32(dev, "solomon,page-offset", &par->page_offset))
                par->page_offset = 1;
 
+       if (device_property_read_u32(dev, "solomon,col-offset", &par->col_offset))
+               par->col_offset = 0;
+
        if (device_property_read_u32(dev, "solomon,com-offset", &par->com_offset))
                par->com_offset = 0;
 
index afe6d1b7c3a0dd8932707d3afd41f4dca322c9d7..c05cdabeb11c2d543cfe40821d75b57e446b594a 100644 (file)
@@ -733,7 +733,7 @@ static ssize_t show_vgapass(struct device *device, struct device_attribute *attr
 {
        struct fb_info *info = dev_get_drvdata(device);
        struct sstfb_par *par = info->par;
-       return snprintf(buf, PAGE_SIZE, "%d\n", par->vgapass);
+       return sprintf(buf, "%d\n", par->vgapass);
 }
 
 static struct device_attribute device_attrs[] = {
index e9869135d833a3a67cdb4e19c23932a70fd7ed0a..666fbe2f671c9358bb469737f2820779a88a1f1b 100644 (file)
@@ -989,8 +989,10 @@ tgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
        /* We can fill 2k pixels per operation.  Notice blocks that fit
           the width of the screen so that we can take advantage of this
           and fill more than one line per write.  */
-       if (width == line_length)
-               width *= height, height = 1;
+       if (width == line_length) {
+               width *= height;
+               height = 1;
+       }
 
        /* The write into the frame buffer must be aligned to 4 bytes,
           but we are allowed to encode the offset within the word in
@@ -1171,8 +1173,10 @@ copyarea_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
           More than anything else, these control how we do copies.  */
        depos = dy * line_length + dx;
        sepos = sy * line_length + sx;
-       if (backward)
-               depos += width, sepos += width;
+       if (backward) {
+               depos += width;
+               sepos += width;
+       }
 
        /* Next copy full words at a time.  */
        n32 = width / 32;
index 5b014b479f831b8468886ceacb1c1d70cae165fb..f9b3c1cb9530f3119cae58603e77548edcced963 100644 (file)
@@ -1457,7 +1457,7 @@ static ssize_t edid_show(
                        struct file *filp,
                        struct kobject *kobj, struct bin_attribute *a,
                         char *buf, loff_t off, size_t count) {
-       struct device *fbdev = container_of(kobj, struct device, kobj);
+       struct device *fbdev = kobj_to_dev(kobj);
        struct fb_info *fb_info = dev_get_drvdata(fbdev);
        struct dlfb_data *dlfb = fb_info->par;
 
@@ -1479,7 +1479,7 @@ static ssize_t edid_store(
                        struct file *filp,
                        struct kobject *kobj, struct bin_attribute *a,
                        char *src, loff_t src_off, size_t src_size) {
-       struct device *fbdev = container_of(kobj, struct device, kobj);
+       struct device *fbdev = kobj_to_dev(kobj);
        struct fb_info *fb_info = dev_get_drvdata(fbdev);
        struct dlfb_data *dlfb = fb_info->par;
        int ret;
index 578d3541e3d6f802d9930036d54a71e0e6362293..1e8a38a7967d890a9e44fb245e2c6ce11f7b0f5c 100644 (file)
@@ -243,7 +243,7 @@ static void vga16fb_update_fix(struct fb_info *info)
 }
 
 static void vga16fb_clock_chip(struct vga16fb_par *par,
-                              unsigned int pixclock,
+                              unsigned int *pixclock,
                               const struct fb_info *info,
                               int mul, int div)
 {
@@ -259,14 +259,14 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
                {     0 /* bad */,    0x00, 0x00}};
        int err;
 
-       pixclock = (pixclock * mul) / div;
+       *pixclock = (*pixclock * mul) / div;
        best = vgaclocks;
-       err = pixclock - best->pixclock;
+       err = *pixclock - best->pixclock;
        if (err < 0) err = -err;
        for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
                int tmp;
 
-               tmp = pixclock - ptr->pixclock;
+               tmp = *pixclock - ptr->pixclock;
                if (tmp < 0) tmp = -tmp;
                if (tmp < err) {
                        err = tmp;
@@ -275,7 +275,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
        }
        par->misc |= best->misc;
        par->clkdiv = best->seq_clock_mode;
-       pixclock = (best->pixclock * div) / mul;                
+       *pixclock = (best->pixclock * div) / mul;
 }
                               
 #define FAIL(X) return -EINVAL
@@ -497,10 +497,10 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var,
 
        if (mode & MODE_8BPP)
                /* pixel clock == vga clock / 2 */
-               vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
+               vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
        else
                /* pixel clock == vga clock */
-               vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
+               vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
        
        var->red.offset = var->green.offset = var->blue.offset = 
        var->transp.offset = 0;
index 703ddee9a24438495b7c9ec158c03788c23a2f80..89d75079b73071be5ddf876be6db07f21c4cfed3 100644 (file)
@@ -558,9 +558,8 @@ static void via_teardown_subdevs(void)
 /*
  * Power management functions
  */
-#ifdef CONFIG_PM
-static LIST_HEAD(viafb_pm_hooks);
-static DEFINE_MUTEX(viafb_pm_hooks_lock);
+static __maybe_unused LIST_HEAD(viafb_pm_hooks);
+static __maybe_unused DEFINE_MUTEX(viafb_pm_hooks_lock);
 
 void viafb_pm_register(struct viafb_pm_hooks *hooks)
 {
@@ -580,12 +579,10 @@ void viafb_pm_unregister(struct viafb_pm_hooks *hooks)
 }
 EXPORT_SYMBOL_GPL(viafb_pm_unregister);
 
-static int via_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused via_suspend(struct device *dev)
 {
        struct viafb_pm_hooks *hooks;
 
-       if (state.event != PM_EVENT_SUSPEND)
-               return 0;
        /*
         * "I've occasionally hit a few drivers that caused suspend
         * failures, and each and every time it was a driver bug, and
@@ -600,24 +597,13 @@ static int via_suspend(struct pci_dev *pdev, pm_message_t state)
                hooks->suspend(hooks->private);
        mutex_unlock(&viafb_pm_hooks_lock);
 
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
        return 0;
 }
 
-static int via_resume(struct pci_dev *pdev)
+static int __maybe_unused via_resume(struct device *dev)
 {
        struct viafb_pm_hooks *hooks;
 
-       /* Get the bus side powered up */
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-       if (pci_enable_device(pdev))
-               return 0;
-
-       pci_set_master(pdev);
-
        /* Now bring back any subdevs */
        mutex_lock(&viafb_pm_hooks_lock);
        list_for_each_entry(hooks, &viafb_pm_hooks, list)
@@ -626,7 +612,6 @@ static int via_resume(struct pci_dev *pdev)
 
        return 0;
 }
-#endif /* CONFIG_PM */
 
 static int via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -712,15 +697,23 @@ static const struct pci_device_id via_pci_table[] = {
 };
 MODULE_DEVICE_TABLE(pci, via_pci_table);
 
+static const struct dev_pm_ops via_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = via_suspend,
+       .resume         = via_resume,
+       .freeze         = NULL,
+       .thaw           = via_resume,
+       .poweroff       = NULL,
+       .restore        = via_resume,
+#endif
+};
+
 static struct pci_driver via_driver = {
        .name           = "viafb",
        .id_table       = via_pci_table,
        .probe          = via_pci_probe,
        .remove         = via_pci_remove,
-#ifdef CONFIG_PM
-       .suspend        = via_suspend,
-       .resume         = via_resume,
-#endif
+       .driver.pm      = &via_pm_ops,
 };
 
 static int __init via_core_init(void)
index 98ff8235c9e9980769d2e13e08a29cd9ebf9afb4..7a959e5ba90b83b9a3cf7a3f844274f094019b6b 100644 (file)
@@ -815,12 +815,11 @@ static void vt8623_pci_remove(struct pci_dev *dev)
 }
 
 
-#ifdef CONFIG_PM
 /* PCI suspend */
 
-static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
+static int __maybe_unused vt8623_pci_suspend(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct vt8623fb_info *par = info->par;
 
        dev_info(info->device, "suspend\n");
@@ -828,7 +827,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
        console_lock();
        mutex_lock(&(par->open_lock));
 
-       if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+       if (par->ref_count == 0) {
                mutex_unlock(&(par->open_lock));
                console_unlock();
                return 0;
@@ -836,10 +835,6 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
        fb_set_suspend(info, 1);
 
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-
        mutex_unlock(&(par->open_lock));
        console_unlock();
 
@@ -849,9 +844,9 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
 /* PCI resume */
 
-static int vt8623_pci_resume(struct pci_dev* dev)
+static int __maybe_unused vt8623_pci_resume(struct device *dev)
 {
-       struct fb_info *info = pci_get_drvdata(dev);
+       struct fb_info *info = dev_get_drvdata(dev);
        struct vt8623fb_info *par = info->par;
 
        dev_info(info->device, "resume\n");
@@ -862,14 +857,6 @@ static int vt8623_pci_resume(struct pci_dev* dev)
        if (par->ref_count == 0)
                goto fail;
 
-       pci_set_power_state(dev, PCI_D0);
-       pci_restore_state(dev);
-
-       if (pci_enable_device(dev))
-               goto fail;
-
-       pci_set_master(dev);
-
        vt8623fb_set_par(info);
        fb_set_suspend(info, 0);
 
@@ -879,10 +866,17 @@ fail:
 
        return 0;
 }
-#else
-#define vt8623_pci_suspend NULL
-#define vt8623_pci_resume NULL
-#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops vt8623_pci_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = vt8623_pci_suspend,
+       .resume         = vt8623_pci_resume,
+       .freeze         = NULL,
+       .thaw           = vt8623_pci_resume,
+       .poweroff       = vt8623_pci_suspend,
+       .restore        = vt8623_pci_resume,
+#endif /* CONFIG_PM_SLEEP */
+};
 
 /* List of boards that we are trying to support */
 
@@ -898,8 +892,7 @@ static struct pci_driver vt8623fb_pci_driver = {
        .id_table       = vt8623_devices,
        .probe          = vt8623_pci_probe,
        .remove         = vt8623_pci_remove,
-       .suspend        = vt8623_pci_suspend,
-       .resume         = vt8623_pci_resume,
+       .driver.pm      = &vt8623_pci_pm_ops,
 };
 
 /* Cleanup */
index b0e390b3288e84fe37a1963b52151827149e336a..bda8aa7c22804fdff2b22be75d2924648401f28a 100644 (file)
@@ -36,6 +36,7 @@ struct dw_mipi_dsi_phy_ops {
                             unsigned int *lane_mbps);
        int (*get_timing)(void *priv_data, unsigned int lane_mbps,
                          struct dw_mipi_dsi_dphy_timing *timing);
+       int (*get_esc_clk_rate)(void *priv_data, unsigned int *esc_clk_rate);
 };
 
 struct dw_mipi_dsi_host_ops {
index 0988351d743c446454a7bfb4e1a35158afabb955..f4f68e7a9149ed721d6ed4588333078958f46f9a 100644 (file)
@@ -92,7 +92,7 @@ struct drm_device {
         * NULL.
         *
         * Instead of using this pointer it is recommended that drivers use
-        * drm_dev_init() and embed struct &drm_device in their larger
+        * devm_drm_dev_alloc() and embed struct &drm_device in their larger
         * per-device structure.
         */
        void *dev_private;
index 7116abc1a04e039d8b46e73a93e8b7293d02bacd..9b11a2f0babc088d59bf392502e36ed39b5c05e3 100644 (file)
@@ -163,13 +163,12 @@ struct drm_driver {
        /**
         * @load:
         *
-        * Backward-compatible driver callback to complete
-        * initialization steps after the driver is registered.  For
-        * this reason, may suffer from race conditions and its use is
-        * deprecated for new drivers.  It is therefore only supported
-        * for existing drivers not yet converted to the new scheme.
-        * See drm_dev_init() and drm_dev_register() for proper and
-        * race-free way to set up a &struct drm_device.
+        * Backward-compatible driver callback to complete initialization steps
+        * after the driver is registered.  For this reason, may suffer from
+        * race conditions and its use is deprecated for new drivers.  It is
+        * therefore only supported for existing drivers not yet converted to
+        * the new scheme.  See devm_drm_dev_alloc() and drm_dev_register() for
+        * proper and race-free way to set up a &struct drm_device.
         *
         * This is deprecated, do not use!
         *
@@ -592,9 +591,6 @@ struct drm_driver {
 int drm_dev_init(struct drm_device *dev,
                 struct drm_driver *driver,
                 struct device *parent);
-int devm_drm_dev_init(struct device *parent,
-                     struct drm_device *dev,
-                     struct drm_driver *driver);
 
 void *__devm_drm_dev_alloc(struct device *parent, struct drm_driver *driver,
                           size_t size, size_t offset);
index 035332f3723f2dfce6d9594285371f075aca317f..62cc6e6c3a4fdb08eb9fafe274c72660c890f519 100644 (file)
@@ -9,7 +9,6 @@
 #include <drm/drm_modes.h>
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_bo_driver.h>
-#include <drm/ttm/ttm_placement.h>
 
 #include <linux/kernel.h> /* for container_of() */
 
@@ -20,9 +19,9 @@ struct drm_simple_display_pipe;
 struct filp;
 struct vm_area_struct;
 
-#define DRM_GEM_VRAM_PL_FLAG_VRAM      TTM_PL_FLAG_VRAM
-#define DRM_GEM_VRAM_PL_FLAG_SYSTEM    TTM_PL_FLAG_SYSTEM
-#define DRM_GEM_VRAM_PL_FLAG_TOPDOWN   TTM_PL_FLAG_TOPDOWN
+#define DRM_GEM_VRAM_PL_FLAG_SYSTEM    (1 << 0)
+#define DRM_GEM_VRAM_PL_FLAG_VRAM      (1 << 1)
+#define DRM_GEM_VRAM_PL_FLAG_TOPDOWN   (1 << 2)
 
 /*
  * Buffer-object helpers
@@ -101,9 +100,6 @@ u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo);
 s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo);
 int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag);
 int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo);
-void *drm_gem_vram_kmap(struct drm_gem_vram_object *gbo, bool map,
-                       bool *is_iomem);
-void drm_gem_vram_kunmap(struct drm_gem_vram_object *gbo);
 void *drm_gem_vram_vmap(struct drm_gem_vram_object *gbo);
 void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, void *vaddr);
 
index eee3c9de6c4f9f29240e0471e8a1a810048b7ba5..cdf2a299ccd43ee7e41b2623459e1da5452a7235 100644 (file)
@@ -350,14 +350,15 @@ struct drm_display_mode {
        u8 type;
 
        /**
-        * @private_flags:
+        * @expose_to_userspace:
         *
-        * Driver private flags. private_flags can only be used for mode
-        * objects passed to drivers in modeset operations. It shouldn't be used
-        * by atomic drivers since they can store any additional data by
-        * subclassing state structures.
+        * Indicates whether the mode is to be exposed to the userspace.
+        * This is to maintain a set of exposed modes while preparing
+        * user-mode's list in drm_mode_getconnector ioctl. The purpose of
+        * this only lies in the ioctl function, and is not to be used
+        * outside the function.
         */
-       int private_flags;
+       bool expose_to_userspace;
 
        /**
         * @head:
@@ -366,19 +367,6 @@ struct drm_display_mode {
         */
        struct list_head head;
 
-       /**
-        * @export_head:
-        *
-        * struct list_head for modes to be exposed to the userspace.
-        * This is to maintain a list of exposed modes while preparing
-        * user-mode's list in drm_mode_getconnector ioctl. The purpose of this
-        * list_head only lies in the ioctl function, and is not expected to be
-        * used outside the function.
-        * Once used, the stale pointers are not reset, but left as it is, to
-        * avoid overhead of protecting it by mode_config.mutex.
-        */
-       struct list_head export_head;
-
        /**
         * @name:
         *
index 9af7422b44cf0fb712223c3b24330a737b85a9dd..bf141e74a1c229061e9e60b60b9302c987246c37 100644 (file)
@@ -88,7 +88,8 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr);
 int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
 int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma);
 
-struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages);
+struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
+                                      struct page **pages, unsigned int nr_pages);
 struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj,
                                     int flags);
 
index 6c580987ba16315f487947c4085b5b850ba3930a..36ff64e2736cd9526da946d54381817c75870235 100644 (file)
@@ -151,7 +151,6 @@ struct ttm_buffer_object {
        struct list_head lru;
        struct list_head ddestroy;
        struct list_head swap;
-       struct list_head io_reserve_lru;
 
        /**
         * Members protected by a bo reservation.
index bc8d0ebb75689016a9754a65ce4d6efbb0686ad8..303a89d1066d09d980b726da86bae34654b3a473 100644 (file)
@@ -77,8 +77,9 @@ struct ttm_bo_driver {
         * Returns:
         * -ENOMEM: Out of memory.
         */
-       int (*ttm_tt_populate)(struct ttm_tt *ttm,
-                       struct ttm_operation_ctx *ctx);
+       int (*ttm_tt_populate)(struct ttm_bo_device *bdev,
+                              struct ttm_tt *ttm,
+                              struct ttm_operation_ctx *ctx);
 
        /**
         * ttm_tt_unpopulate
@@ -87,7 +88,43 @@ struct ttm_bo_driver {
         *
         * Free all backing page
         */
-       void (*ttm_tt_unpopulate)(struct ttm_tt *ttm);
+       void (*ttm_tt_unpopulate)(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
+
+       /**
+        * ttm_tt_bind
+        *
+        * @bdev: Pointer to a ttm device
+        * @ttm: Pointer to a struct ttm_tt.
+        * @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 (*ttm_tt_bind)(struct ttm_bo_device *bdev, struct ttm_tt *ttm, struct ttm_resource *bo_mem);
+
+       /**
+        * ttm_tt_unbind
+        *
+        * @bdev: Pointer to a ttm device
+        * @ttm: Pointer to a struct ttm_tt.
+        *
+        * Unbind previously bound backend pages. This function should be
+        * able to handle differences between aperture and system page sizes.
+        */
+       void (*ttm_tt_unbind)(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
+
+       /**
+        * ttm_tt_destroy
+        *
+        * @bdev: Pointer to a ttm device
+        * @ttm: Pointer to a struct ttm_tt.
+        *
+        * Destroy the backend. This will be call back from ttm_tt_destroy so
+        * don't call ttm_tt_destroy from the callback or infinite loop.
+        */
+       void (*ttm_tt_destroy)(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
 
        /**
         * struct ttm_bo_driver member eviction_valuable
@@ -356,23 +393,6 @@ struct ttm_lru_bulk_move {
        struct ttm_lru_bulk_move_pos swap[TTM_MAX_BO_PRIORITY];
 };
 
-/**
- * ttm_flag_masked
- *
- * @old: Pointer to the result and original value.
- * @new: New value of bits.
- * @mask: Mask of bits to change.
- *
- * Convenience function to change a number of bits identified by a mask.
- */
-
-static inline uint32_t
-ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)
-{
-       *old ^= (*old ^ new) & mask;
-       return *old;
-}
-
 /*
  * ttm_bo.c
  */
@@ -441,11 +461,6 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);
  */
 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_resource_manager *man, bool interruptible);
-void ttm_mem_io_unlock(struct ttm_resource_manager *man);
-
 /**
  * ttm_bo_reserve:
  *
@@ -524,6 +539,23 @@ static inline void ttm_bo_move_to_lru_tail_unlocked(struct ttm_buffer_object *bo
        spin_unlock(&ttm_bo_glob.lru_lock);
 }
 
+/**
+ * ttm_bo_move_null = assign memory for a buffer object.
+ * @bo: The bo to assign the memory to
+ * @new_mem: The memory to be assigned.
+ *
+ * Assign the memory from new_mem to the memory of the buffer object bo.
+ */
+static inline void ttm_bo_move_null(struct ttm_buffer_object *bo,
+                                   struct ttm_resource *new_mem)
+{
+       struct ttm_resource *old_mem = &bo->mem;
+
+       WARN_ON(old_mem->mm_node != NULL);
+       *old_mem = *new_mem;
+       new_mem->mm_node = NULL;
+}
+
 /**
  * ttm_bo_unreserve
  *
index e88a8e39767bf5adc4941441581cd50496cfbf33..d4022655eae40650c2d0b47ac90ef85991fcaa14 100644 (file)
 #define TTM_PL_VRAM             2
 #define TTM_PL_PRIV             3
 
-#define TTM_PL_FLAG_SYSTEM      (1 << TTM_PL_SYSTEM)
-#define TTM_PL_FLAG_TT          (1 << TTM_PL_TT)
-#define TTM_PL_FLAG_VRAM        (1 << TTM_PL_VRAM)
-#define TTM_PL_FLAG_PRIV        (1 << TTM_PL_PRIV)
-#define TTM_PL_MASK_MEM         0x0000FFFF
-
 /*
  * Other flags that affects data placement.
  * TTM_PL_FLAG_CACHED indicates cache-coherent mappings
@@ -71,8 +65,6 @@
                                 TTM_PL_FLAG_UNCACHED | \
                                 TTM_PL_FLAG_WC)
 
-#define TTM_PL_MASK_MEMTYPE     (TTM_PL_MASK_MEM | TTM_PL_MASK_CACHING)
-
 /**
  * struct ttm_place
  *
@@ -85,6 +77,7 @@
 struct ttm_place {
        unsigned        fpfn;
        unsigned        lpfn;
+       uint32_t        mem_type;
        uint32_t        flags;
 };
 
index 6d4226190480bd4a90671f16e872fd0688026783..7b8a3157fbb32c8aff402bcf304d78d2157c066d 100644 (file)
@@ -113,10 +113,6 @@ struct ttm_resource_manager_func {
  * @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.
@@ -134,16 +130,8 @@ struct ttm_resource_manager {
        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.
         */
@@ -160,21 +148,15 @@ struct ttm_resource_manager {
  * struct ttm_bus_placement
  *
  * @addr:              mapped virtual address
- * @base:              bus base address
+ * @offset:            physical addr
  * @is_iomem:          is this io memory ?
- * @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   offset;
+       phys_addr_t     offset;
        bool            is_iomem;
-       bool            io_reserved_vm;
-       uint64_t        io_reserved_count;
 };
 
 /**
index 241cc40839ed8a070645ea99a36ba4e617164749..146544ba1c100500143892d9122a753b14dfe419 100644 (file)
@@ -48,48 +48,9 @@ enum ttm_caching_state {
        tt_cached
 };
 
-struct ttm_backend_func {
-       /**
-        * struct ttm_backend_func member bind
-        *
-        * @ttm: Pointer to a struct ttm_tt.
-        * @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_resource *bo_mem);
-
-       /**
-        * struct ttm_backend_func member unbind
-        *
-        * @ttm: Pointer to a struct ttm_tt.
-        *
-        * Unbind previously bound backend pages. This function should be
-        * able to handle differences between aperture and system page sizes.
-        */
-       void (*unbind) (struct ttm_tt *ttm);
-
-       /**
-        * struct ttm_backend_func member destroy
-        *
-        * @ttm: Pointer to a struct ttm_tt.
-        *
-        * Destroy the backend. This will be call back from ttm_tt_destroy so
-        * don't call ttm_tt_destroy from the callback or infinite loop.
-        */
-       void (*destroy) (struct ttm_tt *ttm);
-};
-
 /**
  * struct ttm_tt
  *
- * @bdev: Pointer to a struct ttm_bo_device.
- * @func: Pointer to a struct ttm_backend_func that describes
- * the backend methods.
- * pointer.
  * @pages: Array of pages backing the data.
  * @num_pages: Number of pages in the page array.
  * @bdev: Pointer to the current struct ttm_bo_device.
@@ -103,8 +64,6 @@ struct ttm_backend_func {
  * memory.
  */
 struct ttm_tt {
-       struct ttm_bo_device *bdev;
-       struct ttm_backend_func *func;
        struct page **pages;
        uint32_t page_flags;
        unsigned long num_pages;
@@ -183,7 +142,8 @@ void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma);
  *
  * Bind the pages of @ttm to an aperture location identified by @bo_mem
  */
-int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
+int ttm_tt_bind(struct ttm_bo_device *bdev,
+               struct ttm_tt *ttm, struct ttm_resource *bo_mem,
                struct ttm_operation_ctx *ctx);
 
 /**
@@ -193,7 +153,7 @@ int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem,
  *
  * Unbind, unpopulate and destroy common struct ttm_tt.
  */
-void ttm_tt_destroy(struct ttm_tt *ttm);
+void ttm_tt_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
 
 /**
  * ttm_ttm_unbind:
@@ -202,7 +162,7 @@ void ttm_tt_destroy(struct ttm_tt *ttm);
  *
  * Unbind a struct ttm_tt.
  */
-void ttm_tt_unbind(struct ttm_tt *ttm);
+void ttm_tt_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
 
 /**
  * ttm_tt_swapin:
@@ -227,7 +187,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm);
  * and cache flushes and potential page splitting / combining.
  */
 int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement);
-int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage);
+int ttm_tt_swapout(struct ttm_bo_device *bdev, struct ttm_tt *ttm, struct file *persistent_swap_storage);
 
 /**
  * ttm_tt_populate - allocate pages for a ttm
@@ -236,7 +196,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage);
  *
  * Calls the driver method to allocate pages for a ttm
  */
-int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx);
+int ttm_tt_populate(struct ttm_bo_device *bdev, struct ttm_tt *ttm, struct ttm_operation_ctx *ctx);
 
 /**
  * ttm_tt_unpopulate - free pages from a ttm
@@ -245,7 +205,7 @@ int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx);
  *
  * Calls the driver method to free all pages from a ttm
  */
-void ttm_tt_unpopulate(struct ttm_tt *ttm);
+void ttm_tt_unpopulate(struct ttm_bo_device *bdev, struct ttm_tt *ttm);
 
 #if IS_ENABLED(CONFIG_AGP)
 #include <linux/agp_backend.h>
@@ -265,8 +225,9 @@ void ttm_tt_unpopulate(struct ttm_tt *ttm);
 struct ttm_tt *ttm_agp_tt_create(struct ttm_buffer_object *bo,
                                 struct agp_bridge_data *bridge,
                                 uint32_t page_flags);
-int ttm_agp_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx);
-void ttm_agp_tt_unpopulate(struct ttm_tt *ttm);
+int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem);
+void ttm_agp_unbind(struct ttm_tt *ttm);
+void ttm_agp_destroy(struct ttm_tt *ttm);
 #endif
 
 #endif
index a2ca294eaebe7bef322576a9c7519666249cdc87..957b398d30e5d88959c3374157689b5c6b412803 100644 (file)
@@ -283,6 +283,7 @@ struct dma_buf_ops {
  * @exp_name: name of the exporter; useful for debugging.
  * @name: userspace-provided name; useful for accounting and debugging,
  *        protected by @resv.
+ * @name_lock: spinlock to protect name access
  * @owner: pointer to exporter module; used for refcounting when exporter is a
  *         kernel module.
  * @list_node: node for dma_buf accounting and debugging.
@@ -311,7 +312,7 @@ struct dma_buf {
        void *vmap_ptr;
        const char *exp_name;
        const char *name;
-       spinlock_t name_lock; /* spinlock to protect name access */
+       spinlock_t name_lock;
        struct module *owner;
        struct list_head list_node;
        void *priv;
index 51b91c8b69d582cf9d48b873ea5f9da55a1a18d0..4a3f8741bb7e5453e86349a3f3825ed0ab36e1c6 100644 (file)
@@ -33,6 +33,7 @@ struct font_desc {
 #define        MINI4x6_IDX     9
 #define FONT6x10_IDX   10
 #define TER16x32_IDX   11
+#define FONT6x8_IDX    12
 
 extern const struct font_desc  font_vga_8x8,
                        font_vga_8x16,
@@ -45,7 +46,8 @@ extern const struct font_desc font_vga_8x8,
                        font_acorn_8x8,
                        font_mini_4x6,
                        font_6x10,
-                       font_ter_16x32;
+                       font_ter_16x32,
+                       font_6x8;
 
 /* Find a font with a specific name */
 
index 9e802deedb2d4c6c627de13819ac9d92dc5193a8..8737599b9148a4004d5ab753eab4127fdfc7a74a 100644 (file)
@@ -47,7 +47,6 @@ struct via_port_cfg {
 /*
  * Allow subdevs to register suspend/resume hooks.
  */
-#ifdef CONFIG_PM
 struct viafb_pm_hooks {
        struct list_head list;
        int (*suspend)(void *private);
@@ -57,7 +56,6 @@ struct viafb_pm_hooks {
 
 void viafb_pm_register(struct viafb_pm_hooks *hooks);
 void viafb_pm_unregister(struct viafb_pm_hooks *hooks);
-#endif /* CONFIG_PM */
 
 /*
  * This is the global viafb "device" containing stuff needed by
diff --git a/include/video/mbxfb.h b/include/video/mbxfb.h
deleted file mode 100644 (file)
index 35921cb..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __MBX_FB_H
-#define __MBX_FB_H
-
-#include <asm/ioctl.h>
-#include <asm/types.h>
-
-struct mbxfb_val {
-       unsigned int    defval;
-       unsigned int    min;
-       unsigned int    max;
-};
-
-struct fb_info;
-
-struct mbxfb_platform_data {
-               /* Screen info */
-               struct mbxfb_val xres;
-               struct mbxfb_val yres;
-               struct mbxfb_val bpp;
-
-               /* Memory info */
-               unsigned long memsize; /* if 0 use ODFB? */
-               unsigned long timings1;
-               unsigned long timings2;
-               unsigned long timings3;
-
-               int (*probe)(struct fb_info *fb);
-               int (*remove)(struct fb_info *fb);
-};
-
-/* planar */
-#define MBXFB_FMT_YUV16                0
-#define MBXFB_FMT_YUV12                1
-
-/* packed */
-#define MBXFB_FMT_UY0VY1       2
-#define MBXFB_FMT_VY0UY1       3
-#define MBXFB_FMT_Y0UY1V       4
-#define MBXFB_FMT_Y0VY1U       5
-struct mbxfb_overlaySetup {
-       __u32 enable;
-       __u32 x, y;
-       __u32 width, height;
-       __u32 fmt;
-       __u32 mem_offset;
-       __u32 scaled_width;
-       __u32 scaled_height;
-
-       /* Filled by the driver */
-       __u32 U_offset;
-       __u32 V_offset;
-
-       __u16 Y_stride;
-       __u16 UV_stride;
-};
-
-#define MBXFB_ALPHABLEND_NONE          0
-#define MBXFB_ALPHABLEND_GLOBAL                1
-#define MBXFB_ALPHABLEND_PIXEL         2
-
-#define MBXFB_COLORKEY_DISABLED                0
-#define MBXFB_COLORKEY_PREVIOUS                1
-#define MBXFB_COLORKEY_CURRENT         2
-struct mbxfb_alphaCtl {
-       __u8 overlay_blend_mode;
-       __u8 overlay_colorkey_mode;
-       __u8 overlay_global_alpha;
-       __u32 overlay_colorkey;
-       __u32 overlay_colorkey_mask;
-
-       __u8 graphics_blend_mode;
-       __u8 graphics_colorkey_mode;
-       __u8 graphics_global_alpha;
-       __u32 graphics_colorkey;
-       __u32 graphics_colorkey_mask;
-};
-
-#define MBXFB_PLANE_GRAPHICS   0
-#define MBXFB_PLANE_VIDEO      1
-struct mbxfb_planeorder {
-       __u8 bottom;
-       __u8 top;
-};
-
-struct mbxfb_reg {
-       __u32 addr;     /* offset from 0x03fe 0000 */
-       __u32 val;              /* value */
-       __u32 mask;             /* which bits to touch (for write) */
-};
-
-#define MBXFB_IOCX_OVERLAY             _IOWR(0xF4, 0x00,struct mbxfb_overlaySetup)
-#define MBXFB_IOCG_ALPHA               _IOR(0xF4, 0x01,struct mbxfb_alphaCtl)
-#define MBXFB_IOCS_ALPHA               _IOW(0xF4, 0x02,struct mbxfb_alphaCtl)
-#define MBXFB_IOCS_PLANEORDER  _IOR(0xF4, 0x03,struct mbxfb_planeorder)
-#define MBXFB_IOCS_REG                 _IOW(0xF4, 0x04,struct mbxfb_reg)
-#define MBXFB_IOCX_REG                 _IOWR(0xF4, 0x05,struct mbxfb_reg)
-
-#endif /* __MBX_FB_H */
index 37baa79cdd71fa83dee7321a684f60fdc1acded5..c035fde66aebee47c0f7b6dfbc38dbdf10de0eef 100644 (file)
@@ -119,6 +119,12 @@ config FONT_TER16x32
          This is the high resolution, large version for use with HiDPI screens.
          If the standard font is unreadable for you, say Y, otherwise say N.
 
+config FONT_6x8
+       bool "OLED 6x8 font" if FONTS
+       depends on FRAMEBUFFER_CONSOLE
+       help
+         This font is useful for small displays (OLED).
+
 config FONT_AUTOSELECT
        def_bool y
        depends on !FONT_8x8
@@ -132,6 +138,7 @@ config FONT_AUTOSELECT
        depends on !FONT_SUN12x22
        depends on !FONT_10x18
        depends on !FONT_TER16x32
+       depends on !FONT_6x8
        select FONT_8x16
 
 endif # FONT_SUPPORT
index ed95070860deb0c4fb06fca7f360505e88889506..e16f68492174a30397368b65e548021cf9273836 100644 (file)
@@ -15,6 +15,7 @@ font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
 font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
 font-objs-$(CONFIG_FONT_6x10)      += font_6x10.o
 font-objs-$(CONFIG_FONT_TER16x32)  += font_ter16x32.o
+font-objs-$(CONFIG_FONT_6x8)       += font_6x8.o
 
 font-objs += $(font-objs-y)
 
diff --git a/lib/fonts/font_6x8.c b/lib/fonts/font_6x8.c
new file mode 100644 (file)
index 0000000..e064477
--- /dev/null
@@ -0,0 +1,2576 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/font.h>
+
+#define FONTDATAMAX 2048
+
+static const unsigned char fontdata_6x8[FONTDATAMAX] = {
+
+       /* 0 0x00 '^@' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 1 0x01 '^A' */
+       0x78, /* 011110 */
+       0x84, /* 100001 */
+       0xCC, /* 110011 */
+       0x84, /* 100001 */
+       0xCC, /* 110011 */
+       0xB4, /* 101101 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 2 0x02 '^B' */
+       0x78, /* 011110 */
+       0xFC, /* 111111 */
+       0xB4, /* 101101 */
+       0xFC, /* 111111 */
+       0xB4, /* 101101 */
+       0xCC, /* 110011 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 3 0x03 '^C' */
+       0x00, /* 000000 */
+       0x28, /* 001010 */
+       0x7C, /* 011111 */
+       0x7C, /* 011111 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 4 0x04 '^D' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x7C, /* 011111 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 5 0x05 '^E' */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x6C, /* 011011 */
+       0x6C, /* 011011 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 6 0x06 '^F' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x7C, /* 011111 */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 7 0x07 '^G' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x78, /* 011110 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 8 0x08 '^H' */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xCC, /* 110011 */
+       0x84, /* 100001 */
+       0xCC, /* 110011 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+
+       /* 9 0x09 '^I' */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x48, /* 010010 */
+       0x84, /* 100001 */
+       0x48, /* 010010 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 10 0x0A '^J' */
+       0xFC, /* 111111 */
+       0xCC, /* 110011 */
+       0xB4, /* 101101 */
+       0x78, /* 011110 */
+       0xB4, /* 101101 */
+       0xCC, /* 110011 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+
+       /* 11 0x0B '^K' */
+       0x3C, /* 001111 */
+       0x14, /* 000101 */
+       0x20, /* 001000 */
+       0x78, /* 011110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 12 0x0C '^L' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 13 0x0D '^M' */
+       0x18, /* 000110 */
+       0x14, /* 000101 */
+       0x14, /* 000101 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x70, /* 011100 */
+       0x60, /* 011000 */
+       0x00, /* 000000 */
+
+       /* 14 0x0E '^N' */
+       0x3C, /* 001111 */
+       0x24, /* 001001 */
+       0x3C, /* 001111 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x6C, /* 011011 */
+       0x6C, /* 011011 */
+       0x00, /* 000000 */
+
+       /* 15 0x0F '^O' */
+       0x10, /* 000100 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x6C, /* 011011 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 16 0x10 '^P' */
+       0x40, /* 010000 */
+       0x60, /* 011000 */
+       0x70, /* 011100 */
+       0x78, /* 011110 */
+       0x70, /* 011100 */
+       0x60, /* 011000 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+
+       /* 17 0x11 '^Q' */
+       0x04, /* 000001 */
+       0x0C, /* 000011 */
+       0x1C, /* 000111 */
+       0x3C, /* 001111 */
+       0x1C, /* 000111 */
+       0x0C, /* 000011 */
+       0x04, /* 000001 */
+       0x00, /* 000000 */
+
+       /* 18 0x12 '^R' */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x10, /* 000100 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 19 0x13 '^S' */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x00, /* 000000 */
+       0x48, /* 010010 */
+       0x00, /* 000000 */
+
+       /* 20 0x14 '^T' */
+       0x3C, /* 001111 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x3C, /* 001111 */
+       0x14, /* 000101 */
+       0x14, /* 000101 */
+       0x14, /* 000101 */
+       0x00, /* 000000 */
+
+       /* 21 0x15 '^U' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x30, /* 001100 */
+       0x28, /* 001010 */
+       0x14, /* 000101 */
+       0x0C, /* 000011 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+
+       /* 22 0x16 '^V' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xF8, /* 111110 */
+       0xF8, /* 111110 */
+       0xF8, /* 111110 */
+       0x00, /* 000000 */
+
+       /* 23 0x17 '^W' */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x10, /* 000100 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x7C, /* 011111 */
+
+       /* 24 0x18 '^X' */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 25 0x19 '^Y' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 26 0x1A '^Z' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x7C, /* 011111 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 27 0x1B '^[' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x7C, /* 011111 */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 28 0x1C '^\' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 29 0x1D '^]' */
+       0x00, /* 000000 */
+       0x48, /* 010010 */
+       0x84, /* 100001 */
+       0xFC, /* 111111 */
+       0x84, /* 100001 */
+       0x48, /* 010010 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 30 0x1E '^^' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x7C, /* 011111 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 31 0x1F '^_' */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x7C, /* 011111 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 32 0x20 ' ' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 33 0x21 '!' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 34 0x22 '"' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 35 0x23 '#' */
+       0x00, /* 000000 */
+       0x28, /* 001010 */
+       0x7C, /* 011111 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x7C, /* 011111 */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+
+       /* 36 0x24 '$' */
+       0x10, /* 000000 */
+       0x38, /* 001000 */
+       0x40, /* 010000 */
+       0x30, /* 001000 */
+       0x08, /* 000000 */
+       0x70, /* 011000 */
+       0x20, /* 001000 */
+       0x00, /* 000000 */
+
+       /* 37 0x25 '%' */
+       0x64, /* 011001 */
+       0x64, /* 011001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x4C, /* 010011 */
+       0x4C, /* 010011 */
+       0x00, /* 000000 */
+
+       /* 38 0x26 '&' */
+       0x30, /* 001100 */
+       0x48, /* 010010 */
+       0x50, /* 010100 */
+       0x20, /* 001000 */
+       0x54, /* 010101 */
+       0x48, /* 010010 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 39 0x27 ''' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 40 0x28 '(' */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x20, /* 001000 */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+
+       /* 41 0x29 ')' */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x00, /* 000000 */
+
+       /* 42 0x2A '*' */
+       0x10, /* 000100 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 43 0x2B '+' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 44 0x2C ',' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x30, /* 001100 */
+       0x20, /* 001000 */
+
+       /* 45 0x2D '-' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 46 0x2E '.' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x18, /* 000110 */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+
+       /* 47 0x2F '/' */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x20, /* 001000 */
+       0x40, /* 010000 */
+
+       /* 48 0x30 '0' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x54, /* 010101 */
+       0x64, /* 011001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 49 0x31 '1' */
+       0x10, /* 000100 */
+       0x30, /* 001100 */
+       0x50, /* 010100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 50 0x32 '2' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 51 0x33 '3' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x04, /* 000001 */
+       0x18, /* 000110 */
+       0x04, /* 000001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 52 0x34 '4' */
+       0x08, /* 000010 */
+       0x18, /* 000110 */
+       0x28, /* 001010 */
+       0x48, /* 010010 */
+       0x7C, /* 011111 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+
+       /* 53 0x35 '5' */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x04, /* 000001 */
+       0x04, /* 000001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 54 0x36 '6' */
+       0x18, /* 000110 */
+       0x20, /* 001000 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 55 0x37 '7' */
+       0x7C, /* 011111 */
+       0x04, /* 000001 */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 56 0x38 '8' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 57 0x39 '9' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+
+       /* 58 0x3A ':' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x18, /* 000110 */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x18, /* 000110 */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+
+       /* 59 0x3B ';' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x30, /* 001100 */
+       0x20, /* 001000 */
+
+       /* 60 0x3C '<' */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x04, /* 000001 */
+       0x00, /* 000000 */
+
+       /* 61 0x3D '=' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 62 0x3E '>' */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x00, /* 000000 */
+
+       /* 63 0x3F '?' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 64 0x40 '@' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x5C, /* 010111 */
+       0x54, /* 010101 */
+       0x5C, /* 010111 */
+       0x40, /* 010000 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 65 0x41 'A' */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 66 0x42 'B' */
+       0x78, /* 011110 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x38, /* 001110 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 67 0x43 'C' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 68 0x44 'D' */
+       0x78, /* 011110 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 69 0x45 'E' */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 70 0x46 'F' */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+
+       /* 71 0x47 'G' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x5C, /* 010111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 72 0x48 'H' */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 73 0x49 'I' */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 74 0x4A 'J' */
+       0x1C, /* 000111 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+
+       /* 75 0x4B 'K' */
+       0x44, /* 010001 */
+       0x48, /* 010010 */
+       0x50, /* 010100 */
+       0x60, /* 011000 */
+       0x50, /* 010100 */
+       0x48, /* 010010 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 76 0x4C 'L' */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 77 0x4D 'M' */
+       0x44, /* 010001 */
+       0x6C, /* 011011 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 78 0x4E 'N' */
+       0x44, /* 010001 */
+       0x64, /* 011001 */
+       0x54, /* 010101 */
+       0x4C, /* 010011 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 79 0x4F 'O' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 80 0x50 'P' */
+       0x78, /* 011110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x78, /* 011110 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+
+       /* 81 0x51 'Q' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x54, /* 010101 */
+       0x48, /* 010010 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 82 0x52 'R' */
+       0x78, /* 011110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x78, /* 011110 */
+       0x50, /* 010100 */
+       0x48, /* 010010 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 83 0x53 'S' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 84 0x54 'T' */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 85 0x55 'U' */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 86 0x56 'V' */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 87 0x57 'W' */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x6C, /* 011011 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 88 0x58 'X' */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 89 0x59 'Y' */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 90 0x5A 'Z' */
+       0x7C, /* 011111 */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x40, /* 010000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 91 0x5B '[' */
+       0x18, /* 000110 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+
+       /* 92 0x5C '\' */
+       0x40, /* 010000 */
+       0x20, /* 001000 */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x04, /* 000001 */
+
+       /* 93 0x5D ']' */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+
+       /* 94 0x5E '^' */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 95 0x5F '_' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+
+       /* 96 0x60 '`' */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 97 0x61 'a' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 98 0x62 'b' */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x58, /* 010110 */
+       0x64, /* 011001 */
+       0x44, /* 010001 */
+       0x64, /* 011001 */
+       0x58, /* 010110 */
+       0x00, /* 000000 */
+
+       /* 99 0x63 'c' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 100 0x64 'd' */
+       0x04, /* 000001 */
+       0x04, /* 000001 */
+       0x34, /* 001101 */
+       0x4C, /* 010011 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 101 0x65 'e' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 102 0x66 'f' */
+       0x0C, /* 000011 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 103 0x67 'g' */
+       0x00, /* 000000 */
+       0x34, /* 001101 */
+       0x4C, /* 010011 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x04, /* 000001 */
+       0x38, /* 001110 */
+
+       /* 104 0x68 'h' */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 105 0x69 'i' */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 106 0x6A 'j' */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x60, /* 011000 */
+
+       /* 107 0x6B 'k' */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x48, /* 010010 */
+       0x50, /* 010100 */
+       0x70, /* 011100 */
+       0x48, /* 010010 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 108 0x6C 'l' */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 109 0x6D 'm' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x68, /* 011010 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x00, /* 000000 */
+
+       /* 110 0x6E 'n' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x58, /* 010110 */
+       0x64, /* 011001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 111 0x6F 'o' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 112 0x70 'p' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x78, /* 011110 */
+       0x44, /* 010001 */
+       0x64, /* 011001 */
+       0x58, /* 010110 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+
+       /* 113 0x71 'q' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x04, /* 000001 */
+       0x04, /* 000001 */
+
+       /* 114 0x72 'r' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x58, /* 010110 */
+       0x64, /* 011001 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+
+       /* 115 0x73 's' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x3C, /* 001111 */
+       0x40, /* 010000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 116 0x74 't' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x0C, /* 000011 */
+       0x00, /* 000000 */
+
+       /* 117 0x75 'u' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 118 0x76 'v' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 119 0x77 'w' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+
+       /* 120 0x78 'x' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 121 0x79 'y' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x04, /* 000001 */
+       0x38, /* 001110 */
+
+       /* 122 0x7A 'z' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 123 0x7B '{' */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+
+       /* 124 0x7C '|' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 125 0x7D '}' */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x00, /* 000000 */
+
+       /* 126 0x7E '~' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x20, /* 001000 */
+       0x54, /* 010101 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 127 0x7F '\7f' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 128 0x80 '\200' */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+
+       /* 129 0x81 '\201' */
+       0x00, /* 000000 */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 130 0x82 '\202' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 131 0x83 '\203' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 132 0x84 '\204' */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 133 0x85 '\205' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 134 0x86 '\206' */
+       0x3C, /* 001111 */
+       0x18, /* 000110 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 135 0x87 '\207' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+
+       /* 136 0x88 '\210' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 137 0x89 '\211' */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 138 0x8A '\212' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 139 0x8B '\213' */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 140 0x8C '\214' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 141 0x8D '\215' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 142 0x8E '\216' */
+       0x44, /* 010001 */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 143 0x8F '\217' */
+       0x30, /* 001100 */
+       0x48, /* 010010 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 144 0x90 '\220' */
+       0x10, /* 000100 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x78, /* 011110 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 145 0x91 '\221' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x78, /* 011110 */
+       0x14, /* 000101 */
+       0x7C, /* 011111 */
+       0x50, /* 010100 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 146 0x92 '\222' */
+       0x3C, /* 001111 */
+       0x50, /* 010100 */
+       0x50, /* 010100 */
+       0x78, /* 011110 */
+       0x50, /* 010100 */
+       0x50, /* 010100 */
+       0x5C, /* 010111 */
+       0x00, /* 000000 */
+
+       /* 147 0x93 '\223' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 148 0x94 '\224' */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 149 0x95 '\225' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 150 0x96 '\226' */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 151 0x97 '\227' */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 152 0x98 '\230' */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x04, /* 000001 */
+       0x38, /* 001110 */
+
+       /* 153 0x99 '\231' */
+       0x84, /* 100001 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 154 0x9A '\232' */
+       0x88, /* 100010 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 155 0x9B '\233' */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x50, /* 010100 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 156 0x9C '\234' */
+       0x30, /* 001100 */
+       0x48, /* 010010 */
+       0x40, /* 010000 */
+       0x70, /* 011100 */
+       0x40, /* 010000 */
+       0x44, /* 010001 */
+       0x78, /* 011110 */
+       0x00, /* 000000 */
+
+       /* 157 0x9D '\235' */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 158 0x9E '\236' */
+       0x70, /* 011100 */
+       0x48, /* 010010 */
+       0x70, /* 011100 */
+       0x48, /* 010010 */
+       0x5C, /* 010111 */
+       0x48, /* 010010 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 159 0x9F '\237' */
+       0x0C, /* 000011 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x60, /* 011000 */
+       0x00, /* 000000 */
+
+       /* 160 0xA0 '\240' */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 161 0xA1 '\241' */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x30, /* 001100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 162 0xA2 '\242' */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 163 0xA3 '\243' */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x4C, /* 010011 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 164 0xA4 '\244' */
+       0x34, /* 001101 */
+       0x58, /* 010110 */
+       0x00, /* 000000 */
+       0x58, /* 010110 */
+       0x64, /* 011001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 165 0xA5 '\245' */
+       0x58, /* 010110 */
+       0x44, /* 010001 */
+       0x64, /* 011001 */
+       0x54, /* 010101 */
+       0x4C, /* 010011 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 166 0xA6 '\246' */
+       0x38, /* 001110 */
+       0x04, /* 000001 */
+       0x3C, /* 001111 */
+       0x44, /* 010001 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 167 0xA7 '\247' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 168 0xA8 '\250' */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x40, /* 010000 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 169 0xA9 '\251' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 170 0xAA '\252' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x04, /* 000001 */
+       0x04, /* 000001 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 171 0xAB '\253' */
+       0x20, /* 001000 */
+       0x24, /* 001001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x44, /* 010001 */
+       0x08, /* 000010 */
+       0x1C, /* 000111 */
+
+       /* 172 0xAC '\254' */
+       0x20, /* 001000 */
+       0x24, /* 001001 */
+       0x28, /* 001010 */
+       0x10, /* 000100 */
+       0x28, /* 001010 */
+       0x58, /* 010110 */
+       0x3C, /* 001111 */
+       0x08, /* 000010 */
+
+       /* 173 0xAD '\255' */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+
+       /* 174 0xAE '\256' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x24, /* 001001 */
+       0x48, /* 010010 */
+       0x90, /* 100100 */
+       0x48, /* 010010 */
+       0x24, /* 001001 */
+       0x00, /* 000000 */
+
+       /* 175 0xAF '\257' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x90, /* 100100 */
+       0x48, /* 010010 */
+       0x24, /* 001001 */
+       0x48, /* 010010 */
+       0x90, /* 100100 */
+       0x00, /* 000000 */
+
+       /* 176 0xB0 '\260' */
+       0x10, /* 000100 */
+       0x44, /* 010001 */
+       0x10, /* 000100 */
+       0x44, /* 010001 */
+       0x10, /* 000100 */
+       0x44, /* 010001 */
+       0x10, /* 000100 */
+       0x44, /* 010001 */
+
+       /* 177 0xB1 '\261' */
+       0xA8, /* 101010 */
+       0x54, /* 010101 */
+       0xA8, /* 101010 */
+       0x54, /* 010101 */
+       0xA8, /* 101010 */
+       0x54, /* 010101 */
+       0xA8, /* 101010 */
+       0x54, /* 010101 */
+
+       /* 178 0xB2 '\262' */
+       0xDC, /* 110111 */
+       0x74, /* 011101 */
+       0xDC, /* 110111 */
+       0x74, /* 011101 */
+       0xDC, /* 110111 */
+       0x74, /* 011101 */
+       0xDC, /* 110111 */
+       0x74, /* 011101 */
+
+       /* 179 0xB3 '\263' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 180 0xB4 '\264' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 181 0xB5 '\265' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 182 0xB6 '\266' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xE8, /* 111010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 183 0xB7 '\267' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xF8, /* 111110 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 184 0xB8 '\270' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 185 0xB9 '\271' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xE8, /* 111010 */
+       0x08, /* 000010 */
+       0xE8, /* 111010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 186 0xBA '\272' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 187 0xBB '\273' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xF8, /* 111110 */
+       0x08, /* 000010 */
+       0xE8, /* 111010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 188 0xBC '\274' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xE8, /* 111010 */
+       0x08, /* 000010 */
+       0xF8, /* 111110 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 189 0xBD '\275' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xF8, /* 111110 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 190 0xBE '\276' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 191 0xBF '\277' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xF0, /* 111100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 192 0xC0 '\300' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 193 0xC1 '\301' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 194 0xC2 '\302' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 195 0xC3 '\303' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 196 0xC4 '\304' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 197 0xC5 '\305' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xFC, /* 111111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 198 0xC6 '\306' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 199 0xC7 '\307' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x2C, /* 001011 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 200 0xC8 '\310' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x2C, /* 001011 */
+       0x20, /* 001000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 201 0xC9 '\311' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x3C, /* 001111 */
+       0x20, /* 001000 */
+       0x2C, /* 001011 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 202 0xCA '\312' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xEC, /* 111011 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 203 0xCB '\313' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0xEC, /* 111011 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 204 0xCC '\314' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x2C, /* 001011 */
+       0x20, /* 001000 */
+       0x2C, /* 001011 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 205 0xCD '\315' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 206 0xCE '\316' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xEC, /* 111011 */
+       0x00, /* 000000 */
+       0xEC, /* 111011 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 207 0xCF '\317' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 208 0xD0 '\320' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 209 0xD1 '\321' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 210 0xD2 '\322' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 211 0xD3 '\323' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 212 0xD4 '\324' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 213 0xD5 '\325' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 214 0xD6 '\326' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x3C, /* 001111 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 215 0xD7 '\327' */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0xFC, /* 111111 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+
+       /* 216 0xD8 '\330' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xFC, /* 111111 */
+       0x10, /* 000100 */
+       0xFC, /* 111111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 217 0xD9 '\331' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0xF0, /* 111100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 218 0xDA '\332' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x1C, /* 000111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 219 0xDB '\333' */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+
+       /* 220 0xDC '\334' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+
+       /* 221 0xDD '\335' */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+       0xE0, /* 111000 */
+
+       /* 222 0xDE '\336' */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+       0x1C, /* 000111 */
+
+       /* 223 0xDF '\337' */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 224 0xE0 '\340' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x34, /* 001101 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x34, /* 001101 */
+       0x00, /* 000000 */
+
+       /* 225 0xE1 '\341' */
+       0x24, /* 001001 */
+       0x44, /* 010001 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x58, /* 010110 */
+       0x40, /* 010000 */
+
+       /* 226 0xE2 '\342' */
+       0x7C, /* 011111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+
+       /* 227 0xE3 '\343' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x28, /* 001010 */
+       0x00, /* 000000 */
+
+       /* 228 0xE4 '\344' */
+       0x7C, /* 011111 */
+       0x24, /* 001001 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x24, /* 001001 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 229 0xE5 '\345' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x3C, /* 001111 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+
+       /* 230 0xE6 '\346' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x74, /* 011101 */
+       0x40, /* 010000 */
+
+       /* 231 0xE7 '\347' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x0C, /* 000011 */
+       0x00, /* 000000 */
+
+       /* 232 0xE8 '\350' */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 233 0xE9 '\351' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x7C, /* 011111 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 234 0xEA '\352' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x28, /* 001010 */
+       0x6C, /* 011011 */
+       0x00, /* 000000 */
+
+       /* 235 0xEB '\353' */
+       0x18, /* 000110 */
+       0x20, /* 001000 */
+       0x18, /* 000110 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x24, /* 001001 */
+       0x18, /* 000110 */
+       0x00, /* 000000 */
+
+       /* 236 0xEC '\354' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 237 0xED '\355' */
+       0x00, /* 000000 */
+       0x04, /* 000001 */
+       0x38, /* 001110 */
+       0x54, /* 010101 */
+       0x54, /* 010101 */
+       0x38, /* 001110 */
+       0x40, /* 010000 */
+       0x00, /* 000000 */
+
+       /* 238 0xEE '\356' */
+       0x3C, /* 001111 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x38, /* 001110 */
+       0x40, /* 010000 */
+       0x40, /* 010000 */
+       0x3C, /* 001111 */
+       0x00, /* 000000 */
+
+       /* 239 0xEF '\357' */
+       0x38, /* 001110 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x44, /* 010001 */
+       0x00, /* 000000 */
+
+       /* 240 0xF0 '\360' */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0xFC, /* 111111 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 241 0xF1 '\361' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x7C, /* 011111 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+
+       /* 242 0xF2 '\362' */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 243 0xF3 '\363' */
+       0x08, /* 000010 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x10, /* 000100 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 244 0xF4 '\364' */
+       0x0C, /* 000011 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+
+       /* 245 0xF5 '\365' */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x10, /* 000100 */
+       0x60, /* 011000 */
+
+       /* 246 0xF6 '\366' */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x7C, /* 011111 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 247 0xF7 '\367' */
+       0x00, /* 000000 */
+       0x20, /* 001000 */
+       0x54, /* 010101 */
+       0x08, /* 000010 */
+       0x20, /* 001000 */
+       0x54, /* 010101 */
+       0x08, /* 000010 */
+       0x00, /* 000000 */
+
+       /* 248 0xF8 '\370' */
+       0x30, /* 001100 */
+       0x48, /* 010010 */
+       0x48, /* 010010 */
+       0x30, /* 001100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 249 0xF9 '\371' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x38, /* 001110 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 250 0xFA '\372' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x10, /* 000100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 251 0xFB '\373' */
+       0x04, /* 000001 */
+       0x08, /* 000010 */
+       0x08, /* 000010 */
+       0x50, /* 010100 */
+       0x50, /* 010100 */
+       0x20, /* 001000 */
+       0x20, /* 001000 */
+       0x00, /* 000000 */
+
+       /* 252 0xFC '\374' */
+       0x60, /* 011000 */
+       0x50, /* 010100 */
+       0x50, /* 010100 */
+       0x50, /* 010100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 253 0xFD '\375' */
+       0x60, /* 011000 */
+       0x10, /* 000100 */
+       0x20, /* 001000 */
+       0x70, /* 011100 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+
+       /* 254 0xFE '\376' */
+       0x00, /* 000000 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x38, /* 001110 */
+       0x00, /* 000000 */
+
+       /* 255 0xFF '\377' */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+       0x00, /* 000000 */
+};
+
+const struct font_desc font_6x8 = {
+       .idx    = FONT6x8_IDX,
+       .name   = "6x8",
+       .width  = 6,
+       .height = 8,
+       .data   = fontdata_6x8,
+       .pref   = 0,
+};
index e7258d8c252b272b56222ca662ccb197f3bbdf23..5f4b07b56cd9c1db3ac68425aa1439671df801a3 100644 (file)
@@ -57,6 +57,9 @@ static const struct font_desc *fonts[] = {
 #ifdef CONFIG_FONT_TER16x32
        &font_ter_16x32,
 #endif
+#ifdef CONFIG_FONT_6x8
+       &font_6x8,
+#endif
 };
 
 #define num_fonts ARRAY_SIZE(fonts)