Merge tag 'drm-misc-next-2020-02-10' of git://anongit.freedesktop.org/drm/drm-misc...
authorDave Airlie <airlied@redhat.com>
Thu, 20 Feb 2020 05:21:02 +0000 (15:21 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 20 Feb 2020 19:44:40 +0000 (05:44 +1000)
drm-misc-next for 5.7:

UAPI Changes:
  - lima: Add support for heap buffers

Cross-subsystem Changes:

Core Changes:
  - Implement mode_config mode_valid for memory constrained drivers
  - Bus format negociation between bridges
  - Consolidate fake vblank events for drivers without vblank interrupts
  - drm/bufs: dma_alloc related cleanups
  - drm/dp_mst: Various fixes
  - drm/print: New drm_device based print helpers
  - Thomas is a drm-misc maintainer now!

Driver Changes:
  - DPMS cleanups for atomic drivers
  - Removal of owner field in SPI tinydrm drivers
  - Removal of explicit dependency on DT for tinydrm drivers
  - Conversion to YAML schemas for DT bindings
  - tidss: New driver
  - virtio: various reworks and fixes
  - Our usual dozen or so new panels or bridges

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20200210093421.xu4sofldm6wm6xq6@gilmour.lan
261 files changed:
Documentation/devicetree/bindings/display/bridge/ps8640.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/ilitek,ili9486.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/auo,b080uan01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,b101aw03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,b101ean01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,b101xtn01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,b116xw03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,b133htn01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,b133xtn01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,g133han01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,g185han01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,p320hvn03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/auo,t215hvn01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/avic,tm070ddh03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt [deleted file]
Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt [deleted file]
Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt [deleted file]
Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/cdtech,s043wq26h-ct7.txt [deleted file]
Documentation/devicetree/bindings/display/panel/cdtech,s070wv95-ct16.txt [deleted file]
Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt [deleted file]
Documentation/devicetree/bindings/display/panel/chunghwa,claa101wa01a.txt [deleted file]
Documentation/devicetree/bindings/display/panel/chunghwa,claa101wb03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt [deleted file]
Documentation/devicetree/bindings/display/panel/dlc,dlc1010gig.txt [deleted file]
Documentation/devicetree/bindings/display/panel/edt,et-series.txt [deleted file]
Documentation/devicetree/bindings/display/panel/evervision,vgg804821.txt [deleted file]
Documentation/devicetree/bindings/display/panel/feixin,k101-im2ba02.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/foxlink,fl500wvr00-a0t.txt [deleted file]
Documentation/devicetree/bindings/display/panel/friendlyarm,hd702e.txt [deleted file]
Documentation/devicetree/bindings/display/panel/giantplus,gpg482739qs5.txt [deleted file]
Documentation/devicetree/bindings/display/panel/hannstar,hsd070pww1.txt [deleted file]
Documentation/devicetree/bindings/display/panel/hannstar,hsd100pxn1.txt [deleted file]
Documentation/devicetree/bindings/display/panel/hit,tx23d38vm0caa.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,at043tn24.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,at070tn92.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,g101ice-l01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,g121i1-l01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,g121x1-l03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,n116bge.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,n156bge-l21.txt [deleted file]
Documentation/devicetree/bindings/display/panel/innolux,zj070na-01p.txt [deleted file]
Documentation/devicetree/bindings/display/panel/koe,tx14d24vm1bpa.txt [deleted file]
Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt [deleted file]
Documentation/devicetree/bindings/display/panel/kyo,tcg121xglp.txt [deleted file]
Documentation/devicetree/bindings/display/panel/lemaker,bl035-rgb-002.txt [deleted file]
Documentation/devicetree/bindings/display/panel/lg,lb070wv8.txt [deleted file]
Documentation/devicetree/bindings/display/panel/lg,lp079qx1-sp0v.txt [deleted file]
Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt [deleted file]
Documentation/devicetree/bindings/display/panel/lg,lp120up1.txt [deleted file]
Documentation/devicetree/bindings/display/panel/lg,lp129qe.txt [deleted file]
Documentation/devicetree/bindings/display/panel/mitsubishi,aa070mc01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/nec,nl12880b20-05.txt [deleted file]
Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt [deleted file]
Documentation/devicetree/bindings/display/panel/netron-dy,e231732.txt [deleted file]
Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt [deleted file]
Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt [deleted file]
Documentation/devicetree/bindings/display/panel/nvd,9128.txt [deleted file]
Documentation/devicetree/bindings/display/panel/okaya,rs800480t-7x0gp.txt [deleted file]
Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt [deleted file]
Documentation/devicetree/bindings/display/panel/ontat,yx700wv03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt [deleted file]
Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/ortustech,com37h3m05dtc.txt [deleted file]
Documentation/devicetree/bindings/display/panel/ortustech,com37h3m99dtc.txt [deleted file]
Documentation/devicetree/bindings/display/panel/ortustech,com43h4m85ulc.txt [deleted file]
Documentation/devicetree/bindings/display/panel/osddisplays,osd070t1718-19ts.txt [deleted file]
Documentation/devicetree/bindings/display/panel/osddisplays,osd101t2045-53ts.txt [deleted file]
Documentation/devicetree/bindings/display/panel/panasonic,vvx10f004b00.txt [deleted file]
Documentation/devicetree/bindings/display/panel/panasonic,vvx10f034n00.txt [deleted file]
Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/panel-simple.yaml
Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt [deleted file]
Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt [deleted file]
Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt [deleted file]
Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/samsung,ltn101nt05.txt [deleted file]
Documentation/devicetree/bindings/display/panel/samsung,ltn140at29-301.txt [deleted file]
Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams452ef01.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt [deleted file]
Documentation/devicetree/bindings/display/panel/sharp,lq070y3dg3b.txt [deleted file]
Documentation/devicetree/bindings/display/panel/sharp,lq101k1ly04.txt [deleted file]
Documentation/devicetree/bindings/display/panel/sharp,lq123p1jx31.txt [deleted file]
Documentation/devicetree/bindings/display/panel/shelly,sca07010-bfn-lnn.txt [deleted file]
Documentation/devicetree/bindings/display/panel/starry,kr122ea0sra.txt [deleted file]
Documentation/devicetree/bindings/display/panel/tianma,tm070jdhg30.txt [deleted file]
Documentation/devicetree/bindings/display/panel/tianma,tm070rvhg71.txt [deleted file]
Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt [deleted file]
Documentation/devicetree/bindings/display/panel/tpk,f07a-0102.txt [deleted file]
Documentation/devicetree/bindings/display/panel/tpk,f10a-0102.txt [deleted file]
Documentation/devicetree/bindings/display/panel/urt,umsh-8596md.txt [deleted file]
Documentation/devicetree/bindings/display/panel/vl050_8048nt_c01.txt [deleted file]
Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt [deleted file]
Documentation/devicetree/bindings/display/sitronix,st7735r.txt [deleted file]
Documentation/devicetree/bindings/display/sitronix,st7735r.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/gpu/todo.rst
MAINTAINERS
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/arc/arcpgu_crtc.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/Makefile
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/parade-ps8640.c [new file with mode: 0644]
drivers/gpu/drm/cirrus/cirrus.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_atomic_state_helper.c
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_bridge.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_crtc_internal.h
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_debugfs_crc.c
drivers/gpu/drm/drm_dma.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_file.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_gem_vram_helper.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_mipi_dbi.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/drm_vblank.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/vlv_dsi.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_switcheroo.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/lima/lima_drv.c
drivers/gpu/drm/lima/lima_drv.h
drivers/gpu/drm/lima/lima_gem.c
drivers/gpu/drm/lima/lima_gem.h
drivers/gpu/drm/lima/lima_gp.c
drivers/gpu/drm/lima/lima_mmu.c
drivers/gpu/drm/lima/lima_mmu.h
drivers/gpu/drm/lima/lima_regs.h
drivers/gpu/drm/lima/lima_sched.c
drivers/gpu/drm/lima/lima_sched.h
drivers/gpu/drm/lima/lima_vm.c
drivers/gpu/drm/lima/lima_vm.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_vga.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/panel/panel-tpo-td028ttec1.c
drivers/gpu/drm/panfrost/panfrost_gpu.c
drivers/gpu/drm/panfrost/panfrost_job.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/rcar-du/rcar_lvds.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
drivers/gpu/drm/stm/ltdc.c
drivers/gpu/drm/stm/ltdc.h
drivers/gpu/drm/tidss/Kconfig [new file with mode: 0644]
drivers/gpu/drm/tidss/Makefile [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_crtc.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_crtc.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_dispc.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_dispc.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_dispc_regs.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_drv.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_drv.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_encoder.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_encoder.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_irq.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_irq.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_kms.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_kms.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_plane.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_plane.h [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_scale_coefs.c [new file with mode: 0644]
drivers/gpu/drm/tidss/tidss_scale_coefs.h [new file with mode: 0644]
drivers/gpu/drm/tiny/Kconfig
drivers/gpu/drm/tiny/Makefile
drivers/gpu/drm/tiny/gm12u320.c
drivers/gpu/drm/tiny/ili9225.c
drivers/gpu/drm/tiny/ili9486.c [new file with mode: 0644]
drivers/gpu/drm/tiny/repaper.c
drivers/gpu/drm/tiny/st7586.c
drivers/gpu/drm/tiny/st7735r.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/udl/udl_connector.c
drivers/gpu/drm/udl/udl_modeset.c
drivers/gpu/drm/vboxvideo/vbox_mode.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/virtio/virtgpu_debugfs.c
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_kms.c
drivers/gpu/drm/virtio/virtgpu_vq.c
drivers/gpu/drm/vkms/vkms_plane.c
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
drivers/gpu/drm/xen/xen_drm_front_kms.c
drivers/gpu/drm/zte/zx_plane.c
drivers/video/backlight/Kconfig
drivers/video/console/Kconfig
drivers/video/fbdev/cg14.c
drivers/video/fbdev/core/Makefile
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/hyperv_fb.c
drivers/video/fbdev/nvidia/nvidia.c
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/pxa168fb.c
drivers/video/fbdev/s1d13xxxfb.c
drivers/video/fbdev/sa1100fb.c
drivers/video/fbdev/ssd1307fb.c
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_atomic_state_helper.h
include/drm/drm_bridge.h
include/drm/drm_connector.h
include/drm/drm_crtc.h
include/drm/drm_device.h
include/drm/drm_dp_helper.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_drv.h
include/drm/drm_file.h
include/drm/drm_gem_vram_helper.h
include/drm/drm_legacy.h
include/drm/drm_mipi_dbi.h
include/drm/drm_panel.h
include/drm/drm_print.h
include/drm/drm_simple_kms_helper.h
include/drm/drm_vblank.h
include/drm/ttm/ttm_bo_driver.h
include/uapi/drm/drm.h
include/uapi/drm/lima_drm.h
include/video/samsung_fimd.h

diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml
new file mode 100644 (file)
index 0000000..5dff936
--- /dev/null
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ps8640.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MIPI DSI to eDP Video Format Converter Device Tree Bindings
+
+maintainers:
+  - Nicolas Boichat <drinkcat@chromium.org>
+  - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+  The PS8640 is a low power MIPI-to-eDP video format converter supporting
+  mobile devices with embedded panel resolutions up to 2048 x 1536. The
+  device accepts a single channel of MIPI DSI v1.1, with up to four lanes
+  plus clock, at a transmission rate up to 1.5Gbit/sec per lane. The
+  device outputs eDP v1.4, one or two lanes, at a link rate of up to
+  3.24Gbit/sec per lane.
+
+properties:
+  compatible:
+    const: parade,ps8640
+
+  reg:
+    maxItems: 1
+    description: Base I2C address of the device.
+
+  powerdown-gpios:
+    maxItems: 1
+    description: GPIO connected to active low powerdown.
+
+  reset-gpios:
+    maxItems: 1
+    description: GPIO connected to active low reset.
+
+  vdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+
+  vdd33-supply:
+    maxItems: 1
+    description: Regulator for 3.3V digital core power.
+
+  ports:
+    type: object
+    description:
+      A node containing DSI input & output port nodes with endpoint
+      definitions as documented in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+      Documentation/devicetree/bindings/graph.txt
+    properties:
+      port@0:
+        type: object
+        description: |
+          Video port for DSI input
+
+      port@1:
+        type: object
+        description: |
+          Video port for eDP output (panel or connector).
+
+    required:
+      - port@0
+
+required:
+  - compatible
+  - reg
+  - powerdown-gpios
+  - reset-gpios
+  - vdd12-supply
+  - vdd33-supply
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ps8640: edp-bridge@18 {
+            compatible = "parade,ps8640";
+            reg = <0x18>;
+            powerdown-gpios = <&pio 116 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&pio 115 GPIO_ACTIVE_LOW>;
+            vdd12-supply = <&ps8640_fixed_1v2>;
+            vdd33-supply = <&mt6397_vgp2_reg>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    ps8640_in: endpoint {
+                        remote-endpoint = <&dsi0_out>;
+                    };
+                };
+
+                port@1 {
+                    reg = <1>;
+                    ps8640_out: endpoint {
+                        remote-endpoint = <&panel_in>;
+                   };
+                };
+            };
+        };
+    };
+
diff --git a/Documentation/devicetree/bindings/display/ilitek,ili9486.yaml b/Documentation/devicetree/bindings/display/ilitek,ili9486.yaml
new file mode 100644 (file)
index 0000000..66e93e5
--- /dev/null
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/ilitek,ili9486.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ilitek ILI9486 display panels device tree bindings
+
+maintainers:
+  - Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
+
+description:
+  This binding is for display panels using an Ilitek ILI9486 controller in SPI
+  mode.
+
+allOf:
+  - $ref: panel/panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          # Waveshare 3.5" 320x480 Color TFT LCD
+        - waveshare,rpi-lcd-35
+          # Ozzmaker 3.5" 320x480 Color TFT LCD
+        - ozzmaker,piscreen
+      - const: ilitek,ili9486
+
+  spi-max-frequency:
+    maximum: 32000000
+
+  dc-gpios:
+    maxItems: 1
+    description: Display data/command selection (D/CX)
+
+  backlight: true
+  reg: true
+  reset-gpios: true
+  rotation: true
+
+required:
+  - compatible
+  - reg
+  - dc-gpios
+  - reset-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    backlight: backlight {
+            compatible = "gpio-backlight";
+            gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
+    };
+    spi {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+
+            display@0{
+                    compatible = "waveshare,rpi-lcd-35", "ilitek,ili9486";
+                    reg = <0>;
+                    spi-max-frequency = <32000000>;
+                    dc-gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+                    reset-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
+                    rotation = <180>;
+                    backlight = <&backlight>;
+            };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b080uan01.txt b/Documentation/devicetree/bindings/display/panel/auo,b080uan01.txt
deleted file mode 100644 (file)
index bae0e2b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 8.0" WUXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101ean01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/display/panel/auo,b101aw03.txt
deleted file mode 100644 (file)
index 72e088a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 10.1" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101aw03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b101ean01.txt b/Documentation/devicetree/bindings/display/panel/auo,b101ean01.txt
deleted file mode 100644 (file)
index 3590b07..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 10.1" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101ean01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b101xtn01.txt b/Documentation/devicetree/bindings/display/panel/auo,b101xtn01.txt
deleted file mode 100644 (file)
index 889d511..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b101xtn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b116xw03.txt b/Documentation/devicetree/bindings/display/panel/auo,b116xw03.txt
deleted file mode 100644 (file)
index 690d0a5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel
-
-Required properties:
-- compatible: should be "auo,b116xw03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b133htn01.txt b/Documentation/devicetree/bindings/display/panel/auo,b133htn01.txt
deleted file mode 100644 (file)
index 302226b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
-
-Required properties:
-- compatible: should be "auo,b133htn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,b133xtn01.txt b/Documentation/devicetree/bindings/display/panel/auo,b133xtn01.txt
deleted file mode 100644 (file)
index 7443b7c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,b133xtn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt b/Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt
deleted file mode 100644 (file)
index 49e4105..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-AU Optronics Corporation 7.0" FHD (800 x 480) TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,g070vvn01"
-- backlight: phandle of the backlight device attached to the panel
-- power-supply: single regulator to provide the supply voltage
-
-Required nodes:
-- port: Parallel port mapping to connect this display
-
-This panel needs single power supply voltage. Its backlight is conntrolled
-via PWM signal.
-
-Example:
---------
-
-Example device-tree definition when connected to iMX6Q based board
-
-       lcd_panel: lcd-panel {
-               compatible = "auo,g070vvn01";
-               backlight = <&backlight_lcd>;
-               power-supply = <&reg_display>;
-
-               port {
-                       lcd_panel_in: endpoint {
-                               remote-endpoint = <&lcd_display_out>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt b/Documentation/devicetree/bindings/display/panel/auo,g101evn010.txt
deleted file mode 100644 (file)
index bc6a0c8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-AU Optronics Corporation 10.1" (1280x800) color TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,g101evn010"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt b/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt
deleted file mode 100644 (file)
index 85626ed..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-AU Optronics Corporation 10.4" (800x600) color TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,g104sn02"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g133han01.txt b/Documentation/devicetree/bindings/display/panel/auo,g133han01.txt
deleted file mode 100644 (file)
index 3afc767..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,g133han01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,g185han01.txt b/Documentation/devicetree/bindings/display/panel/auo,g185han01.txt
deleted file mode 100644 (file)
index ed657c2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,g185han01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,p320hvn03.txt b/Documentation/devicetree/bindings/display/panel/auo,p320hvn03.txt
deleted file mode 100644 (file)
index 59bb6cd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,p320hvn03"
-- power-supply: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/auo,t215hvn01.txt b/Documentation/devicetree/bindings/display/panel/auo,t215hvn01.txt
deleted file mode 100644 (file)
index cbd9da3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel
-
-Required properties:
-- compatible: should be "auo,t215hvn01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/avic,tm070ddh03.txt b/Documentation/devicetree/bindings/display/panel/avic,tm070ddh03.txt
deleted file mode 100644 (file)
index b6f2f3e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
-
-Required properties:
-- compatible: should be "avic,tm070ddh03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt
deleted file mode 100644 (file)
index 55183d3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-BOE HV070WSA-100 7.01" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "boe,hv070wsa-100"
-- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
-- enable-gpios: GPIO pin to enable and disable panel (active high)
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
-
-The device node can contain one 'port' child node with one child
-'endpoint' node, according to the bindings defined in [1]. This
-node should describe panel's video bus.
-
-[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
-
-Example:
-
-       panel: panel {
-               compatible = "boe,hv070wsa-100";
-               power-supply = <&vcc_3v3_reg>;
-               enable-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>;
-               port {
-                       panel_ep: endpoint {
-                               remote-endpoint = <&bridge_out_ep>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt b/Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt
deleted file mode 100644 (file)
index b258d6a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "boe,nv101wxmn51"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt b/Documentation/devicetree/bindings/display/panel/boe,tv080wum-nl0.txt
deleted file mode 100644 (file)
index 50be5e2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Boe Corporation 8.0" WUXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "boe,tv080wum-nl0"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml b/Documentation/devicetree/bindings/display/panel/boe,tv101wum-nl6.yaml
new file mode 100644 (file)
index 0000000..7402134
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/boe,tv101wum-nl6.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: BOE TV101WUM-NL6 DSI Display Panel
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+  - Sam Ravnborg <sam@ravnborg.org>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    enum:
+        # BOE TV101WUM-NL6 10.1" WUXGA TFT LCD panel
+      - boe,tv101wum-nl6
+        # AUO KD101N80-45NA 10.1" WUXGA TFT LCD panel
+      - auo,kd101n80-45na
+        # BOE TV101WUM-N53 10.1" WUXGA TFT LCD panel
+      - boe,tv101wum-n53
+        # AUO B101UAN08.3 10.1" WUXGA TFT LCD panel
+      - auo,b101uan08.3
+
+  reg:
+    description: the virtual channel number of a DSI peripheral
+
+  enable-gpios:
+    description: a GPIO spec for the enable pin
+
+  pp1800-supply:
+    description: core voltage supply
+
+  avdd-supply:
+    description: phandle of the regulator that provides positive voltage
+
+  avee-supply:
+    description: phandle of the regulator that provides negative voltage
+
+  backlight:
+    description: phandle of the backlight device attached to the panel
+
+  port: true
+
+required:
+ - compatible
+ - reg
+ - enable-gpios
+ - pp1800-supply
+ - avdd-supply
+ - avee-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        panel@0 {
+            compatible = "boe,tv101wum-nl6";
+            reg = <0>;
+            enable-gpios = <&pio 45 0>;
+            avdd-supply = <&ppvarn_lcd>;
+            avee-supply = <&ppvarp_lcd>;
+            pp1800-supply = <&pp1800_lcd>;
+            backlight = <&backlight_lcd0>;
+            status = "okay";
+            port {
+                panel_in: endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/cdtech,s043wq26h-ct7.txt b/Documentation/devicetree/bindings/display/panel/cdtech,s043wq26h-ct7.txt
deleted file mode 100644 (file)
index 057f7f3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-CDTech(H.K.) Electronics Limited 4.3" 480x272 color TFT-LCD panel
-
-Required properties:
-- compatible: should be "cdtech,s043wq26h-ct7"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/cdtech,s070wv95-ct16.txt b/Documentation/devicetree/bindings/display/panel/cdtech,s070wv95-ct16.txt
deleted file mode 100644 (file)
index 505615d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel
-
-Required properties:
-- compatible: should be "cdtech,s070wv95-ct16"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt b/Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt
deleted file mode 100644 (file)
index dd22685..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "chunghwa,claa070wp03xg"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wa01a.txt b/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wa01a.txt
deleted file mode 100644 (file)
index f24614e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "chunghwa,claa101wa01a"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/display/panel/chunghwa,claa101wb03.txt
deleted file mode 100644 (file)
index 0ab2c05..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "chunghwa,claa101wb03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt b/Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt
deleted file mode 100644 (file)
index 897085e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface.
-
-Required properties:
-- compatible: should be "dataimage,scf0700c48ggu18"
-- power-supply: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/dlc,dlc1010gig.txt b/Documentation/devicetree/bindings/display/panel/dlc,dlc1010gig.txt
deleted file mode 100644 (file)
index fbf5dcd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-DLC Display Co. DLC1010GIG 10.1" WXGA TFT LCD Panel
-
-Required properties:
-- compatible: should be "dlc,dlc1010gig"
-- power-supply: See simple-panel.txt
-
-Optional properties:
-- enable-gpios: See simple-panel.txt
-- backlight: See simple-panel.txt
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/edt,et-series.txt b/Documentation/devicetree/bindings/display/panel/edt,et-series.txt
deleted file mode 100644 (file)
index b7ac1c7..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Emerging Display Technology Corp. Displays
-==========================================
-
-
-Display bindings for EDT Display Technology Corp. Displays which are
-compatible with the simple-panel binding, which is specified in
-simple-panel.txt
-
-3,5" QVGA TFT Panels
---------------------
-+-----------------+---------------------+-------------------------------------+
-| Identifier      | compatbile          | description                         |
-+=================+=====================+=====================================+
-| ET035012DM6     | edt,et035012dm6     | 3.5" QVGA TFT LCD panel             |
-+-----------------+---------------------+-------------------------------------+
-
-4,3" WVGA TFT Panels
---------------------
-
-+-----------------+---------------------+-------------------------------------+
-| Identifier      | compatbile          | description                         |
-+=================+=====================+=====================================+
-| ETM0430G0DH6    | edt,etm0430g0dh6    | 480x272 TFT Display                 |
-+-----------------+---------------------+-------------------------------------+
-
-5,7" WVGA TFT Panels
---------------------
-
-+-----------------+---------------------+-------------------------------------+
-| Identifier      | compatbile          | description                         |
-+=================+=====================+=====================================+
-| ET057090DHU     | edt,et057090dhu     | 5.7" VGA TFT LCD panel              |
-+-----------------+---------------------+-------------------------------------+
-
-
-7,0" WVGA TFT Panels
---------------------
-
-+-----------------+---------------------+-------------------------------------+
-| Identifier      | compatbile          | description                         |
-+=================+=====================+=====================================+
-| ETM0700G0DH6    | edt,etm070080dh6    | WVGA TFT Display with capacitive    |
-|                 | edt,etm0700g0dh6    | Touchscreen                         |
-+-----------------+---------------------+-------------------------------------+
-| ETM0700G0BDH6   | edt,etm070080bdh6   | Same as ETM0700G0DH6 but with       |
-|                 |                     | inverted pixel clock.               |
-+-----------------+---------------------+-------------------------------------+
-| ETM0700G0EDH6   | edt,etm070080edh6   | Same display as the ETM0700G0BDH6,  |
-|                 |                     | but with changed Hardware for the   |
-|                 |                     | backlight and the touch interface   |
-+-----------------+---------------------+-------------------------------------+
-| ET070080DH6     | edt,etm070080dh6    | Same timings as the ETM0700G0DH6,   |
-|                 |                     | but with resistive touch.           |
-+-----------------+---------------------+-------------------------------------+
-
diff --git a/Documentation/devicetree/bindings/display/panel/evervision,vgg804821.txt b/Documentation/devicetree/bindings/display/panel/evervision,vgg804821.txt
deleted file mode 100644 (file)
index 82d22e1..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Evervision Electronics Co. Ltd. VGG804821 5.0" WVGA TFT LCD Panel
-
-Required properties:
-- compatible: should be "evervision,vgg804821"
-- power-supply: See simple-panel.txt
-
-Optional properties:
-- backlight: See simple-panel.txt
-- enable-gpios: See simple-panel.txt
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/feixin,k101-im2ba02.yaml b/Documentation/devicetree/bindings/display/panel/feixin,k101-im2ba02.yaml
new file mode 100644 (file)
index 0000000..927f1ee
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/feixin,k101-im2ba02.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Feixin K101 IM2BA02 10.1" MIPI-DSI LCD panel
+
+maintainers:
+  - Icenowy Zheng <icenowy@aosc.io>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    const: feixin,k101-im2ba02
+  reg: true
+  backlight: true
+  reset-gpios: true
+  avdd-supply:
+     description: regulator that supplies the AVDD voltage
+  dvdd-supply:
+     description: regulator that supplies the DVDD voltage
+  cvdd-supply:
+     description: regulator that supplies the CVDD voltage
+
+required:
+  - compatible
+  - reg
+  - avdd-supply
+  - dvdd-supply
+  - cvdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        panel@0 {
+            compatible = "feixin,k101-im2ba02";
+            reg = <0>;
+            avdd-supply = <&reg_dc1sw>;
+            dvdd-supply = <&reg_dc1sw>;
+            cvdd-supply = <&reg_ldo_io1>;
+            reset-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>;
+            backlight = <&backlight>;
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/display/panel/foxlink,fl500wvr00-a0t.txt b/Documentation/devicetree/bindings/display/panel/foxlink,fl500wvr00-a0t.txt
deleted file mode 100644 (file)
index b47f9d8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Foxlink Group 5" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "foxlink,fl500wvr00-a0t"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/friendlyarm,hd702e.txt b/Documentation/devicetree/bindings/display/panel/friendlyarm,hd702e.txt
deleted file mode 100644 (file)
index 6c9156f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-FriendlyELEC HD702E 800x1280 LCD panel
-
-HD702E lcd is FriendlyELEC developed eDP LCD panel with 800x1280
-resolution. It has built in Goodix, GT9271 captive touchscreen
-with backlight adjustable via PWM.
-
-Required properties:
-- compatible: should be "friendlyarm,hd702e"
-- power-supply: regulator to provide the supply voltage
-
-Optional properties:
-- backlight: phandle of the backlight device attached to the panel
-
-Optional nodes:
-- Video port for LCD panel input.
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
-
-Example:
-
-       panel {
-               compatible ="friendlyarm,hd702e", "simple-panel";
-               backlight = <&backlight>;
-               power-supply = <&vcc3v3_sys>;
-
-               port {
-                       panel_in_edp: endpoint {
-                               remote-endpoint = <&edp_out_panel>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/giantplus,gpg482739qs5.txt b/Documentation/devicetree/bindings/display/panel/giantplus,gpg482739qs5.txt
deleted file mode 100644 (file)
index 24b0b62..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "giantplus,gpg48273qs5"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/hannstar,hsd070pww1.txt b/Documentation/devicetree/bindings/display/panel/hannstar,hsd070pww1.txt
deleted file mode 100644 (file)
index 7da1d5c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "hannstar,hsd070pww1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/hannstar,hsd100pxn1.txt b/Documentation/devicetree/bindings/display/panel/hannstar,hsd100pxn1.txt
deleted file mode 100644 (file)
index 8270319..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel
-
-Required properties:
-- compatible: should be "hannstar,hsd100pxn1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/hit,tx23d38vm0caa.txt b/Documentation/devicetree/bindings/display/panel/hit,tx23d38vm0caa.txt
deleted file mode 100644 (file)
index 04caaae..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
-
-Required properties:
-- compatible: should be "hit,tx23d38vm0caa"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,at043tn24.txt b/Documentation/devicetree/bindings/display/panel/innolux,at043tn24.txt
deleted file mode 100644 (file)
index 4104226..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux AT043TN24 4.3" WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,at043tn24"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,at070tn92.txt b/Documentation/devicetree/bindings/display/panel/innolux,at070tn92.txt
deleted file mode 100644 (file)
index 3e10cd7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux AT070TN92 7.0" WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,at070tn92"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt b/Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt
deleted file mode 100644 (file)
index 7c234cf..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,g070y2-l01"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g101ice-l01.txt b/Documentation/devicetree/bindings/display/panel/innolux,g101ice-l01.txt
deleted file mode 100644 (file)
index 9e75904..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 10.1" G101ICE-L01 WXGA (1280x800) LVDS panel
-
-Required properties:
-- compatible: should be "innolux,g101ice-l01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g121i1-l01.txt b/Documentation/devicetree/bindings/display/panel/innolux,g121i1-l01.txt
deleted file mode 100644 (file)
index 2743b07..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,g121i1-l01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g121x1-l03.txt b/Documentation/devicetree/bindings/display/panel/innolux,g121x1-l03.txt
deleted file mode 100644 (file)
index 6497446..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,g121x1-l03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,n116bge.txt b/Documentation/devicetree/bindings/display/panel/innolux,n116bge.txt
deleted file mode 100644 (file)
index 081bb93..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,n116bge"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,n156bge-l21.txt b/Documentation/devicetree/bindings/display/panel/innolux,n156bge-l21.txt
deleted file mode 100644 (file)
index 7825844..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-InnoLux 15.6" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,n156bge-l21"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,zj070na-01p.txt b/Documentation/devicetree/bindings/display/panel/innolux,zj070na-01p.txt
deleted file mode 100644 (file)
index 824f87f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
-
-Required properties:
-- compatible: should be "innolux,zj070na-01p"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/koe,tx14d24vm1bpa.txt b/Documentation/devicetree/bindings/display/panel/koe,tx14d24vm1bpa.txt
deleted file mode 100644 (file)
index be7ac66..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel
-
-Required properties:
-- compatible: should be "koe,tx14d24vm1bpa"
-- backlight: phandle of the backlight device attached to the panel
-- power-supply: single regulator to provide the supply voltage
-
-Required nodes:
-- port: Parallel port mapping to connect this display
-
-This panel needs single power supply voltage. Its backlight is conntrolled
-via PWM signal.
-
-Example:
---------
-
-Example device-tree definition when connected to iMX53 based board
-
-       lcd_panel: lcd-panel {
-               compatible = "koe,tx14d24vm1bpa";
-               backlight = <&backlight_lcd>;
-               power-supply = <&reg_3v3>;
-
-               port {
-                       lcd_panel_in: endpoint {
-                               remote-endpoint = <&lcd_display_out>;
-                       };
-               };
-       };
-
-Then one needs to extend the dispX node:
-
-       lcd_display: disp1 {
-
-               port@1 {
-                       reg = <1>;
-
-                       lcd_display_out: endpoint {
-                               remote-endpoint = <&lcd_panel_in>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt b/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt
deleted file mode 100644 (file)
index 6a036ed..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS panel
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
-
-Required properties:
-- compatible: should be "koe,tx31d200vm0baa"
-
-Optional properties:
-- backlight: phandle of the backlight device attached to the panel
-
-Optional nodes:
-- Video port for LVDS panel input.
-
-Example:
-       panel {
-               compatible = "koe,tx31d200vm0baa";
-               backlight = <&backlight_lvds>;
-
-               port {
-                       panel_in: endpoint {
-                               remote-endpoint = <&lvds0_out>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/kyo,tcg121xglp.txt b/Documentation/devicetree/bindings/display/panel/kyo,tcg121xglp.txt
deleted file mode 100644 (file)
index a8e940f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Kyocera Corporation 12.1" XGA (1024x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "kyo,tcg121xglp"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lemaker,bl035-rgb-002.txt b/Documentation/devicetree/bindings/display/panel/lemaker,bl035-rgb-002.txt
deleted file mode 100644 (file)
index 74ee7ea..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-LeMaker BL035-RGB-002 3.5" QVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "lemaker,bl035-rgb-002"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lb070wv8.txt b/Documentation/devicetree/bindings/display/panel/lg,lb070wv8.txt
deleted file mode 100644 (file)
index a7588e5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG 7" (800x480 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lb070wv8"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp079qx1-sp0v.txt b/Documentation/devicetree/bindings/display/panel/lg,lp079qx1-sp0v.txt
deleted file mode 100644 (file)
index b9877ac..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG LP079QX1-SP0V 7.9" (1536x2048 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lp079qx1-sp0v"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt b/Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt
deleted file mode 100644 (file)
index 4214151..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG 9.7" (2048x1536 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lp097qx1-spa1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp120up1.txt b/Documentation/devicetree/bindings/display/panel/lg,lp120up1.txt
deleted file mode 100644 (file)
index 8c5de69..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG 12.0" (1920x1280 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lp120up1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/lg,lp129qe.txt b/Documentation/devicetree/bindings/display/panel/lg,lp129qe.txt
deleted file mode 100644 (file)
index 9f262e0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-LG 12.9" (2560x1700 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "lg,lp129qe"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/mitsubishi,aa070mc01.txt b/Documentation/devicetree/bindings/display/panel/mitsubishi,aa070mc01.txt
deleted file mode 100644 (file)
index 7d8f6ee..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "mitsubishi,aa070mc01-ca1"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/nec,nl12880b20-05.txt b/Documentation/devicetree/bindings/display/panel/nec,nl12880b20-05.txt
deleted file mode 100644 (file)
index 71cbc49..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel
-
-Required properties:
-- compatible: should be "nec,nl12880bc20-05"
-- power-supply: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt b/Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt
deleted file mode 100644 (file)
index 8e1914d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "nec,nl4827hc19-05b"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/netron-dy,e231732.txt b/Documentation/devicetree/bindings/display/panel/netron-dy,e231732.txt
deleted file mode 100644 (file)
index c6d06b5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Netron-DY E231732 7.0" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "netron-dy,e231732"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt b/Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt
deleted file mode 100644 (file)
index e78292b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Newhaven Display International 480 x 272 TFT LCD panel
-
-Required properties:
-- compatible: should be "newhaven,nhd-4.3-480272ef-atxl"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt b/Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt
deleted file mode 100644 (file)
index 1a639fd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel
-
-Required properties:
-- compatible: should be "nlt,nl192108ac18-02d"
-- power-supply: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/nvd,9128.txt b/Documentation/devicetree/bindings/display/panel/nvd,9128.txt
deleted file mode 100644 (file)
index 17bcd01..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-New Vision Display 7.0" 800 RGB x 480 TFT LCD panel
-
-Required properties:
-- compatible: should be "nvd,9128"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/okaya,rs800480t-7x0gp.txt b/Documentation/devicetree/bindings/display/panel/okaya,rs800480t-7x0gp.txt
deleted file mode 100644 (file)
index ddf8e21..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel
-
-Required properties:
-- compatible: should be "okaya,rs800480t-7x0gp"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt b/Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt
deleted file mode 100644 (file)
index 74540a0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Olimex 4.3" TFT LCD panel
-
-Required properties:
-- compatible: should be "olimex,lcd-olinuxino-43-ts"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/ontat,yx700wv03.txt b/Documentation/devicetree/bindings/display/panel/ontat,yx700wv03.txt
deleted file mode 100644 (file)
index 3d8a5e0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-On Tat Industrial Company 7" DPI TFT panel.
-
-Required properties:
-- compatible: should be "ontat,yx700wv03"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt
deleted file mode 100644 (file)
index 203b03e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode)
-
-The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using
-a MIPI-DSI video interface. Its backlight is managed through the DSI link.
-
-Required properties:
-  - compatible: "orisetech,otm8009a"
-  - reg: the virtual channel number of a DSI peripheral
-
-Optional properties:
-  - reset-gpios: a GPIO spec for the reset pin (active low).
-  - power-supply: phandle of the regulator that provides the supply voltage.
-
-Example:
-&dsi {
-       ...
-       panel@0 {
-               compatible = "orisetech,otm8009a";
-               reg = <0>;
-               reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>;
-               power-supply = <&v1v8>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml
new file mode 100644 (file)
index 0000000..6e6ac99
--- /dev/null
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/orisetech,otm8009a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode)
+
+maintainers:
+  - Philippe CORNU <philippe.cornu@st.com>
+
+description: |
+             The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using
+             a MIPI-DSI video interface. Its backlight is managed through the DSI link.
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+
+  compatible:
+    const: orisetech,otm8009a
+
+  reg:
+    maxItems: 1
+    description: DSI virtual channel
+
+  enable-gpios: true
+  port: true
+  power-supply: true
+
+  reset-gpios:
+    maxItems: 1
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    dsi@0 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      panel@0 {
+        compatible = "orisetech,otm8009a";
+        reg = <0>;
+        reset-gpios = <&gpiof 15 0>;
+        power-supply = <&v1v8>;
+      };
+    };
+...
+
diff --git a/Documentation/devicetree/bindings/display/panel/ortustech,com37h3m05dtc.txt b/Documentation/devicetree/bindings/display/panel/ortustech,com37h3m05dtc.txt
deleted file mode 100644 (file)
index c16907c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-OrtusTech COM37H3M05DTC Blanview 3.7" VGA portrait TFT-LCD panel
-
-Required properties:
-- compatible: should be "ortustech,com37h3m05dtc"
-
-Optional properties:
-- enable-gpios: GPIO pin to enable or disable the panel
-- backlight: phandle of the backlight device attached to the panel
-- power-supply: phandle of the regulator that provides the supply voltage
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/ortustech,com37h3m99dtc.txt b/Documentation/devicetree/bindings/display/panel/ortustech,com37h3m99dtc.txt
deleted file mode 100644 (file)
index 06a73c3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-OrtusTech COM37H3M99DTC Blanview 3.7" VGA portrait TFT-LCD panel
-
-Required properties:
-- compatible: should be "ortustech,com37h3m99dtc"
-
-Optional properties:
-- enable-gpios: GPIO pin to enable or disable the panel
-- backlight: phandle of the backlight device attached to the panel
-- power-supply: phandle of the regulator that provides the supply voltage
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/ortustech,com43h4m85ulc.txt b/Documentation/devicetree/bindings/display/panel/ortustech,com43h4m85ulc.txt
deleted file mode 100644 (file)
index de19e93..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
-
-Required properties:
-- compatible: should be "ortustech,com43h4m85ulc"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/osddisplays,osd070t1718-19ts.txt b/Documentation/devicetree/bindings/display/panel/osddisplays,osd070t1718-19ts.txt
deleted file mode 100644 (file)
index e57883c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-OSD Displays OSD070T1718-19TS 7" WVGA TFT LCD panel
-
-Required properties:
-- compatible: shall be "osddisplays,osd070t1718-19ts"
-- power-supply: see simple-panel.txt
-
-Optional properties:
-- backlight: see simple-panel.txt
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory. No other simple-panel properties than
-the ones specified herein are valid.
diff --git a/Documentation/devicetree/bindings/display/panel/osddisplays,osd101t2045-53ts.txt b/Documentation/devicetree/bindings/display/panel/osddisplays,osd101t2045-53ts.txt
deleted file mode 100644 (file)
index 85c0b2c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel
-
-Required properties:
-- compatible: should be "osddisplays,osd101t2045-53ts"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f004b00.txt
deleted file mode 100644 (file)
index d328b03..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Panasonic Corporation 10.1" WUXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "panasonic,vvx10f004b00"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f034n00.txt b/Documentation/devicetree/bindings/display/panel/panasonic,vvx10f034n00.txt
deleted file mode 100644 (file)
index 37dedf6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-Panasonic 10" WUXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "panasonic,vvx10f034n00"
-- reg: DSI virtual channel of the peripheral
-- power-supply: phandle of the regulator that provides the supply voltage
-
-Optional properties:
-- backlight: phandle of the backlight device attached to the panel
-
-Example:
-
-       mdss_dsi@fd922800 {
-               panel@0 {
-                       compatible = "panasonic,vvx10f034n00";
-                       reg = <0>;
-                       power-supply = <&vreg_vsp>;
-                       backlight = <&lp8566_wled>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
new file mode 100644 (file)
index 0000000..8b60368
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/panel-simple-dsi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Simple DSI panels with a single power-supply
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+  - Sam Ravnborg <sam@ravnborg.org>
+
+description: |
+  This binding file is a collection of the DSI panels that
+  requires only a single power-supply.
+  There are optionally a backlight and an enable GPIO.
+  The panel may use an OF graph binding for the association to the display,
+  or it may be a direct child node of the display.
+
+  If the panel is more advanced a dedicated binding file is required.
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+
+  compatible:
+    enum:
+      # compatible must be listed in alphabetical order, ordered by compatible.
+      # The description in the comment is mandatory for each compatible.
+
+        # Panasonic 10" WUXGA TFT LCD panel
+      - panasonic,vvx10f034n00
+
+  reg:
+    maxItems: 1
+    description: DSI virtual channel
+
+  backlight: true
+  enable-gpios: true
+  port: true
+  power-supply: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - power-supply
+  - reg
+
+examples:
+  - |
+    mdss_dsi@fd922800 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      panel@0 {
+        compatible = "panasonic,vvx10f034n00";
+        reg = <0>;
+        power-supply = <&vcc_lcd_reg>;
+
+        port {
+          panel: endpoint {
+            remote-endpoint = <&ltdc_out>;
+          };
+        };
+      };
+    };
index 8fe60ee..cf23b0a 100644 (file)
@@ -33,16 +33,221 @@ properties:
       - ampire,am-480272h3tmqw-t01h
         # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
       - ampire,am800480r3tmqwa1h
+        # AU Optronics Corporation 8.0" WUXGA TFT LCD panel
+      - auo,b080uan01
+        # AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+      - auo,b101aw03
+        # AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+      - auo,b101ean01
+        # AU Optronics Corporation 10.1" WXGA TFT LCD panel
+      - auo,b101xtn01
         # AUO B116XAK01 eDP TFT LCD panel
       - auo,b116xa01
+        # AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel
+      - auo,b116xw03
+        # AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
+      - auo,b133htn01
+        # AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel
+      - auo,b133xtn01
+        # AU Optronics Corporation 7.0" FHD (800 x 480) TFT LCD panel
+      - auo,g070vvn01
+        # AU Optronics Corporation 10.1" (1280x800) color TFT LCD panel
+      - auo,g101evn010
+        # AU Optronics Corporation 10.4" (800x600) color TFT LCD panel
+      - auo,g104sn02
+        # AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel
+      - auo,g133han01
+        # AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel
+      - auo,g185han01
+        # AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel
+      - auo,p320hvn03
+        # AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel
+      - auo,t215hvn01
+        # Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
+      - avic,tm070ddh03
+        # BOE HV070WSA-100 7.01" WSVGA TFT LCD panel
+      - boe,hv070wsa-100
+        # BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel
+      - boe,nv101wxmn51
         # BOE NV140FHM-N49 14.0" FHD a-Si FT panel
       - boe,nv140fhmn49
+        # Boe Corporation 8.0" WUXGA TFT LCD panel
+      - boe,tv080wum-nl0
+        # CDTech(H.K.) Electronics Limited 4.3" 480x272 color TFT-LCD panel
+      - cdtech,s043wq26h-ct7
+        # CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel
+      - cdtech,s070wv95-ct16
+        # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
+      - chunghwa,claa070wp03xg
+        # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
+      - chunghwa,claa101wa01a
+        # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
+      - chunghwa,claa101wb03
+        # DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface.
+      - dataimage,scf0700c48ggu18
+        # DLC Display Co. DLC1010GIG 10.1" WXGA TFT LCD Panel
+      - dlc,dlc1010gig
+        # Emerging Display Technology Corp. 3.5" QVGA TFT LCD panel
+      - edt,et035012dm6
+        # Emerging Display Technology Corp. 480x272 TFT Display with capacitive touch
+      - edt,etm043080dh6gp
+        # Emerging Display Technology Corp. 480x272 TFT Display
+      - edt,etm0430g0dh6
+        # Emerging Display Technology Corp. 5.7" VGA TFT LCD panel
+      - edt,et057090dhu
+        # Emerging Display Technology Corp. WVGA TFT Display with capacitive touch
+      - edt,etm070080dh6
+        # Emerging Display Technology Corp. WVGA TFT Display with capacitive touch
+      - edt,etm0700g0dh6
+        # Emerging Display Technology Corp. WVGA TFT Display with capacitive touch
+        # Same as ETM0700G0DH6 but with inverted pixel clock.
+      - edt,etm070080bdh6
+        # Emerging Display Technology Corp. WVGA TFT Display with capacitive touch
+        # Same display as the ETM0700G0BDH6, but with changed hardware for the
+        # backlight and the touch interface.
+      - edt,etm070080edh6
+        # Emerging Display Technology Corp. WVGA TFT Display with capacitive touch
+        # Same timings as the ETM0700G0DH6, but with resistive touch.
+      - edt,etm070080dh6
+        # Evervision Electronics Co. Ltd. VGG804821 5.0" WVGA TFT LCD Panel
+      - evervision,vgg804821
+        # Foxlink Group 5" WVGA TFT LCD panel
+      - foxlink,fl500wvr00-a0t
+        # Frida FRD350H54004 3.5" QVGA TFT LCD panel
+      - frida,frd350h54004
+        # FriendlyELEC HD702E 800x1280 LCD panel
+      - friendlyarm,hd702e
+        # GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
+      - giantplus,gpg48273qs5
         # GiantPlus GPM940B0 3.0" QVGA TFT LCD panel
       - giantplus,gpm940b0
+        # HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel
+      - hannstar,hsd070pww1
+        # HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel
+      - hannstar,hsd100pxn1
+        # Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
+      - hit,tx23d38vm0caa
+        # Innolux AT043TN24 4.3" WQVGA TFT LCD panel
+      - innolux,at043tn24
+        # Innolux AT070TN92 7.0" WQVGA TFT LCD panel
+      - innolux,at070tn92
+        # Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel
+      - innolux,g070y2-l01
+        # Innolux Corporation 10.1" G101ICE-L01 WXGA (1280x800) LVDS panel
+      - innolux,g101ice-l01
+        # Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel
+      - innolux,g121i1-l01
+        # Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
+      - innolux,g121x1-l03
+        # Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
+      - innolux,n116bge
+        # InnoLux 15.6" WXGA TFT LCD panel
+      - innolux,n156bge-l21
+        # Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
+      - innolux,zj070na-01p
+        # Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel
+      - koe,tx14d24vm1bpa
+        # Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS panel
+      - koe,tx31d200vm0baa
+        # Kyocera Corporation 12.1" XGA (1024x768) TFT LCD panel
+      - kyo,tcg121xglp
+        # LeMaker BL035-RGB-002 3.5" QVGA TFT LCD panel
+      - lemaker,bl035-rgb-002
+        # LG 7" (800x480 pixels) TFT LCD panel
+      - lg,lb070wv8
+        # LG LP079QX1-SP0V 7.9" (1536x2048 pixels) TFT LCD panel
+      - lg,lp079qx1-sp0v
+        # LG 9.7" (2048x1536 pixels) TFT LCD panel
+      - lg,lp097qx1-spa1
+        # LG 12.0" (1920x1280 pixels) TFT LCD panel
+      - lg,lp120up1
+        # LG 12.9" (2560x1700 pixels) TFT LCD panel
+      - lg,lp129qe
+        # Logic Technologies LT161010-2NHC 7" WVGA TFT Cap Touch Module
+      - logictechno,lt161010-2nhc
+        # Logic Technologies LT161010-2NHR 7" WVGA TFT Resistive Touch Module
+      - logictechno,lt161010-2nhr
+        # Logic Technologies LT170410-2WHC 10.1" 1280x800 IPS TFT Cap Touch Mod.
+      - logictechno,lt170410-2whc
+        # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel
+      - mitsubishi,aa070mc01-ca1
+        # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel
+      - nec,nl12880bc20-05
+        # NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
+      - nec,nl4827hc19-05b
+        # Netron-DY E231732 7.0" WSVGA TFT LCD panel
+      - netron-dy,e231732
+        # Newhaven Display International 480 x 272 TFT LCD panel
+      - newhaven,nhd-4.3-480272ef-atxl
+        # NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel
+      - nlt,nl192108ac18-02d
+        # New Vision Display 7.0" 800 RGB x 480 TFT LCD panel
+      - nvd,9128
+        # OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel
+      - okaya,rs800480t-7x0gp
+        # Olimex 4.3" TFT LCD panel
+      - olimex,lcd-olinuxino-43-ts
+        # On Tat Industrial Company 7" DPI TFT panel.
+      - ontat,yx700wv03
+        # OrtusTech COM37H3M05DTC Blanview 3.7" VGA portrait TFT-LCD panel
+      - ortustech,com37h3m05dtc
+        # OrtusTech COM37H3M99DTC Blanview 3.7" VGA portrait TFT-LCD panel
+      - ortustech,com37h3m99dtc
+        # OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
+      - ortustech,com43h4m85ulc
+        # OSD Displays OSD070T1718-19TS 7" WVGA TFT LCD panel
+      - osddisplays,osd070t1718-19ts
+        # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel
+      - osddisplays,osd101t2045-53ts
+        # QiaoDian XianShi Corporation 4"3 TFT LCD panel
+      - qiaodian,qd43003c0-40
+        # Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel
+      - rocktech,rk070er9427
+        # Samsung 12.2" (2560x1600 pixels) TFT LCD panel
+      - samsung,lsn122dl01-c01
+        # Samsung Electronics 10.1" WSVGA TFT LCD panel
+      - samsung,ltn101nt05
+        # Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
+      - samsung,ltn140at29-301
         # Satoz SAT050AT40H12R2 5.0" WVGA TFT LCD panel
       - satoz,sat050at40h12r2
+        # Sharp LQ035Q7DB03 3.5" QVGA TFT LCD panel
+      - sharp,lq035q7db03
+        # Sharp LQ070Y3DG3B 7.0" WVGA landscape TFT LCD panel
+      - sharp,lq070y3dg3b
+        # Sharp Display Corp. LQ101K1LY04 10.07" WXGA TFT LCD panel
+      - sharp,lq101k1ly04
+        # Sharp 12.3" (2400x1600 pixels) TFT LCD panel
+      - sharp,lq123p1jx31
         # Sharp LS020B1DD01D 2.0" HQVGA TFT LCD panel
       - sharp,ls020b1dd01d
+        # Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
+      - shelly,sca07010-bfn-lnn
+        # Starry 12.2" (1920x1200 pixels) TFT LCD panel
+      - starry,kr122ea0sra
+        # Tianma Micro-electronics TM070JDHG30 7.0" WXGA TFT LCD panel
+      - tianma,tm070jdhg30
+        # Tianma Micro-electronics TM070RVHG71 7.0" WXGA TFT LCD panel
+      - tianma,tm070rvhg71
+        # Toshiba 8.9" WXGA (1280x768) TFT LCD panel
+      - toshiba,lt089ac29000
+        # TPK U.S.A. LLC Fusion 7" 800 x 480 (WVGA) LCD panel with capacitive touch
+      - tpk,f07a-0102
+        # TPK U.S.A. LLC Fusion 10.1" 1024 x 600 (WSVGA) LCD panel with capacitive touch
+      - tpk,f10a-0102
+        # United Radiant Technology UMSH-8596MD-xT 7.0" WVGA TFT LCD panel
+        # Supported are LVDS versions (-11T, -19T) and parallel ones
+        # (-T, -1T, -7T, -20T).
+      - urt,umsh-8596md-t
+      - urt,umsh-8596md-1t
+      - urt,umsh-8596md-7t
+      - urt,umsh-8596md-11t
+      - urt,umsh-8596md-19t
+      - urt,umsh-8596md-20t
+        # VXT 800x480 color TFT LCD panel
+      - vxt,vl050-8048nt-c01
+        # Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel
+      - winstar,wf35ltiacd
 
   backlight: true
   enable-gpios: true
diff --git a/Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt b/Documentation/devicetree/bindings/display/panel/qiaodian,qd43003c0-40.txt
deleted file mode 100644 (file)
index 0fbdab8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-QiaoDian XianShi Corporation 4"3 TFT LCD panel
-
-Required properties:
-- compatible: should be "qiaodian,qd43003c0-40"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt
deleted file mode 100644 (file)
index cbb79ef..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel
-
-The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD
-panel connected using a MIPI-DSI video interface.
-
-Required properties:
-  - compatible: "raydium,rm68200"
-  - reg: the virtual channel number of a DSI peripheral
-
-Optional properties:
-  - reset-gpios: a GPIO spec for the reset pin (active low).
-  - power-supply: phandle of the regulator that provides the supply voltage.
-  - backlight: phandle of the backlight device attached to the panel.
-
-Example:
-&dsi {
-       ...
-       panel@0 {
-               compatible = "raydium,rm68200";
-               reg = <0>;
-               reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>;
-               power-supply = <&v1v8>;
-               backlight = <&pwm_backlight>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml
new file mode 100644 (file)
index 0000000..09149f1
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/raydium,rm68200.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel
+
+maintainers:
+  - Philippe CORNU <philippe.cornu@st.com>
+
+description: |
+             The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD
+             panel connected using a MIPI-DSI video interface.
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+
+  compatible:
+    const: raydium,rm68200
+
+  reg:
+    maxItems: 1
+    description: DSI virtual channel
+
+  backlight: true
+  enable-gpios: true
+  port: true
+  power-supply: true
+
+  reset-gpios:
+    maxItems: 1
+
+additionalProperties: false
+
+required:
+  - compatible
+  - power-supply
+  - reg
+
+examples:
+  - |
+    dsi@0 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      panel@0 {
+        compatible = "raydium,rm68200";
+        reg = <0>;
+        reset-gpios = <&gpiof 15 0>;
+        power-supply = <&v1v8>;
+        backlight = <&pwm_backlight>;
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt b/Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt
deleted file mode 100644 (file)
index eb1fb9f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
-
-Required properties:
-- compatible: should be "rocktech,rk070er9427"
-
-Optional properties:
-- backlight: phandle of the backlight device attached to the panel
-
-Optional nodes:
-- Video port for LCD panel input.
-
-Example:
-       panel {
-               compatible = "rocktech,rk070er9427";
-               backlight = <&backlight_lcd>;
-
-               port {
-                       lcd_panel_in: endpoint {
-                               remote-endpoint = <&lcd_display_out>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt b/Documentation/devicetree/bindings/display/panel/samsung,lsn122dl01-c01.txt
deleted file mode 100644 (file)
index dba298b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Samsung 12.2" (2560x1600 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "samsung,lsn122dl01-c01"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ltn101nt05.txt b/Documentation/devicetree/bindings/display/panel/samsung,ltn101nt05.txt
deleted file mode 100644 (file)
index ef522c6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Samsung Electronics 10.1" WSVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "samsung,ltn101nt05"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ltn140at29-301.txt b/Documentation/devicetree/bindings/display/panel/samsung,ltn140at29-301.txt
deleted file mode 100644 (file)
index e7f969d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "samsung,ltn140at29-301"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams452ef01.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams452ef01.yaml
new file mode 100644 (file)
index 0000000..7a685d0
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/samsung,s6e88a0-ams452ef01.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung AMS452EF01 AMOLED panel with S6E88A0 video mode DSI controller
+
+maintainers:
+  - Michael Srba <Michael.Srba@seznam.cz>
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    const: samsung,s6e88a0-ams452ef01
+  reg: true
+  reset-gpios: true
+  vdd3-supply:
+     description: core voltage supply
+  vci-supply:
+     description: voltage supply for analog circuits
+
+required:
+  - compatible
+  - reg
+  - vdd3-supply
+  - vci-supply
+  - reset-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            panel@0 {
+                    reg = <0>;
+
+                    compatible = "samsung,s6e88a0-ams452ef01";
+
+                    vdd3-supply = <&pm8916_l17>;
+                    vci-supply = <&reg_vlcd_vci>;
+                    reset-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>;
+            };
+    };
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt b/Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt
deleted file mode 100644 (file)
index 0753f69..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Sharp LQ035Q7DB03 3.5" QVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "sharp,lq035q7db03"
-- power-supply: phandle of the regulator that provides the supply voltage
-
-Optional properties:
-- enable-gpios: GPIO pin to enable or disable the panel
-- backlight: phandle of the backlight device attached to the panel
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq070y3dg3b.txt b/Documentation/devicetree/bindings/display/panel/sharp,lq070y3dg3b.txt
deleted file mode 100644 (file)
index 95534b5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Sharp LQ070Y3DG3B 7.0" WVGA landscape TFT LCD panel
-
-Required properties:
-- compatible: should be "sharp,lq070y3dg3b"
-
-Optional properties:
-- enable-gpios: GPIO pin to enable or disable the panel
-- backlight: phandle of the backlight device attached to the panel
-- power-supply: phandle of the regulator that provides the supply voltage
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq101k1ly04.txt b/Documentation/devicetree/bindings/display/panel/sharp,lq101k1ly04.txt
deleted file mode 100644 (file)
index 4aff25b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Sharp Display Corp. LQ101K1LY04 10.07" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "sharp,lq101k1ly04"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq123p1jx31.txt b/Documentation/devicetree/bindings/display/panel/sharp,lq123p1jx31.txt
deleted file mode 100644 (file)
index bcb0e8a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Sharp 12.3" (2400x1600 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "sharp,lq123p1jx31"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/shelly,sca07010-bfn-lnn.txt b/Documentation/devicetree/bindings/display/panel/shelly,sca07010-bfn-lnn.txt
deleted file mode 100644 (file)
index fc1ea9e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
-
-Required properties:
-- compatible: should be "shelly,sca07010-bfn-lnn"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/starry,kr122ea0sra.txt b/Documentation/devicetree/bindings/display/panel/starry,kr122ea0sra.txt
deleted file mode 100644 (file)
index 1e87fe6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Starry 12.2" (1920x1200 pixels) TFT LCD panel
-
-Required properties:
-- compatible: should be "starry,kr122ea0sra"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/tianma,tm070jdhg30.txt b/Documentation/devicetree/bindings/display/panel/tianma,tm070jdhg30.txt
deleted file mode 100644 (file)
index eb9501a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Tianma Micro-electronics TM070JDHG30 7.0" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "tianma,tm070jdhg30"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/tianma,tm070rvhg71.txt b/Documentation/devicetree/bindings/display/panel/tianma,tm070rvhg71.txt
deleted file mode 100644 (file)
index b25261e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Tianma Micro-electronics TM070RVHG71 7.0" WXGA TFT LCD panel
-
-Required properties:
-- compatible: should be "tianma,tm070rvhg71"
-- power-supply: single regulator to provide the supply voltage
-- backlight: phandle of the backlight device attached to the panel
-
-Required nodes:
-- port: LVDS port mapping to connect this display
-
-This panel needs single power supply voltage. Its backlight is conntrolled
-via PWM signal.
-
-Example:
---------
-
-Example device-tree definition when connected to iMX6Q based board
-
-       panel: panel-lvds0 {
-               compatible = "tianma,tm070rvhg71";
-               backlight = <&backlight_lvds>;
-               power-supply = <&reg_lvds>;
-
-               port {
-                       panel_in_lvds0: endpoint {
-                               remote-endpoint = <&lvds0_out>;
-                       };
-               };
-       };
diff --git a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt
deleted file mode 100644 (file)
index 8982611..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-Toshiba 8.9" WXGA (1280x768) TFT LCD panel
-
-Required properties:
-- compatible: should be "toshiba,lt089ac29000"
-- power-supply: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/tpk,f07a-0102.txt b/Documentation/devicetree/bindings/display/panel/tpk,f07a-0102.txt
deleted file mode 100644 (file)
index a2613b9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-TPK U.S.A. LLC Fusion 7" integrated projected capacitive touch display with,
-800 x 480 (WVGA) LCD panel.
-
-Required properties:
-- compatible: should be "tpk,f07a-0102"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/tpk,f10a-0102.txt b/Documentation/devicetree/bindings/display/panel/tpk,f10a-0102.txt
deleted file mode 100644 (file)
index b9d0511..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-TPK U.S.A. LLC Fusion 10.1" integrated projected capacitive touch display with,
-1024 x 600 (WSVGA) LCD panel.
-
-Required properties:
-- compatible: should be "tpk,f10a-0102"
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/urt,umsh-8596md.txt b/Documentation/devicetree/bindings/display/panel/urt,umsh-8596md.txt
deleted file mode 100644 (file)
index 088a6ce..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-United Radiant Technology UMSH-8596MD-xT 7.0" WVGA TFT LCD panel
-
-Supported are LVDS versions (-11T, -19T) and parallel ones
-(-T, -1T, -7T, -20T).
-
-Required properties:
-- compatible: should be one of:
-  "urt,umsh-8596md-t",
-  "urt,umsh-8596md-1t",
-  "urt,umsh-8596md-7t",
-  "urt,umsh-8596md-11t",
-  "urt,umsh-8596md-19t",
-  "urt,umsh-8596md-20t".
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/vl050_8048nt_c01.txt b/Documentation/devicetree/bindings/display/panel/vl050_8048nt_c01.txt
deleted file mode 100644 (file)
index b42bf06..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-VXT 800x480 color TFT LCD panel
-
-Required properties:
-- compatible: should be "vxt,vl050-8048nt-c01"
-- power-supply: as specified in the base binding
-
-Optional properties:
-- backlight: as specified in the base binding
-- enable-gpios: as specified in the base binding
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt b/Documentation/devicetree/bindings/display/panel/winstar,wf35ltiacd.txt
deleted file mode 100644 (file)
index 2a7e6e3..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel
-
-Required properties:
-- compatible: should be "winstar,wf35ltiacd"
-- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
-
-This binding is compatible with the simple-panel binding, which is specified
-in simple-panel.txt in this directory.
-
-Example:
-       backlight: backlight {
-               compatible = "pwm-backlight";
-               pwms = <&hlcdc_pwm 0 50000 PWM_POLARITY_INVERTED>;
-               brightness-levels = <0 31 63 95 127 159 191 223 255>;
-               default-brightness-level = <191>;
-               power-supply = <&bl_reg>;
-       };
-
-       bl_reg: backlight_regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "backlight-power-supply";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-       };
-
-       panel: panel {
-               compatible = "winstar,wf35ltiacd", "simple-panel";
-               backlight = <&backlight>;
-               power-supply = <&panel_reg>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               port {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       panel_input: endpoint {
-                               remote-endpoint = <&hlcdc_panel_output>;
-                       };
-               };
-       };
-
-       panel_reg: panel_regulator {
-               compatible = "regulator-fixed";
-               regulator-name = "panel-power-supply";
-               regulator-min-microvolt = <3300000>;
-               regulator-max-microvolt = <3300000>;
-       };
diff --git a/Documentation/devicetree/bindings/display/sitronix,st7735r.txt b/Documentation/devicetree/bindings/display/sitronix,st7735r.txt
deleted file mode 100644 (file)
index cd5c718..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-Sitronix ST7735R display panels
-
-This binding is for display panels using a Sitronix ST7735R controller in SPI
-mode.
-
-Required properties:
-- compatible:  "jianda,jd-t18003-t01", "sitronix,st7735r"
-- dc-gpios:    Display data/command selection (D/CX)
-- reset-gpios: Reset signal (RSTX)
-
-The node for this driver must be a child node of a SPI controller, hence
-all mandatory properties described in ../spi/spi-bus.txt must be specified.
-
-Optional properties:
-- rotation:    panel rotation in degrees counter clockwise (0,90,180,270)
-- backlight:   phandle of the backlight device attached to the panel
-
-Example:
-
-       backlight: backlight {
-               compatible = "gpio-backlight";
-               gpios = <&gpio 44 GPIO_ACTIVE_HIGH>;
-       };
-
-       ...
-
-       display@0{
-               compatible = "jianda,jd-t18003-t01", "sitronix,st7735r";
-               reg = <0>;
-               spi-max-frequency = <32000000>;
-               dc-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
-               reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>;
-               rotation = <270>;
-               backlight = &backlight;
-       };
diff --git a/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml b/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
new file mode 100644 (file)
index 0000000..0cebaae
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/sitronix,st7735r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sitronix ST7735R Display Panels Device Tree Bindings
+
+maintainers:
+  - David Lechner <david@lechnology.com>
+
+description:
+  This binding is for display panels using a Sitronix ST7715R or ST7735R
+  controller in SPI mode.
+
+allOf:
+  - $ref: panel/panel-common.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - description:
+          Adafruit 1.8" 160x128 Color TFT LCD (Product ID 358 or 618)
+        items:
+          - enum:
+              - jianda,jd-t18003-t01
+          - const: sitronix,st7735r
+      - description:
+          Okaya 1.44" 128x128 Color TFT LCD (E.g. Renesas YRSK-LCD-PMOD)
+        items:
+          - enum:
+              - okaya,rh128128t
+          - const: sitronix,st7715r
+
+  spi-max-frequency:
+    maximum: 32000000
+
+  dc-gpios:
+    maxItems: 1
+    description: Display data/command selection (D/CX)
+
+  backlight: true
+  reg: true
+  reset-gpios: true
+  rotation: true
+
+required:
+  - compatible
+  - reg
+  - dc-gpios
+  - reset-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    backlight: backlight {
+            compatible = "gpio-backlight";
+            gpios = <&gpio 44 GPIO_ACTIVE_HIGH>;
+    };
+
+    spi {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            display@0{
+                    compatible = "jianda,jd-t18003-t01", "sitronix,st7735r";
+                    reg = <0>;
+                    spi-max-frequency = <32000000>;
+                    dc-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
+                    reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>;
+                    rotation = <270>;
+            };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
new file mode 100644 (file)
index 0000000..cac61a9
--- /dev/null
@@ -0,0 +1,152 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Texas Instruments Incorporated
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/ti/ti,am65x-dss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Texas Instruments AM65x Display Subsystem
+
+maintainers:
+  - Jyri Sarha <jsarha@ti.com>
+  - Tomi Valkeinen <tomi.valkeinen@ti.com>
+
+description: |
+  The AM65x TI Keystone Display SubSystem with two output ports and
+  two video planes. The first video port supports OLDI and the second
+  supports DPI format. The fist plane is full video plane with all
+  features and the second is a "lite plane" without scaling support.
+
+properties:
+  compatible:
+    const: ti,am65x-dss
+
+  reg:
+    description:
+      Addresses to each DSS memory region described in the SoC's TRM.
+    items:
+      - description: common DSS register area
+      - description: VIDL1 light video plane
+      - description: VID video plane
+      - description: OVR1 overlay manager for vp1
+      - description: OVR2 overlay manager for vp2
+      - description: VP1 video port 1
+      - description: VP2 video port 2
+
+  reg-names:
+    items:
+      - const: common
+      - const: vidl1
+      - const: vid
+      - const: ovr1
+      - const: ovr2
+      - const: vp1
+      - const: vp2
+
+  clocks:
+    items:
+      - description: fck DSS functional clock
+      - description: vp1 Video Port 1 pixel clock
+      - description: vp2 Video Port 2 pixel clock
+
+  clock-names:
+    items:
+      - const: fck
+      - const: vp1
+      - const: vp2
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+    description: phandle to the associated power domain
+
+  ports:
+    type: object
+    description:
+      Ports as described in Documentation/devictree/bindings/graph.txt
+    properties:
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      port@0:
+        type: object
+        description:
+          The DSS OLDI output port node form video port 1
+
+      port@1:
+        type: object
+        description:
+          The DSS DPI output port node from video port 2
+
+    required:
+      - "#address-cells"
+      - "#size-cells"
+
+  ti,am65x-oldi-io-ctrl:
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/phandle-array"
+      - maxItems: 1
+    description:
+      phandle to syscon device node mapping OLDI IO_CTRL registers.
+      The mapped range should point to OLDI_DAT0_IO_CTRL, map it and
+      following OLDI_DAT1_IO_CTRL, OLDI_DAT2_IO_CTRL, OLDI_DAT3_IO_CTRL,
+      and OLDI_CLK_IO_CTRL registers. This property is needed for OLDI
+      interface to work.
+
+  max-memory-bandwidth:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Input memory (from main memory to dispc) bandwidth limit in
+      bytes per second
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - interrupts
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+    dss: dss@04a00000 {
+            compatible = "ti,am65x-dss";
+            reg =   <0x0 0x04a00000 0x0 0x1000>, /* common */
+                    <0x0 0x04a02000 0x0 0x1000>, /* vidl1 */
+                    <0x0 0x04a06000 0x0 0x1000>, /* vid */
+                    <0x0 0x04a07000 0x0 0x1000>, /* ovr1 */
+                    <0x0 0x04a08000 0x0 0x1000>, /* ovr2 */
+                    <0x0 0x04a0a000 0x0 0x1000>, /* vp1 */
+                    <0x0 0x04a0b000 0x0 0x1000>; /* vp2 */
+            reg-names = "common", "vidl1", "vid",
+                    "ovr1", "ovr2", "vp1", "vp2";
+            ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>;
+            power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>;
+            clocks =        <&k3_clks 67 1>,
+                            <&k3_clks 216 1>,
+                            <&k3_clks 67 2>;
+            clock-names = "fck", "vp1", "vp2";
+            interrupts = <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>;
+            ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    port@0 {
+                            reg = <0>;
+                            oldi_out0: endpoint {
+                                    remote-endpoint = <&lcd_in0>;
+                            };
+                    };
+            };
+    };
diff --git a/Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
new file mode 100644 (file)
index 0000000..ade9b2f
--- /dev/null
@@ -0,0 +1,208 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Texas Instruments Incorporated
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/ti/ti,j721e-dss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Texas Instruments J721E Display Subsystem
+
+maintainers:
+  - Jyri Sarha <jsarha@ti.com>
+  - Tomi Valkeinen <tomi.valkeinen@ti.com>
+
+description: |
+  The J721E TI Keystone Display SubSystem with four output ports and
+  four video planes. There is two full video planes and two "lite
+  planes" without scaling support. The video ports can be connected to
+  the SoC's DPI pins or to integrated display bridges on the SoC.
+
+properties:
+  compatible:
+    const: ti,j721e-dss
+
+  reg:
+    items:
+      - description: common_m DSS Master common
+      - description: common_s0 DSS Shared common 0
+      - description: common_s1 DSS Shared common 1
+      - description: common_s2 DSS Shared common 2
+      - description: VIDL1 light video plane 1
+      - description: VIDL2 light video plane 2
+      - description: VID1 video plane 1
+      - description: VID1 video plane 2
+      - description: OVR1 overlay manager for vp1
+      - description: OVR2 overlay manager for vp2
+      - description: OVR3 overlay manager for vp3
+      - description: OVR4 overlay manager for vp4
+      - description: VP1 video port 1
+      - description: VP2 video port 2
+      - description: VP3 video port 3
+      - description: VP4 video port 4
+      - description: WB Write Back
+
+  reg-names:
+    items:
+      - const: common_m
+      - const: common_s0
+      - const: common_s1
+      - const: common_s2
+      - const: vidl1
+      - const: vidl2
+      - const: vid1
+      - const: vid2
+      - const: ovr1
+      - const: ovr2
+      - const: ovr3
+      - const: ovr4
+      - const: vp1
+      - const: vp2
+      - const: vp3
+      - const: vp4
+      - const: wb
+
+  clocks:
+    items:
+      - description: fck DSS functional clock
+      - description: vp1 Video Port 1 pixel clock
+      - description: vp2 Video Port 2 pixel clock
+      - description: vp3 Video Port 3 pixel clock
+      - description: vp4 Video Port 4 pixel clock
+
+  clock-names:
+    items:
+      - const: fck
+      - const: vp1
+      - const: vp2
+      - const: vp3
+      - const: vp4
+
+  interrupts:
+     items:
+      - description: common_m DSS Master common
+      - description: common_s0 DSS Shared common 0
+      - description: common_s1 DSS Shared common 1
+      - description: common_s2 DSS Shared common 2
+
+  interrupt-names:
+    items:
+      - const: common_m
+      - const: common_s0
+      - const: common_s1
+      - const: common_s2
+
+  power-domains:
+    maxItems: 1
+    description: phandle to the associated power domain
+
+  ports:
+    type: object
+    description:
+      Ports as described in Documentation/devictree/bindings/graph.txt
+    properties:
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      port@0:
+        type: object
+        description:
+          The output port node form video port 1
+
+      port@1:
+        type: object
+        description:
+          The output port node from video port 2
+
+      port@2:
+        type: object
+        description:
+          The output port node from video port 3
+
+      port@3:
+        type: object
+        description:
+          The output port node from video port 4
+
+    required:
+      - "#address-cells"
+      - "#size-cells"
+
+  max-memory-bandwidth:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Input memory (from main memory to dispc) bandwidth limit in
+      bytes per second
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - interrupts
+  - interrupt-names
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+    dss: dss@04a00000 {
+            compatible = "ti,j721e-dss";
+            reg =   <0x00 0x04a00000 0x00 0x10000>, /* common_m */
+                    <0x00 0x04a10000 0x00 0x10000>, /* common_s0*/
+                    <0x00 0x04b00000 0x00 0x10000>, /* common_s1*/
+                    <0x00 0x04b10000 0x00 0x10000>, /* common_s2*/
+                    <0x00 0x04a20000 0x00 0x10000>, /* vidl1 */
+                    <0x00 0x04a30000 0x00 0x10000>, /* vidl2 */
+                    <0x00 0x04a50000 0x00 0x10000>, /* vid1 */
+                    <0x00 0x04a60000 0x00 0x10000>, /* vid2 */
+                    <0x00 0x04a70000 0x00 0x10000>, /* ovr1 */
+                    <0x00 0x04a90000 0x00 0x10000>, /* ovr2 */
+                    <0x00 0x04ab0000 0x00 0x10000>, /* ovr3 */
+                    <0x00 0x04ad0000 0x00 0x10000>, /* ovr4 */
+                    <0x00 0x04a80000 0x00 0x10000>, /* vp1 */
+                    <0x00 0x04aa0000 0x00 0x10000>, /* vp2 */
+                    <0x00 0x04ac0000 0x00 0x10000>, /* vp3 */
+                    <0x00 0x04ae0000 0x00 0x10000>, /* vp4 */
+                    <0x00 0x04af0000 0x00 0x10000>; /* wb */
+            reg-names = "common_m", "common_s0",
+                    "common_s1", "common_s2",
+                    "vidl1", "vidl2","vid1","vid2",
+                    "ovr1", "ovr2", "ovr3", "ovr4",
+                    "vp1", "vp2", "vp3", "vp4",
+                    "wb";
+            clocks =        <&k3_clks 152 0>,
+                            <&k3_clks 152 1>,
+                            <&k3_clks 152 4>,
+                            <&k3_clks 152 9>,
+                            <&k3_clks 152 13>;
+            clock-names = "fck", "vp1", "vp2", "vp3", "vp4";
+            power-domains = <&k3_pds 152 TI_SCI_PD_EXCLUSIVE>;
+            interrupts =    <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 603 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>;
+            interrupt-names =       "common_m",
+                                    "common_s0",
+                                    "common_s1",
+                                    "common_s2";
+            ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    port@0 {
+                            reg = <0>;
+
+                            dpi_out_0: endpoint {
+                                    remote-endpoint = <&dp_bridge_input>;
+                            };
+                    };
+            };
+    };
diff --git a/Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
new file mode 100644 (file)
index 0000000..385bd06
--- /dev/null
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Texas Instruments Incorporated
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/ti/ti,k2g-dss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Texas Instruments K2G Display Subsystem
+
+maintainers:
+  - Jyri Sarha <jsarha@ti.com>
+  - Tomi Valkeinen <tomi.valkeinen@ti.com>
+
+description: |
+  The K2G DSS is an ultra-light version of TI Keystone Display
+  SubSystem. It has only one output port and video plane. The
+  output is DPI.
+
+properties:
+  compatible:
+    const: ti,k2g-dss
+
+  reg:
+    items:
+      - description: cfg DSS top level
+      - description: common DISPC common
+      - description: VID1 video plane 1
+      - description: OVR1 overlay manager for vp1
+      - description: VP1 video port 1
+
+  reg-names:
+    items:
+      - const: cfg
+      - const: common
+      - const: vid1
+      - const: ovr1
+      - const: vp1
+
+  clocks:
+    items:
+      - description: fck DSS functional clock
+      - description: vp1 Video Port 1 pixel clock
+
+  clock-names:
+    items:
+      - const: fck
+      - const: vp1
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+    description: phandle to the associated power domain
+
+  port:
+    type: object
+    description:
+      Port as described in Documentation/devictree/bindings/graph.txt.
+      The DSS DPI output port node
+
+  max-memory-bandwidth:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Input memory (from main memory to dispc) bandwidth limit in
+      bytes per second
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - interrupts
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    dss: dss@02540000 {
+            compatible = "ti,k2g-dss";
+            reg =   <0x02540000 0x400>,
+                    <0x02550000 0x1000>,
+                    <0x02557000 0x1000>,
+                    <0x0255a800 0x100>,
+                    <0x0255ac00 0x100>;
+            reg-names = "cfg", "common", "vid1", "ovr1", "vp1";
+            clocks =        <&k2g_clks 0x2 0>,
+                            <&k2g_clks 0x2 1>;
+            clock-names = "fck", "vp1";
+            interrupts = <GIC_SPI 247 IRQ_TYPE_EDGE_RISING>;
+
+            power-domains = <&k2g_pds 0x2>;
+
+            max-memory-bandwidth = <230000000>;
+
+            port {
+                    dpi_out: endpoint {
+                            remote-endpoint = <&sii9022_in>;
+                    };
+            };
+    };
index 9e67944..9a0cca2 100644 (file)
@@ -337,12 +337,16 @@ patternProperties:
     description: Fastrax Oy
   "^fcs,.*":
     description: Fairchild Semiconductor
+  "^feixin,.*":
+    description: Shenzhen Feixin Photoelectic Co., Ltd
   "^feiyang,.*":
     description: Shenzhen Fly Young Technology Co.,LTD.
   "^firefly,.*":
     description: Firefly
   "^focaltech,.*":
     description: FocalTech Systems Co.,Ltd
+  "^frida,.*":
+    description: Shenzhen Frida LCD Co., Ltd.
   "^friendlyarm,.*":
     description: Guangzhou FriendlyARM Computer Tech Co., Ltd
   "^fsl,.*":
@@ -553,6 +557,8 @@ patternProperties:
     description: Linear Technology Corporation
   "^logicpd,.*":
     description: Logic PD, Inc.
+  "^logictechno,.*":
+    description: Logic Technologies Limited
   "^longcheer,.*":
     description: Longcheer Technology (Shanghai) Co., Ltd.
   "^loongson,.*":
index bc869b2..370ac67 100644 (file)
@@ -72,6 +72,28 @@ Contact: Ville Syrjälä, Daniel Vetter, driver maintainers
 
 Level: Advanced
 
+Improve plane atomic_check helpers
+----------------------------------
+
+Aside from the clipped coordinates right above there's a few suboptimal things
+with the current helpers:
+
+- drm_plane_helper_funcs->atomic_check gets called for enabled or disabled
+  planes. At best this seems to confuse drivers, worst it means they blow up
+  when the plane is disabled without the CRTC. The only special handling is
+  resetting values in the plane state structures, which instead should be moved
+  into the drm_plane_funcs->atomic_duplicate_state functions.
+
+- Once that's done, helpers could stop calling ->atomic_check for disabled
+  planes.
+
+- Then we could go through all the drivers and remove the more-or-less confused
+  checks for plane_state->fb and plane_state->crtc.
+
+Contact: Daniel Vetter
+
+Level: Advanced
+
 Convert early atomic drivers to async commit helpers
 ----------------------------------------------------
 
index a0d8649..978766c 100644 (file)
@@ -5262,6 +5262,12 @@ T:       git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
 F:     drivers/gpu/drm/tve200/
 
+DRM DRIVER FOR FEIXIN K101 IM2BA02 MIPI-DSI LCD PANELS
+M:     Icenowy Zheng <icenowy@aosc.io>
+S:     Maintained
+F:     drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
+F:     Documentation/devicetree/bindings/display/panel/feixin,k101-im2ba02.yaml
+
 DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
 M:     Jagan Teki <jagan@amarulasolutions.com>
 S:     Maintained
@@ -5281,6 +5287,13 @@ S:       Maintained
 F:     drivers/gpu/drm/tiny/ili9225.c
 F:     Documentation/devicetree/bindings/display/ilitek,ili9225.txt
 
+DRM DRIVER FOR ILITEK ILI9486 PANELS
+M:     Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+S:     Maintained
+F:     drivers/gpu/drm/tiny/ili9486.c
+F:     Documentation/devicetree/bindings/display/ilitek,ili9486.yaml
+
 DRM DRIVER FOR HX8357D PANELS
 M:     Eric Anholt <eric@anholt.net>
 T:     git git://anongit.freedesktop.org/drm/drm-misc
@@ -5409,7 +5422,7 @@ M:        David Lechner <david@lechnology.com>
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
 F:     drivers/gpu/drm/tiny/st7735r.c
-F:     Documentation/devicetree/bindings/display/sitronix,st7735r.txt
+F:     Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
 
 DRM DRIVER FOR SONY ACX424AKP PANELS
 M:     Linus Walleij <linus.walleij@linaro.org>
@@ -5489,6 +5502,7 @@ F:        include/linux/vga*
 DRM DRIVERS AND MISC GPU PATCHES
 M:     Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
 M:     Maxime Ripard <mripard@kernel.org>
+M:     Thomas Zimmermann <tzimmermann@suse.de>
 W:     https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
 S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
@@ -5568,7 +5582,6 @@ S:        Supported
 F:     drivers/gpu/drm/fsl-dcu/
 F:     Documentation/devicetree/bindings/display/fsl,dcu.txt
 F:     Documentation/devicetree/bindings/display/fsl,tcon.txt
-F:     Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR FREESCALE IMX
@@ -5684,6 +5697,17 @@ S:       Maintained
 F:     drivers/gpu/drm/omapdrm/
 F:     Documentation/devicetree/bindings/display/ti/
 
+DRM DRIVERS FOR TI KEYSTONE
+M:     Jyri Sarha <jsarha@ti.com>
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+F:     drivers/gpu/drm/tidss/
+F:     Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
+F:     Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
+F:     Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+
 DRM DRIVERS FOR V3D
 M:     Eric Anholt <eric@anholt.net>
 S:     Supported
index d0aa6cf..4bffa08 100644 (file)
@@ -389,6 +389,8 @@ source "drivers/gpu/drm/aspeed/Kconfig"
 
 source "drivers/gpu/drm/mcde/Kconfig"
 
+source "drivers/gpu/drm/tidss/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
index 6493088..ca0ca77 100644 (file)
@@ -122,3 +122,4 @@ obj-$(CONFIG_DRM_LIMA)  += lima/
 obj-$(CONFIG_DRM_PANFROST) += panfrost/
 obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
 obj-$(CONFIG_DRM_MCDE) += mcde/
+obj-$(CONFIG_DRM_TIDSS) += tidss/
index 39cd545..53fdafd 100644 (file)
@@ -1136,7 +1136,7 @@ static bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev)
        * locking inversion with the driver load path. And the access here is
        * completely racy anyway. So don't bother with locking for now.
        */
-       return dev->open_count == 0;
+       return atomic_read(&dev->open_count) == 0;
 }
 
 static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
index dee4462..3ab46d4 100644 (file)
@@ -69,11 +69,6 @@ static int amdgpu_map_buffer(struct ttm_buffer_object *bo,
 static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
 static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev);
 
-static int amdgpu_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
-{
-       return 0;
-}
-
 /**
  * amdgpu_init_mem_type - Initialize a memory manager for a specific type of
  * memory request.
@@ -1638,7 +1633,6 @@ static struct ttm_bo_driver amdgpu_bo_driver = {
        .ttm_tt_create = &amdgpu_ttm_tt_create,
        .ttm_tt_populate = &amdgpu_ttm_tt_populate,
        .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
-       .invalidate_caches = &amdgpu_invalidate_caches,
        .init_mem_type = &amdgpu_init_mem_type,
        .eviction_valuable = amdgpu_ttm_bo_eviction_valuable,
        .evict_flags = &amdgpu_evict_flags,
index 8ae1e1f..be7c29c 100644 (file)
@@ -9,7 +9,6 @@
 #include <drm/drm_device.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_vblank.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
 #include <linux/clk.h>
@@ -138,24 +137,9 @@ static void arc_pgu_crtc_atomic_disable(struct drm_crtc *crtc,
                              ~ARCPGU_CTRL_ENABLE_MASK);
 }
 
-static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc,
-                                     struct drm_crtc_state *state)
-{
-       struct drm_pending_vblank_event *event = crtc->state->event;
-
-       if (event) {
-               crtc->state->event = NULL;
-
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-       }
-}
-
 static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = {
        .mode_valid     = arc_pgu_crtc_mode_valid,
        .mode_set_nofb  = arc_pgu_crtc_mode_set_nofb,
-       .atomic_begin   = arc_pgu_crtc_atomic_begin,
        .atomic_enable  = arc_pgu_crtc_atomic_enable,
        .atomic_disable = arc_pgu_crtc_atomic_disable,
 };
index b79f484..18a0a4c 100644 (file)
@@ -388,31 +388,9 @@ static int ast_get_dram_info(struct drm_device *dev)
        return 0;
 }
 
-enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev,
-                                               const struct drm_display_mode *mode)
-{
-       static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGBA8888 */
-
-       struct ast_private *ast = dev->dev_private;
-       unsigned long fbsize, fbpages, max_fbpages;
-
-       /* To support double buffering, a framebuffer may not
-        * consume more than half of the available VRAM.
-        */
-       max_fbpages = (ast->vram_size / 2) >> PAGE_SHIFT;
-
-       fbsize = mode->hdisplay * mode->vdisplay * max_bpp;
-       fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);
-
-       if (fbpages > max_fbpages)
-               return MODE_MEM;
-
-       return MODE_OK;
-}
-
 static const struct drm_mode_config_funcs ast_mode_funcs = {
        .fb_create = drm_gem_fb_create,
-       .mode_valid = ast_mode_config_mode_valid,
+       .mode_valid = drm_vram_helper_mode_valid,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
index 34608f0..7810a84 100644 (file)
@@ -833,8 +833,6 @@ static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
        struct ast_vbios_mode_info *vbios_mode_info;
        struct drm_display_mode *adjusted_mode;
 
-       crtc->state->no_vblank = true;
-
        ast_state = to_ast_crtc_state(crtc->state);
 
        format = ast_state->format;
index 3f0006c..7410b0e 100644 (file)
@@ -7,7 +7,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_vblank.h>
 
 #include "bochs.h"
 
@@ -57,16 +56,8 @@ static void bochs_pipe_update(struct drm_simple_display_pipe *pipe,
                              struct drm_plane_state *old_state)
 {
        struct bochs_device *bochs = pipe->crtc.dev->dev_private;
-       struct drm_crtc *crtc = &pipe->crtc;
 
        bochs_plane_update(bochs, pipe->plane.state);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               crtc->state->event = NULL;
-               spin_unlock_irq(&crtc->dev->event_lock);
-       }
 }
 
 static const struct drm_simple_display_pipe_funcs bochs_pipe_funcs = {
@@ -92,32 +83,11 @@ static int bochs_connector_get_modes(struct drm_connector *connector)
        return count;
 }
 
-static enum drm_mode_status bochs_connector_mode_valid(struct drm_connector *connector,
-                                     struct drm_display_mode *mode)
-{
-       struct bochs_device *bochs =
-               container_of(connector, struct bochs_device, connector);
-       unsigned long size = mode->hdisplay * mode->vdisplay * 4;
-
-       /*
-        * Make sure we can fit two framebuffers into video memory.
-        * This allows up to 1600x1200 with 16 MB (default size).
-        * If you want more try this:
-        *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
-        */
-       if (size * 2 > bochs->fb_size)
-               return MODE_BAD;
-
-       return MODE_OK;
-}
-
 static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
        .get_modes = bochs_connector_get_modes,
-       .mode_valid = bochs_connector_mode_valid,
 };
 
 static const struct drm_connector_funcs bochs_connector_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = drm_connector_cleanup,
        .reset = drm_atomic_helper_connector_reset,
@@ -157,6 +127,7 @@ bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
 
 const struct drm_mode_config_funcs bochs_mode_funcs = {
        .fb_create = bochs_gem_fb_create,
+       .mode_valid = drm_vram_helper_mode_valid,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
index 0b9ca58..8397bf7 100644 (file)
@@ -72,6 +72,17 @@ config DRM_PARADE_PS8622
        ---help---
          Parade eDP-LVDS bridge chip driver.
 
+config DRM_PARADE_PS8640
+       tristate "Parade PS8640 MIPI DSI to eDP Converter"
+       depends on OF
+       select DRM_KMS_HELPER
+       select DRM_MIPI_DSI
+       select DRM_PANEL
+       help
+         Choose this option if you have PS8640 for display
+         The PS8640 is a high-performance and low-power
+         MIPI DSI to eDP converter
+
 config DRM_SIL_SII8620
        tristate "Silicon Image SII8620 HDMI/MHL bridge"
        depends on OF
index cd16ce8..1eb5376 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
+obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
 obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
 obj-$(CONFIG_DRM_SII902X) += sii902x.o
 obj-$(CONFIG_DRM_SII9234) += sii9234.o
index 6effe53..dfb59a5 100644 (file)
@@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
        return conn_state->crtc;
 }
 
-static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
-                                                struct drm_atomic_state *state)
+static void
+analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+                                    struct drm_bridge_state *old_bridge_state)
 {
+       struct drm_atomic_state *old_state = old_bridge_state->base.state;
        struct analogix_dp_device *dp = bridge->driver_private;
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state;
        int ret;
 
-       crtc = analogix_dp_get_new_crtc(dp, state);
+       crtc = analogix_dp_get_new_crtc(dp, old_state);
        if (!crtc)
                return;
 
-       old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+       old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
        /* Don't touch the panel if we're coming back from PSR */
        if (old_crtc_state && old_crtc_state->self_refresh_active)
                return;
@@ -1366,20 +1368,22 @@ out_dp_clk_pre:
        return ret;
 }
 
-static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
-                                            struct drm_atomic_state *state)
+static void
+analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
+                                struct drm_bridge_state *old_bridge_state)
 {
+       struct drm_atomic_state *old_state = old_bridge_state->base.state;
        struct analogix_dp_device *dp = bridge->driver_private;
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state;
        int timeout_loop = 0;
        int ret;
 
-       crtc = analogix_dp_get_new_crtc(dp, state);
+       crtc = analogix_dp_get_new_crtc(dp, old_state);
        if (!crtc)
                return;
 
-       old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+       old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
        /* Not a full enable, just disable PSR and continue */
        if (old_crtc_state && old_crtc_state->self_refresh_active) {
                ret = analogix_dp_disable_psr(dp);
@@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
        dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
-static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
-                                             struct drm_atomic_state *state)
+static void
+analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
+                                 struct drm_bridge_state *old_bridge_state)
 {
+       struct drm_atomic_state *old_state = old_bridge_state->base.state;
        struct analogix_dp_device *dp = bridge->driver_private;
        struct drm_crtc *crtc;
        struct drm_crtc_state *new_crtc_state = NULL;
 
-       crtc = analogix_dp_get_new_crtc(dp, state);
+       crtc = analogix_dp_get_new_crtc(dp, old_state);
        if (!crtc)
                goto out;
 
-       new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
        if (!new_crtc_state)
                goto out;
 
@@ -1463,20 +1469,21 @@ out:
        analogix_dp_bridge_disable(bridge);
 }
 
-static
-void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
-                                           struct drm_atomic_state *state)
+static void
+analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
+                               struct drm_bridge_state *old_bridge_state)
 {
+       struct drm_atomic_state *old_state = old_bridge_state->base.state;
        struct analogix_dp_device *dp = bridge->driver_private;
        struct drm_crtc *crtc;
        struct drm_crtc_state *new_crtc_state;
        int ret;
 
-       crtc = analogix_dp_get_new_crtc(dp, state);
+       crtc = analogix_dp_get_new_crtc(dp, old_state);
        if (!crtc)
                return;
 
-       new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
        if (!new_crtc_state || !new_crtc_state->self_refresh_active)
                return;
 
@@ -1563,6 +1570,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
 }
 
 static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
+       .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+       .atomic_reset = drm_atomic_helper_bridge_reset,
        .atomic_pre_enable = analogix_dp_bridge_atomic_pre_enable,
        .atomic_enable = analogix_dp_bridge_atomic_enable,
        .atomic_disable = analogix_dp_bridge_atomic_disable,
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
new file mode 100644 (file)
index 0000000..c6c0668
--- /dev/null
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define PAGE2_GPIO_H           0xa7
+#define PS_GPIO9               BIT(1)
+#define PAGE2_I2C_BYPASS       0xea
+#define I2C_BYPASS_EN          0xd0
+#define PAGE2_MCS_EN           0xf3
+#define MCS_EN                 BIT(0)
+#define PAGE3_SET_ADD          0xfe
+#define VDO_CTL_ADD            0x13
+#define VDO_DIS                        0x18
+#define VDO_EN                 0x1c
+#define DP_NUM_LANES           4
+
+/*
+ * PS8640 uses multiple addresses:
+ * page[0]: for DP control
+ * page[1]: for VIDEO Bridge
+ * page[2]: for control top
+ * page[3]: for DSI Link Control1
+ * page[4]: for MIPI Phy
+ * page[5]: for VPLL
+ * page[6]: for DSI Link Control2
+ * page[7]: for SPI ROM mapping
+ */
+enum page_addr_offset {
+       PAGE0_DP_CNTL = 0,
+       PAGE1_VDO_BDG,
+       PAGE2_TOP_CNTL,
+       PAGE3_DSI_CNTL1,
+       PAGE4_MIPI_PHY,
+       PAGE5_VPLL,
+       PAGE6_DSI_CNTL2,
+       PAGE7_SPI_CNTL,
+       MAX_DEVS
+};
+
+enum ps8640_vdo_control {
+       DISABLE = VDO_DIS,
+       ENABLE = VDO_EN,
+};
+
+struct ps8640 {
+       struct drm_bridge bridge;
+       struct drm_bridge *panel_bridge;
+       struct mipi_dsi_device *dsi;
+       struct i2c_client *page[MAX_DEVS];
+       struct regulator_bulk_data supplies[2];
+       struct gpio_desc *gpio_reset;
+       struct gpio_desc *gpio_powerdown;
+};
+
+static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
+{
+       return container_of(e, struct ps8640, bridge);
+}
+
+static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
+                                    const enum ps8640_vdo_control ctrl)
+{
+       struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
+       u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl };
+       int ret;
+
+       ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
+                                            sizeof(vdo_ctrl_buf),
+                                            vdo_ctrl_buf);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void ps8640_pre_enable(struct drm_bridge *bridge)
+{
+       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+       struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
+       unsigned long timeout;
+       int ret, status;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
+                                   ps_bridge->supplies);
+       if (ret < 0) {
+               DRM_ERROR("cannot enable regulators %d\n", ret);
+               return;
+       }
+
+       gpiod_set_value(ps_bridge->gpio_powerdown, 0);
+       gpiod_set_value(ps_bridge->gpio_reset, 1);
+       usleep_range(2000, 2500);
+       gpiod_set_value(ps_bridge->gpio_reset, 0);
+
+       /*
+        * Wait for the ps8640 embedded MCU to be ready
+        * First wait 200ms and then check the MCU ready flag every 20ms
+        */
+       msleep(200);
+
+       timeout = jiffies + msecs_to_jiffies(200) + 1;
+
+       while (time_is_after_jiffies(timeout)) {
+               status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
+               if (status < 0) {
+                       DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
+                       goto err_regulators_disable;
+               }
+               if ((status & PS_GPIO9) == PS_GPIO9)
+                       break;
+
+               msleep(20);
+       }
+
+       msleep(50);
+
+       /*
+        * The Manufacturer Command Set (MCS) is a device dependent interface
+        * intended for factory programming of the display module default
+        * parameters. Once the display module is configured, the MCS shall be
+        * disabled by the manufacturer. Once disabled, all MCS commands are
+        * ignored by the display interface.
+        */
+       status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
+       if (status < 0) {
+               DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
+               goto err_regulators_disable;
+       }
+
+       ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
+                                       status & ~MCS_EN);
+       if (ret < 0) {
+               DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
+               goto err_regulators_disable;
+       }
+
+       ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE);
+       if (ret) {
+               DRM_ERROR("failed to enable VDO: %d\n", ret);
+               goto err_regulators_disable;
+       }
+
+       /* Switch access edp panel's edid through i2c */
+       ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
+                                       I2C_BYPASS_EN);
+       if (ret < 0) {
+               DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
+               goto err_regulators_disable;
+       }
+
+       return;
+
+err_regulators_disable:
+       regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+                              ps_bridge->supplies);
+}
+
+static void ps8640_post_disable(struct drm_bridge *bridge)
+{
+       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+       int ret;
+
+       ret = ps8640_bridge_vdo_control(ps_bridge, DISABLE);
+       if (ret < 0)
+               DRM_ERROR("failed to disable VDO: %d\n", ret);
+
+       gpiod_set_value(ps_bridge->gpio_reset, 1);
+       gpiod_set_value(ps_bridge->gpio_powerdown, 1);
+       ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
+                                    ps_bridge->supplies);
+       if (ret < 0)
+               DRM_ERROR("cannot disable regulators %d\n", ret);
+}
+
+static int ps8640_bridge_attach(struct drm_bridge *bridge)
+{
+       struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+       struct device *dev = &ps_bridge->page[0]->dev;
+       struct device_node *in_ep, *dsi_node;
+       struct mipi_dsi_device *dsi;
+       struct mipi_dsi_host *host;
+       int ret;
+       const struct mipi_dsi_device_info info = { .type = "ps8640",
+                                                  .channel = 0,
+                                                  .node = NULL,
+                                                };
+       /* port@0 is ps8640 dsi input port */
+       in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
+       if (!in_ep)
+               return -ENODEV;
+
+       dsi_node = of_graph_get_remote_port_parent(in_ep);
+       of_node_put(in_ep);
+       if (!dsi_node)
+               return -ENODEV;
+
+       host = of_find_mipi_dsi_host_by_node(dsi_node);
+       of_node_put(dsi_node);
+       if (!host)
+               return -ENODEV;
+
+       dsi = mipi_dsi_device_register_full(host, &info);
+       if (IS_ERR(dsi)) {
+               dev_err(dev, "failed to create dsi device\n");
+               ret = PTR_ERR(dsi);
+               return ret;
+       }
+
+       ps_bridge->dsi = dsi;
+
+       dsi->host = host;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
+                         MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->lanes = DP_NUM_LANES;
+       ret = mipi_dsi_attach(dsi);
+       if (ret)
+               goto err_dsi_attach;
+
+       /* Attach the panel-bridge to the dsi bridge */
+       return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+                                &ps_bridge->bridge);
+
+err_dsi_attach:
+       mipi_dsi_device_unregister(dsi);
+       return ret;
+}
+
+static const struct drm_bridge_funcs ps8640_bridge_funcs = {
+       .attach = ps8640_bridge_attach,
+       .post_disable = ps8640_post_disable,
+       .pre_enable = ps8640_pre_enable,
+};
+
+static int ps8640_probe(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct device_node *np = dev->of_node;
+       struct ps8640 *ps_bridge;
+       struct drm_panel *panel;
+       int ret;
+       u32 i;
+
+       ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
+       if (!ps_bridge)
+               return -ENOMEM;
+
+       /* port@1 is ps8640 output port */
+       ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
+       if (ret < 0)
+               return ret;
+       if (!panel)
+               return -ENODEV;
+
+       panel->connector_type = DRM_MODE_CONNECTOR_eDP;
+
+       ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
+       if (IS_ERR(ps_bridge->panel_bridge))
+               return PTR_ERR(ps_bridge->panel_bridge);
+
+       ps_bridge->supplies[0].supply = "vdd33";
+       ps_bridge->supplies[1].supply = "vdd12";
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
+                                     ps_bridge->supplies);
+       if (ret)
+               return ret;
+
+       ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown",
+                                                  GPIOD_OUT_HIGH);
+       if (IS_ERR(ps_bridge->gpio_powerdown))
+               return PTR_ERR(ps_bridge->gpio_powerdown);
+
+       /*
+        * Assert the reset to avoid the bridge being initialized prematurely
+        */
+       ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
+                                              GPIOD_OUT_HIGH);
+       if (IS_ERR(ps_bridge->gpio_reset))
+               return PTR_ERR(ps_bridge->gpio_reset);
+
+       ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
+       ps_bridge->bridge.of_node = dev->of_node;
+
+       ps_bridge->page[PAGE0_DP_CNTL] = client;
+
+       for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
+               ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
+                                                            client->adapter,
+                                                            client->addr + i);
+               if (IS_ERR(ps_bridge->page[i])) {
+                       dev_err(dev, "failed i2c dummy device, address %02x\n",
+                               client->addr + i);
+                       return PTR_ERR(ps_bridge->page[i]);
+               }
+       }
+
+       i2c_set_clientdata(client, ps_bridge);
+
+       drm_bridge_add(&ps_bridge->bridge);
+
+       return 0;
+}
+
+static int ps8640_remove(struct i2c_client *client)
+{
+       struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+       drm_bridge_remove(&ps_bridge->bridge);
+
+       return 0;
+}
+
+static const struct of_device_id ps8640_match[] = {
+       { .compatible = "parade,ps8640" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ps8640_match);
+
+static struct i2c_driver ps8640_driver = {
+       .probe_new = ps8640_probe,
+       .remove = ps8640_remove,
+       .driver = {
+               .name = "ps8640",
+               .of_match_table = ps8640_match,
+       },
+};
+module_i2c_driver(ps8640_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>");
+MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
+MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver");
+MODULE_LICENSE("GPL v2");
index 248c9f7..a91fb0d 100644 (file)
@@ -38,7 +38,6 @@
 #include <drm/drm_modeset_helper_vtables.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
-#include <drm/drm_vblank.h>
 
 #define DRIVER_NAME "cirrus"
 #define DRIVER_DESC "qemu cirrus vga"
@@ -434,13 +433,6 @@ static void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
 
        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
                cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               crtc->state->event = NULL;
-               spin_unlock_irq(&crtc->dev->event_lock);
-       }
 }
 
 static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = {
index d336915..65c46ed 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_uapi.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
@@ -1018,6 +1019,121 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
 }
 
 /**
+ * drm_atomic_get_bridge_state - get bridge state
+ * @state: global atomic state object
+ * @bridge: bridge to get state object for
+ *
+ * This function returns the bridge state for the given bridge, allocating it
+ * if needed. It will also grab the relevant bridge lock to make sure that the
+ * state is consistent.
+ *
+ * Returns:
+ *
+ * Either the allocated state or the error code encoded into the pointer. When
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
+ * entire atomic sequence must be restarted.
+ */
+struct drm_bridge_state *
+drm_atomic_get_bridge_state(struct drm_atomic_state *state,
+                           struct drm_bridge *bridge)
+{
+       struct drm_private_state *obj_state;
+
+       obj_state = drm_atomic_get_private_obj_state(state, &bridge->base);
+       if (IS_ERR(obj_state))
+               return ERR_CAST(obj_state);
+
+       return drm_priv_to_bridge_state(obj_state);
+}
+EXPORT_SYMBOL(drm_atomic_get_bridge_state);
+
+/**
+ * drm_atomic_get_old_bridge_state - get old bridge state, if it exists
+ * @state: global atomic state object
+ * @bridge: bridge to grab
+ *
+ * This function returns the old bridge state for the given bridge, or NULL if
+ * the bridge is not part of the global atomic state.
+ */
+struct drm_bridge_state *
+drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
+                               struct drm_bridge *bridge)
+{
+       struct drm_private_state *obj_state;
+
+       obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base);
+       if (!obj_state)
+               return NULL;
+
+       return drm_priv_to_bridge_state(obj_state);
+}
+EXPORT_SYMBOL(drm_atomic_get_old_bridge_state);
+
+/**
+ * drm_atomic_get_new_bridge_state - get new bridge state, if it exists
+ * @state: global atomic state object
+ * @bridge: bridge to grab
+ *
+ * This function returns the new bridge state for the given bridge, or NULL if
+ * the bridge is not part of the global atomic state.
+ */
+struct drm_bridge_state *
+drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
+                               struct drm_bridge *bridge)
+{
+       struct drm_private_state *obj_state;
+
+       obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base);
+       if (!obj_state)
+               return NULL;
+
+       return drm_priv_to_bridge_state(obj_state);
+}
+EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
+
+/**
+ * drm_atomic_add_encoder_bridges - add bridges attached to an encoder
+ * @state: atomic state
+ * @encoder: DRM encoder
+ *
+ * This function adds all bridges attached to @encoder. This is needed to add
+ * bridge states to @state and make them available when
+ * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are
+ * called
+ *
+ * Returns:
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
+ * then the w/w mutex code has detected a deadlock and the entire atomic
+ * sequence must be restarted. All other errors are fatal.
+ */
+int
+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
+                              struct drm_encoder *encoder)
+{
+       struct drm_bridge_state *bridge_state;
+       struct drm_bridge *bridge;
+
+       if (!encoder)
+               return 0;
+
+       DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
+                        encoder->base.id, encoder->name, state);
+
+       drm_for_each_bridge_in_chain(encoder, bridge) {
+               /* Skip bridges that don't implement the atomic state hooks. */
+               if (!bridge->funcs->atomic_duplicate_state)
+                       continue;
+
+               bridge_state = drm_atomic_get_bridge_state(state, bridge);
+               if (IS_ERR(bridge_state))
+                       return PTR_ERR(bridge_state);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
+
+/**
  * drm_atomic_add_affected_connectors - add connectors for CRTC
  * @state: atomic state
  * @crtc: DRM CRTC
index 4511c2e..85d163f 100644 (file)
@@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state)
                funcs = encoder->helper_private;
 
                bridge = drm_bridge_chain_get_first_bridge(encoder);
-               ret = drm_bridge_chain_mode_fixup(bridge,
-                                       &new_crtc_state->mode,
-                                       &new_crtc_state->adjusted_mode);
-               if (!ret) {
-                       DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
-                       return -EINVAL;
+               ret = drm_atomic_bridge_chain_check(bridge,
+                                                   new_crtc_state,
+                                                   new_conn_state);
+               if (ret) {
+                       DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
+                       return ret;
                }
 
                if (funcs && funcs->atomic_check) {
@@ -583,6 +583,7 @@ mode_valid(struct drm_atomic_state *state)
  * &drm_crtc_state.connectors_changed is set when a connector is added or
  * removed from the CRTC.  &drm_crtc_state.active_changed is set when
  * &drm_crtc_state.active changes, which is used for DPMS.
+ * &drm_crtc_state.no_vblank is set from the result of drm_dev_has_vblank().
  * See also: drm_atomic_crtc_needs_modeset()
  *
  * IMPORTANT:
@@ -649,6 +650,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 
                        return -EINVAL;
                }
+
+               if (drm_dev_has_vblank(dev))
+                       new_crtc_state->no_vblank = false;
+               else
+                       new_crtc_state->no_vblank = true;
        }
 
        ret = handle_conflicting_encoders(state, false);
@@ -730,6 +736,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                        return ret;
        }
 
+       /*
+        * Iterate over all connectors again, and add all affected bridges to
+        * the state.
+        */
+       for_each_oldnew_connector_in_state(state, connector,
+                                          old_connector_state,
+                                          new_connector_state, i) {
+               struct drm_encoder *encoder;
+
+               encoder = old_connector_state->best_encoder;
+               ret = drm_atomic_add_encoder_bridges(state, encoder);
+               if (ret)
+                       return ret;
+
+               encoder = new_connector_state->best_encoder;
+               ret = drm_atomic_add_encoder_bridges(state, encoder);
+               if (ret)
+                       return ret;
+       }
+
        ret = mode_valid(state);
        if (ret)
                return ret;
@@ -2215,7 +2241,9 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
  * when a job is queued, and any change to the pipeline that does not touch the
  * connector is leading to timeouts when calling
  * drm_atomic_helper_wait_for_vblanks() or
- * drm_atomic_helper_wait_for_flip_done().
+ * drm_atomic_helper_wait_for_flip_done(). In addition to writeback
+ * connectors, this function can also fake VBLANK events for CRTCs without
+ * VBLANK interrupt.
  *
  * This is part of the atomic helper support for nonblocking commits, see
  * drm_atomic_helper_setup_commit() for an overview.
@@ -3508,3 +3536,44 @@ fail:
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
+
+/**
+ * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
+ *                                               the input end of a bridge
+ * @bridge: bridge control structure
+ * @bridge_state: new bridge state
+ * @crtc_state: new CRTC state
+ * @conn_state: new connector state
+ * @output_fmt: tested output bus format
+ * @num_input_fmts: will contain the size of the returned array
+ *
+ * This helper is a pluggable implementation of the
+ * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't
+ * modify the bus configuration between their input and their output. It
+ * returns an array of input formats with a single element set to @output_fmt.
+ *
+ * RETURNS:
+ * a valid format array of size @num_input_fmts, or NULL if the allocation
+ * failed
+ */
+u32 *
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
+                                       struct drm_bridge_state *bridge_state,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state,
+                                       u32 output_fmt,
+                                       unsigned int *num_input_fmts)
+{
+       u32 *input_fmts;
+
+       input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
+       if (!input_fmts) {
+               *num_input_fmts = 0;
+               return NULL;
+       }
+
+       *num_input_fmts = 1;
+       input_fmts[0] = output_fmt;
+       return input_fmts;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
index 7cf3cf9..33141d2 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_bridge.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
@@ -551,3 +552,105 @@ void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj
        memcpy(state, obj->state, sizeof(*state));
 }
 EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
+
+/**
+ * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state
+ * @bridge: bridge object
+ * @state: atomic bridge state
+ *
+ * Copies atomic state from a bridge's current state and resets inferred values.
+ * This is useful for drivers that subclass the bridge state.
+ */
+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
+                                               struct drm_bridge_state *state)
+{
+       __drm_atomic_helper_private_obj_duplicate_state(&bridge->base,
+                                                       &state->base);
+       state->bridge = bridge;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state);
+
+/**
+ * drm_atomic_helper_bridge_duplicate_state() - Duplicate a bridge state object
+ * @bridge: bridge object
+ *
+ * Allocates a new bridge state and initializes it with the current bridge
+ * state values. This helper is meant to be used as a bridge
+ * &drm_bridge_funcs.atomic_duplicate_state hook for bridges that don't
+ * subclass the bridge state.
+ */
+struct drm_bridge_state *
+drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge)
+{
+       struct drm_bridge_state *new;
+
+       if (WARN_ON(!bridge->base.state))
+               return NULL;
+
+       new = kzalloc(sizeof(*new), GFP_KERNEL);
+       if (new)
+               __drm_atomic_helper_bridge_duplicate_state(bridge, new);
+
+       return new;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_duplicate_state);
+
+/**
+ * drm_atomic_helper_bridge_destroy_state() - Destroy a bridge state object
+ * @bridge: the bridge this state refers to
+ * @state: bridge state to destroy
+ *
+ * Destroys a bridge state previously created by
+ * &drm_atomic_helper_bridge_reset() or
+ * &drm_atomic_helper_bridge_duplicate_state(). This helper is meant to be
+ * used as a bridge &drm_bridge_funcs.atomic_destroy_state hook for bridges
+ * that don't subclass the bridge state.
+ */
+void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
+                                           struct drm_bridge_state *state)
+{
+       kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
+
+/**
+ * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its
+ *                                     default
+ * @bridge: the bridge this state refers to
+ * @state: bridge state to initialize
+ *
+ * Initializes the bridge state to default values. This is meant to be called
+ * by the bridge &drm_bridge_funcs.atomic_reset hook for bridges that subclass
+ * the bridge state.
+ */
+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
+                                     struct drm_bridge_state *state)
+{
+       memset(state, 0, sizeof(*state));
+       state->bridge = bridge;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
+
+/**
+ * drm_atomic_helper_bridge_reset() - Allocate and initialize a bridge state
+ *                                   to its default
+ * @bridge: the bridge this state refers to
+ * @state: bridge state to initialize
+ *
+ * Allocates the bridge state and initializes it to default values. This helper
+ * is meant to be used as a bridge &drm_bridge_funcs.atomic_reset hook for
+ * bridges that don't subclass the bridge state.
+ */
+struct drm_bridge_state *
+drm_atomic_helper_bridge_reset(struct drm_bridge *bridge)
+{
+       struct drm_bridge_state *bridge_state;
+
+       bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL);
+       if (!bridge_state)
+               return ERR_PTR(-ENOMEM);
+
+       __drm_atomic_helper_bridge_reset(bridge, bridge_state);
+       return bridge_state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_reset);
index cc9acd9..531b876 100644 (file)
@@ -153,11 +153,6 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
                return -ENOMEM;
        }
 
-       if (dev->driver->master_create) {
-               ret = dev->driver->master_create(dev, fpriv->master);
-               if (ret)
-                       goto out_err;
-       }
        fpriv->is_master = 1;
        fpriv->authenticated = 1;
 
@@ -332,9 +327,6 @@ static void drm_master_destroy(struct kref *kref)
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                drm_lease_destroy(master);
 
-       if (dev->driver->master_destroy)
-               dev->driver->master_destroy(dev, master);
-
        drm_legacy_master_rmmaps(dev, master);
 
        idr_destroy(&master->magic_map);
index c2cf0c9..68ab933 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 
+#include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_encoder.h>
 
@@ -89,6 +90,31 @@ void drm_bridge_remove(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_remove);
 
+static struct drm_private_state *
+drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
+{
+       struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+       struct drm_bridge_state *state;
+
+       state = bridge->funcs->atomic_duplicate_state(bridge);
+       return state ? &state->base : NULL;
+}
+
+static void
+drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
+                                    struct drm_private_state *s)
+{
+       struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
+       struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+
+       bridge->funcs->atomic_destroy_state(bridge, state);
+}
+
+static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
+       .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
+       .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
+};
+
 /**
  * drm_bridge_attach - attach the bridge to an encoder's chain
  *
@@ -135,15 +161,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 
        if (bridge->funcs->attach) {
                ret = bridge->funcs->attach(bridge);
-               if (ret < 0) {
-                       list_del(&bridge->chain_node);
-                       bridge->dev = NULL;
-                       bridge->encoder = NULL;
-                       return ret;
+               if (ret < 0)
+                       goto err_reset_bridge;
+       }
+
+       if (bridge->funcs->atomic_reset) {
+               struct drm_bridge_state *state;
+
+               state = bridge->funcs->atomic_reset(bridge);
+               if (IS_ERR(state)) {
+                       ret = PTR_ERR(state);
+                       goto err_detach_bridge;
                }
+
+               drm_atomic_private_obj_init(bridge->dev, &bridge->base,
+                                           &state->base,
+                                           &drm_bridge_priv_state_funcs);
        }
 
        return 0;
+
+err_detach_bridge:
+       if (bridge->funcs->detach)
+               bridge->funcs->detach(bridge);
+
+err_reset_bridge:
+       bridge->dev = NULL;
+       bridge->encoder = NULL;
+       list_del(&bridge->chain_node);
+       return ret;
 }
 EXPORT_SYMBOL(drm_bridge_attach);
 
@@ -155,6 +201,9 @@ void drm_bridge_detach(struct drm_bridge *bridge)
        if (WARN_ON(!bridge->dev))
                return;
 
+       if (bridge->funcs->atomic_reset)
+               drm_atomic_private_obj_fini(&bridge->base);
+
        if (bridge->funcs->detach)
                bridge->funcs->detach(bridge);
 
@@ -409,10 +458,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
-               if (iter->funcs->atomic_disable)
-                       iter->funcs->atomic_disable(iter, old_state);
-               else if (iter->funcs->disable)
+               if (iter->funcs->atomic_disable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               iter);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       iter->funcs->atomic_disable(iter, old_bridge_state);
+               } else if (iter->funcs->disable) {
                        iter->funcs->disable(iter);
+               }
 
                if (iter == bridge)
                        break;
@@ -443,10 +501,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
-               if (bridge->funcs->atomic_post_disable)
-                       bridge->funcs->atomic_post_disable(bridge, old_state);
-               else if (bridge->funcs->post_disable)
+               if (bridge->funcs->atomic_post_disable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               bridge);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       bridge->funcs->atomic_post_disable(bridge,
+                                                          old_bridge_state);
+               } else if (bridge->funcs->post_disable) {
                        bridge->funcs->post_disable(bridge);
+               }
        }
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
@@ -475,10 +543,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
-               if (iter->funcs->atomic_pre_enable)
-                       iter->funcs->atomic_pre_enable(iter, old_state);
-               else if (iter->funcs->pre_enable)
+               if (iter->funcs->atomic_pre_enable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               iter);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       iter->funcs->atomic_pre_enable(iter, old_bridge_state);
+               } else if (iter->funcs->pre_enable) {
                        iter->funcs->pre_enable(iter);
+               }
 
                if (iter == bridge)
                        break;
@@ -508,14 +585,340 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
-               if (bridge->funcs->atomic_enable)
-                       bridge->funcs->atomic_enable(bridge, old_state);
-               else if (bridge->funcs->enable)
+               if (bridge->funcs->atomic_enable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               bridge);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       bridge->funcs->atomic_enable(bridge, old_bridge_state);
+               } else if (bridge->funcs->enable) {
                        bridge->funcs->enable(bridge);
+               }
        }
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
 
+static int drm_atomic_bridge_check(struct drm_bridge *bridge,
+                                  struct drm_crtc_state *crtc_state,
+                                  struct drm_connector_state *conn_state)
+{
+       if (bridge->funcs->atomic_check) {
+               struct drm_bridge_state *bridge_state;
+               int ret;
+
+               bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
+                                                              bridge);
+               if (WARN_ON(!bridge_state))
+                       return -EINVAL;
+
+               ret = bridge->funcs->atomic_check(bridge, bridge_state,
+                                                 crtc_state, conn_state);
+               if (ret)
+                       return ret;
+       } else if (bridge->funcs->mode_fixup) {
+               if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
+                                              &crtc_state->adjusted_mode))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
+                                   struct drm_bridge *cur_bridge,
+                                   struct drm_crtc_state *crtc_state,
+                                   struct drm_connector_state *conn_state,
+                                   u32 out_bus_fmt)
+{
+       struct drm_bridge_state *cur_state;
+       unsigned int num_in_bus_fmts, i;
+       struct drm_bridge *prev_bridge;
+       u32 *in_bus_fmts;
+       int ret;
+
+       prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
+       cur_state = drm_atomic_get_new_bridge_state(crtc_state->state,
+                                                   cur_bridge);
+
+       /*
+        * If bus format negotiation is not supported by this bridge, let's
+        * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and
+        * hope that it can handle this situation gracefully (by providing
+        * appropriate default values).
+        */
+       if (!cur_bridge->funcs->atomic_get_input_bus_fmts) {
+               if (cur_bridge != first_bridge) {
+                       ret = select_bus_fmt_recursive(first_bridge,
+                                                      prev_bridge, crtc_state,
+                                                      conn_state,
+                                                      MEDIA_BUS_FMT_FIXED);
+                       if (ret)
+                               return ret;
+               }
+
+               /*
+                * Driver does not implement the atomic state hooks, but that's
+                * fine, as long as it does not access the bridge state.
+                */
+               if (cur_state) {
+                       cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED;
+                       cur_state->output_bus_cfg.format = out_bus_fmt;
+               }
+
+               return 0;
+       }
+
+       /*
+        * If the driver implements ->atomic_get_input_bus_fmts() it
+        * should also implement the atomic state hooks.
+        */
+       if (WARN_ON(!cur_state))
+               return -EINVAL;
+
+       in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge,
+                                                       cur_state,
+                                                       crtc_state,
+                                                       conn_state,
+                                                       out_bus_fmt,
+                                                       &num_in_bus_fmts);
+       if (!num_in_bus_fmts)
+               return -ENOTSUPP;
+       else if (!in_bus_fmts)
+               return -ENOMEM;
+
+       if (first_bridge == cur_bridge) {
+               cur_state->input_bus_cfg.format = in_bus_fmts[0];
+               cur_state->output_bus_cfg.format = out_bus_fmt;
+               kfree(in_bus_fmts);
+               return 0;
+       }
+
+       for (i = 0; i < num_in_bus_fmts; i++) {
+               ret = select_bus_fmt_recursive(first_bridge, prev_bridge,
+                                              crtc_state, conn_state,
+                                              in_bus_fmts[i]);
+               if (ret != -ENOTSUPP)
+                       break;
+       }
+
+       if (!ret) {
+               cur_state->input_bus_cfg.format = in_bus_fmts[i];
+               cur_state->output_bus_cfg.format = out_bus_fmt;
+       }
+
+       kfree(in_bus_fmts);
+       return ret;
+}
+
+/*
+ * This function is called by &drm_atomic_bridge_chain_check() just before
+ * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
+ * It performs bus format negotiation between bridge elements. The negotiation
+ * happens in reverse order, starting from the last element in the chain up to
+ * @bridge.
+ *
+ * Negotiation starts by retrieving supported output bus formats on the last
+ * bridge element and testing them one by one. The test is recursive, meaning
+ * that for each tested output format, the whole chain will be walked backward,
+ * and each element will have to choose an input bus format that can be
+ * transcoded to the requested output format. When a bridge element does not
+ * support transcoding into a specific output format -ENOTSUPP is returned and
+ * the next bridge element will have to try a different format. If none of the
+ * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail.
+ *
+ * This implementation is relying on
+ * &drm_bridge_funcs.atomic_get_output_bus_fmts() and
+ * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported
+ * input/output formats.
+ *
+ * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by
+ * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts()
+ * tries a single format: &drm_connector.display_info.bus_formats[0] if
+ * available, MEDIA_BUS_FMT_FIXED otherwise.
+ *
+ * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented,
+ * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the
+ * bridge element that lacks this hook and asks the previous element in the
+ * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what
+ * to do in that case (fail if they want to enforce bus format negotiation, or
+ * provide a reasonable default if they need to support pipelines where not
+ * all elements support bus format negotiation).
+ */
+static int
+drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state)
+{
+       struct drm_connector *conn = conn_state->connector;
+       struct drm_encoder *encoder = bridge->encoder;
+       struct drm_bridge_state *last_bridge_state;
+       unsigned int i, num_out_bus_fmts;
+       struct drm_bridge *last_bridge;
+       u32 *out_bus_fmts;
+       int ret = 0;
+
+       last_bridge = list_last_entry(&encoder->bridge_chain,
+                                     struct drm_bridge, chain_node);
+       last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
+                                                           last_bridge);
+
+       if (last_bridge->funcs->atomic_get_output_bus_fmts) {
+               const struct drm_bridge_funcs *funcs = last_bridge->funcs;
+
+               /*
+                * If the driver implements ->atomic_get_output_bus_fmts() it
+                * should also implement the atomic state hooks.
+                */
+               if (WARN_ON(!last_bridge_state))
+                       return -EINVAL;
+
+               out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge,
+                                                       last_bridge_state,
+                                                       crtc_state,
+                                                       conn_state,
+                                                       &num_out_bus_fmts);
+               if (!num_out_bus_fmts)
+                       return -ENOTSUPP;
+               else if (!out_bus_fmts)
+                       return -ENOMEM;
+       } else {
+               num_out_bus_fmts = 1;
+               out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL);
+               if (!out_bus_fmts)
+                       return -ENOMEM;
+
+               if (conn->display_info.num_bus_formats &&
+                   conn->display_info.bus_formats)
+                       out_bus_fmts[0] = conn->display_info.bus_formats[0];
+               else
+                       out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
+       }
+
+       for (i = 0; i < num_out_bus_fmts; i++) {
+               ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state,
+                                              conn_state, out_bus_fmts[i]);
+               if (ret != -ENOTSUPP)
+                       break;
+       }
+
+       kfree(out_bus_fmts);
+
+       return ret;
+}
+
+static void
+drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge,
+                                     struct drm_connector *conn,
+                                     struct drm_atomic_state *state)
+{
+       struct drm_bridge_state *bridge_state, *next_bridge_state;
+       struct drm_bridge *next_bridge;
+       u32 output_flags = 0;
+
+       bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+
+       /* No bridge state attached to this bridge => nothing to propagate. */
+       if (!bridge_state)
+               return;
+
+       next_bridge = drm_bridge_get_next_bridge(bridge);
+
+       /*
+        * Let's try to apply the most common case here, that is, propagate
+        * display_info flags for the last bridge, and propagate the input
+        * flags of the next bridge element to the output end of the current
+        * bridge when the bridge is not the last one.
+        * There are exceptions to this rule, like when signal inversion is
+        * happening at the board level, but that's something drivers can deal
+        * with from their &drm_bridge_funcs.atomic_check() implementation by
+        * simply overriding the flags value we've set here.
+        */
+       if (!next_bridge) {
+               output_flags = conn->display_info.bus_flags;
+       } else {
+               next_bridge_state = drm_atomic_get_new_bridge_state(state,
+                                                               next_bridge);
+               /*
+                * No bridge state attached to the next bridge, just leave the
+                * flags to 0.
+                */
+               if (next_bridge_state)
+                       output_flags = next_bridge_state->input_bus_cfg.flags;
+       }
+
+       bridge_state->output_bus_cfg.flags = output_flags;
+
+       /*
+        * Propage the output flags to the input end of the bridge. Again, it's
+        * not necessarily what all bridges want, but that's what most of them
+        * do, and by doing that by default we avoid forcing drivers to
+        * duplicate the "dummy propagation" logic.
+        */
+       bridge_state->input_bus_cfg.flags = output_flags;
+}
+
+/**
+ * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
+ * @bridge: bridge control structure
+ * @crtc_state: new CRTC state
+ * @conn_state: new connector state
+ *
+ * First trigger a bus format negotiation before calling
+ * &drm_bridge_funcs.atomic_check() (falls back on
+ * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
+ * starting from the last bridge to the first. These are called before calling
+ * &drm_encoder_helper_funcs.atomic_check()
+ *
+ * RETURNS:
+ * 0 on success, a negative error code on failure
+ */
+int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
+                                 struct drm_crtc_state *crtc_state,
+                                 struct drm_connector_state *conn_state)
+{
+       struct drm_connector *conn = conn_state->connector;
+       struct drm_encoder *encoder;
+       struct drm_bridge *iter;
+       int ret;
+
+       if (!bridge)
+               return 0;
+
+       ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state,
+                                                     conn_state);
+       if (ret)
+               return ret;
+
+       encoder = bridge->encoder;
+       list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+               int ret;
+
+               /*
+                * Bus flags are propagated by default. If a bridge needs to
+                * tweak the input bus flags for any reason, it should happen
+                * in its &drm_bridge_funcs.atomic_check() implementation such
+                * that preceding bridges in the chain can propagate the new
+                * bus flags.
+                */
+               drm_atomic_bridge_propagate_bus_flags(iter, conn,
+                                                     crtc_state->state);
+
+               ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
+               if (ret)
+                       return ret;
+
+               if (iter == bridge)
+                       break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
+
 #ifdef CONFIG_OF
 /**
  * of_drm_find_bridge - find the bridge corresponding to the device node in
index 8ce9d73..19297e5 100644 (file)
@@ -149,7 +149,6 @@ static int drm_addmap_core(struct drm_device *dev, resource_size_t offset,
 {
        struct drm_local_map *map;
        struct drm_map_list *list;
-       drm_dma_handle_t *dmah;
        unsigned long user_token;
        int ret;
 
@@ -324,14 +323,14 @@ static int drm_addmap_core(struct drm_device *dev, resource_size_t offset,
                 * As we're limiting the address to 2^32-1 (or less),
                 * casting it down to 32 bits is no problem, but we
                 * need to point to a 64bit variable first. */
-               dmah = drm_pci_alloc(dev, map->size, map->size);
-               if (!dmah) {
+               map->handle = dma_alloc_coherent(&dev->pdev->dev,
+                                                map->size,
+                                                &map->offset,
+                                                GFP_KERNEL);
+               if (!map->handle) {
                        kfree(map);
                        return -ENOMEM;
                }
-               map->handle = dmah->vaddr;
-               map->offset = (unsigned long)dmah->busaddr;
-               kfree(dmah);
                break;
        default:
                kfree(map);
@@ -513,7 +512,6 @@ int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data,
 int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
 {
        struct drm_map_list *r_list = NULL, *list_t;
-       drm_dma_handle_t dmah;
        int found = 0;
        struct drm_master *master;
 
@@ -554,10 +552,10 @@ int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
        case _DRM_SCATTER_GATHER:
                break;
        case _DRM_CONSISTENT:
-               dmah.vaddr = map->handle;
-               dmah.busaddr = map->offset;
-               dmah.size = map->size;
-               __drm_legacy_pci_free(dev, &dmah);
+               dma_free_coherent(&dev->pdev->dev,
+                                 map->size,
+                                 map->handle,
+                                 map->offset);
                break;
        }
        kfree(map);
index 2166000..f632ca0 100644 (file)
@@ -140,6 +140,13 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
                connector->force = mode->force;
        }
 
+       if (mode->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) {
+               DRM_INFO("cmdline forces connector %s panel_orientation to %d\n",
+                        connector->name, mode->panel_orientation);
+               drm_connector_set_panel_orientation(connector,
+                                                   mode->panel_orientation);
+       }
+
        DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
                      connector->name, mode->name,
                      mode->xres, mode->yres,
@@ -1139,7 +1146,8 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
  *     coordinates, so if userspace rotates the picture to adjust for
  *     the orientation it must also apply the same transformation to the
  *     touchscreen input coordinates. This property is initialized by calling
- *     drm_connector_init_panel_orientation_property().
+ *     drm_connector_set_panel_orientation() or
+ *     drm_connector_set_panel_orientation_with_quirk()
  *
  * scaling mode:
  *     This property defines how a non-native mode is upscaled to the native
@@ -2046,38 +2054,41 @@ void drm_connector_set_vrr_capable_property(
 EXPORT_SYMBOL(drm_connector_set_vrr_capable_property);
 
 /**
- * drm_connector_init_panel_orientation_property -
- *     initialize the connecters panel_orientation property
- * @connector: connector for which to init the panel-orientation property.
- * @width: width in pixels of the panel, used for panel quirk detection
- * @height: height in pixels of the panel, used for panel quirk detection
+ * drm_connector_set_panel_orientation - sets the connecter's panel_orientation
+ * @connector: connector for which to set the panel-orientation property.
+ * @panel_orientation: drm_panel_orientation value to set
+ *
+ * This function sets the connector's panel_orientation and attaches
+ * a "panel orientation" property to the connector.
  *
- * This function should only be called for built-in panels, after setting
- * connector->display_info.panel_orientation first (if known).
+ * Calling this function on a connector where the panel_orientation has
+ * already been set is a no-op (e.g. the orientation has been overridden with
+ * a kernel commandline option).
  *
- * This function will check for platform specific (e.g. DMI based) quirks
- * overriding display_info.panel_orientation first, then if panel_orientation
- * is not DRM_MODE_PANEL_ORIENTATION_UNKNOWN it will attach the
- * "panel orientation" property to the connector.
+ * It is allowed to call this function with a panel_orientation of
+ * DRM_MODE_PANEL_ORIENTATION_UNKNOWN, in which case it is a no-op.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_connector_init_panel_orientation_property(
-       struct drm_connector *connector, int width, int height)
+int drm_connector_set_panel_orientation(
+       struct drm_connector *connector,
+       enum drm_panel_orientation panel_orientation)
 {
        struct drm_device *dev = connector->dev;
        struct drm_display_info *info = &connector->display_info;
        struct drm_property *prop;
-       int orientation_quirk;
 
-       orientation_quirk = drm_get_panel_orientation_quirk(width, height);
-       if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
-               info->panel_orientation = orientation_quirk;
+       /* Already set? */
+       if (info->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+               return 0;
 
-       if (info->panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+       /* Don't attach the property if the orientation is unknown */
+       if (panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
                return 0;
 
+       info->panel_orientation = panel_orientation;
+
        prop = dev->mode_config.panel_orientation_property;
        if (!prop) {
                prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
@@ -2094,7 +2105,37 @@ int drm_connector_init_panel_orientation_property(
                                   info->panel_orientation);
        return 0;
 }
-EXPORT_SYMBOL(drm_connector_init_panel_orientation_property);
+EXPORT_SYMBOL(drm_connector_set_panel_orientation);
+
+/**
+ * drm_connector_set_panel_orientation_with_quirk -
+ *     set the connecter's panel_orientation after checking for quirks
+ * @connector: connector for which to init the panel-orientation property.
+ * @panel_orientation: drm_panel_orientation value to set
+ * @width: width in pixels of the panel, used for panel quirk detection
+ * @height: height in pixels of the panel, used for panel quirk detection
+ *
+ * Like drm_connector_set_panel_orientation(), but with a check for platform
+ * specific (e.g. DMI based) quirks overriding the passed in panel_orientation.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_set_panel_orientation_with_quirk(
+       struct drm_connector *connector,
+       enum drm_panel_orientation panel_orientation,
+       int width, int height)
+{
+       int orientation_quirk;
+
+       orientation_quirk = drm_get_panel_orientation_quirk(width, height);
+       if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+               panel_orientation = orientation_quirk;
+
+       return drm_connector_set_panel_orientation(connector,
+                                                  panel_orientation);
+}
+EXPORT_SYMBOL(drm_connector_set_panel_orientation_with_quirk);
 
 int drm_connector_set_obj_prop(struct drm_mode_object *obj,
                                    struct drm_property *property,
index c7d5e4c..16f2413 100644 (file)
@@ -216,6 +216,8 @@ int drm_mode_rmfb_ioctl(struct drm_device *dev,
                        void *data, struct drm_file *file_priv);
 int drm_mode_getfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv);
+int drm_mode_getfb2_ioctl(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv);
 
index eab0f26..4e673d3 100644 (file)
@@ -182,8 +182,7 @@ int drm_debugfs_create_files(const struct drm_info_list *files, int count,
        for (i = 0; i < count; i++) {
                u32 features = files[i].driver_features;
 
-               if (features != 0 &&
-                   (dev->driver->driver_features & features) != features)
+               if (features && !drm_core_check_all_features(dev, features))
                        continue;
 
                tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
index e22b812..5d67a41 100644 (file)
@@ -372,7 +372,7 @@ void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc)
 
        crc_ent = debugfs_create_dir("crc", crtc->debugfs_entry);
 
-       debugfs_create_file("control", S_IRUGO, crc_ent, crtc,
+       debugfs_create_file("control", S_IRUGO | S_IWUSR, crc_ent, crtc,
                            &drm_crtc_crc_control_fops);
        debugfs_create_file("data", S_IRUGO, crc_ent, crtc,
                            &drm_crtc_crc_data_fops);
index e45b078..a7add55 100644 (file)
 #include "drm_legacy.h"
 
 /**
- * Initialize the DMA data.
+ * drm_legacy_dma_setup() - Initialize the DMA data.
  *
- * \param dev DRM device.
- * \return zero on success or a negative value on failure.
+ * @dev: DRM device.
+ * Return: zero on success or a negative value on failure.
  *
  * Allocate and initialize a drm_device_dma structure.
  */
@@ -71,9 +71,9 @@ int drm_legacy_dma_setup(struct drm_device *dev)
 }
 
 /**
- * Cleanup the DMA resources.
+ * drm_legacy_dma_takedown() - Cleanup the DMA resources.
  *
- * \param dev DRM device.
+ * @dev: DRM device.
  *
  * Free all pages associated with DMA buffers, the buffers and pages lists, and
  * finally the drm_device::dma structure itself.
@@ -120,10 +120,10 @@ void drm_legacy_dma_takedown(struct drm_device *dev)
 }
 
 /**
- * Free a buffer.
+ * drm_legacy_free_buffer() - Free a buffer.
  *
- * \param dev DRM device.
- * \param buf buffer to free.
+ * @dev: DRM device.
+ * @buf: buffer to free.
  *
  * Resets the fields of \p buf.
  */
@@ -139,9 +139,10 @@ void drm_legacy_free_buffer(struct drm_device *dev, struct drm_buf * buf)
 }
 
 /**
- * Reclaim the buffers.
+ * drm_legacy_reclaim_buffers() - Reclaim the buffers.
  *
- * \param file_priv DRM file private.
+ * @dev: DRM device.
+ * @file_priv: DRM file private.
  *
  * Frees each buffer associated with \p file_priv not already on the hardware.
  */
index a5364b5..5a103e9 100644 (file)
@@ -470,8 +470,7 @@ void drm_dp_downstream_debug(struct seq_file *m,
        int len;
        uint8_t rev[2];
        int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
-       bool branch_device = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
-                            DP_DWN_STRM_PORT_PRESENT;
+       bool branch_device = drm_dp_is_branch(dpcd);
 
        seq_printf(m, "\tDP branch device present: %s\n",
                   branch_device ? "yes" : "no");
index cce0b1b..a811247 100644 (file)
@@ -3499,9 +3499,9 @@ static int drm_dp_get_vc_payload_bw(u8 dp_link_bw, u8  dp_link_count)
 int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state)
 {
        int ret = 0;
-       int i = 0;
        struct drm_dp_mst_branch *mstb = NULL;
 
+       mutex_lock(&mgr->payload_lock);
        mutex_lock(&mgr->lock);
        if (mst_state == mgr->mst_state)
                goto out_unlock;
@@ -3509,6 +3509,8 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
        mgr->mst_state = mst_state;
        /* set the device into MST mode */
        if (mst_state) {
+               struct drm_dp_payload reset_pay;
+
                WARN_ON(mgr->mst_primary);
 
                /* get dpcd info */
@@ -3538,17 +3540,15 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                drm_dp_mst_topology_get_mstb(mgr->mst_primary);
 
                ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-                                                        DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
-               if (ret < 0) {
+                                        DP_MST_EN |
+                                        DP_UP_REQ_EN |
+                                        DP_UPSTREAM_IS_SRC);
+               if (ret < 0)
                        goto out_unlock;
-               }
 
-               {
-                       struct drm_dp_payload reset_pay;
-                       reset_pay.start_slot = 0;
-                       reset_pay.num_slots = 0x3f;
-                       drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
-               }
+               reset_pay.start_slot = 0;
+               reset_pay.num_slots = 0x3f;
+               drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
 
                queue_work(system_long_wq, &mgr->work);
 
@@ -3560,27 +3560,19 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                /* this can fail if the device is gone */
                drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
                ret = 0;
-               mutex_lock(&mgr->payload_lock);
-               memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
+               memset(mgr->payloads, 0,
+                      mgr->max_payloads * sizeof(mgr->payloads[0]));
+               memset(mgr->proposed_vcpis, 0,
+                      mgr->max_payloads * sizeof(mgr->proposed_vcpis[0]));
                mgr->payload_mask = 0;
                set_bit(0, &mgr->payload_mask);
-               for (i = 0; i < mgr->max_payloads; i++) {
-                       struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i];
-
-                       if (vcpi) {
-                               vcpi->vcpi = 0;
-                               vcpi->num_slots = 0;
-                       }
-                       mgr->proposed_vcpis[i] = NULL;
-               }
                mgr->vcpi_mask = 0;
-               mutex_unlock(&mgr->payload_lock);
-
                mgr->payload_id_table_cleared = false;
        }
 
 out_unlock:
        mutex_unlock(&mgr->lock);
+       mutex_unlock(&mgr->payload_lock);
        if (mstb)
                drm_dp_mst_topology_put_mstb(mstb);
        return ret;
@@ -3708,7 +3700,7 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
 {
        int len;
        u8 replyblock[32];
-       int replylen, origlen, curreply;
+       int replylen, curreply;
        int ret;
        struct drm_dp_sideband_msg_rx *msg;
        int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE : DP_SIDEBAND_MSG_DOWN_REP_BASE;
@@ -3728,7 +3720,6 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
        }
        replylen = msg->curchunk_len + msg->curchunk_hdrlen;
 
-       origlen = replylen;
        replylen -= len;
        curreply = len;
        while (replylen > 0) {
index 92d1672..1075b3a 100644 (file)
@@ -220,7 +220,7 @@ void drm_file_free(struct drm_file *file)
        DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
                  task_pid_nr(current),
                  (long)old_encode_dev(file->minor->kdev->devt),
-                 dev->open_count);
+                 atomic_read(&dev->open_count));
 
        if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
            dev->driver->preclose)
@@ -379,7 +379,7 @@ int drm_open(struct inode *inode, struct file *filp)
                return PTR_ERR(minor);
 
        dev = minor->dev;
-       if (!dev->open_count++)
+       if (!atomic_fetch_inc(&dev->open_count))
                need_setup = 1;
 
        /* share address_space across all char-devs of a single device */
@@ -398,7 +398,7 @@ int drm_open(struct inode *inode, struct file *filp)
        return 0;
 
 err_undo:
-       dev->open_count--;
+       atomic_dec(&dev->open_count);
        drm_minor_release(minor);
        return retcode;
 }
@@ -440,11 +440,11 @@ int drm_release(struct inode *inode, struct file *filp)
 
        mutex_lock(&drm_global_mutex);
 
-       DRM_DEBUG("open_count = %d\n", dev->open_count);
+       DRM_DEBUG("open_count = %d\n", atomic_read(&dev->open_count));
 
        drm_close_helper(filp);
 
-       if (!--dev->open_count)
+       if (atomic_dec_and_test(&dev->open_count))
                drm_lastclose(dev);
 
        mutex_unlock(&drm_global_mutex);
@@ -456,6 +456,40 @@ int drm_release(struct inode *inode, struct file *filp)
 EXPORT_SYMBOL(drm_release);
 
 /**
+ * drm_release_noglobal - release method for DRM file
+ * @inode: device inode
+ * @filp: file pointer.
+ *
+ * This function may be used by drivers as their &file_operations.release
+ * method. It frees any resources associated with the open file prior to taking
+ * the drm_global_mutex, which then calls the &drm_driver.postclose driver
+ * callback. If this is the last open file for the DRM device also proceeds to
+ * call the &drm_driver.lastclose driver callback.
+ *
+ * RETURNS:
+ *
+ * Always succeeds and returns 0.
+ */
+int drm_release_noglobal(struct inode *inode, struct file *filp)
+{
+       struct drm_file *file_priv = filp->private_data;
+       struct drm_minor *minor = file_priv->minor;
+       struct drm_device *dev = minor->dev;
+
+       drm_close_helper(filp);
+
+       if (atomic_dec_and_mutex_lock(&dev->open_count, &drm_global_mutex)) {
+               drm_lastclose(dev);
+               mutex_unlock(&drm_global_mutex);
+       }
+
+       drm_minor_release(minor);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_release_noglobal);
+
+/**
  * drm_read - read method for DRM file
  * @filp: file pointer
  * @buffer: userspace destination pointer for the read
index 5756431..57ac94c 100644 (file)
@@ -31,6 +31,7 @@
 #include <drm/drm_file.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_gem.h>
 #include <drm/drm_print.h>
 #include <drm/drm_util.h>
 
@@ -548,7 +549,128 @@ int drm_mode_getfb(struct drm_device *dev,
 
 out:
        drm_framebuffer_put(fb);
+       return ret;
+}
+
+/**
+ * drm_mode_getfb2 - get extended FB info
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_mode_getfb2_ioctl(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd2 *r = data;
+       struct drm_framebuffer *fb;
+       unsigned int i;
+       int ret;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
+       if (!fb)
+               return -ENOENT;
+
+       /* For multi-plane framebuffers, we require the driver to place the
+        * GEM objects directly in the drm_framebuffer. For single-plane
+        * framebuffers, we can fall back to create_handle.
+        */
+       if (!fb->obj[0] &&
+           (fb->format->num_planes > 1 || !fb->funcs->create_handle)) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       r->height = fb->height;
+       r->width = fb->width;
+       r->pixel_format = fb->format->format;
+
+       r->flags = 0;
+       if (dev->mode_config.allow_fb_modifiers)
+               r->flags |= DRM_MODE_FB_MODIFIERS;
+
+       for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
+               r->handles[i] = 0;
+               r->pitches[i] = 0;
+               r->offsets[i] = 0;
+               r->modifier[i] = 0;
+       }
+
+       for (i = 0; i < fb->format->num_planes; i++) {
+               r->pitches[i] = fb->pitches[i];
+               r->offsets[i] = fb->offsets[i];
+               if (dev->mode_config.allow_fb_modifiers)
+                       r->modifier[i] = fb->modifier;
+       }
+
+       /* GET_FB2() is an unprivileged ioctl so we must not return a
+        * buffer-handle to non master/root processes! To match GET_FB()
+        * just return invalid handles (0) for non masters/root
+        * rather than making GET_FB2() privileged.
+        */
+       if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN)) {
+               ret = 0;
+               goto out;
+       }
 
+       for (i = 0; i < fb->format->num_planes; i++) {
+               int j;
+
+               /* If we reuse the same object for multiple planes, also
+                * return the same handle.
+                */
+               for (j = 0; j < i; j++) {
+                       if (fb->obj[i] == fb->obj[j]) {
+                               r->handles[i] = r->handles[j];
+                               break;
+                       }
+               }
+
+               if (r->handles[i])
+                       continue;
+
+               if (fb->obj[i]) {
+                       ret = drm_gem_handle_create(file_priv, fb->obj[i],
+                                                   &r->handles[i]);
+               } else {
+                       WARN_ON(i > 0);
+                       ret = fb->funcs->create_handle(fb, file_priv,
+                                                      &r->handles[i]);
+               }
+
+               if (ret != 0)
+                       goto out;
+       }
+
+out:
+       if (ret != 0) {
+               /* Delete any previously-created handles on failure. */
+               for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
+                       int j;
+
+                       if (r->handles[i])
+                               drm_gem_handle_delete(file_priv, r->handles[i]);
+
+                       /* Zero out any handles identical to the one we just
+                        * deleted.
+                        */
+                       for (j = i + 1; j < ARRAY_SIZE(r->handles); j++) {
+                               if (r->handles[j] == r->handles[i])
+                                       r->handles[j] = 0;
+                       }
+               }
+       }
+
+       drm_framebuffer_put(fb);
        return ret;
 }
 
index a486332..92a11bb 100644 (file)
@@ -1141,3 +1141,64 @@ void drm_vram_helper_release_mm(struct drm_device *dev)
        dev->vram_mm = NULL;
 }
 EXPORT_SYMBOL(drm_vram_helper_release_mm);
+
+/*
+ * Mode-config helpers
+ */
+
+static enum drm_mode_status
+drm_vram_helper_mode_valid_internal(struct drm_device *dev,
+                                   const struct drm_display_mode *mode,
+                                   unsigned long max_bpp)
+{
+       struct drm_vram_mm *vmm = dev->vram_mm;
+       unsigned long fbsize, fbpages, max_fbpages;
+
+       if (WARN_ON(!dev->vram_mm))
+               return MODE_BAD;
+
+       max_fbpages = (vmm->vram_size / 2) >> PAGE_SHIFT;
+
+       fbsize = mode->hdisplay * mode->vdisplay * max_bpp;
+       fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);
+
+       if (fbpages > max_fbpages)
+               return MODE_MEM;
+
+       return MODE_OK;
+}
+
+/**
+ * drm_vram_helper_mode_valid - Tests if a display mode's
+ *     framebuffer fits into the available video memory.
+ * @dev:       the DRM device
+ * @mode:      the mode to test
+ *
+ * This function tests if enough video memory is available for using the
+ * specified display mode. Atomic modesetting requires importing the
+ * designated framebuffer into video memory before evicting the active
+ * one. Hence, any framebuffer may consume at most half of the available
+ * VRAM. Display modes that require a larger framebuffer can not be used,
+ * even if the CRTC does support them. Each framebuffer is assumed to
+ * have 32-bit color depth.
+ *
+ * Note:
+ * The function can only test if the display mode is supported in
+ * general. If there are too many framebuffers pinned to video memory,
+ * a display mode may still not be usable in practice. The color depth of
+ * 32-bit fits all current use case. A more flexible test can be added
+ * when necessary.
+ *
+ * Returns:
+ * MODE_OK if the display mode is supported, or an error code of type
+ * enum drm_mode_status otherwise.
+ */
+enum drm_mode_status
+drm_vram_helper_mode_valid(struct drm_device *dev,
+                          const struct drm_display_mode *mode)
+{
+       static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */
+
+       return drm_vram_helper_mode_valid_internal(dev, mode, max_bpp);
+}
+EXPORT_SYMBOL(drm_vram_helper_mode_valid);
index 5afb396..9e41972 100644 (file)
@@ -671,6 +671,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB2, drm_mode_getfb2_ioctl, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0),
index 16bff1b..558baf9 100644 (file)
@@ -24,7 +24,6 @@
 #include <drm/drm_modes.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_vblank.h>
 #include <video/mipi_display.h>
 
 #define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
@@ -238,6 +237,23 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(mipi_dbi_buf_copy);
 
+static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev,
+                                       unsigned int xs, unsigned int xe,
+                                       unsigned int ys, unsigned int ye)
+{
+       struct mipi_dbi *dbi = &dbidev->dbi;
+
+       xs += dbidev->left_offset;
+       xe += dbidev->left_offset;
+       ys += dbidev->top_offset;
+       ye += dbidev->top_offset;
+
+       mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, (xs >> 8) & 0xff,
+                        xs & 0xff, (xe >> 8) & 0xff, xe & 0xff);
+       mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, (ys >> 8) & 0xff,
+                        ys & 0xff, (ye >> 8) & 0xff, ye & 0xff);
+}
+
 static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
 {
        struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
@@ -271,12 +287,8 @@ static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
                tr = cma_obj->vaddr;
        }
 
-       mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,
-                        (rect->x1 >> 8) & 0xff, rect->x1 & 0xff,
-                        ((rect->x2 - 1) >> 8) & 0xff, (rect->x2 - 1) & 0xff);
-       mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS,
-                        (rect->y1 >> 8) & 0xff, rect->y1 & 0xff,
-                        ((rect->y2 - 1) >> 8) & 0xff, (rect->y2 - 1) & 0xff);
+       mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1,
+                                   rect->y2 - 1);
 
        ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr,
                                   width * height * 2);
@@ -299,18 +311,10 @@ void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
                          struct drm_plane_state *old_state)
 {
        struct drm_plane_state *state = pipe->plane.state;
-       struct drm_crtc *crtc = &pipe->crtc;
        struct drm_rect rect;
 
        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
                mipi_dbi_fb_dirty(state->fb, &rect);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-               crtc->state->event = NULL;
-       }
 }
 EXPORT_SYMBOL(mipi_dbi_pipe_update);
 
@@ -366,10 +370,7 @@ static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev)
 
        memset(dbidev->tx_buf, 0, len);
 
-       mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0,
-                        ((width - 1) >> 8) & 0xFF, (width - 1) & 0xFF);
-       mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0,
-                        ((height - 1) >> 8) & 0xFF, (height - 1) & 0xFF);
+       mipi_dbi_set_window_address(dbidev, 0, width - 1, 0, height - 1);
        mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START,
                             (u8 *)dbidev->tx_buf, len);
 
index f2e43d3..c6bb987 100644 (file)
@@ -51,8 +51,6 @@
 drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
 {
        drm_dma_handle_t *dmah;
-       unsigned long addr;
-       size_t sz;
 
        /* pci_alloc_consistent only guarantees alignment to the smallest
         * PAGE_SIZE order which is greater than or equal to the requested size.
@@ -68,47 +66,18 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali
        dmah->size = size;
        dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size,
                                         &dmah->busaddr,
-                                        GFP_KERNEL | __GFP_COMP);
+                                        GFP_KERNEL);
 
        if (dmah->vaddr == NULL) {
                kfree(dmah);
                return NULL;
        }
 
-       /* XXX - Is virt_to_page() legal for consistent mem? */
-       /* Reserve */
-       for (addr = (unsigned long)dmah->vaddr, sz = size;
-            sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-               SetPageReserved(virt_to_page((void *)addr));
-       }
-
        return dmah;
 }
 
 EXPORT_SYMBOL(drm_pci_alloc);
 
-/*
- * Free a PCI consistent memory block without freeing its descriptor.
- *
- * This function is for internal use in the Linux-specific DRM core code.
- */
-void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
-{
-       unsigned long addr;
-       size_t sz;
-
-       if (dmah->vaddr) {
-               /* XXX - Is virt_to_page() legal for consistent mem? */
-               /* Unreserve */
-               for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
-                    sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-                       ClearPageReserved(virt_to_page((void *)addr));
-               }
-               dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
-                                 dmah->busaddr);
-       }
-}
-
 /**
  * drm_pci_free - Free a PCI consistent memory block
  * @dev: DRM device
@@ -119,7 +88,8 @@ void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
  */
 void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 {
-       __drm_legacy_pci_free(dev, dmah);
+       dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
+                         dmah->busaddr);
        kfree(dmah);
 }
 
index 669c93f..42d4641 100644 (file)
  *  - Signal a syncobj (set a trivially signaled fence)
  *  - Wait for a syncobj's fence to appear and be signaled
  *
+ * The syncobj userspace API also provides operations to manipulate a syncobj
+ * in terms of a timeline of struct &dma_fence_chain rather than a single
+ * struct &dma_fence, through the following operations:
+ *
+ *   - Signal a given point on the timeline
+ *   - Wait for a given point to appear and/or be signaled
+ *   - Import and export from/to a given point of a timeline
+ *
  * At it's core, a syncobj is simply a wrapper around a pointer to a struct
  * &dma_fence which may be NULL.
  * When a syncobj is first created, its pointer is either NULL or a pointer
  * to an already signaled fence depending on whether the
  * &DRM_SYNCOBJ_CREATE_SIGNALED flag is passed to
  * &DRM_IOCTL_SYNCOBJ_CREATE.
- * When GPU work which signals a syncobj is enqueued in a DRM driver,
- * the syncobj fence is replaced with a fence which will be signaled by the
- * completion of that work.
- * When GPU work which waits on a syncobj is enqueued in a DRM driver, the
- * driver retrieves syncobj's current fence at the time the work is enqueued
- * waits on that fence before submitting the work to hardware.
- * If the syncobj's fence is NULL, the enqueue operation is expected to fail.
- * All manipulation of the syncobjs's fence happens in terms of the current
- * fence at the time the ioctl is called by userspace regardless of whether
- * that operation is an immediate host-side operation (signal or reset) or
- * or an operation which is enqueued in some driver queue.
- * &DRM_IOCTL_SYNCOBJ_RESET and &DRM_IOCTL_SYNCOBJ_SIGNAL can be used to
- * manipulate a syncobj from the host by resetting its pointer to NULL or
+ *
+ * If the syncobj is considered as a binary (its state is either signaled or
+ * unsignaled) primitive, when GPU work is enqueued in a DRM driver to signal
+ * the syncobj, the syncobj's fence is replaced with a fence which will be
+ * signaled by the completion of that work.
+ * If the syncobj is considered as a timeline primitive, when GPU work is
+ * enqueued in a DRM driver to signal the a given point of the syncobj, a new
+ * struct &dma_fence_chain pointing to the DRM driver's fence and also
+ * pointing to the previous fence that was in the syncobj. The new struct
+ * &dma_fence_chain fence replace the syncobj's fence and will be signaled by
+ * completion of the DRM driver's work and also any work associated with the
+ * fence previously in the syncobj.
+ *
+ * When GPU work which waits on a syncobj is enqueued in a DRM driver, at the
+ * time the work is enqueued, it waits on the syncobj's fence before
+ * submitting the work to hardware. That fence is either :
+ *
+ *    - The syncobj's current fence if the syncobj is considered as a binary
+ *      primitive.
+ *    - The struct &dma_fence associated with a given point if the syncobj is
+ *      considered as a timeline primitive.
+ *
+ * If the syncobj's fence is NULL or not present in the syncobj's timeline,
+ * the enqueue operation is expected to fail.
+ *
+ * With binary syncobj, all manipulation of the syncobjs's fence happens in
+ * terms of the current fence at the time the ioctl is called by userspace
+ * regardless of whether that operation is an immediate host-side operation
+ * (signal or reset) or or an operation which is enqueued in some driver
+ * queue. &DRM_IOCTL_SYNCOBJ_RESET and &DRM_IOCTL_SYNCOBJ_SIGNAL can be used
+ * to manipulate a syncobj from the host by resetting its pointer to NULL or
  * setting its pointer to a fence which is already signaled.
  *
+ * With a timeline syncobj, all manipulation of the synobj's fence happens in
+ * terms of a u64 value referring to point in the timeline. See
+ * dma_fence_chain_find_seqno() to see how a given point is found in the
+ * timeline.
+ *
+ * Note that applications should be careful to always use timeline set of
+ * ioctl() when dealing with syncobj considered as timeline. Using a binary
+ * set of ioctl() with a syncobj considered as timeline could result incorrect
+ * synchronization. The use of binary syncobj is supported through the
+ * timeline set of ioctl() by using a point value of 0, this will reproduce
+ * the behavior of the binary set of ioctl() (for example replace the
+ * syncobj's fence when signaling).
+ *
  *
  * Host-side wait on syncobjs
  * --------------------------
  * synchronize between the two.
  * This requirement is inherited from the Vulkan fence API.
  *
+ * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj
+ * handles as well as an array of u64 points and does a host-side wait on all
+ * of syncobj fences at the given points simultaneously.
+ *
+ * &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT also adds the ability to wait for a given
+ * fence to materialize on the timeline without waiting for the fence to be
+ * signaled by using the &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE flag. This
+ * requirement is inherited from the wait-before-signal behavior required by
+ * the Vulkan timeline semaphore API.
+ *
  *
  * Import/export of syncobjs
  * -------------------------
  * Because sync files are immutable, resetting or signaling the syncobj
  * will not affect any sync files whose fences have been imported into the
  * syncobj.
+ *
+ *
+ * Import/export of timeline points in timeline syncobjs
+ * -----------------------------------------------------
+ *
+ * &DRM_IOCTL_SYNCOBJ_TRANSFER provides a mechanism to transfer a struct
+ * &dma_fence_chain of a syncobj at a given u64 point to another u64 point
+ * into another syncobj.
+ *
+ * Note that if you want to transfer a struct &dma_fence_chain from a given
+ * point on a timeline syncobj from/into a binary syncobj, you can use the
+ * point 0 to mean take/replace the fence in the syncobj.
  */
 
 #include <linux/anon_inodes.h>
index 1659b13..27a99c4 100644 (file)
  * &drm_driver.max_vblank_count. In that case the vblank core only disables the
  * vblanks after a timer has expired, which can be configured through the
  * ``vblankoffdelay`` module parameter.
+ *
+ * Drivers for hardware without support for vertical-blanking interrupts
+ * must not call drm_vblank_init(). For such drivers, atomic helpers will
+ * automatically generate fake vblank events as part of the display update.
+ * This functionality also can be controlled by the driver by enabling and
+ * disabling struct drm_crtc_state.no_vblank.
  */
 
 /* Retry timestamp calculation up to 3 times to satisfy
@@ -502,6 +508,28 @@ err:
 EXPORT_SYMBOL(drm_vblank_init);
 
 /**
+ * drm_dev_has_vblank - test if vblanking has been initialized for
+ *                      a device
+ * @dev: the device
+ *
+ * Drivers may call this function to test if vblank support is
+ * initialized for a device. For most hardware this means that vblanking
+ * can also be enabled.
+ *
+ * Atomic helpers use this function to initialize
+ * &drm_crtc_state.no_vblank. See also drm_atomic_helper_check_modeset().
+ *
+ * Returns:
+ * True if vblanking has been initialized for the given device, false
+ * otherwise.
+ */
+bool drm_dev_has_vblank(const struct drm_device *dev)
+{
+       return dev->num_crtcs != 0;
+}
+EXPORT_SYMBOL(drm_dev_has_vblank);
+
+/**
  * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC
  * @crtc: which CRTC's vblank waitqueue to retrieve
  *
index 52e87e4..64619fe 100644 (file)
@@ -269,8 +269,6 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                }
 
                if (!found_maps) {
-                       drm_dma_handle_t dmah;
-
                        switch (map->type) {
                        case _DRM_REGISTERS:
                        case _DRM_FRAME_BUFFER:
@@ -284,10 +282,10 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                        case _DRM_SCATTER_GATHER:
                                break;
                        case _DRM_CONSISTENT:
-                               dmah.vaddr = map->handle;
-                               dmah.busaddr = map->offset;
-                               dmah.size = map->size;
-                               __drm_legacy_pci_free(dev, &dmah);
+                               dma_free_coherent(&dev->pdev->dev,
+                                                 map->size,
+                                                 map->handle,
+                                                 map->offset);
                                break;
                        }
                        kfree(map);
index 50b988f..99397ac 100644 (file)
@@ -54,6 +54,7 @@ int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
 }
 
 const struct drm_mode_config_funcs hibmc_mode_funcs = {
+       .mode_valid = drm_vram_helper_mode_valid,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
        .fb_create = drm_gem_fb_create,
index f8e8821..a745730 100644 (file)
@@ -1668,9 +1668,8 @@ static void icl_dsi_add_properties(struct intel_connector *connector)
 
        connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
 
-       connector->base.display_info.panel_orientation =
-                       intel_dsi_get_panel_orientation(connector);
-       drm_connector_init_panel_orientation_property(&connector->base,
+       drm_connector_set_panel_orientation_with_quirk(&connector->base,
+                               intel_dsi_get_panel_orientation(connector),
                                connector->panel.fixed_mode->hdisplay,
                                connector->panel.fixed_mode->vdisplay);
 }
index 888ea8a..fdd943a 100644 (file)
@@ -1181,8 +1181,6 @@ struct intel_hdmi {
 };
 
 struct intel_dp_mst_encoder;
-#define DP_MAX_DOWNSTREAM_PORTS                0x10
-
 /*
  * enum link_m_n_set:
  *     When platform provides two set of M_N registers for dp, we can
index c7424e2..4074d83 100644 (file)
@@ -3149,7 +3149,7 @@ static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
         * FIXME should really check all downstream ports...
         */
        return intel_dp->dpcd[DP_DPCD_REV] == 0x11 &&
-               intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
+               drm_dp_is_branch(intel_dp->dpcd) &&
                intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
 }
 
@@ -7401,9 +7401,12 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        intel_connector->panel.backlight.power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector, pipe);
 
-       if (fixed_mode)
-               drm_connector_init_panel_orientation_property(
-                       connector, fixed_mode->hdisplay, fixed_mode->vdisplay);
+       if (fixed_mode) {
+               /* We do not know the orientation, but their might be a quirk */
+               drm_connector_set_panel_orientation_with_quirk(connector,
+                               DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
+                               fixed_mode->hdisplay, fixed_mode->vdisplay);
+       }
 
        return true;
 
index daf4fc3..4514529 100644 (file)
@@ -1628,10 +1628,9 @@ static void vlv_dsi_add_properties(struct intel_connector *connector)
 
                connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
 
-               connector->base.display_info.panel_orientation =
-                       vlv_dsi_get_panel_orientation(connector);
-               drm_connector_init_panel_orientation_property(
+               drm_connector_set_panel_orientation_with_quirk(
                                &connector->base,
+                               vlv_dsi_get_panel_orientation(connector),
                                connector->panel.fixed_mode->hdisplay,
                                connector->panel.fixed_mode->vdisplay);
        }
index f7385ab..2312b95 100644 (file)
@@ -2672,7 +2672,7 @@ const struct dev_pm_ops i915_pm_ops = {
 static const struct file_operations i915_driver_fops = {
        .owner = THIS_MODULE,
        .open = drm_open,
-       .release = drm_release,
+       .release = drm_release_noglobal,
        .unlocked_ioctl = drm_ioctl,
        .mmap = i915_gem_mmap,
        .poll = drm_poll,
index 39c79e1..ed69b5d 100644 (file)
@@ -43,7 +43,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
         * locking inversion with the driver load path. And the access here is
         * completely racy anyway. So don't bother with locking for now.
         */
-       return i915 && i915->drm.open_count == 0;
+       return i915 && atomic_read(&i915->drm.open_count) == 0;
 }
 
 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
index 28826c0..6776ebb 100644 (file)
@@ -359,7 +359,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
        if (!fb)
                return 0;
 
-       if (!state->crtc)
+       if (WARN_ON(!state->crtc))
                return -EINVAL;
 
        crtc_state =
index 3dca424..142acff 100644 (file)
@@ -24,6 +24,7 @@
 struct imx_parallel_display {
        struct drm_connector connector;
        struct drm_encoder encoder;
+       struct drm_bridge bridge;
        struct device *dev;
        void *edid;
        int edid_len;
@@ -31,7 +32,7 @@ struct imx_parallel_display {
        u32 bus_flags;
        struct drm_display_mode mode;
        struct drm_panel *panel;
-       struct drm_bridge *bridge;
+       struct drm_bridge *next_bridge;
 };
 
 static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
@@ -44,6 +45,11 @@ static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e)
        return container_of(e, struct imx_parallel_display, encoder);
 }
 
+static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
+{
+       return container_of(b, struct imx_parallel_display, bridge);
+}
+
 static int imx_pd_connector_get_modes(struct drm_connector *connector)
 {
        struct imx_parallel_display *imxpd = con_to_imxpd(connector);
@@ -89,37 +95,148 @@ static struct drm_encoder *imx_pd_connector_best_encoder(
        return &imxpd->encoder;
 }
 
-static void imx_pd_encoder_enable(struct drm_encoder *encoder)
+static void imx_pd_bridge_enable(struct drm_bridge *bridge)
 {
-       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+       struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 
        drm_panel_prepare(imxpd->panel);
        drm_panel_enable(imxpd->panel);
 }
 
-static void imx_pd_encoder_disable(struct drm_encoder *encoder)
+static void imx_pd_bridge_disable(struct drm_bridge *bridge)
 {
-       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+       struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 
        drm_panel_disable(imxpd->panel);
        drm_panel_unprepare(imxpd->panel);
 }
 
-static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder,
-                                      struct drm_crtc_state *crtc_state,
-                                      struct drm_connector_state *conn_state)
+static const u32 imx_pd_bus_fmts[] = {
+       MEDIA_BUS_FMT_RGB888_1X24,
+       MEDIA_BUS_FMT_BGR888_1X24,
+       MEDIA_BUS_FMT_GBR888_1X24,
+       MEDIA_BUS_FMT_RGB666_1X18,
+       MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
+       MEDIA_BUS_FMT_RGB565_1X16,
+};
+
+static u32 *
+imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
+                                        struct drm_bridge_state *bridge_state,
+                                        struct drm_crtc_state *crtc_state,
+                                        struct drm_connector_state *conn_state,
+                                        unsigned int *num_output_fmts)
 {
-       struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
        struct drm_display_info *di = &conn_state->connector->display_info;
-       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+       struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
+       u32 *output_fmts;
 
-       if (!imxpd->bus_format && di->num_bus_formats) {
-               imx_crtc_state->bus_flags = di->bus_flags;
-               imx_crtc_state->bus_format = di->bus_formats[0];
-       } else {
-               imx_crtc_state->bus_flags = imxpd->bus_flags;
-               imx_crtc_state->bus_format = imxpd->bus_format;
+       if (!imxpd->bus_format && !di->num_bus_formats) {
+               *num_output_fmts = ARRAY_SIZE(imx_pd_bus_fmts);
+               return kmemdup(imx_pd_bus_fmts, sizeof(imx_pd_bus_fmts),
+                              GFP_KERNEL);
+       }
+
+       *num_output_fmts = 1;
+       output_fmts = kmalloc(sizeof(*output_fmts), GFP_KERNEL);
+       if (!output_fmts)
+               return NULL;
+
+       if (!imxpd->bus_format && di->num_bus_formats)
+               output_fmts[0] = di->bus_formats[0];
+       else
+               output_fmts[0] = imxpd->bus_format;
+
+       return output_fmts;
+}
+
+static bool imx_pd_format_supported(u32 output_fmt)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) {
+               if (imx_pd_bus_fmts[i] == output_fmt)
+                       return true;
+       }
+
+       return false;
+}
+
+static u32 *
+imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+                                       struct drm_bridge_state *bridge_state,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state,
+                                       u32 output_fmt,
+                                       unsigned int *num_input_fmts)
+{
+       struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
+       u32 *input_fmts;
+
+       /*
+        * If the next bridge does not support bus format negotiation, let's
+        * use the static bus format definition (imxpd->bus_format) if it's
+        * specified, RGB888 when it's not.
+        */
+       if (output_fmt == MEDIA_BUS_FMT_FIXED)
+               output_fmt = imxpd->bus_format ? : MEDIA_BUS_FMT_RGB888_1X24;
+
+       /* Now make sure the requested output format is supported. */
+       if ((imxpd->bus_format && imxpd->bus_format != output_fmt) ||
+           !imx_pd_format_supported(output_fmt)) {
+               *num_input_fmts = 0;
+               return NULL;
+       }
+
+       *num_input_fmts = 1;
+       input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
+       if (!input_fmts)
+               return NULL;
+
+       input_fmts[0] = output_fmt;
+       return input_fmts;
+}
+
+static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
+                                     struct drm_bridge_state *bridge_state,
+                                     struct drm_crtc_state *crtc_state,
+                                     struct drm_connector_state *conn_state)
+{
+       struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+       struct drm_display_info *di = &conn_state->connector->display_info;
+       struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
+       struct drm_bridge_state *next_bridge_state = NULL;
+       struct drm_bridge *next_bridge;
+       u32 bus_flags, bus_fmt;
+
+       next_bridge = drm_bridge_get_next_bridge(bridge);
+       if (next_bridge)
+               next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
+                                                                   next_bridge);
+
+       if (next_bridge_state)
+               bus_flags = next_bridge_state->input_bus_cfg.flags;
+       else if (!imxpd->bus_format && di->num_bus_formats)
+               bus_flags = di->bus_flags;
+       else
+               bus_flags = imxpd->bus_flags;
+
+       bus_fmt = bridge_state->input_bus_cfg.format;
+       if (!imx_pd_format_supported(bus_fmt))
+               return -EINVAL;
+
+       if (bus_flags &
+           ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH |
+             DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE |
+             DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) {
+               dev_warn(imxpd->dev, "invalid bus_flags (%x)\n", bus_flags);
+               return -EINVAL;
        }
+
+       bridge_state->output_bus_cfg.flags = bus_flags;
+       bridge_state->input_bus_cfg.flags = bus_flags;
+       imx_crtc_state->bus_flags = bus_flags;
+       imx_crtc_state->bus_format = bridge_state->input_bus_cfg.format;
        imx_crtc_state->di_hsync_pin = 2;
        imx_crtc_state->di_vsync_pin = 3;
 
@@ -143,10 +260,15 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
        .destroy = imx_drm_encoder_destroy,
 };
 
-static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
-       .enable = imx_pd_encoder_enable,
-       .disable = imx_pd_encoder_disable,
-       .atomic_check = imx_pd_encoder_atomic_check,
+static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
+       .enable = imx_pd_bridge_enable,
+       .disable = imx_pd_bridge_disable,
+       .atomic_reset = drm_atomic_helper_bridge_reset,
+       .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+       .atomic_check = imx_pd_bridge_atomic_check,
+       .atomic_get_input_bus_fmts = imx_pd_bridge_atomic_get_input_bus_fmts,
+       .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
 };
 
 static int imx_pd_register(struct drm_device *drm,
@@ -166,11 +288,13 @@ static int imx_pd_register(struct drm_device *drm,
         */
        imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
 
-       drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs);
        drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs,
                         DRM_MODE_ENCODER_NONE, NULL);
 
-       if (!imxpd->bridge) {
+       imxpd->bridge.funcs = &imx_pd_bridge_funcs;
+       drm_bridge_attach(encoder, &imxpd->bridge, NULL);
+
+       if (!imxpd->next_bridge) {
                drm_connector_helper_add(&imxpd->connector,
                                &imx_pd_connector_helper_funcs);
                drm_connector_init(drm, &imxpd->connector,
@@ -181,8 +305,9 @@ static int imx_pd_register(struct drm_device *drm,
        if (imxpd->panel)
                drm_panel_attach(imxpd->panel, &imxpd->connector);
 
-       if (imxpd->bridge) {
-               ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
+       if (imxpd->next_bridge) {
+               ret = drm_bridge_attach(encoder, imxpd->next_bridge,
+                                       &imxpd->bridge);
                if (ret < 0) {
                        dev_err(imxpd->dev, "failed to attach bridge: %d\n",
                                ret);
@@ -227,7 +352,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
        imxpd->bus_format = bus_format;
 
        /* port@1 is the output port */
-       ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge);
+       ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
+                                         &imxpd->next_bridge);
        if (ret && ret != -ENODEV)
                return ret;
 
index 124efe4..2daac64 100644 (file)
 #include "lima_vm.h"
 
 int lima_sched_timeout_ms;
+uint lima_heap_init_nr_pages = 8;
 
 MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms");
 module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444);
 
+MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages");
+module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444);
+
 static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file)
 {
        struct drm_lima_get_param *args = data;
@@ -68,7 +72,7 @@ static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_
        if (args->pad)
                return -EINVAL;
 
-       if (args->flags)
+       if (args->flags & ~(LIMA_BO_FLAG_HEAP))
                return -EINVAL;
 
        if (args->size == 0)
@@ -241,6 +245,12 @@ static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = {
 
 DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops);
 
+/**
+ * Changelog:
+ *
+ * - 1.1.0 - add heap buffer support
+ */
+
 static struct drm_driver lima_drm_driver = {
        .driver_features    = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
        .open               = lima_drm_driver_open,
@@ -250,9 +260,9 @@ static struct drm_driver lima_drm_driver = {
        .fops               = &lima_drm_driver_fops,
        .name               = "lima",
        .desc               = "lima DRM",
-       .date               = "20190217",
+       .date               = "20191231",
        .major              = 1,
-       .minor              = 0,
+       .minor              = 1,
        .patchlevel         = 0,
 
        .gem_create_object  = lima_gem_create_object,
index 69c7344..f492ecc 100644 (file)
@@ -9,6 +9,7 @@
 #include "lima_ctx.h"
 
 extern int lima_sched_timeout_ms;
+extern uint lima_heap_init_nr_pages;
 
 struct lima_vm;
 struct lima_bo;
index d0059d8..5404e0d 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/mm.h>
 #include <linux/sync_file.h>
 #include <linux/pagemap.h>
+#include <linux/shmem_fs.h>
+#include <linux/dma-mapping.h>
 
 #include <drm/drm_file.h>
 #include <drm/drm_syncobj.h>
 #include "lima_gem.h"
 #include "lima_vm.h"
 
+int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
+{
+       struct page **pages;
+       struct address_space *mapping = bo->base.base.filp->f_mapping;
+       struct device *dev = bo->base.base.dev->dev;
+       size_t old_size = bo->heap_size;
+       size_t new_size = bo->heap_size ? bo->heap_size * 2 :
+               (lima_heap_init_nr_pages << PAGE_SHIFT);
+       struct sg_table sgt;
+       int i, ret;
+
+       if (bo->heap_size >= bo->base.base.size)
+               return -ENOSPC;
+
+       new_size = min(new_size, bo->base.base.size);
+
+       mutex_lock(&bo->base.pages_lock);
+
+       if (bo->base.pages) {
+               pages = bo->base.pages;
+       } else {
+               pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
+                                      sizeof(*pages), GFP_KERNEL | __GFP_ZERO);
+               if (!pages) {
+                       mutex_unlock(&bo->base.pages_lock);
+                       return -ENOMEM;
+               }
+
+               bo->base.pages = pages;
+               bo->base.pages_use_count = 1;
+
+               mapping_set_unevictable(mapping);
+       }
+
+       for (i = old_size >> PAGE_SHIFT; i < new_size >> PAGE_SHIFT; i++) {
+               struct page *page = shmem_read_mapping_page(mapping, i);
+
+               if (IS_ERR(page)) {
+                       mutex_unlock(&bo->base.pages_lock);
+                       return PTR_ERR(page);
+               }
+               pages[i] = page;
+       }
+
+       mutex_unlock(&bo->base.pages_lock);
+
+       ret = sg_alloc_table_from_pages(&sgt, pages, i, 0,
+                                       new_size, GFP_KERNEL);
+       if (ret)
+               return ret;
+
+       if (bo->base.sgt) {
+               dma_unmap_sg(dev, bo->base.sgt->sgl,
+                            bo->base.sgt->nents, DMA_BIDIRECTIONAL);
+               sg_free_table(bo->base.sgt);
+       } else {
+               bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL);
+               if (!bo->base.sgt) {
+                       sg_free_table(&sgt);
+                       return -ENOMEM;
+               }
+       }
+
+       dma_map_sg(dev, sgt.sgl, sgt.nents, DMA_BIDIRECTIONAL);
+
+       *bo->base.sgt = sgt;
+
+       if (vm) {
+               ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT);
+               if (ret)
+                       return ret;
+       }
+
+       bo->heap_size = new_size;
+       return 0;
+}
+
 int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
                           u32 size, u32 flags, u32 *handle)
 {
@@ -22,7 +101,8 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
        gfp_t mask;
        struct drm_gem_shmem_object *shmem;
        struct drm_gem_object *obj;
-       struct sg_table *sgt;
+       struct lima_bo *bo;
+       bool is_heap = flags & LIMA_BO_FLAG_HEAP;
 
        shmem = drm_gem_shmem_create(dev, size);
        if (IS_ERR(shmem))
@@ -36,10 +116,18 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
        mask |= __GFP_DMA32;
        mapping_set_gfp_mask(obj->filp->f_mapping, mask);
 
-       sgt = drm_gem_shmem_get_pages_sgt(obj);
-       if (IS_ERR(sgt)) {
-               err = PTR_ERR(sgt);
-               goto out;
+       if (is_heap) {
+               bo = to_lima_bo(obj);
+               err = lima_heap_alloc(bo, NULL);
+               if (err)
+                       goto out;
+       } else {
+               struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(obj);
+
+               if (IS_ERR(sgt)) {
+                       err = PTR_ERR(sgt);
+                       goto out;
+               }
        }
 
        err = drm_gem_handle_create(file, obj, handle);
@@ -79,17 +167,47 @@ static void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *f
        lima_vm_bo_del(vm, bo);
 }
 
+static int lima_gem_pin(struct drm_gem_object *obj)
+{
+       struct lima_bo *bo = to_lima_bo(obj);
+
+       if (bo->heap_size)
+               return -EINVAL;
+
+       return drm_gem_shmem_pin(obj);
+}
+
+static void *lima_gem_vmap(struct drm_gem_object *obj)
+{
+       struct lima_bo *bo = to_lima_bo(obj);
+
+       if (bo->heap_size)
+               return ERR_PTR(-EINVAL);
+
+       return drm_gem_shmem_vmap(obj);
+}
+
+static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+       struct lima_bo *bo = to_lima_bo(obj);
+
+       if (bo->heap_size)
+               return -EINVAL;
+
+       return drm_gem_shmem_mmap(obj, vma);
+}
+
 static const struct drm_gem_object_funcs lima_gem_funcs = {
        .free = lima_gem_free_object,
        .open = lima_gem_object_open,
        .close = lima_gem_object_close,
        .print_info = drm_gem_shmem_print_info,
-       .pin = drm_gem_shmem_pin,
+       .pin = lima_gem_pin,
        .unpin = drm_gem_shmem_unpin,
        .get_sg_table = drm_gem_shmem_get_sg_table,
-       .vmap = drm_gem_shmem_vmap,
+       .vmap = lima_gem_vmap,
        .vunmap = drm_gem_shmem_vunmap,
-       .mmap = drm_gem_shmem_mmap,
+       .mmap = lima_gem_mmap,
 };
 
 struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size)
index 1800feb..ccea061 100644 (file)
@@ -7,12 +7,15 @@
 #include <drm/drm_gem_shmem_helper.h>
 
 struct lima_submit;
+struct lima_vm;
 
 struct lima_bo {
        struct drm_gem_shmem_object base;
 
        struct mutex lock;
        struct list_head va;
+
+       size_t heap_size;
 };
 
 static inline struct lima_bo *
@@ -31,6 +34,7 @@ static inline struct dma_resv *lima_bo_resv(struct lima_bo *bo)
        return bo->base.base.resv;
 }
 
+int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm);
 struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size);
 int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
                           u32 size, u32 flags, u32 *handle);
index ccf49fa..52b210f 100644 (file)
@@ -11,6 +11,8 @@
 #include "lima_device.h"
 #include "lima_gp.h"
 #include "lima_regs.h"
+#include "lima_gem.h"
+#include "lima_vm.h"
 
 #define gp_write(reg, data) writel(data, ip->iomem + reg)
 #define gp_read(reg) readl(ip->iomem + reg)
@@ -20,6 +22,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data)
        struct lima_ip *ip = data;
        struct lima_device *dev = ip->dev;
        struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
+       struct lima_sched_task *task = pipe->current_task;
        u32 state = gp_read(LIMA_GP_INT_STAT);
        u32 status = gp_read(LIMA_GP_STATUS);
        bool done = false;
@@ -29,8 +32,16 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data)
                return IRQ_NONE;
 
        if (state & LIMA_GP_IRQ_MASK_ERROR) {
-               dev_err(dev->dev, "gp error irq state=%x status=%x\n",
-                       state, status);
+               if ((state & LIMA_GP_IRQ_MASK_ERROR) ==
+                   LIMA_GP_IRQ_PLBU_OUT_OF_MEM) {
+                       dev_dbg(dev->dev, "gp out of heap irq status=%x\n",
+                               status);
+               } else {
+                       dev_err(dev->dev, "gp error irq state=%x status=%x\n",
+                               state, status);
+                       if (task)
+                               task->recoverable = false;
+               }
 
                /* mask all interrupts before hard reset */
                gp_write(LIMA_GP_INT_MASK, 0);
@@ -43,6 +54,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data)
                bool active = status & (LIMA_GP_STATUS_VS_ACTIVE |
                                        LIMA_GP_STATUS_PLBU_ACTIVE);
                done = valid && !active;
+               pipe->error = false;
        }
 
        gp_write(LIMA_GP_INT_CLEAR, state);
@@ -121,6 +133,22 @@ static void lima_gp_task_run(struct lima_sched_pipe *pipe,
        u32 cmd = 0;
        int i;
 
+       /* update real heap buffer size for GP */
+       for (i = 0; i < task->num_bos; i++) {
+               struct lima_bo *bo = task->bos[i];
+
+               if (bo->heap_size &&
+                   lima_vm_get_va(task->vm, bo) ==
+                   f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]) {
+                       f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
+                               f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] +
+                               bo->heap_size;
+                       task->recoverable = true;
+                       task->heap = bo;
+                       break;
+               }
+       }
+
        if (f[LIMA_GP_VSCL_START_ADDR >> 2] !=
            f[LIMA_GP_VSCL_END_ADDR >> 2])
                cmd |= LIMA_GP_CMD_START_VS;
@@ -184,6 +212,31 @@ static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe)
        lima_sched_pipe_task_done(pipe);
 }
 
+static int lima_gp_task_recover(struct lima_sched_pipe *pipe)
+{
+       struct lima_ip *ip = pipe->processor[0];
+       struct lima_sched_task *task = pipe->current_task;
+       struct drm_lima_gp_frame *frame = task->frame;
+       u32 *f = frame->frame;
+       size_t fail_size =
+               f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] -
+               f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2];
+
+       if (fail_size == task->heap->heap_size) {
+               int ret;
+
+               ret = lima_heap_alloc(task->heap, task->vm);
+               if (ret < 0)
+                       return ret;
+       }
+
+       gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
+       gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR,
+                f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size);
+       gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
+       return 0;
+}
+
 static void lima_gp_print_version(struct lima_ip *ip)
 {
        u32 version, major, minor;
@@ -270,6 +323,7 @@ int lima_gp_pipe_init(struct lima_device *dev)
        pipe->task_fini = lima_gp_task_fini;
        pipe->task_error = lima_gp_task_error;
        pipe->task_mmu_error = lima_gp_task_mmu_error;
+       pipe->task_recover = lima_gp_task_recover;
 
        return 0;
 }
index 97ec09d..f79d2af 100644 (file)
@@ -99,6 +99,11 @@ void lima_mmu_fini(struct lima_ip *ip)
 
 }
 
+void lima_mmu_flush_tlb(struct lima_ip *ip)
+{
+       mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE);
+}
+
 void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm)
 {
        struct lima_device *dev = ip->dev;
index 8c78319..4f8ccbe 100644 (file)
@@ -10,6 +10,7 @@ struct lima_vm;
 int lima_mmu_init(struct lima_ip *ip);
 void lima_mmu_fini(struct lima_ip *ip);
 
+void lima_mmu_flush_tlb(struct lima_ip *ip);
 void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm);
 void lima_mmu_page_fault_resume(struct lima_ip *ip);
 
index ace8ece..0124c90 100644 (file)
 #define   LIMA_MMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4)
 #define   LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5)
 #define   LIMA_MMU_STATUS_BUS_ID(x)           ((x >> 6) & 0x1F)
+#define   LIMA_MMU_STATUS_STALL_NOT_ACTIVE    BIT(31)
 #define LIMA_MMU_COMMAND                      0x0008
 #define   LIMA_MMU_COMMAND_ENABLE_PAGING      0x00
 #define   LIMA_MMU_COMMAND_DISABLE_PAGING     0x01
index b561dd0..3886999 100644 (file)
@@ -313,6 +313,26 @@ static const struct drm_sched_backend_ops lima_sched_ops = {
        .free_job = lima_sched_free_job,
 };
 
+static void lima_sched_recover_work(struct work_struct *work)
+{
+       struct lima_sched_pipe *pipe =
+               container_of(work, struct lima_sched_pipe, recover_work);
+       int i;
+
+       for (i = 0; i < pipe->num_l2_cache; i++)
+               lima_l2_cache_flush(pipe->l2_cache[i]);
+
+       if (pipe->bcast_mmu) {
+               lima_mmu_flush_tlb(pipe->bcast_mmu);
+       } else {
+               for (i = 0; i < pipe->num_mmu; i++)
+                       lima_mmu_flush_tlb(pipe->mmu[i]);
+       }
+
+       if (pipe->task_recover(pipe))
+               drm_sched_fault(&pipe->base);
+}
+
 int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
 {
        unsigned int timeout = lima_sched_timeout_ms > 0 ?
@@ -321,6 +341,8 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
        pipe->fence_context = dma_fence_context_alloc(1);
        spin_lock_init(&pipe->fence_lock);
 
+       INIT_WORK(&pipe->recover_work, lima_sched_recover_work);
+
        return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0,
                              msecs_to_jiffies(timeout), name);
 }
@@ -332,11 +354,14 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)
 
 void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
 {
-       if (pipe->error)
-               drm_sched_fault(&pipe->base);
-       else {
-               struct lima_sched_task *task = pipe->current_task;
-
+       struct lima_sched_task *task = pipe->current_task;
+
+       if (pipe->error) {
+               if (task && task->recoverable)
+                       schedule_work(&pipe->recover_work);
+               else
+                       drm_sched_fault(&pipe->base);
+       } else {
                pipe->task_fini(pipe);
                dma_fence_signal(task->fence);
        }
index 1d814fe..d64393f 100644 (file)
@@ -20,6 +20,9 @@ struct lima_sched_task {
        struct lima_bo **bos;
        int num_bos;
 
+       bool recoverable;
+       struct lima_bo *heap;
+
        /* pipe fence */
        struct dma_fence *fence;
 };
@@ -68,6 +71,9 @@ struct lima_sched_pipe {
        void (*task_fini)(struct lima_sched_pipe *pipe);
        void (*task_error)(struct lima_sched_pipe *pipe);
        void (*task_mmu_error)(struct lima_sched_pipe *pipe);
+       int (*task_recover)(struct lima_sched_pipe *pipe);
+
+       struct work_struct recover_work;
 };
 
 int lima_sched_task_init(struct lima_sched_task *task,
index 840e235..5b92fb8 100644 (file)
@@ -155,6 +155,7 @@ err_out0:
 void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
 {
        struct lima_bo_va *bo_va;
+       u32 size;
 
        mutex_lock(&bo->lock);
 
@@ -166,8 +167,9 @@ void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
 
        mutex_lock(&vm->lock);
 
+       size = bo->heap_size ? bo->heap_size : bo_va->node.size;
        lima_vm_unmap_range(vm, bo_va->node.start,
-                           bo_va->node.start + bo_va->node.size - 1);
+                           bo_va->node.start + size - 1);
 
        drm_mm_remove_node(&bo_va->node);
 
@@ -277,3 +279,45 @@ void lima_vm_print(struct lima_vm *vm)
                }
        }
 }
+
+int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, int pageoff)
+{
+       struct lima_bo_va *bo_va;
+       struct sg_dma_page_iter sg_iter;
+       int offset = 0, err;
+       u32 base;
+
+       mutex_lock(&bo->lock);
+
+       bo_va = lima_vm_bo_find(vm, bo);
+       if (!bo_va) {
+               err = -ENOENT;
+               goto err_out0;
+       }
+
+       mutex_lock(&vm->lock);
+
+       base = bo_va->node.start + (pageoff << PAGE_SHIFT);
+       for_each_sg_dma_page(bo->base.sgt->sgl, &sg_iter,
+                            bo->base.sgt->nents, pageoff) {
+               err = lima_vm_map_page(vm, sg_page_iter_dma_address(&sg_iter),
+                                      base + offset);
+               if (err)
+                       goto err_out1;
+
+               offset += PAGE_SIZE;
+       }
+
+       mutex_unlock(&vm->lock);
+
+       mutex_unlock(&bo->lock);
+       return 0;
+
+err_out1:
+       if (offset)
+               lima_vm_unmap_range(vm, base, base + offset - 1);
+       mutex_unlock(&vm->lock);
+err_out0:
+       mutex_unlock(&bo->lock);
+       return err;
+}
index e0bdedc..22aeec7 100644 (file)
@@ -58,5 +58,6 @@ static inline void lima_vm_put(struct lima_vm *vm)
 }
 
 void lima_vm_print(struct lima_vm *vm);
+int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, int pageoff);
 
 #endif
index 1b62ccc..2b4b21b 100644 (file)
@@ -647,13 +647,6 @@ nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
 }
 
 static int
-nouveau_bo_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
-{
-       /* We'll do this from user space. */
-       return 0;
-}
-
-static int
 nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                         struct ttm_mem_type_manager *man)
 {
@@ -1697,7 +1690,6 @@ struct ttm_bo_driver nouveau_bo_driver = {
        .ttm_tt_create = &nouveau_ttm_tt_create,
        .ttm_tt_populate = &nouveau_ttm_tt_populate,
        .ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
-       .invalidate_caches = nouveau_bo_invalidate_caches,
        .init_mem_type = nouveau_bo_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = nouveau_bo_evict_flags,
index d865d8a..c85dd8a 100644 (file)
@@ -72,7 +72,7 @@ nouveau_switcheroo_can_switch(struct pci_dev *pdev)
         * locking inversion with the driver load path. And the access here is
         * completely racy anyway. So don't bother with locking for now.
         */
-       return dev->open_count == 0;
+       return atomic_read(&dev->open_count) == 0;
 }
 
 static const struct vga_switcheroo_client_ops
index ae44ac2..da3b846 100644 (file)
@@ -29,6 +29,15 @@ config DRM_PANEL_BOE_HIMAX8279D
          24 bit RGB per pixel. It provides a MIPI DSI interface to
          the host and has a built-in LED backlight.
 
+config DRM_PANEL_BOE_TV101WUM_NL6
+       tristate "BOE TV101WUM and AUO KD101N80 45NA 1200x1920 panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y here if you want to support for BOE TV101WUM and AUO KD101N80
+         45NA WUXGA PANEL DSI Video Mode panel
+
 config DRM_PANEL_LVDS
        tristate "Generic LVDS panel driver"
        depends on OF
@@ -50,6 +59,15 @@ config DRM_PANEL_SIMPLE
          that it can be automatically turned off when the panel goes into a
          low power state.
 
+config DRM_PANEL_FEIXIN_K101_IM2BA02
+       tristate "Feixin K101 IM2BA02 panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y here if you want to enable support for the Feixin K101 IM2BA02
+         4-lane 800x1280 MIPI DSI panel.
+
 config DRM_PANEL_FEIYANG_FY07024DI26A30D
        tristate "Feiyang FY07024DI26A30-D MIPI-DSI LCD panel"
        depends on OF
@@ -275,6 +293,12 @@ config DRM_PANEL_SAMSUNG_S6E63M0
          Say Y here if you want to enable support for Samsung S6E63M0
          AMOLED LCD panel.
 
+config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01
+       tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller"
+       depends on OF
+       select DRM_MIPI_DSI
+       select VIDEOMODE_HELPERS
+
 config DRM_PANEL_SAMSUNG_S6E8AA0
        tristate "Samsung S6E8AA0 DSI video mode panel"
        depends on OF
index 7c4d3c5..af1e2a3 100644 (file)
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o
+obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o
 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
 obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
@@ -28,6 +30,7 @@ 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_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
 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
new file mode 100644 (file)
index 0000000..48a1642
--- /dev/null
@@ -0,0 +1,854 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Jitao Shi <jitao.shi@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct panel_desc {
+       const struct drm_display_mode *modes;
+       unsigned int bpc;
+
+       /**
+        * @width_mm: width of the panel's active display area
+        * @height_mm: height of the panel's active display area
+        */
+       struct {
+               unsigned int width_mm;
+               unsigned int height_mm;
+       } size;
+
+       unsigned long mode_flags;
+       enum mipi_dsi_pixel_format format;
+       const struct panel_init_cmd *init_cmds;
+       unsigned int lanes;
+       bool discharge_on_disable;
+};
+
+struct boe_panel {
+       struct drm_panel base;
+       struct mipi_dsi_device *dsi;
+
+       const struct panel_desc *desc;
+
+       struct regulator *pp1800;
+       struct regulator *avee;
+       struct regulator *avdd;
+       struct gpio_desc *enable_gpio;
+
+       bool prepared;
+};
+
+enum dsi_cmd_type {
+       INIT_DCS_CMD,
+       DELAY_CMD,
+};
+
+struct panel_init_cmd {
+       enum dsi_cmd_type type;
+       size_t len;
+       const char *data;
+};
+
+#define _INIT_DCS_CMD(...) { \
+       .type = INIT_DCS_CMD, \
+       .len = sizeof((char[]){__VA_ARGS__}), \
+       .data = (char[]){__VA_ARGS__} }
+
+#define _INIT_DELAY_CMD(...) { \
+       .type = DELAY_CMD,\
+       .len = sizeof((char[]){__VA_ARGS__}), \
+       .data = (char[]){__VA_ARGS__} }
+
+static const struct panel_init_cmd boe_init_cmd[] = {
+       _INIT_DELAY_CMD(24),
+       _INIT_DCS_CMD(0xB0, 0x05),
+       _INIT_DCS_CMD(0xB1, 0xE5),
+       _INIT_DCS_CMD(0xB3, 0x52),
+       _INIT_DCS_CMD(0xB0, 0x00),
+       _INIT_DCS_CMD(0xB3, 0x88),
+       _INIT_DCS_CMD(0xB0, 0x04),
+       _INIT_DCS_CMD(0xB8, 0x00),
+       _INIT_DCS_CMD(0xB0, 0x00),
+       _INIT_DCS_CMD(0xB6, 0x03),
+       _INIT_DCS_CMD(0xBA, 0x8B),
+       _INIT_DCS_CMD(0xBF, 0x1A),
+       _INIT_DCS_CMD(0xC0, 0x0F),
+       _INIT_DCS_CMD(0xC2, 0x0C),
+       _INIT_DCS_CMD(0xC3, 0x02),
+       _INIT_DCS_CMD(0xC4, 0x0C),
+       _INIT_DCS_CMD(0xC5, 0x02),
+       _INIT_DCS_CMD(0xB0, 0x01),
+       _INIT_DCS_CMD(0xE0, 0x26),
+       _INIT_DCS_CMD(0xE1, 0x26),
+       _INIT_DCS_CMD(0xDC, 0x00),
+       _INIT_DCS_CMD(0xDD, 0x00),
+       _INIT_DCS_CMD(0xCC, 0x26),
+       _INIT_DCS_CMD(0xCD, 0x26),
+       _INIT_DCS_CMD(0xC8, 0x00),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xD2, 0x03),
+       _INIT_DCS_CMD(0xD3, 0x03),
+       _INIT_DCS_CMD(0xE6, 0x04),
+       _INIT_DCS_CMD(0xE7, 0x04),
+       _INIT_DCS_CMD(0xC4, 0x09),
+       _INIT_DCS_CMD(0xC5, 0x09),
+       _INIT_DCS_CMD(0xD8, 0x0A),
+       _INIT_DCS_CMD(0xD9, 0x0A),
+       _INIT_DCS_CMD(0xC2, 0x0B),
+       _INIT_DCS_CMD(0xC3, 0x0B),
+       _INIT_DCS_CMD(0xD6, 0x0C),
+       _INIT_DCS_CMD(0xD7, 0x0C),
+       _INIT_DCS_CMD(0xC0, 0x05),
+       _INIT_DCS_CMD(0xC1, 0x05),
+       _INIT_DCS_CMD(0xD4, 0x06),
+       _INIT_DCS_CMD(0xD5, 0x06),
+       _INIT_DCS_CMD(0xCA, 0x07),
+       _INIT_DCS_CMD(0xCB, 0x07),
+       _INIT_DCS_CMD(0xDE, 0x08),
+       _INIT_DCS_CMD(0xDF, 0x08),
+       _INIT_DCS_CMD(0xB0, 0x02),
+       _INIT_DCS_CMD(0xC0, 0x00),
+       _INIT_DCS_CMD(0xC1, 0x0D),
+       _INIT_DCS_CMD(0xC2, 0x17),
+       _INIT_DCS_CMD(0xC3, 0x26),
+       _INIT_DCS_CMD(0xC4, 0x31),
+       _INIT_DCS_CMD(0xC5, 0x1C),
+       _INIT_DCS_CMD(0xC6, 0x2C),
+       _INIT_DCS_CMD(0xC7, 0x33),
+       _INIT_DCS_CMD(0xC8, 0x31),
+       _INIT_DCS_CMD(0xC9, 0x37),
+       _INIT_DCS_CMD(0xCA, 0x37),
+       _INIT_DCS_CMD(0xCB, 0x37),
+       _INIT_DCS_CMD(0xCC, 0x39),
+       _INIT_DCS_CMD(0xCD, 0x2E),
+       _INIT_DCS_CMD(0xCE, 0x2F),
+       _INIT_DCS_CMD(0xCF, 0x2F),
+       _INIT_DCS_CMD(0xD0, 0x07),
+       _INIT_DCS_CMD(0xD2, 0x00),
+       _INIT_DCS_CMD(0xD3, 0x0D),
+       _INIT_DCS_CMD(0xD4, 0x17),
+       _INIT_DCS_CMD(0xD5, 0x26),
+       _INIT_DCS_CMD(0xD6, 0x31),
+       _INIT_DCS_CMD(0xD7, 0x3F),
+       _INIT_DCS_CMD(0xD8, 0x3F),
+       _INIT_DCS_CMD(0xD9, 0x3F),
+       _INIT_DCS_CMD(0xDA, 0x3F),
+       _INIT_DCS_CMD(0xDB, 0x37),
+       _INIT_DCS_CMD(0xDC, 0x37),
+       _INIT_DCS_CMD(0xDD, 0x37),
+       _INIT_DCS_CMD(0xDE, 0x39),
+       _INIT_DCS_CMD(0xDF, 0x2E),
+       _INIT_DCS_CMD(0xE0, 0x2F),
+       _INIT_DCS_CMD(0xE1, 0x2F),
+       _INIT_DCS_CMD(0xE2, 0x07),
+       _INIT_DCS_CMD(0xB0, 0x03),
+       _INIT_DCS_CMD(0xC8, 0x0B),
+       _INIT_DCS_CMD(0xC9, 0x07),
+       _INIT_DCS_CMD(0xC3, 0x00),
+       _INIT_DCS_CMD(0xE7, 0x00),
+       _INIT_DCS_CMD(0xC5, 0x2A),
+       _INIT_DCS_CMD(0xDE, 0x2A),
+       _INIT_DCS_CMD(0xCA, 0x43),
+       _INIT_DCS_CMD(0xC9, 0x07),
+       _INIT_DCS_CMD(0xE4, 0xC0),
+       _INIT_DCS_CMD(0xE5, 0x0D),
+       _INIT_DCS_CMD(0xCB, 0x00),
+       _INIT_DCS_CMD(0xB0, 0x06),
+       _INIT_DCS_CMD(0xB8, 0xA5),
+       _INIT_DCS_CMD(0xC0, 0xA5),
+       _INIT_DCS_CMD(0xC7, 0x0F),
+       _INIT_DCS_CMD(0xD5, 0x32),
+       _INIT_DCS_CMD(0xB8, 0x00),
+       _INIT_DCS_CMD(0xC0, 0x00),
+       _INIT_DCS_CMD(0xBC, 0x00),
+       _INIT_DCS_CMD(0xB0, 0x07),
+       _INIT_DCS_CMD(0xB1, 0x00),
+       _INIT_DCS_CMD(0xB2, 0x02),
+       _INIT_DCS_CMD(0xB3, 0x0F),
+       _INIT_DCS_CMD(0xB4, 0x25),
+       _INIT_DCS_CMD(0xB5, 0x39),
+       _INIT_DCS_CMD(0xB6, 0x4E),
+       _INIT_DCS_CMD(0xB7, 0x72),
+       _INIT_DCS_CMD(0xB8, 0x97),
+       _INIT_DCS_CMD(0xB9, 0xDC),
+       _INIT_DCS_CMD(0xBA, 0x22),
+       _INIT_DCS_CMD(0xBB, 0xA4),
+       _INIT_DCS_CMD(0xBC, 0x2B),
+       _INIT_DCS_CMD(0xBD, 0x2F),
+       _INIT_DCS_CMD(0xBE, 0xA9),
+       _INIT_DCS_CMD(0xBF, 0x25),
+       _INIT_DCS_CMD(0xC0, 0x61),
+       _INIT_DCS_CMD(0xC1, 0x97),
+       _INIT_DCS_CMD(0xC2, 0xB2),
+       _INIT_DCS_CMD(0xC3, 0xCD),
+       _INIT_DCS_CMD(0xC4, 0xD9),
+       _INIT_DCS_CMD(0xC5, 0xE7),
+       _INIT_DCS_CMD(0xC6, 0xF4),
+       _INIT_DCS_CMD(0xC7, 0xFA),
+       _INIT_DCS_CMD(0xC8, 0xFC),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xCA, 0x00),
+       _INIT_DCS_CMD(0xCB, 0x16),
+       _INIT_DCS_CMD(0xCC, 0xAF),
+       _INIT_DCS_CMD(0xCD, 0xFF),
+       _INIT_DCS_CMD(0xCE, 0xFF),
+       _INIT_DCS_CMD(0xB0, 0x08),
+       _INIT_DCS_CMD(0xB1, 0x04),
+       _INIT_DCS_CMD(0xB2, 0x05),
+       _INIT_DCS_CMD(0xB3, 0x11),
+       _INIT_DCS_CMD(0xB4, 0x24),
+       _INIT_DCS_CMD(0xB5, 0x39),
+       _INIT_DCS_CMD(0xB6, 0x4F),
+       _INIT_DCS_CMD(0xB7, 0x72),
+       _INIT_DCS_CMD(0xB8, 0x98),
+       _INIT_DCS_CMD(0xB9, 0xDC),
+       _INIT_DCS_CMD(0xBA, 0x23),
+       _INIT_DCS_CMD(0xBB, 0xA6),
+       _INIT_DCS_CMD(0xBC, 0x2C),
+       _INIT_DCS_CMD(0xBD, 0x30),
+       _INIT_DCS_CMD(0xBE, 0xAA),
+       _INIT_DCS_CMD(0xBF, 0x26),
+       _INIT_DCS_CMD(0xC0, 0x62),
+       _INIT_DCS_CMD(0xC1, 0x9B),
+       _INIT_DCS_CMD(0xC2, 0xB5),
+       _INIT_DCS_CMD(0xC3, 0xCF),
+       _INIT_DCS_CMD(0xC4, 0xDB),
+       _INIT_DCS_CMD(0xC5, 0xE8),
+       _INIT_DCS_CMD(0xC6, 0xF5),
+       _INIT_DCS_CMD(0xC7, 0xFA),
+       _INIT_DCS_CMD(0xC8, 0xFC),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xCA, 0x00),
+       _INIT_DCS_CMD(0xCB, 0x16),
+       _INIT_DCS_CMD(0xCC, 0xAF),
+       _INIT_DCS_CMD(0xCD, 0xFF),
+       _INIT_DCS_CMD(0xCE, 0xFF),
+       _INIT_DCS_CMD(0xB0, 0x09),
+       _INIT_DCS_CMD(0xB1, 0x04),
+       _INIT_DCS_CMD(0xB2, 0x02),
+       _INIT_DCS_CMD(0xB3, 0x16),
+       _INIT_DCS_CMD(0xB4, 0x24),
+       _INIT_DCS_CMD(0xB5, 0x3B),
+       _INIT_DCS_CMD(0xB6, 0x4F),
+       _INIT_DCS_CMD(0xB7, 0x73),
+       _INIT_DCS_CMD(0xB8, 0x99),
+       _INIT_DCS_CMD(0xB9, 0xE0),
+       _INIT_DCS_CMD(0xBA, 0x26),
+       _INIT_DCS_CMD(0xBB, 0xAD),
+       _INIT_DCS_CMD(0xBC, 0x36),
+       _INIT_DCS_CMD(0xBD, 0x3A),
+       _INIT_DCS_CMD(0xBE, 0xAE),
+       _INIT_DCS_CMD(0xBF, 0x2A),
+       _INIT_DCS_CMD(0xC0, 0x66),
+       _INIT_DCS_CMD(0xC1, 0x9E),
+       _INIT_DCS_CMD(0xC2, 0xB8),
+       _INIT_DCS_CMD(0xC3, 0xD1),
+       _INIT_DCS_CMD(0xC4, 0xDD),
+       _INIT_DCS_CMD(0xC5, 0xE9),
+       _INIT_DCS_CMD(0xC6, 0xF6),
+       _INIT_DCS_CMD(0xC7, 0xFA),
+       _INIT_DCS_CMD(0xC8, 0xFC),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xCA, 0x00),
+       _INIT_DCS_CMD(0xCB, 0x16),
+       _INIT_DCS_CMD(0xCC, 0xAF),
+       _INIT_DCS_CMD(0xCD, 0xFF),
+       _INIT_DCS_CMD(0xCE, 0xFF),
+       _INIT_DCS_CMD(0xB0, 0x0A),
+       _INIT_DCS_CMD(0xB1, 0x00),
+       _INIT_DCS_CMD(0xB2, 0x02),
+       _INIT_DCS_CMD(0xB3, 0x0F),
+       _INIT_DCS_CMD(0xB4, 0x25),
+       _INIT_DCS_CMD(0xB5, 0x39),
+       _INIT_DCS_CMD(0xB6, 0x4E),
+       _INIT_DCS_CMD(0xB7, 0x72),
+       _INIT_DCS_CMD(0xB8, 0x97),
+       _INIT_DCS_CMD(0xB9, 0xDC),
+       _INIT_DCS_CMD(0xBA, 0x22),
+       _INIT_DCS_CMD(0xBB, 0xA4),
+       _INIT_DCS_CMD(0xBC, 0x2B),
+       _INIT_DCS_CMD(0xBD, 0x2F),
+       _INIT_DCS_CMD(0xBE, 0xA9),
+       _INIT_DCS_CMD(0xBF, 0x25),
+       _INIT_DCS_CMD(0xC0, 0x61),
+       _INIT_DCS_CMD(0xC1, 0x97),
+       _INIT_DCS_CMD(0xC2, 0xB2),
+       _INIT_DCS_CMD(0xC3, 0xCD),
+       _INIT_DCS_CMD(0xC4, 0xD9),
+       _INIT_DCS_CMD(0xC5, 0xE7),
+       _INIT_DCS_CMD(0xC6, 0xF4),
+       _INIT_DCS_CMD(0xC7, 0xFA),
+       _INIT_DCS_CMD(0xC8, 0xFC),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xCA, 0x00),
+       _INIT_DCS_CMD(0xCB, 0x16),
+       _INIT_DCS_CMD(0xCC, 0xAF),
+       _INIT_DCS_CMD(0xCD, 0xFF),
+       _INIT_DCS_CMD(0xCE, 0xFF),
+       _INIT_DCS_CMD(0xB0, 0x0B),
+       _INIT_DCS_CMD(0xB1, 0x04),
+       _INIT_DCS_CMD(0xB2, 0x05),
+       _INIT_DCS_CMD(0xB3, 0x11),
+       _INIT_DCS_CMD(0xB4, 0x24),
+       _INIT_DCS_CMD(0xB5, 0x39),
+       _INIT_DCS_CMD(0xB6, 0x4F),
+       _INIT_DCS_CMD(0xB7, 0x72),
+       _INIT_DCS_CMD(0xB8, 0x98),
+       _INIT_DCS_CMD(0xB9, 0xDC),
+       _INIT_DCS_CMD(0xBA, 0x23),
+       _INIT_DCS_CMD(0xBB, 0xA6),
+       _INIT_DCS_CMD(0xBC, 0x2C),
+       _INIT_DCS_CMD(0xBD, 0x30),
+       _INIT_DCS_CMD(0xBE, 0xAA),
+       _INIT_DCS_CMD(0xBF, 0x26),
+       _INIT_DCS_CMD(0xC0, 0x62),
+       _INIT_DCS_CMD(0xC1, 0x9B),
+       _INIT_DCS_CMD(0xC2, 0xB5),
+       _INIT_DCS_CMD(0xC3, 0xCF),
+       _INIT_DCS_CMD(0xC4, 0xDB),
+       _INIT_DCS_CMD(0xC5, 0xE8),
+       _INIT_DCS_CMD(0xC6, 0xF5),
+       _INIT_DCS_CMD(0xC7, 0xFA),
+       _INIT_DCS_CMD(0xC8, 0xFC),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xCA, 0x00),
+       _INIT_DCS_CMD(0xCB, 0x16),
+       _INIT_DCS_CMD(0xCC, 0xAF),
+       _INIT_DCS_CMD(0xCD, 0xFF),
+       _INIT_DCS_CMD(0xCE, 0xFF),
+       _INIT_DCS_CMD(0xB0, 0x0C),
+       _INIT_DCS_CMD(0xB1, 0x04),
+       _INIT_DCS_CMD(0xB2, 0x02),
+       _INIT_DCS_CMD(0xB3, 0x16),
+       _INIT_DCS_CMD(0xB4, 0x24),
+       _INIT_DCS_CMD(0xB5, 0x3B),
+       _INIT_DCS_CMD(0xB6, 0x4F),
+       _INIT_DCS_CMD(0xB7, 0x73),
+       _INIT_DCS_CMD(0xB8, 0x99),
+       _INIT_DCS_CMD(0xB9, 0xE0),
+       _INIT_DCS_CMD(0xBA, 0x26),
+       _INIT_DCS_CMD(0xBB, 0xAD),
+       _INIT_DCS_CMD(0xBC, 0x36),
+       _INIT_DCS_CMD(0xBD, 0x3A),
+       _INIT_DCS_CMD(0xBE, 0xAE),
+       _INIT_DCS_CMD(0xBF, 0x2A),
+       _INIT_DCS_CMD(0xC0, 0x66),
+       _INIT_DCS_CMD(0xC1, 0x9E),
+       _INIT_DCS_CMD(0xC2, 0xB8),
+       _INIT_DCS_CMD(0xC3, 0xD1),
+       _INIT_DCS_CMD(0xC4, 0xDD),
+       _INIT_DCS_CMD(0xC5, 0xE9),
+       _INIT_DCS_CMD(0xC6, 0xF6),
+       _INIT_DCS_CMD(0xC7, 0xFA),
+       _INIT_DCS_CMD(0xC8, 0xFC),
+       _INIT_DCS_CMD(0xC9, 0x00),
+       _INIT_DCS_CMD(0xCA, 0x00),
+       _INIT_DCS_CMD(0xCB, 0x16),
+       _INIT_DCS_CMD(0xCC, 0xAF),
+       _INIT_DCS_CMD(0xCD, 0xFF),
+       _INIT_DCS_CMD(0xCE, 0xFF),
+       _INIT_DCS_CMD(0xB0, 0x00),
+       _INIT_DCS_CMD(0xB3, 0x08),
+       _INIT_DCS_CMD(0xB0, 0x04),
+       _INIT_DCS_CMD(0xB8, 0x68),
+       _INIT_DELAY_CMD(150),
+       {},
+};
+
+static const struct panel_init_cmd auo_kd101n80_45na_init_cmd[] = {
+       _INIT_DELAY_CMD(24),
+       _INIT_DCS_CMD(0x11),
+       _INIT_DELAY_CMD(120),
+       _INIT_DCS_CMD(0x29),
+       _INIT_DELAY_CMD(120),
+       {},
+};
+
+static const struct panel_init_cmd auo_b101uan08_3_init_cmd[] = {
+       _INIT_DELAY_CMD(24),
+       _INIT_DCS_CMD(0xB0, 0x01),
+       _INIT_DCS_CMD(0xC0, 0x48),
+       _INIT_DCS_CMD(0xC1, 0x48),
+       _INIT_DCS_CMD(0xC2, 0x47),
+       _INIT_DCS_CMD(0xC3, 0x47),
+       _INIT_DCS_CMD(0xC4, 0x46),
+       _INIT_DCS_CMD(0xC5, 0x46),
+       _INIT_DCS_CMD(0xC6, 0x45),
+       _INIT_DCS_CMD(0xC7, 0x45),
+       _INIT_DCS_CMD(0xC8, 0x64),
+       _INIT_DCS_CMD(0xC9, 0x64),
+       _INIT_DCS_CMD(0xCA, 0x4F),
+       _INIT_DCS_CMD(0xCB, 0x4F),
+       _INIT_DCS_CMD(0xCC, 0x40),
+       _INIT_DCS_CMD(0xCD, 0x40),
+       _INIT_DCS_CMD(0xCE, 0x66),
+       _INIT_DCS_CMD(0xCF, 0x66),
+       _INIT_DCS_CMD(0xD0, 0x4F),
+       _INIT_DCS_CMD(0xD1, 0x4F),
+       _INIT_DCS_CMD(0xD2, 0x41),
+       _INIT_DCS_CMD(0xD3, 0x41),
+       _INIT_DCS_CMD(0xD4, 0x48),
+       _INIT_DCS_CMD(0xD5, 0x48),
+       _INIT_DCS_CMD(0xD6, 0x47),
+       _INIT_DCS_CMD(0xD7, 0x47),
+       _INIT_DCS_CMD(0xD8, 0x46),
+       _INIT_DCS_CMD(0xD9, 0x46),
+       _INIT_DCS_CMD(0xDA, 0x45),
+       _INIT_DCS_CMD(0xDB, 0x45),
+       _INIT_DCS_CMD(0xDC, 0x64),
+       _INIT_DCS_CMD(0xDD, 0x64),
+       _INIT_DCS_CMD(0xDE, 0x4F),
+       _INIT_DCS_CMD(0xDF, 0x4F),
+       _INIT_DCS_CMD(0xE0, 0x40),
+       _INIT_DCS_CMD(0xE1, 0x40),
+       _INIT_DCS_CMD(0xE2, 0x66),
+       _INIT_DCS_CMD(0xE3, 0x66),
+       _INIT_DCS_CMD(0xE4, 0x4F),
+       _INIT_DCS_CMD(0xE5, 0x4F),
+       _INIT_DCS_CMD(0xE6, 0x41),
+       _INIT_DCS_CMD(0xE7, 0x41),
+       _INIT_DELAY_CMD(150),
+       {},
+};
+
+static inline struct boe_panel *to_boe_panel(struct drm_panel *panel)
+{
+       return container_of(panel, struct boe_panel, base);
+}
+
+static int boe_panel_init_dcs_cmd(struct boe_panel *boe)
+{
+       struct mipi_dsi_device *dsi = boe->dsi;
+       struct drm_panel *panel = &boe->base;
+       int i, err = 0;
+
+       if (boe->desc->init_cmds) {
+               const struct panel_init_cmd *init_cmds = boe->desc->init_cmds;
+
+               for (i = 0; init_cmds[i].len != 0; i++) {
+                       const struct panel_init_cmd *cmd = &init_cmds[i];
+
+                       switch (cmd->type) {
+                       case DELAY_CMD:
+                               msleep(cmd->data[0]);
+                               err = 0;
+                               break;
+
+                       case INIT_DCS_CMD:
+                               err = mipi_dsi_dcs_write(dsi, cmd->data[0],
+                                                        cmd->len <= 1 ? NULL :
+                                                        &cmd->data[1],
+                                                        cmd->len - 1);
+                               break;
+
+                       default:
+                               err = -EINVAL;
+                       }
+
+                       if (err < 0) {
+                               dev_err(panel->dev,
+                                       "failed to write command %u\n", i);
+                               return err;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int boe_panel_enter_sleep_mode(struct boe_panel *boe)
+{
+       struct mipi_dsi_device *dsi = boe->dsi;
+       int ret;
+
+       dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_set_display_off(dsi);
+       if (ret < 0)
+               return ret;
+
+       ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int boe_panel_unprepare(struct drm_panel *panel)
+{
+       struct boe_panel *boe = to_boe_panel(panel);
+       int ret;
+
+       if (!boe->prepared)
+               return 0;
+
+       ret = boe_panel_enter_sleep_mode(boe);
+       if (ret < 0) {
+               dev_err(panel->dev, "failed to set panel off: %d\n", ret);
+               return ret;
+       }
+
+       msleep(150);
+
+       if (boe->desc->discharge_on_disable) {
+               regulator_disable(boe->avee);
+               regulator_disable(boe->avdd);
+               usleep_range(5000, 7000);
+               gpiod_set_value(boe->enable_gpio, 0);
+               usleep_range(5000, 7000);
+               regulator_disable(boe->pp1800);
+       } else {
+               gpiod_set_value(boe->enable_gpio, 0);
+               usleep_range(500, 1000);
+               regulator_disable(boe->avee);
+               regulator_disable(boe->avdd);
+               usleep_range(5000, 7000);
+               regulator_disable(boe->pp1800);
+       }
+
+       boe->prepared = false;
+
+       return 0;
+}
+
+static int boe_panel_prepare(struct drm_panel *panel)
+{
+       struct boe_panel *boe = to_boe_panel(panel);
+       int ret;
+
+       if (boe->prepared)
+               return 0;
+
+       gpiod_set_value(boe->enable_gpio, 0);
+       usleep_range(1000, 1500);
+
+       ret = regulator_enable(boe->pp1800);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(3000, 5000);
+
+       ret = regulator_enable(boe->avdd);
+       if (ret < 0)
+               goto poweroff1v8;
+       ret = regulator_enable(boe->avee);
+       if (ret < 0)
+               goto poweroffavdd;
+
+       usleep_range(5000, 10000);
+
+       gpiod_set_value(boe->enable_gpio, 1);
+       usleep_range(1000, 2000);
+       gpiod_set_value(boe->enable_gpio, 0);
+       usleep_range(1000, 2000);
+       gpiod_set_value(boe->enable_gpio, 1);
+       usleep_range(6000, 10000);
+
+       ret = boe_panel_init_dcs_cmd(boe);
+       if (ret < 0) {
+               dev_err(panel->dev, "failed to init panel: %d\n", ret);
+               goto poweroff;
+       }
+
+       boe->prepared = true;
+
+       return 0;
+
+poweroff:
+       regulator_disable(boe->avee);
+poweroffavdd:
+       regulator_disable(boe->avdd);
+poweroff1v8:
+       usleep_range(5000, 7000);
+       regulator_disable(boe->pp1800);
+       gpiod_set_value(boe->enable_gpio, 0);
+
+       return ret;
+}
+
+static int boe_panel_enable(struct drm_panel *panel)
+{
+       msleep(130);
+       return 0;
+}
+
+static const struct drm_display_mode boe_tv101wum_nl6_default_mode = {
+       .clock = 159425,
+       .hdisplay = 1200,
+       .hsync_start = 1200 + 100,
+       .hsync_end = 1200 + 100 + 40,
+       .htotal = 1200 + 100 + 40 + 24,
+       .vdisplay = 1920,
+       .vsync_start = 1920 + 10,
+       .vsync_end = 1920 + 10 + 14,
+       .vtotal = 1920 + 10 + 14 + 4,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc boe_tv101wum_nl6_desc = {
+       .modes = &boe_tv101wum_nl6_default_mode,
+       .bpc = 8,
+       .size = {
+               .width_mm = 135,
+               .height_mm = 216,
+       },
+       .lanes = 4,
+       .format = MIPI_DSI_FMT_RGB888,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+                     MIPI_DSI_MODE_LPM,
+       .init_cmds = boe_init_cmd,
+       .discharge_on_disable = false,
+};
+
+static const struct drm_display_mode auo_kd101n80_45na_default_mode = {
+       .clock = 157000,
+       .hdisplay = 1200,
+       .hsync_start = 1200 + 80,
+       .hsync_end = 1200 + 80 + 24,
+       .htotal = 1200 + 80 + 24 + 36,
+       .vdisplay = 1920,
+       .vsync_start = 1920 + 16,
+       .vsync_end = 1920 + 16 + 4,
+       .vtotal = 1920 + 16 + 4 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_kd101n80_45na_desc = {
+       .modes = &auo_kd101n80_45na_default_mode,
+       .bpc = 8,
+       .size = {
+               .width_mm = 135,
+               .height_mm = 216,
+       },
+       .lanes = 4,
+       .format = MIPI_DSI_FMT_RGB888,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+                     MIPI_DSI_MODE_LPM,
+       .init_cmds = auo_kd101n80_45na_init_cmd,
+       .discharge_on_disable = true,
+};
+
+static const struct drm_display_mode boe_tv101wum_n53_default_mode = {
+       .clock = 159916,
+       .hdisplay = 1200,
+       .hsync_start = 1200 + 80,
+       .hsync_end = 1200 + 80 + 24,
+       .htotal = 1200 + 80 + 24 + 60,
+       .vdisplay = 1920,
+       .vsync_start = 1920 + 20,
+       .vsync_end = 1920 + 20 + 4,
+       .vtotal = 1920 + 20 + 4 + 10,
+       .vrefresh = 60,
+       .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct panel_desc boe_tv101wum_n53_desc = {
+       .modes = &boe_tv101wum_n53_default_mode,
+       .bpc = 8,
+       .size = {
+               .width_mm = 135,
+               .height_mm = 216,
+       },
+       .lanes = 4,
+       .format = MIPI_DSI_FMT_RGB888,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+                     MIPI_DSI_MODE_LPM,
+       .init_cmds = boe_init_cmd,
+};
+
+static const struct drm_display_mode auo_b101uan08_3_default_mode = {
+       .clock = 159667,
+       .hdisplay = 1200,
+       .hsync_start = 1200 + 60,
+       .hsync_end = 1200 + 60 + 4,
+       .htotal = 1200 + 60 + 4 + 80,
+       .vdisplay = 1920,
+       .vsync_start = 1920 + 34,
+       .vsync_end = 1920 + 34 + 2,
+       .vtotal = 1920 + 34 + 2 + 24,
+       .vrefresh = 60,
+       .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct panel_desc auo_b101uan08_3_desc = {
+       .modes = &auo_b101uan08_3_default_mode,
+       .bpc = 8,
+       .size = {
+               .width_mm = 135,
+               .height_mm = 216,
+       },
+       .lanes = 4,
+       .format = MIPI_DSI_FMT_RGB888,
+       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+                     MIPI_DSI_MODE_LPM,
+       .init_cmds = auo_b101uan08_3_init_cmd,
+};
+
+static int boe_panel_get_modes(struct drm_panel *panel,
+                              struct drm_connector *connector)
+{
+       struct boe_panel *boe = to_boe_panel(panel);
+       const struct drm_display_mode *m = boe->desc->modes;
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(connector->dev, m);
+       if (!mode) {
+               dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+                       m->hdisplay, m->vdisplay, m->vrefresh);
+               return -ENOMEM;
+       }
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_set_name(mode);
+       drm_mode_probed_add(connector, mode);
+
+       connector->display_info.width_mm = boe->desc->size.width_mm;
+       connector->display_info.height_mm = boe->desc->size.height_mm;
+       connector->display_info.bpc = boe->desc->bpc;
+
+       return 1;
+}
+
+static const struct drm_panel_funcs boe_panel_funcs = {
+       .unprepare = boe_panel_unprepare,
+       .prepare = boe_panel_prepare,
+       .enable = boe_panel_enable,
+       .get_modes = boe_panel_get_modes,
+};
+
+static int boe_panel_add(struct boe_panel *boe)
+{
+       struct device *dev = &boe->dsi->dev;
+       int err;
+
+       boe->avdd = devm_regulator_get(dev, "avdd");
+       if (IS_ERR(boe->avdd))
+               return PTR_ERR(boe->avdd);
+
+       boe->avee = devm_regulator_get(dev, "avee");
+       if (IS_ERR(boe->avee))
+               return PTR_ERR(boe->avee);
+
+       boe->pp1800 = devm_regulator_get(dev, "pp1800");
+       if (IS_ERR(boe->pp1800))
+               return PTR_ERR(boe->pp1800);
+
+       boe->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(boe->enable_gpio)) {
+               dev_err(dev, "cannot get reset-gpios %ld\n",
+                       PTR_ERR(boe->enable_gpio));
+               return PTR_ERR(boe->enable_gpio);
+       }
+
+       gpiod_set_value(boe->enable_gpio, 0);
+
+       drm_panel_init(&boe->base, dev, &boe_panel_funcs,
+                      DRM_MODE_CONNECTOR_DSI);
+
+       err = drm_panel_of_backlight(&boe->base);
+       if (err)
+               return err;
+
+       boe->base.funcs = &boe_panel_funcs;
+       boe->base.dev = &boe->dsi->dev;
+
+       return drm_panel_add(&boe->base);
+}
+
+static int boe_panel_probe(struct mipi_dsi_device *dsi)
+{
+       struct boe_panel *boe;
+       int ret;
+       const struct panel_desc *desc;
+
+       boe = devm_kzalloc(&dsi->dev, sizeof(*boe), GFP_KERNEL);
+       if (!boe)
+               return -ENOMEM;
+
+       desc = of_device_get_match_data(&dsi->dev);
+       dsi->lanes = desc->lanes;
+       dsi->format = desc->format;
+       dsi->mode_flags = desc->mode_flags;
+       boe->desc = desc;
+       boe->dsi = dsi;
+       ret = boe_panel_add(boe);
+       if (ret < 0)
+               return ret;
+
+       mipi_dsi_set_drvdata(dsi, boe);
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret)
+               drm_panel_remove(&boe->base);
+
+       return ret;
+}
+
+static void boe_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+       struct boe_panel *boe = mipi_dsi_get_drvdata(dsi);
+
+       drm_panel_disable(&boe->base);
+       drm_panel_unprepare(&boe->base);
+}
+
+static int boe_panel_remove(struct mipi_dsi_device *dsi)
+{
+       struct boe_panel *boe = mipi_dsi_get_drvdata(dsi);
+       int ret;
+
+       boe_panel_shutdown(dsi);
+
+       ret = mipi_dsi_detach(dsi);
+       if (ret < 0)
+               dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
+
+       if (boe->base.dev)
+               drm_panel_remove(&boe->base);
+
+       return 0;
+}
+
+static const struct of_device_id boe_of_match[] = {
+       { .compatible = "boe,tv101wum-nl6",
+         .data = &boe_tv101wum_nl6_desc
+       },
+       { .compatible = "auo,kd101n80-45na",
+         .data = &auo_kd101n80_45na_desc
+       },
+       { .compatible = "boe,tv101wum-n53",
+         .data = &boe_tv101wum_n53_desc
+       },
+       { .compatible = "auo,b101uan08.3",
+         .data = &auo_b101uan08_3_desc
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, boe_of_match);
+
+static struct mipi_dsi_driver boe_panel_driver = {
+       .driver = {
+               .name = "panel-boe-tv101wum-nl6",
+               .of_match_table = boe_of_match,
+       },
+       .probe = boe_panel_probe,
+       .remove = boe_panel_remove,
+       .shutdown = boe_panel_shutdown,
+};
+module_mipi_dsi_driver(boe_panel_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_DESCRIPTION("BOE tv101wum-nl6 1200x1920 video mode panel driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
new file mode 100644 (file)
index 0000000..fddbfdd
--- /dev/null
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2020 Icenowy Zheng <icenowy@aosc.io>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define K101_IM2BA02_INIT_CMD_LEN      2
+
+static const char * const regulator_names[] = {
+       "dvdd",
+       "avdd",
+       "cvdd"
+};
+
+struct k101_im2ba02 {
+       struct drm_panel        panel;
+       struct mipi_dsi_device  *dsi;
+
+       struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
+       struct gpio_desc        *reset;
+};
+
+static inline struct k101_im2ba02 *panel_to_k101_im2ba02(struct drm_panel *panel)
+{
+       return container_of(panel, struct k101_im2ba02, panel);
+}
+
+struct k101_im2ba02_init_cmd {
+       u8 data[K101_IM2BA02_INIT_CMD_LEN];
+};
+
+static const struct k101_im2ba02_init_cmd k101_im2ba02_init_cmds[] = {
+       /* Switch to page 0 */
+       { .data = { 0xE0, 0x00 } },
+
+       /* Seems to be some password */
+       { .data = { 0xE1, 0x93} },
+       { .data = { 0xE2, 0x65 } },
+       { .data = { 0xE3, 0xF8 } },
+
+       /* Lane number, 0x02 - 3 lanes, 0x03 - 4 lanes */
+       { .data = { 0x80, 0x03 } },
+
+       /* Sequence control */
+       { .data = { 0x70, 0x02 } },
+       { .data = { 0x71, 0x23 } },
+       { .data = { 0x72, 0x06 } },
+
+       /* Switch to page 1 */
+       { .data = { 0xE0, 0x01 } },
+
+       /* Set VCOM */
+       { .data = { 0x00, 0x00 } },
+       { .data = { 0x01, 0x66 } },
+       /* Set VCOM_Reverse */
+       { .data = { 0x03, 0x00 } },
+       { .data = { 0x04, 0x25 } },
+
+       /* Set Gamma Power, VG[MS][PN] */
+       { .data = { 0x17, 0x00 } },
+       { .data = { 0x18, 0x6D } },
+       { .data = { 0x19, 0x00 } },
+       { .data = { 0x1A, 0x00 } },
+       { .data = { 0x1B, 0xBF } }, /* VGMN = -4.5V */
+       { .data = { 0x1C, 0x00 } },
+
+       /* Set Gate Power */
+       { .data = { 0x1F, 0x3E } }, /* VGH_R = 15V */
+       { .data = { 0x20, 0x28 } }, /* VGL_R = -11V */
+       { .data = { 0x21, 0x28 } }, /* VGL_R2 = -11V */
+       { .data = { 0x22, 0x0E } }, /* PA[6:4] = 0, PA[0] = 0 */
+
+       /* Set Panel */
+       { .data = { 0x37, 0x09 } }, /* SS = 1, BGR = 1 */
+
+       /* Set RGBCYC */
+       { .data = { 0x38, 0x04 } }, /* JDT = 100 column inversion */
+       { .data = { 0x39, 0x08 } }, /* RGB_N_EQ1 */
+       { .data = { 0x3A, 0x12 } }, /* RGB_N_EQ2 */
+       { .data = { 0x3C, 0x78 } }, /* set EQ3 for TE_H */
+       { .data = { 0x3D, 0xFF } }, /* set CHGEN_ON */
+       { .data = { 0x3E, 0xFF } }, /* set CHGEN_OFF */
+       { .data = { 0x3F, 0x7F } }, /* set CHGEN_OFF2 */
+
+       /* Set TCON parameter */
+       { .data = { 0x40, 0x06 } }, /* RSO = 800 points */
+       { .data = { 0x41, 0xA0 } }, /* LN = 1280 lines */
+
+       /* Set power voltage */
+       { .data = { 0x55, 0x0F } }, /* DCDCM */
+       { .data = { 0x56, 0x01 } },
+       { .data = { 0x57, 0x69 } },
+       { .data = { 0x58, 0x0A } },
+       { .data = { 0x59, 0x0A } },
+       { .data = { 0x5A, 0x45 } },
+       { .data = { 0x5B, 0x15 } },
+
+       /* Set gamma */
+       { .data = { 0x5D, 0x7C } },
+       { .data = { 0x5E, 0x65 } },
+       { .data = { 0x5F, 0x55 } },
+       { .data = { 0x60, 0x49 } },
+       { .data = { 0x61, 0x44 } },
+       { .data = { 0x62, 0x35 } },
+       { .data = { 0x63, 0x3A } },
+       { .data = { 0x64, 0x23 } },
+       { .data = { 0x65, 0x3D } },
+       { .data = { 0x66, 0x3C } },
+       { .data = { 0x67, 0x3D } },
+       { .data = { 0x68, 0x5D } },
+       { .data = { 0x69, 0x4D } },
+       { .data = { 0x6A, 0x56 } },
+       { .data = { 0x6B, 0x48 } },
+       { .data = { 0x6C, 0x45 } },
+       { .data = { 0x6D, 0x38 } },
+       { .data = { 0x6E, 0x25 } },
+       { .data = { 0x6F, 0x00 } },
+       { .data = { 0x70, 0x7C } },
+       { .data = { 0x71, 0x65 } },
+       { .data = { 0x72, 0x55 } },
+       { .data = { 0x73, 0x49 } },
+       { .data = { 0x74, 0x44 } },
+       { .data = { 0x75, 0x35 } },
+       { .data = { 0x76, 0x3A } },
+       { .data = { 0x77, 0x23 } },
+       { .data = { 0x78, 0x3D } },
+       { .data = { 0x79, 0x3C } },
+       { .data = { 0x7A, 0x3D } },
+       { .data = { 0x7B, 0x5D } },
+       { .data = { 0x7C, 0x4D } },
+       { .data = { 0x7D, 0x56 } },
+       { .data = { 0x7E, 0x48 } },
+       { .data = { 0x7F, 0x45 } },
+       { .data = { 0x80, 0x38 } },
+       { .data = { 0x81, 0x25 } },
+       { .data = { 0x82, 0x00 } },
+
+       /* Switch to page 2, for GIP */
+       { .data = { 0xE0, 0x02 } },
+
+       { .data = { 0x00, 0x1E } },
+       { .data = { 0x01, 0x1E } },
+       { .data = { 0x02, 0x41 } },
+       { .data = { 0x03, 0x41 } },
+       { .data = { 0x04, 0x43 } },
+       { .data = { 0x05, 0x43 } },
+       { .data = { 0x06, 0x1F } },
+       { .data = { 0x07, 0x1F } },
+       { .data = { 0x08, 0x1F } },
+       { .data = { 0x09, 0x1F } },
+       { .data = { 0x0A, 0x1E } },
+       { .data = { 0x0B, 0x1E } },
+       { .data = { 0x0C, 0x1F } },
+       { .data = { 0x0D, 0x47 } },
+       { .data = { 0x0E, 0x47 } },
+       { .data = { 0x0F, 0x45 } },
+       { .data = { 0x10, 0x45 } },
+       { .data = { 0x11, 0x4B } },
+       { .data = { 0x12, 0x4B } },
+       { .data = { 0x13, 0x49 } },
+       { .data = { 0x14, 0x49 } },
+       { .data = { 0x15, 0x1F } },
+
+       { .data = { 0x16, 0x1E } },
+       { .data = { 0x17, 0x1E } },
+       { .data = { 0x18, 0x40 } },
+       { .data = { 0x19, 0x40 } },
+       { .data = { 0x1A, 0x42 } },
+       { .data = { 0x1B, 0x42 } },
+       { .data = { 0x1C, 0x1F } },
+       { .data = { 0x1D, 0x1F } },
+       { .data = { 0x1E, 0x1F } },
+       { .data = { 0x1F, 0x1f } },
+       { .data = { 0x20, 0x1E } },
+       { .data = { 0x21, 0x1E } },
+       { .data = { 0x22, 0x1f } },
+       { .data = { 0x23, 0x46 } },
+       { .data = { 0x24, 0x46 } },
+       { .data = { 0x25, 0x44 } },
+       { .data = { 0x26, 0x44 } },
+       { .data = { 0x27, 0x4A } },
+       { .data = { 0x28, 0x4A } },
+       { .data = { 0x29, 0x48 } },
+       { .data = { 0x2A, 0x48 } },
+       { .data = { 0x2B, 0x1f } },
+
+       { .data = { 0x2C, 0x1F } },
+       { .data = { 0x2D, 0x1F } },
+       { .data = { 0x2E, 0x42 } },
+       { .data = { 0x2F, 0x42 } },
+       { .data = { 0x30, 0x40 } },
+       { .data = { 0x31, 0x40 } },
+       { .data = { 0x32, 0x1E } },
+       { .data = { 0x33, 0x1E } },
+       { .data = { 0x34, 0x1F } },
+       { .data = { 0x35, 0x1F } },
+       { .data = { 0x36, 0x1E } },
+       { .data = { 0x37, 0x1E } },
+       { .data = { 0x38, 0x1F } },
+       { .data = { 0x39, 0x48 } },
+       { .data = { 0x3A, 0x48 } },
+       { .data = { 0x3B, 0x4A } },
+       { .data = { 0x3C, 0x4A } },
+       { .data = { 0x3D, 0x44 } },
+       { .data = { 0x3E, 0x44 } },
+       { .data = { 0x3F, 0x46 } },
+       { .data = { 0x40, 0x46 } },
+       { .data = { 0x41, 0x1F } },
+
+       { .data = { 0x42, 0x1F } },
+       { .data = { 0x43, 0x1F } },
+       { .data = { 0x44, 0x43 } },
+       { .data = { 0x45, 0x43 } },
+       { .data = { 0x46, 0x41 } },
+       { .data = { 0x47, 0x41 } },
+       { .data = { 0x48, 0x1E } },
+       { .data = { 0x49, 0x1E } },
+       { .data = { 0x4A, 0x1E } },
+       { .data = { 0x4B, 0x1F } },
+       { .data = { 0x4C, 0x1E } },
+       { .data = { 0x4D, 0x1E } },
+       { .data = { 0x4E, 0x1F } },
+       { .data = { 0x4F, 0x49 } },
+       { .data = { 0x50, 0x49 } },
+       { .data = { 0x51, 0x4B } },
+       { .data = { 0x52, 0x4B } },
+       { .data = { 0x53, 0x45 } },
+       { .data = { 0x54, 0x45 } },
+       { .data = { 0x55, 0x47 } },
+       { .data = { 0x56, 0x47 } },
+       { .data = { 0x57, 0x1F } },
+
+       { .data = { 0x58, 0x10 } },
+       { .data = { 0x59, 0x00 } },
+       { .data = { 0x5A, 0x00 } },
+       { .data = { 0x5B, 0x30 } },
+       { .data = { 0x5C, 0x02 } },
+       { .data = { 0x5D, 0x40 } },
+       { .data = { 0x5E, 0x01 } },
+       { .data = { 0x5F, 0x02 } },
+       { .data = { 0x60, 0x30 } },
+       { .data = { 0x61, 0x01 } },
+       { .data = { 0x62, 0x02 } },
+       { .data = { 0x63, 0x6A } },
+       { .data = { 0x64, 0x6A } },
+       { .data = { 0x65, 0x05 } },
+       { .data = { 0x66, 0x12 } },
+       { .data = { 0x67, 0x74 } },
+       { .data = { 0x68, 0x04 } },
+       { .data = { 0x69, 0x6A } },
+       { .data = { 0x6A, 0x6A } },
+       { .data = { 0x6B, 0x08 } },
+
+       { .data = { 0x6C, 0x00 } },
+       { .data = { 0x6D, 0x04 } },
+       { .data = { 0x6E, 0x04 } },
+       { .data = { 0x6F, 0x88 } },
+       { .data = { 0x70, 0x00 } },
+       { .data = { 0x71, 0x00 } },
+       { .data = { 0x72, 0x06 } },
+       { .data = { 0x73, 0x7B } },
+       { .data = { 0x74, 0x00 } },
+       { .data = { 0x75, 0x07 } },
+       { .data = { 0x76, 0x00 } },
+       { .data = { 0x77, 0x5D } },
+       { .data = { 0x78, 0x17 } },
+       { .data = { 0x79, 0x1F } },
+       { .data = { 0x7A, 0x00 } },
+       { .data = { 0x7B, 0x00 } },
+       { .data = { 0x7C, 0x00 } },
+       { .data = { 0x7D, 0x03 } },
+       { .data = { 0x7E, 0x7B } },
+
+       { .data = { 0xE0, 0x04 } },
+       { .data = { 0x2B, 0x2B } },
+       { .data = { 0x2E, 0x44 } },
+
+       { .data = { 0xE0, 0x01 } },
+       { .data = { 0x0E, 0x01 } },
+
+       { .data = { 0xE0, 0x03 } },
+       { .data = { 0x98, 0x2F } },
+
+       { .data = { 0xE0, 0x00 } },
+       { .data = { 0xE6, 0x02 } },
+       { .data = { 0xE7, 0x02 } },
+
+       { .data = { 0x11, 0x00 } },
+};
+
+static const struct k101_im2ba02_init_cmd timed_cmds[] = {
+       { .data = { 0x29, 0x00 } },
+       { .data = { 0x35, 0x00 } },
+};
+
+static int k101_im2ba02_prepare(struct drm_panel *panel)
+{
+       struct k101_im2ba02 *ctx = panel_to_k101_im2ba02(panel);
+       struct mipi_dsi_device *dsi = ctx->dsi;
+       unsigned int i;
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+       if (ret)
+               return ret;
+
+       msleep(30);
+
+       gpiod_set_value(ctx->reset, 1);
+       msleep(50);
+
+       gpiod_set_value(ctx->reset, 0);
+       msleep(50);
+
+       gpiod_set_value(ctx->reset, 1);
+       msleep(200);
+
+       for (i = 0; i < ARRAY_SIZE(k101_im2ba02_init_cmds); i++) {
+               const struct k101_im2ba02_init_cmd *cmd = &k101_im2ba02_init_cmds[i];
+
+               ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data, K101_IM2BA02_INIT_CMD_LEN);
+               if (ret < 0)
+                       goto powerdown;
+       }
+
+       return 0;
+
+powerdown:
+       gpiod_set_value(ctx->reset, 0);
+       msleep(50);
+
+       return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int k101_im2ba02_enable(struct drm_panel *panel)
+{
+       struct k101_im2ba02 *ctx = panel_to_k101_im2ba02(panel);
+       const struct k101_im2ba02_init_cmd *cmd = &timed_cmds[1];
+       int ret;
+
+       msleep(150);
+
+       ret = mipi_dsi_dcs_set_display_on(ctx->dsi);
+       if (ret < 0)
+               return ret;
+
+       msleep(50);
+
+       return mipi_dsi_dcs_write_buffer(ctx->dsi, cmd->data, K101_IM2BA02_INIT_CMD_LEN);
+}
+
+static int k101_im2ba02_disable(struct drm_panel *panel)
+{
+       struct k101_im2ba02 *ctx = panel_to_k101_im2ba02(panel);
+
+       return mipi_dsi_dcs_set_display_off(ctx->dsi);
+}
+
+static int k101_im2ba02_unprepare(struct drm_panel *panel)
+{
+       struct k101_im2ba02 *ctx = panel_to_k101_im2ba02(panel);
+       int ret;
+
+       ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
+       if (ret < 0)
+               DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
+                             ret);
+
+       ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+       if (ret < 0)
+               DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
+                             ret);
+
+       msleep(200);
+
+       gpiod_set_value(ctx->reset, 0);
+       msleep(20);
+
+       return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static const struct drm_display_mode k101_im2ba02_default_mode = {
+       .clock = 70000,
+       .vrefresh = 60,
+
+       .hdisplay = 800,
+       .hsync_start = 800 + 20,
+       .hsync_end = 800 + 20 + 20,
+       .htotal = 800 + 20 + 20 + 20,
+
+       .vdisplay = 1280,
+       .vsync_start = 1280 + 16,
+       .vsync_end = 1280 + 16 + 4,
+       .vtotal = 1280 + 16 + 4 + 4,
+
+       .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+       .width_mm       = 136,
+       .height_mm      = 217,
+};
+
+static int k101_im2ba02_get_modes(struct drm_panel *panel,
+                                 struct drm_connector *connector)
+{
+       struct k101_im2ba02 *ctx = panel_to_k101_im2ba02(panel);
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(connector->dev, &k101_im2ba02_default_mode);
+       if (!mode) {
+               DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
+                             k101_im2ba02_default_mode.hdisplay,
+                             k101_im2ba02_default_mode.vdisplay,
+                             k101_im2ba02_default_mode.vrefresh);
+               return -ENOMEM;
+       }
+
+       drm_mode_set_name(mode);
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
+static const struct drm_panel_funcs k101_im2ba02_funcs = {
+       .disable = k101_im2ba02_disable,
+       .unprepare = k101_im2ba02_unprepare,
+       .prepare = k101_im2ba02_prepare,
+       .enable = k101_im2ba02_enable,
+       .get_modes = k101_im2ba02_get_modes,
+};
+
+static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi)
+{
+       struct k101_im2ba02 *ctx;
+       unsigned int i;
+       int ret;
+
+       ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       mipi_dsi_set_drvdata(dsi, ctx);
+       ctx->dsi = dsi;
+
+       for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
+               ctx->supplies[i].supply = regulator_names[i];
+
+       ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies),
+                                     ctx->supplies);
+       if (ret < 0) {
+               DRM_DEV_ERROR(&dsi->dev, "Couldn't get regulators\n");
+               return ret;
+       }
+
+       ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(ctx->reset)) {
+               DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
+               return PTR_ERR(ctx->reset);
+       }
+
+       drm_panel_init(&ctx->panel, &dsi->dev, &k101_im2ba02_funcs,
+                      DRM_MODE_CONNECTOR_DSI);
+
+       ret = drm_panel_of_backlight(&ctx->panel);
+       if (ret)
+               return ret;
+
+       ret = drm_panel_add(&ctx->panel);
+       if (ret < 0)
+               return ret;
+
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->lanes = 4;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0) {
+               drm_panel_remove(&ctx->panel);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int k101_im2ba02_dsi_remove(struct mipi_dsi_device *dsi)
+{
+       struct k101_im2ba02 *ctx = mipi_dsi_get_drvdata(dsi);
+
+       mipi_dsi_detach(dsi);
+       drm_panel_remove(&ctx->panel);
+
+       return 0;
+}
+
+static const struct of_device_id k101_im2ba02_of_match[] = {
+       { .compatible = "feixin,k101-im2ba02", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, k101_im2ba02_of_match);
+
+static struct mipi_dsi_driver k101_im2ba02_driver = {
+       .probe = k101_im2ba02_dsi_probe,
+       .remove = k101_im2ba02_dsi_remove,
+       .driver = {
+               .name = "feixin-k101-im2ba02",
+               .of_match_table = k101_im2ba02_of_match,
+       },
+};
+module_mipi_dsi_driver(k101_im2ba02_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_DESCRIPTION("Feixin K101 IM2BA02 MIPI-DSI LCD panel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
new file mode 100644 (file)
index 0000000..9d843fc
--- /dev/null
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2019, Michael Srba
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+struct s6e88a0_ams452ef01 {
+       struct drm_panel panel;
+       struct mipi_dsi_device *dsi;
+       struct regulator_bulk_data supplies[2];
+       struct gpio_desc *reset_gpio;
+
+       bool prepared;
+};
+
+static inline struct
+s6e88a0_ams452ef01 *to_s6e88a0_ams452ef01(struct drm_panel *panel)
+{
+       return container_of(panel, struct s6e88a0_ams452ef01, panel);
+}
+
+#define dsi_dcs_write_seq(dsi, seq...) do {                            \
+               static const u8 d[] = { seq };                          \
+               int ret;                                                \
+               ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
+               if (ret < 0)                                            \
+                       return ret;                                     \
+       } while (0)
+
+static void s6e88a0_ams452ef01_reset(struct s6e88a0_ams452ef01 *ctx)
+{
+       gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+       usleep_range(5000, 6000);
+       gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+       usleep_range(1000, 2000);
+       gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+       usleep_range(10000, 11000);
+}
+
+static int s6e88a0_ams452ef01_on(struct s6e88a0_ams452ef01 *ctx)
+{
+       struct mipi_dsi_device *dsi = ctx->dsi;
+       struct device *dev = &dsi->dev;
+       int ret;
+
+       dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+       dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); // enable LEVEL2 commands
+       dsi_dcs_write_seq(dsi, 0xcc, 0x4c); // set Pixel Clock Divider polarity
+
+       ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+       if (ret < 0) {
+               dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
+               return ret;
+       }
+       msleep(120);
+
+       // set default brightness/gama
+       dsi_dcs_write_seq(dsi, 0xca,
+                         0x01, 0x00, 0x01, 0x00, 0x01, 0x00,   // V255 RR,GG,BB
+                         0x80, 0x80, 0x80,                     // V203 R,G,B
+                         0x80, 0x80, 0x80,                     // V151 R,G,B
+                         0x80, 0x80, 0x80,                     // V87  R,G,B
+                         0x80, 0x80, 0x80,                     // V51  R,G,B
+                         0x80, 0x80, 0x80,                     // V35  R,G,B
+                         0x80, 0x80, 0x80,                     // V23  R,G,B
+                         0x80, 0x80, 0x80,                     // V11  R,G,B
+                         0x6b, 0x68, 0x71,                     // V3   R,G,B
+                         0x00, 0x00, 0x00);                    // V1   R,G,B
+       // set default Amoled Off Ratio
+       dsi_dcs_write_seq(dsi, 0xb2, 0x40, 0x0a, 0x17, 0x00, 0x0a);
+       dsi_dcs_write_seq(dsi, 0xb6, 0x2c, 0x0b); // set default elvss voltage
+       dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
+       dsi_dcs_write_seq(dsi, 0xf7, 0x03); // gamma/aor update
+       dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); // disable LEVEL2 commands
+
+       ret = mipi_dsi_dcs_set_display_on(dsi);
+       if (ret < 0) {
+               dev_err(dev, "Failed to set display on: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s6e88a0_ams452ef01_off(struct s6e88a0_ams452ef01 *ctx)
+{
+       struct mipi_dsi_device *dsi = ctx->dsi;
+       struct device *dev = &dsi->dev;
+       int ret;
+
+       dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+       ret = mipi_dsi_dcs_set_display_off(dsi);
+       if (ret < 0) {
+               dev_err(dev, "Failed to set display off: %d\n", ret);
+               return ret;
+       }
+       msleep(35);
+
+       ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+       if (ret < 0) {
+               dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
+               return ret;
+       }
+       msleep(120);
+
+       return 0;
+}
+
+static int s6e88a0_ams452ef01_prepare(struct drm_panel *panel)
+{
+       struct s6e88a0_ams452ef01 *ctx = to_s6e88a0_ams452ef01(panel);
+       struct device *dev = &ctx->dsi->dev;
+       int ret;
+
+       if (ctx->prepared)
+               return 0;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to enable regulators: %d\n", ret);
+               return ret;
+       }
+
+       s6e88a0_ams452ef01_reset(ctx);
+
+       ret = s6e88a0_ams452ef01_on(ctx);
+       if (ret < 0) {
+               dev_err(dev, "Failed to initialize panel: %d\n", ret);
+               gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+               regulator_bulk_disable(ARRAY_SIZE(ctx->supplies),
+                                      ctx->supplies);
+               return ret;
+       }
+
+       ctx->prepared = true;
+       return 0;
+}
+
+static int s6e88a0_ams452ef01_unprepare(struct drm_panel *panel)
+{
+       struct s6e88a0_ams452ef01 *ctx = to_s6e88a0_ams452ef01(panel);
+       struct device *dev = &ctx->dsi->dev;
+       int ret;
+
+       if (!ctx->prepared)
+               return 0;
+
+       ret = s6e88a0_ams452ef01_off(ctx);
+       if (ret < 0)
+               dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+       gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+       regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+
+       ctx->prepared = false;
+       return 0;
+}
+
+static const struct drm_display_mode s6e88a0_ams452ef01_mode = {
+       .clock = (540 + 88 + 4 + 20) * (960 + 14 + 2 + 8) * 60 / 1000,
+       .hdisplay = 540,
+       .hsync_start = 540 + 88,
+       .hsync_end = 540 + 88 + 4,
+       .htotal = 540 + 88 + 4 + 20,
+       .vdisplay = 960,
+       .vsync_start = 960 + 14,
+       .vsync_end = 960 + 14 + 2,
+       .vtotal = 960 + 14 + 2 + 8,
+       .vrefresh = 60,
+       .width_mm = 56,
+       .height_mm = 100,
+};
+
+static int s6e88a0_ams452ef01_get_modes(struct drm_panel *panel,
+                                       struct drm_connector *connector)
+{
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(connector->dev, &s6e88a0_ams452ef01_mode);
+       if (!mode)
+               return -ENOMEM;
+
+       drm_mode_set_name(mode);
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
+static const struct drm_panel_funcs s6e88a0_ams452ef01_panel_funcs = {
+       .unprepare = s6e88a0_ams452ef01_unprepare,
+       .prepare = s6e88a0_ams452ef01_prepare,
+       .get_modes = s6e88a0_ams452ef01_get_modes,
+};
+
+static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct s6e88a0_ams452ef01 *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->supplies[0].supply = "vdd3";
+       ctx->supplies[1].supply = "vci";
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+                                     ctx->supplies);
+       if (ret < 0) {
+               dev_err(dev, "Failed to get regulators: %d\n", ret);
+               return ret;
+       }
+
+       ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(ctx->reset_gpio)) {
+               ret = PTR_ERR(ctx->reset_gpio);
+               dev_err(dev, "Failed to get reset-gpios: %d\n", ret);
+               return ret;
+       }
+
+       ctx->dsi = dsi;
+       mipi_dsi_set_drvdata(dsi, ctx);
+
+       dsi->lanes = 2;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST;
+
+       drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs,
+                      DRM_MODE_CONNECTOR_DSI);
+
+       ret = drm_panel_add(&ctx->panel);
+       if (ret < 0) {
+               dev_err(dev, "Failed to add panel: %d\n", ret);
+               return ret;
+       }
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0) {
+               dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int s6e88a0_ams452ef01_remove(struct mipi_dsi_device *dsi)
+{
+       struct s6e88a0_ams452ef01 *ctx = mipi_dsi_get_drvdata(dsi);
+       int ret;
+
+       ret = mipi_dsi_detach(dsi);
+       if (ret < 0)
+               dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+       drm_panel_remove(&ctx->panel);
+
+       return 0;
+}
+
+static const struct of_device_id s6e88a0_ams452ef01_of_match[] = {
+       { .compatible = "samsung,s6e88a0-ams452ef01" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, s6e88a0_ams452ef01_of_match);
+
+static struct mipi_dsi_driver s6e88a0_ams452ef01_driver = {
+       .probe = s6e88a0_ams452ef01_probe,
+       .remove = s6e88a0_ams452ef01_remove,
+       .driver = {
+               .name = "panel-s6e88a0-ams452ef01",
+               .of_match_table = s6e88a0_ams452ef01_of_match,
+       },
+};
+module_mipi_dsi_driver(s6e88a0_ams452ef01_driver);
+
+MODULE_AUTHOR("Michael Srba <Michael.Srba@seznam.cz>");
+MODULE_DESCRIPTION("MIPI-DSI based Panel Driver for AMS452EF01 AMOLED LCD with a S6E88A0 controller");
+MODULE_LICENSE("GPL v2");
index e14c14a..d901ccb 100644 (file)
@@ -1301,6 +1301,37 @@ static const struct panel_desc edt_et035012dm6 = {
        .bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_NEGEDGE,
 };
 
+static const struct drm_display_mode edt_etm043080dh6gp_mode = {
+       .clock = 10870,
+       .hdisplay = 480,
+       .hsync_start = 480 + 8,
+       .hsync_end = 480 + 8 + 4,
+       .htotal = 480 + 8 + 4 + 41,
+
+       /*
+        * IWG22M: Y resolution changed for "dc_linuxfb" module crashing while
+        * fb_align
+        */
+
+       .vdisplay = 288,
+       .vsync_start = 288 + 2,
+       .vsync_end = 288 + 2 + 4,
+       .vtotal = 288 + 2 + 4 + 10,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc edt_etm043080dh6gp = {
+       .modes = &edt_etm043080dh6gp_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 100,
+               .height = 65,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+       .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
+
 static const struct drm_display_mode edt_etm0430g0dh6_mode = {
        .clock = 9000,
        .hdisplay = 480,
@@ -1440,6 +1471,33 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
+static const struct drm_display_mode frida_frd350h54004_mode = {
+       .clock = 6000,
+       .hdisplay = 320,
+       .hsync_start = 320 + 44,
+       .hsync_end = 320 + 44 + 16,
+       .htotal = 320 + 44 + 16 + 20,
+       .vdisplay = 240,
+       .vsync_start = 240 + 2,
+       .vsync_end = 240 + 2 + 6,
+       .vtotal = 240 + 2 + 6 + 2,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+};
+
+static const struct panel_desc frida_frd350h54004 = {
+       .modes = &frida_frd350h54004_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 77,
+               .height = 64,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
+       .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
+
 static const struct drm_display_mode friendlyarm_hd702e_mode = {
        .clock          = 67185,
        .hdisplay       = 800,
@@ -2080,6 +2138,64 @@ static const struct panel_desc lg_lp129qe = {
        },
 };
 
+static const struct display_timing logictechno_lt161010_2nh_timing = {
+       .pixelclock = { 26400000, 33300000, 46800000 },
+       .hactive = { 800, 800, 800 },
+       .hfront_porch = { 16, 210, 354 },
+       .hback_porch = { 46, 46, 46 },
+       .hsync_len = { 1, 20, 40 },
+       .vactive = { 480, 480, 480 },
+       .vfront_porch = { 7, 22, 147 },
+       .vback_porch = { 23, 23, 23 },
+       .vsync_len = { 1, 10, 20 },
+       .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
+                DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
+                DISPLAY_FLAGS_SYNC_POSEDGE,
+};
+
+static const struct panel_desc logictechno_lt161010_2nh = {
+       .timings = &logictechno_lt161010_2nh_timing,
+       .num_timings = 1,
+       .size = {
+               .width = 154,
+               .height = 86,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH |
+                    DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+                    DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
+       .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
+
+static const struct display_timing logictechno_lt170410_2whc_timing = {
+       .pixelclock = { 68900000, 71100000, 73400000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 23, 60, 71 },
+       .hback_porch = { 23, 60, 71 },
+       .hsync_len = { 15, 40, 47 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 5, 7, 10 },
+       .vback_porch = { 5, 7, 10 },
+       .vsync_len = { 6, 9, 12 },
+       .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
+                DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
+                DISPLAY_FLAGS_SYNC_POSEDGE,
+};
+
+static const struct panel_desc logictechno_lt170410_2whc = {
+       .timings = &logictechno_lt170410_2whc_timing,
+       .num_timings = 1,
+       .size = {
+               .width = 217,
+               .height = 136,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH |
+                    DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
+                    DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
+       .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
 static const struct drm_display_mode mitsubishi_aa070mc01_mode = {
        .clock = 30400,
        .hdisplay = 800,
@@ -3023,7 +3139,7 @@ static const struct panel_desc toshiba_lt089ac29000 = {
                .width = 194,
                .height = 116,
        },
-       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
        .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
        .connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
@@ -3286,6 +3402,9 @@ static const struct of_device_id platform_of_match[] = {
                .compatible = "edt,et035012dm6",
                .data = &edt_et035012dm6,
        }, {
+               .compatible = "edt,etm043080dh6gp",
+               .data = &edt_etm043080dh6gp,
+       }, {
                .compatible = "edt,etm0430g0dh6",
                .data = &edt_etm0430g0dh6,
        }, {
@@ -3310,6 +3429,9 @@ static const struct of_device_id platform_of_match[] = {
                .compatible = "foxlink,fl500wvr00-a0t",
                .data = &foxlink_fl500wvr00_a0t,
        }, {
+               .compatible = "frida,frd350h54004",
+               .data = &frida_frd350h54004,
+       }, {
                .compatible = "friendlyarm,hd702e",
                .data = &friendlyarm_hd702e,
        }, {
@@ -3388,6 +3510,15 @@ static const struct of_device_id platform_of_match[] = {
                .compatible = "logicpd,type28",
                .data = &logicpd_type_28,
        }, {
+               .compatible = "logictechno,lt161010-2nhc",
+               .data = &logictechno_lt161010_2nh,
+       }, {
+               .compatible = "logictechno,lt161010-2nhr",
+               .data = &logictechno_lt161010_2nh,
+       }, {
+               .compatible = "logictechno,lt170410-2whc",
+               .data = &logictechno_lt170410_2whc,
+       }, {
                .compatible = "mitsubishi,aa070mc01-ca1",
                .data = &mitsubishi_aa070mc01,
        }, {
index cf29405..aeca15d 100644 (file)
@@ -86,7 +86,12 @@ struct td028ttec1_panel {
 
 #define to_td028ttec1_device(p) container_of(p, struct td028ttec1_panel, panel)
 
-static int jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err)
+/*
+ * noinline_for_stack so we don't get multiple copies of tx_buf
+ * on the stack in case of gcc-plugin-structleak
+ */
+static int noinline_for_stack
+jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err)
 {
        struct spi_device *spi = lcd->spi;
        u16 tx_buf = JBT_COMMAND | reg;
@@ -105,8 +110,9 @@ static int jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err)
        return ret;
 }
 
-static int jbt_reg_write_1(struct td028ttec1_panel *lcd,
-                          u8 reg, u8 data, int *err)
+static int noinline_for_stack
+jbt_reg_write_1(struct td028ttec1_panel *lcd,
+               u8 reg, u8 data, int *err)
 {
        struct spi_device *spi = lcd->spi;
        u16 tx_buf[2];
@@ -128,8 +134,9 @@ static int jbt_reg_write_1(struct td028ttec1_panel *lcd,
        return ret;
 }
 
-static int jbt_reg_write_2(struct td028ttec1_panel *lcd,
-                          u8 reg, u16 data, int *err)
+static int noinline_for_stack
+jbt_reg_write_2(struct td028ttec1_panel *lcd,
+               u8 reg, u16 data, int *err)
 {
        struct spi_device *spi = lcd->spi;
        u16 tx_buf[3];
index 8822ec1..1b9b79c 100644 (file)
@@ -309,10 +309,6 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev)
        ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO,
                val, val == pfdev->features.l2_present, 100, 1000);
 
-       gpu_write(pfdev, STACK_PWRON_LO, pfdev->features.stack_present);
-       ret |= readl_relaxed_poll_timeout(pfdev->iomem + STACK_READY_LO,
-               val, val == pfdev->features.stack_present, 100, 1000);
-
        gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present);
        ret |= readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO,
                val, val == pfdev->features.shader_present, 100, 1000);
@@ -329,7 +325,6 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
 {
        gpu_write(pfdev, TILER_PWROFF_LO, 0);
        gpu_write(pfdev, SHADER_PWROFF_LO, 0);
-       gpu_write(pfdev, STACK_PWROFF_LO, 0);
        gpu_write(pfdev, L2_PWROFF_LO, 0);
 }
 
@@ -351,7 +346,7 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
                return -ENODEV;
 
        err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler,
-                              IRQF_SHARED, "gpu", pfdev);
+                              IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev);
        if (err) {
                dev_err(pfdev->dev, "failed to request gpu irq");
                return err;
index 7157dfd..8fd8726 100644 (file)
@@ -512,7 +512,7 @@ int panfrost_job_init(struct panfrost_device *pfdev)
                return -ENODEV;
 
        ret = devm_request_irq(pfdev->dev, irq, panfrost_job_irq_handler,
-                              IRQF_SHARED, "job", pfdev);
+                              IRQF_SHARED, KBUILD_MODNAME "-job", pfdev);
        if (ret) {
                dev_err(pfdev->dev, "failed to request job irq");
                return ret;
index 763cfca..23314f4 100644 (file)
@@ -641,9 +641,11 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
        if (irq <= 0)
                return -ENODEV;
 
-       err = devm_request_threaded_irq(pfdev->dev, irq, panfrost_mmu_irq_handler,
+       err = devm_request_threaded_irq(pfdev->dev, irq,
+                                       panfrost_mmu_irq_handler,
                                        panfrost_mmu_irq_handler_thread,
-                                       IRQF_SHARED, "mmu", pfdev);
+                                       IRQF_SHARED, KBUILD_MODNAME "-mmu",
+                                       pfdev);
 
        if (err) {
                dev_err(pfdev->dev, "failed to request mmu irq");
index 16d73b2..ab4f8dd 100644 (file)
@@ -31,7 +31,6 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_vblank.h>
 
 #include "qxl_drv.h"
 #include "qxl_object.h"
@@ -372,19 +371,6 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
 static void qxl_crtc_atomic_flush(struct drm_crtc *crtc,
                                  struct drm_crtc_state *old_crtc_state)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_pending_vblank_event *event;
-       unsigned long flags;
-
-       if (crtc->state && crtc->state->event) {
-               event = crtc->state->event;
-               crtc->state->event = NULL;
-
-               spin_lock_irqsave(&dev->event_lock, flags);
-               drm_crtc_send_vblank_event(crtc, event);
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-       }
-
        qxl_crtc_update_monitors_config(crtc, "flush");
 }
 
index 16a5e90..62a5e42 100644 (file)
@@ -48,11 +48,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
        return qdev;
 }
 
-static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
-{
-       return 0;
-}
-
 static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                             struct ttm_mem_type_manager *man)
 {
@@ -256,7 +251,6 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
 
 static struct ttm_bo_driver qxl_bo_driver = {
        .ttm_tt_create = &qxl_ttm_tt_create,
-       .invalidate_caches = &qxl_invalidate_caches,
        .init_mem_type = &qxl_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = &qxl_evict_flags,
index a522e09..266e3cb 100644 (file)
@@ -1263,7 +1263,7 @@ static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
         * locking inversion with the driver load path. And the access here is
         * completely racy anyway. So don't bother with locking for now.
         */
-       return dev->open_count == 0;
+       return atomic_read(&dev->open_count) == 0;
 }
 
 static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
index 3b92311..badf1b6 100644 (file)
@@ -66,11 +66,6 @@ static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
        return rdev;
 }
 
-static int radeon_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
-{
-       return 0;
-}
-
 static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                                struct ttm_mem_type_manager *man)
 {
@@ -774,7 +769,6 @@ static struct ttm_bo_driver radeon_bo_driver = {
        .ttm_tt_create = &radeon_ttm_tt_create,
        .ttm_tt_populate = &radeon_ttm_tt_populate,
        .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate,
-       .invalidate_caches = &radeon_invalidate_caches,
        .init_mem_type = &radeon_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = &radeon_evict_flags,
index 8ffa4fb..06432c8 100644 (file)
@@ -590,8 +590,9 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
 }
 
 static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
-                                   struct drm_atomic_state *state)
+                                   struct drm_bridge_state *old_bridge_state)
 {
+       struct drm_atomic_state *state = old_bridge_state->base.state;
        struct drm_connector *connector;
        struct drm_crtc *crtc;
 
@@ -603,7 +604,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
 }
 
 static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
-                                    struct drm_atomic_state *state)
+                                    struct drm_bridge_state *old_bridge_state)
 {
        struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
 
@@ -618,7 +619,8 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
 
        /* Disable the companion LVDS encoder in dual-link mode. */
        if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
-               lvds->companion->funcs->atomic_disable(lvds->companion, state);
+               lvds->companion->funcs->atomic_disable(lvds->companion,
+                                                      old_bridge_state);
 
        clk_disable_unprepare(lvds->clocks.mod);
 }
@@ -682,6 +684,9 @@ static void rcar_lvds_detach(struct drm_bridge *bridge)
 static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
        .attach = rcar_lvds_attach,
        .detach = rcar_lvds_detach,
+       .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+       .atomic_reset = drm_atomic_helper_bridge_reset,
        .atomic_enable = rcar_lvds_atomic_enable,
        .atomic_disable = rcar_lvds_atomic_disable,
        .mode_fixup = rcar_lvds_mode_fixup,
index 7582d0e..0d18846 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/dma-buf.h>
 #include <linux/iommu.h>
+#include <linux/vmalloc.h>
 
 #include <drm/drm.h>
 #include <drm/drm_gem.h>
index d04b349..cecb2cc 100644 (file)
@@ -724,7 +724,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
        int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
                                        DRM_PLANE_HELPER_NO_SCALING;
 
-       if (!crtc || !fb)
+       if (!crtc || WARN_ON(!fb))
                return 0;
 
        crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
index 0b3d18c..cc67262 100644 (file)
@@ -328,7 +328,7 @@ static inline uint16_t scl_get_bili_dn_vskip(int src_h, int dst_h,
 {
        int act_height;
 
-       act_height = (src_h + vskiplines - 1) / vskiplines;
+       act_height = DIV_ROUND_UP(src_h, vskiplines);
 
        if (act_height == dst_h)
                return GET_SCL_FT_BILI_DN(src_h, dst_h) / vskiplines;
index 4b16563..2e1f266 100644 (file)
@@ -377,7 +377,9 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
        dsi->pllref_clk = devm_clk_get(dev, "ref");
        if (IS_ERR(dsi->pllref_clk)) {
                ret = PTR_ERR(dsi->pllref_clk);
-               DRM_ERROR("Unable to get pll reference clock: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       DRM_ERROR("Unable to get pll reference clock: %d\n",
+                                 ret);
                goto err_clk_get;
        }
 
index c2815e8..8750ee8 100644 (file)
@@ -648,9 +648,14 @@ static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
 static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc)
 {
        struct ltdc_device *ldev = crtc_to_ltdc(crtc);
+       struct drm_crtc_state *state = crtc->state;
 
        DRM_DEBUG_DRIVER("\n");
-       reg_set(ldev->regs, LTDC_IER, IER_LIE);
+
+       if (state->enable)
+               reg_set(ldev->regs, LTDC_IER, IER_LIE);
+       else
+               return -EPERM;
 
        return 0;
 }
@@ -1146,12 +1151,14 @@ static int ltdc_get_caps(struct drm_device *ddev)
                ldev->caps.pad_max_freq_hz = 90000000;
                if (ldev->caps.hw_version == HWVER_10200)
                        ldev->caps.pad_max_freq_hz = 65000000;
+               ldev->caps.nb_irq = 2;
                break;
        case HWVER_20101:
                ldev->caps.reg_ofs = REG_OFS_4;
                ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1;
                ldev->caps.non_alpha_only_l1 = false;
                ldev->caps.pad_max_freq_hz = 150000000;
+               ldev->caps.nb_irq = 4;
                break;
        default:
                return -ENODEV;
@@ -1251,13 +1258,21 @@ int ltdc_load(struct drm_device *ddev)
        reg_clear(ldev->regs, LTDC_IER,
                  IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE);
 
-       for (i = 0; i < MAX_IRQ; i++) {
+       ret = ltdc_get_caps(ddev);
+       if (ret) {
+               DRM_ERROR("hardware identifier (0x%08x) not supported!\n",
+                         ldev->caps.hw_version);
+               goto err;
+       }
+
+       DRM_DEBUG_DRIVER("ltdc hw version 0x%08x\n", ldev->caps.hw_version);
+
+       for (i = 0; i < ldev->caps.nb_irq; i++) {
                irq = platform_get_irq(pdev, i);
-               if (irq == -EPROBE_DEFER)
+               if (irq < 0) {
+                       ret = irq;
                        goto err;
-
-               if (irq < 0)
-                       continue;
+               }
 
                ret = devm_request_threaded_irq(dev, irq, ltdc_irq,
                                                ltdc_irq_thread, IRQF_ONESHOT,
@@ -1268,16 +1283,6 @@ int ltdc_load(struct drm_device *ddev)
                }
        }
 
-
-       ret = ltdc_get_caps(ddev);
-       if (ret) {
-               DRM_ERROR("hardware identifier (0x%08x) not supported!\n",
-                         ldev->caps.hw_version);
-               goto err;
-       }
-
-       DRM_DEBUG_DRIVER("ltdc hw version 0x%08x\n", ldev->caps.hw_version);
-
        /* Add endpoints panels or bridges if any */
        for (i = 0; i < MAX_ENDPOINTS; i++) {
                if (panel[i]) {
index a1ad0ae..310e87f 100644 (file)
@@ -19,6 +19,7 @@ struct ltdc_caps {
        const u32 *pix_fmt_hw;  /* supported pixel formats */
        bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */
        int pad_max_freq_hz;    /* max frequency supported by pad */
+       int nb_irq;             /* number of hardware interrupts */
 };
 
 #define LTDC_MAX_LAYER 4
diff --git a/drivers/gpu/drm/tidss/Kconfig b/drivers/gpu/drm/tidss/Kconfig
new file mode 100644 (file)
index 0000000..f790a52
--- /dev/null
@@ -0,0 +1,14 @@
+config DRM_TIDSS
+       tristate "DRM Support for TI Keystone"
+       depends on DRM && OF
+       depends on ARM || ARM64 || COMPILE_TEST
+       select DRM_KMS_HELPER
+       select DRM_KMS_CMA_HELPER
+       select DRM_GEM_CMA_HELPER
+       help
+         The TI Keystone family SoCs introduced a new generation of
+         Display SubSystem. There is currently three Keystone family
+         SoCs released with DSS. Each with somewhat different version
+         of it. The SoCs are 66AK2Gx, AM65x, and J721E. Set this to Y
+         or M to add display support for TI Keystone family
+         platforms.
diff --git a/drivers/gpu/drm/tidss/Makefile b/drivers/gpu/drm/tidss/Makefile
new file mode 100644 (file)
index 0000000..3126452
--- /dev/null
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+tidss-y := tidss_crtc.o \
+       tidss_drv.o \
+       tidss_encoder.o \
+       tidss_kms.o \
+       tidss_irq.o \
+       tidss_plane.o \
+       tidss_scale_coefs.o \
+       tidss_dispc.o
+
+obj-$(CONFIG_DRM_TIDSS) += tidss.o
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
new file mode 100644 (file)
index 0000000..032c31e
--- /dev/null
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "tidss_crtc.h"
+#include "tidss_dispc.h"
+#include "tidss_drv.h"
+#include "tidss_irq.h"
+
+/* Page flip and frame done IRQs */
+
+static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
+{
+       struct drm_device *ddev = tcrtc->crtc.dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct drm_pending_vblank_event *event;
+       unsigned long flags;
+       bool busy;
+
+       spin_lock_irqsave(&ddev->event_lock, flags);
+
+       /*
+        * New settings are taken into use at VFP, and GO bit is cleared at
+        * the same time. This happens before the vertical blank interrupt.
+        * So there is a small change that the driver sets GO bit after VFP, but
+        * before vblank, and we have to check for that case here.
+        */
+       busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport);
+       if (busy) {
+               spin_unlock_irqrestore(&ddev->event_lock, flags);
+               return;
+       }
+
+       event = tcrtc->event;
+       tcrtc->event = NULL;
+
+       if (!event) {
+               spin_unlock_irqrestore(&ddev->event_lock, flags);
+               return;
+       }
+
+       drm_crtc_send_vblank_event(&tcrtc->crtc, event);
+
+       spin_unlock_irqrestore(&ddev->event_lock, flags);
+
+       drm_crtc_vblank_put(&tcrtc->crtc);
+}
+
+void tidss_crtc_vblank_irq(struct drm_crtc *crtc)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+
+       drm_crtc_handle_vblank(crtc);
+
+       tidss_crtc_finish_page_flip(tcrtc);
+}
+
+void tidss_crtc_framedone_irq(struct drm_crtc *crtc)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+
+       complete(&tcrtc->framedone_completion);
+}
+
+void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+
+       dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n",
+                           tcrtc->hw_videoport, irqstatus);
+}
+
+/* drm_crtc_helper_funcs */
+
+static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
+                                  struct drm_crtc_state *state)
+{
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct dispc_device *dispc = tidss->dispc;
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       u32 hw_videoport = tcrtc->hw_videoport;
+       const struct drm_display_mode *mode;
+       enum drm_mode_status ok;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       if (!state->enable)
+               return 0;
+
+       mode = &state->adjusted_mode;
+
+       ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
+       if (ok != MODE_OK) {
+               dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
+                       __func__, mode->hdisplay, mode->vdisplay, mode->clock);
+               return -EINVAL;
+       }
+
+       return dispc_vp_bus_check(dispc, hw_videoport, state);
+}
+
+static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
+                                   struct drm_crtc_state *old_crtc_state)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       unsigned long flags;
+
+       dev_dbg(ddev->dev,
+               "%s: %s enabled %d, needs modeset %d, event %p\n", __func__,
+               crtc->name, drm_atomic_crtc_needs_modeset(crtc->state),
+               crtc->state->enable, crtc->state->event);
+
+       /* There is nothing to do if CRTC is not going to be enabled. */
+       if (!crtc->state->enable)
+               return;
+
+       /*
+        * Flush CRTC changes with go bit only if new modeset is not
+        * coming, so CRTC is enabled trough out the commit.
+        */
+       if (drm_atomic_crtc_needs_modeset(crtc->state))
+               return;
+
+       /* If the GO bit is stuck we better quit here. */
+       if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport)))
+               return;
+
+       /* We should have event if CRTC is enabled through out this commit. */
+       if (WARN_ON(!crtc->state->event))
+               return;
+
+       /* Write vp properties to HW if needed. */
+       dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
+
+       WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+       spin_lock_irqsave(&ddev->event_lock, flags);
+       dispc_vp_go(tidss->dispc, tcrtc->hw_videoport);
+
+       WARN_ON(tcrtc->event);
+
+       tcrtc->event = crtc->state->event;
+       crtc->state->event = NULL;
+
+       spin_unlock_irqrestore(&ddev->event_lock, flags);
+}
+
+static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
+                                    struct drm_crtc_state *old_state)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       unsigned long flags;
+       int r;
+
+       dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
+
+       tidss_runtime_get(tidss);
+
+       r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport,
+                                 mode->clock * 1000);
+       if (r != 0)
+               return;
+
+       r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport);
+       if (r != 0)
+               return;
+
+       dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
+
+       /* Turn vertical blanking interrupt reporting on. */
+       drm_crtc_vblank_on(crtc);
+
+       dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state);
+
+       dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state);
+
+       spin_lock_irqsave(&ddev->event_lock, flags);
+
+       if (crtc->state->event) {
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               crtc->state->event = NULL;
+       }
+
+       spin_unlock_irqrestore(&ddev->event_lock, flags);
+}
+
+static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
+                                     struct drm_crtc_state *old_state)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       unsigned long flags;
+
+       dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
+
+       reinit_completion(&tcrtc->framedone_completion);
+
+       dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport);
+
+       if (!wait_for_completion_timeout(&tcrtc->framedone_completion,
+                                        msecs_to_jiffies(500)))
+               dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d",
+                       tcrtc->hw_videoport);
+
+       dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport);
+
+       spin_lock_irqsave(&ddev->event_lock, flags);
+       if (crtc->state->event) {
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               crtc->state->event = NULL;
+       }
+       spin_unlock_irqrestore(&ddev->event_lock, flags);
+
+       drm_crtc_vblank_off(crtc);
+
+       dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport);
+
+       tidss_runtime_put(tidss);
+}
+
+static
+enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc,
+                                          const struct drm_display_mode *mode)
+{
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+
+       return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
+}
+
+static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
+       .atomic_check = tidss_crtc_atomic_check,
+       .atomic_flush = tidss_crtc_atomic_flush,
+       .atomic_enable = tidss_crtc_atomic_enable,
+       .atomic_disable = tidss_crtc_atomic_disable,
+
+       .mode_valid = tidss_crtc_mode_valid,
+};
+
+/* drm_crtc_funcs */
+
+static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       tidss_runtime_get(tidss);
+
+       tidss_irq_enable_vblank(crtc);
+
+       return 0;
+}
+
+static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       tidss_irq_disable_vblank(crtc);
+
+       tidss_runtime_put(tidss);
+}
+
+static void tidss_crtc_reset(struct drm_crtc *crtc)
+{
+       struct tidss_crtc_state *tcrtc;
+
+       if (crtc->state)
+               __drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+       kfree(crtc->state);
+
+       tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
+       if (!tcrtc) {
+               crtc->state = NULL;
+               return;
+       }
+
+       crtc->state = &tcrtc->base;
+       crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+       struct tidss_crtc_state *state, *current_state;
+
+       if (WARN_ON(!crtc->state))
+               return NULL;
+
+       current_state = to_tidss_crtc_state(crtc->state);
+
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+       state->bus_format = current_state->bus_format;
+       state->bus_flags = current_state->bus_flags;
+
+       return &state->base;
+}
+
+static const struct drm_crtc_funcs tidss_crtc_funcs = {
+       .reset = tidss_crtc_reset,
+       .destroy = drm_crtc_cleanup,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .atomic_duplicate_state = tidss_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+       .enable_vblank = tidss_crtc_enable_vblank,
+       .disable_vblank = tidss_crtc_disable_vblank,
+};
+
+struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
+                                    u32 hw_videoport,
+                                    struct drm_plane *primary)
+{
+       struct tidss_crtc *tcrtc;
+       struct drm_crtc *crtc;
+       unsigned int gamma_lut_size = 0;
+       bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
+       int ret;
+
+       tcrtc = devm_kzalloc(tidss->dev, sizeof(*tcrtc), GFP_KERNEL);
+       if (!tcrtc)
+               return ERR_PTR(-ENOMEM);
+
+       tcrtc->hw_videoport = hw_videoport;
+       init_completion(&tcrtc->framedone_completion);
+
+       crtc =  &tcrtc->crtc;
+
+       ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
+                                       NULL, &tidss_crtc_funcs, NULL);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
+
+       /*
+        * The dispc gamma functions adapt to what ever size we ask
+        * from it no matter what HW supports. X-server assumes 256
+        * element gamma tables so lets use that.
+        */
+       if (tidss->feat->vp_feat.color.gamma_size)
+               gamma_lut_size = 256;
+
+       drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size);
+       if (gamma_lut_size)
+               drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
+
+       return tcrtc;
+}
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.h b/drivers/gpu/drm/tidss/tidss_crtc.h
new file mode 100644 (file)
index 0000000..df9d90b
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_CRTC_H__
+#define __TIDSS_CRTC_H__
+
+#include <linux/completion.h>
+#include <linux/wait.h>
+
+#include <drm/drm_crtc.h>
+
+#define to_tidss_crtc(c) container_of((c), struct tidss_crtc, crtc)
+
+struct tidss_device;
+
+struct tidss_crtc {
+       struct drm_crtc crtc;
+
+       u32 hw_videoport;
+
+       struct drm_pending_vblank_event *event;
+
+       struct completion framedone_completion;
+};
+
+#define to_tidss_crtc_state(x) container_of(x, struct tidss_crtc_state, base)
+
+struct tidss_crtc_state {
+       /* Must be first. */
+       struct drm_crtc_state base;
+
+       u32 bus_format;
+       u32 bus_flags;
+};
+
+void tidss_crtc_vblank_irq(struct drm_crtc *crtc);
+void tidss_crtc_framedone_irq(struct drm_crtc *crtc);
+void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus);
+
+struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
+                                    u32 hw_videoport,
+                                    struct drm_plane *primary);
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
new file mode 100644 (file)
index 0000000..eeb160d
--- /dev/null
@@ -0,0 +1,2768 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Jyri Sarha <jsarha@ti.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_panel.h>
+
+#include "tidss_crtc.h"
+#include "tidss_dispc.h"
+#include "tidss_drv.h"
+#include "tidss_irq.h"
+#include "tidss_plane.h"
+
+#include "tidss_dispc_regs.h"
+#include "tidss_scale_coefs.h"
+
+static const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
+       [DSS_REVISION_OFF] =                    0x00,
+       [DSS_SYSCONFIG_OFF] =                   0x04,
+       [DSS_SYSSTATUS_OFF] =                   0x08,
+       [DISPC_IRQ_EOI_OFF] =                   0x20,
+       [DISPC_IRQSTATUS_RAW_OFF] =             0x24,
+       [DISPC_IRQSTATUS_OFF] =                 0x28,
+       [DISPC_IRQENABLE_SET_OFF] =             0x2c,
+       [DISPC_IRQENABLE_CLR_OFF] =             0x30,
+
+       [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] =    0x40,
+       [DISPC_GLOBAL_BUFFER_OFF] =             0x44,
+
+       [DISPC_DBG_CONTROL_OFF] =               0x4c,
+       [DISPC_DBG_STATUS_OFF] =                0x50,
+
+       [DISPC_CLKGATING_DISABLE_OFF] =         0x54,
+};
+
+const struct dispc_features dispc_k2g_feats = {
+       .min_pclk_khz = 4375,
+
+       .max_pclk_khz = {
+               [DISPC_VP_DPI] = 150000,
+       },
+
+       /*
+        * XXX According TRM the RGB input buffer width up to 2560 should
+        *     work on 3 taps, but in practice it only works up to 1280.
+        */
+       .scaling = {
+               .in_width_max_5tap_rgb = 1280,
+               .in_width_max_3tap_rgb = 1280,
+               .in_width_max_5tap_yuv = 2560,
+               .in_width_max_3tap_yuv = 2560,
+               .upscale_limit = 16,
+               .downscale_limit_5tap = 4,
+               .downscale_limit_3tap = 2,
+               /*
+                * The max supported pixel inc value is 255. The value
+                * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
+                * The maximum bpp of all formats supported by the HW
+                * is 8. So the maximum supported xinc value is 32,
+                * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
+                */
+               .xinc_max = 32,
+       },
+
+       .subrev = DISPC_K2G,
+
+       .common = "common",
+
+       .common_regs = tidss_k2g_common_regs,
+
+       .num_vps = 1,
+       .vp_name = { "vp1" },
+       .ovr_name = { "ovr1" },
+       .vpclk_name =  { "vp1" },
+       .vp_bus_type = { DISPC_VP_DPI },
+
+       .vp_feat = { .color = {
+                       .has_ctm = true,
+                       .gamma_size = 256,
+                       .gamma_type = TIDSS_GAMMA_8BIT,
+               },
+       },
+
+       .num_planes = 1,
+       .vid_name = { "vid1" },
+       .vid_lite = { false },
+       .vid_order = { 0 },
+};
+
+static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
+       [DSS_REVISION_OFF] =                    0x4,
+       [DSS_SYSCONFIG_OFF] =                   0x8,
+       [DSS_SYSSTATUS_OFF] =                   0x20,
+       [DISPC_IRQ_EOI_OFF] =                   0x24,
+       [DISPC_IRQSTATUS_RAW_OFF] =             0x28,
+       [DISPC_IRQSTATUS_OFF] =                 0x2c,
+       [DISPC_IRQENABLE_SET_OFF] =             0x30,
+       [DISPC_IRQENABLE_CLR_OFF] =             0x40,
+       [DISPC_VID_IRQENABLE_OFF] =             0x44,
+       [DISPC_VID_IRQSTATUS_OFF] =             0x58,
+       [DISPC_VP_IRQENABLE_OFF] =              0x70,
+       [DISPC_VP_IRQSTATUS_OFF] =              0x7c,
+
+       [WB_IRQENABLE_OFF] =                    0x88,
+       [WB_IRQSTATUS_OFF] =                    0x8c,
+
+       [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] =    0x90,
+       [DISPC_GLOBAL_OUTPUT_ENABLE_OFF] =      0x94,
+       [DISPC_GLOBAL_BUFFER_OFF] =             0x98,
+       [DSS_CBA_CFG_OFF] =                     0x9c,
+       [DISPC_DBG_CONTROL_OFF] =               0xa0,
+       [DISPC_DBG_STATUS_OFF] =                0xa4,
+       [DISPC_CLKGATING_DISABLE_OFF] =         0xa8,
+       [DISPC_SECURE_DISABLE_OFF] =            0xac,
+};
+
+const struct dispc_features dispc_am65x_feats = {
+       .max_pclk_khz = {
+               [DISPC_VP_DPI] = 165000,
+               [DISPC_VP_OLDI] = 165000,
+       },
+
+       .scaling = {
+               .in_width_max_5tap_rgb = 1280,
+               .in_width_max_3tap_rgb = 2560,
+               .in_width_max_5tap_yuv = 2560,
+               .in_width_max_3tap_yuv = 4096,
+               .upscale_limit = 16,
+               .downscale_limit_5tap = 4,
+               .downscale_limit_3tap = 2,
+               /*
+                * The max supported pixel inc value is 255. The value
+                * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
+                * The maximum bpp of all formats supported by the HW
+                * is 8. So the maximum supported xinc value is 32,
+                * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
+                */
+               .xinc_max = 32,
+       },
+
+       .subrev = DISPC_AM65X,
+
+       .common = "common",
+       .common_regs = tidss_am65x_common_regs,
+
+       .num_vps = 2,
+       .vp_name = { "vp1", "vp2" },
+       .ovr_name = { "ovr1", "ovr2" },
+       .vpclk_name =  { "vp1", "vp2" },
+       .vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI },
+
+       .vp_feat = { .color = {
+                       .has_ctm = true,
+                       .gamma_size = 256,
+                       .gamma_type = TIDSS_GAMMA_8BIT,
+               },
+       },
+
+       .num_planes = 2,
+       /* note: vid is plane_id 0 and vidl1 is plane_id 1 */
+       .vid_name = { "vid", "vidl1" },
+       .vid_lite = { false, true, },
+       .vid_order = { 1, 0 },
+
+       .errata = {
+               .i2000 = true,
+       },
+};
+
+static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
+       [DSS_REVISION_OFF] =                    0x4,
+       [DSS_SYSCONFIG_OFF] =                   0x8,
+       [DSS_SYSSTATUS_OFF] =                   0x20,
+       [DISPC_IRQ_EOI_OFF] =                   0x80,
+       [DISPC_IRQSTATUS_RAW_OFF] =             0x28,
+       [DISPC_IRQSTATUS_OFF] =                 0x2c,
+       [DISPC_IRQENABLE_SET_OFF] =             0x30,
+       [DISPC_IRQENABLE_CLR_OFF] =             0x34,
+       [DISPC_VID_IRQENABLE_OFF] =             0x38,
+       [DISPC_VID_IRQSTATUS_OFF] =             0x48,
+       [DISPC_VP_IRQENABLE_OFF] =              0x58,
+       [DISPC_VP_IRQSTATUS_OFF] =              0x68,
+
+       [WB_IRQENABLE_OFF] =                    0x78,
+       [WB_IRQSTATUS_OFF] =                    0x7c,
+
+       [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] =    0x98,
+       [DISPC_GLOBAL_OUTPUT_ENABLE_OFF] =      0x9c,
+       [DISPC_GLOBAL_BUFFER_OFF] =             0xa0,
+       [DSS_CBA_CFG_OFF] =                     0xa4,
+       [DISPC_DBG_CONTROL_OFF] =               0xa8,
+       [DISPC_DBG_STATUS_OFF] =                0xac,
+       [DISPC_CLKGATING_DISABLE_OFF] =         0xb0,
+       [DISPC_SECURE_DISABLE_OFF] =            0x90,
+
+       [FBDC_REVISION_1_OFF] =                 0xb8,
+       [FBDC_REVISION_2_OFF] =                 0xbc,
+       [FBDC_REVISION_3_OFF] =                 0xc0,
+       [FBDC_REVISION_4_OFF] =                 0xc4,
+       [FBDC_REVISION_5_OFF] =                 0xc8,
+       [FBDC_REVISION_6_OFF] =                 0xcc,
+       [FBDC_COMMON_CONTROL_OFF] =             0xd0,
+       [FBDC_CONSTANT_COLOR_0_OFF] =           0xd4,
+       [FBDC_CONSTANT_COLOR_1_OFF] =           0xd8,
+       [DISPC_CONNECTIONS_OFF] =               0xe4,
+       [DISPC_MSS_VP1_OFF] =                   0xe8,
+       [DISPC_MSS_VP3_OFF] =                   0xec,
+};
+
+const struct dispc_features dispc_j721e_feats = {
+       .max_pclk_khz = {
+               [DISPC_VP_DPI] = 170000,
+               [DISPC_VP_INTERNAL] = 600000,
+       },
+
+       .scaling = {
+               .in_width_max_5tap_rgb = 2048,
+               .in_width_max_3tap_rgb = 4096,
+               .in_width_max_5tap_yuv = 4096,
+               .in_width_max_3tap_yuv = 4096,
+               .upscale_limit = 16,
+               .downscale_limit_5tap = 4,
+               .downscale_limit_3tap = 2,
+               /*
+                * The max supported pixel inc value is 255. The value
+                * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
+                * The maximum bpp of all formats supported by the HW
+                * is 8. So the maximum supported xinc value is 32,
+                * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
+                */
+               .xinc_max = 32,
+       },
+
+       .subrev = DISPC_J721E,
+
+       .common = "common_m",
+       .common_regs = tidss_j721e_common_regs,
+
+       .num_vps = 4,
+       .vp_name = { "vp1", "vp2", "vp3", "vp4" },
+       .ovr_name = { "ovr1", "ovr2", "ovr3", "ovr4" },
+       .vpclk_name = { "vp1", "vp2", "vp3", "vp4" },
+       /* Currently hard coded VP routing (see dispc_initial_config()) */
+       .vp_bus_type =  { DISPC_VP_INTERNAL, DISPC_VP_DPI,
+                         DISPC_VP_INTERNAL, DISPC_VP_DPI, },
+       .vp_feat = { .color = {
+                       .has_ctm = true,
+                       .gamma_size = 1024,
+                       .gamma_type = TIDSS_GAMMA_10BIT,
+               },
+       },
+       .num_planes = 4,
+       .vid_name = { "vid1", "vidl1", "vid2", "vidl2" },
+       .vid_lite = { 0, 1, 0, 1, },
+       .vid_order = { 1, 3, 0, 2 },
+};
+
+static const u16 *dispc_common_regmap;
+
+struct dss_vp_data {
+       u32 *gamma_table;
+};
+
+struct dss_plane_data {
+       u32 zorder;
+       u32 hw_videoport;
+};
+
+struct dispc_device {
+       struct tidss_device *tidss;
+       struct device *dev;
+
+       void __iomem *base_common;
+       void __iomem *base_vid[TIDSS_MAX_PLANES];
+       void __iomem *base_ovr[TIDSS_MAX_PORTS];
+       void __iomem *base_vp[TIDSS_MAX_PORTS];
+
+       struct regmap *oldi_io_ctrl;
+
+       struct clk *vp_clk[TIDSS_MAX_PORTS];
+
+       const struct dispc_features *feat;
+
+       struct clk *fclk;
+
+       bool is_enabled;
+
+       struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
+
+       struct dss_plane_data plane_data[TIDSS_MAX_PLANES];
+
+       u32 *fourccs;
+       u32 num_fourccs;
+
+       u32 memory_bandwidth_limit;
+};
+
+static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val)
+{
+       iowrite32(val, dispc->base_common + reg);
+}
+
+static u32 dispc_read(struct dispc_device *dispc, u16 reg)
+{
+       return ioread32(dispc->base_common + reg);
+}
+
+static
+void dispc_vid_write(struct dispc_device *dispc, u32 hw_plane, u16 reg, u32 val)
+{
+       void __iomem *base = dispc->base_vid[hw_plane];
+
+       iowrite32(val, base + reg);
+}
+
+static u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg)
+{
+       void __iomem *base = dispc->base_vid[hw_plane];
+
+       return ioread32(base + reg);
+}
+
+static void dispc_ovr_write(struct dispc_device *dispc, u32 hw_videoport,
+                           u16 reg, u32 val)
+{
+       void __iomem *base = dispc->base_ovr[hw_videoport];
+
+       iowrite32(val, base + reg);
+}
+
+static u32 dispc_ovr_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
+{
+       void __iomem *base = dispc->base_ovr[hw_videoport];
+
+       return ioread32(base + reg);
+}
+
+static void dispc_vp_write(struct dispc_device *dispc, u32 hw_videoport,
+                          u16 reg, u32 val)
+{
+       void __iomem *base = dispc->base_vp[hw_videoport];
+
+       iowrite32(val, base + reg);
+}
+
+static u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
+{
+       void __iomem *base = dispc->base_vp[hw_videoport];
+
+       return ioread32(base + reg);
+}
+
+/*
+ * TRM gives bitfields as start:end, where start is the higher bit
+ * number. For example 7:0
+ */
+
+static u32 FLD_MASK(u32 start, u32 end)
+{
+       return ((1 << (start - end + 1)) - 1) << end;
+}
+
+static u32 FLD_VAL(u32 val, u32 start, u32 end)
+{
+       return (val << end) & FLD_MASK(start, end);
+}
+
+static u32 FLD_GET(u32 val, u32 start, u32 end)
+{
+       return (val & FLD_MASK(start, end)) >> end;
+}
+
+static u32 FLD_MOD(u32 orig, u32 val, u32 start, u32 end)
+{
+       return (orig & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end);
+}
+
+static u32 REG_GET(struct dispc_device *dispc, u32 idx, u32 start, u32 end)
+{
+       return FLD_GET(dispc_read(dispc, idx), start, end);
+}
+
+static void REG_FLD_MOD(struct dispc_device *dispc, u32 idx, u32 val,
+                       u32 start, u32 end)
+{
+       dispc_write(dispc, idx, FLD_MOD(dispc_read(dispc, idx), val,
+                                       start, end));
+}
+
+static u32 VID_REG_GET(struct dispc_device *dispc, u32 hw_plane, u32 idx,
+                      u32 start, u32 end)
+{
+       return FLD_GET(dispc_vid_read(dispc, hw_plane, idx), start, end);
+}
+
+static void VID_REG_FLD_MOD(struct dispc_device *dispc, u32 hw_plane, u32 idx,
+                           u32 val, u32 start, u32 end)
+{
+       dispc_vid_write(dispc, hw_plane, idx,
+                       FLD_MOD(dispc_vid_read(dispc, hw_plane, idx),
+                               val, start, end));
+}
+
+static u32 VP_REG_GET(struct dispc_device *dispc, u32 vp, u32 idx,
+                     u32 start, u32 end)
+{
+       return FLD_GET(dispc_vp_read(dispc, vp, idx), start, end);
+}
+
+static void VP_REG_FLD_MOD(struct dispc_device *dispc, u32 vp, u32 idx, u32 val,
+                          u32 start, u32 end)
+{
+       dispc_vp_write(dispc, vp, idx, FLD_MOD(dispc_vp_read(dispc, vp, idx),
+                                              val, start, end));
+}
+
+__maybe_unused
+static u32 OVR_REG_GET(struct dispc_device *dispc, u32 ovr, u32 idx,
+                      u32 start, u32 end)
+{
+       return FLD_GET(dispc_ovr_read(dispc, ovr, idx), start, end);
+}
+
+static void OVR_REG_FLD_MOD(struct dispc_device *dispc, u32 ovr, u32 idx,
+                           u32 val, u32 start, u32 end)
+{
+       dispc_ovr_write(dispc, ovr, idx,
+                       FLD_MOD(dispc_ovr_read(dispc, ovr, idx),
+                               val, start, end));
+}
+
+static dispc_irq_t dispc_vp_irq_from_raw(u32 stat, u32 hw_videoport)
+{
+       dispc_irq_t vp_stat = 0;
+
+       if (stat & BIT(0))
+               vp_stat |= DSS_IRQ_VP_FRAME_DONE(hw_videoport);
+       if (stat & BIT(1))
+               vp_stat |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport);
+       if (stat & BIT(2))
+               vp_stat |= DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
+       if (stat & BIT(4))
+               vp_stat |= DSS_IRQ_VP_SYNC_LOST(hw_videoport);
+
+       return vp_stat;
+}
+
+static u32 dispc_vp_irq_to_raw(dispc_irq_t vpstat, u32 hw_videoport)
+{
+       u32 stat = 0;
+
+       if (vpstat & DSS_IRQ_VP_FRAME_DONE(hw_videoport))
+               stat |= BIT(0);
+       if (vpstat & DSS_IRQ_VP_VSYNC_EVEN(hw_videoport))
+               stat |= BIT(1);
+       if (vpstat & DSS_IRQ_VP_VSYNC_ODD(hw_videoport))
+               stat |= BIT(2);
+       if (vpstat & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
+               stat |= BIT(4);
+
+       return stat;
+}
+
+static dispc_irq_t dispc_vid_irq_from_raw(u32 stat, u32 hw_plane)
+{
+       dispc_irq_t vid_stat = 0;
+
+       if (stat & BIT(0))
+               vid_stat |= DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane);
+
+       return vid_stat;
+}
+
+static u32 dispc_vid_irq_to_raw(dispc_irq_t vidstat, u32 hw_plane)
+{
+       u32 stat = 0;
+
+       if (vidstat & DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane))
+               stat |= BIT(0);
+
+       return stat;
+}
+
+static dispc_irq_t dispc_k2g_vp_read_irqstatus(struct dispc_device *dispc,
+                                              u32 hw_videoport)
+{
+       u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS);
+
+       return dispc_vp_irq_from_raw(stat, hw_videoport);
+}
+
+static void dispc_k2g_vp_write_irqstatus(struct dispc_device *dispc,
+                                        u32 hw_videoport, dispc_irq_t vpstat)
+{
+       u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS, stat);
+}
+
+static dispc_irq_t dispc_k2g_vid_read_irqstatus(struct dispc_device *dispc,
+                                               u32 hw_plane)
+{
+       u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS);
+
+       return dispc_vid_irq_from_raw(stat, hw_plane);
+}
+
+static void dispc_k2g_vid_write_irqstatus(struct dispc_device *dispc,
+                                         u32 hw_plane, dispc_irq_t vidstat)
+{
+       u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
+
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS, stat);
+}
+
+static dispc_irq_t dispc_k2g_vp_read_irqenable(struct dispc_device *dispc,
+                                              u32 hw_videoport)
+{
+       u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE);
+
+       return dispc_vp_irq_from_raw(stat, hw_videoport);
+}
+
+static void dispc_k2g_vp_set_irqenable(struct dispc_device *dispc,
+                                      u32 hw_videoport, dispc_irq_t vpstat)
+{
+       u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE, stat);
+}
+
+static dispc_irq_t dispc_k2g_vid_read_irqenable(struct dispc_device *dispc,
+                                               u32 hw_plane)
+{
+       u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE);
+
+       return dispc_vid_irq_from_raw(stat, hw_plane);
+}
+
+static void dispc_k2g_vid_set_irqenable(struct dispc_device *dispc,
+                                       u32 hw_plane, dispc_irq_t vidstat)
+{
+       u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
+
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE, stat);
+}
+
+static void dispc_k2g_clear_irqstatus(struct dispc_device *dispc,
+                                     dispc_irq_t mask)
+{
+       dispc_k2g_vp_write_irqstatus(dispc, 0, mask);
+       dispc_k2g_vid_write_irqstatus(dispc, 0, mask);
+}
+
+static
+dispc_irq_t dispc_k2g_read_and_clear_irqstatus(struct dispc_device *dispc)
+{
+       dispc_irq_t stat = 0;
+
+       /* always clear the top level irqstatus */
+       dispc_write(dispc, DISPC_IRQSTATUS,
+                   dispc_read(dispc, DISPC_IRQSTATUS));
+
+       stat |= dispc_k2g_vp_read_irqstatus(dispc, 0);
+       stat |= dispc_k2g_vid_read_irqstatus(dispc, 0);
+
+       dispc_k2g_clear_irqstatus(dispc, stat);
+
+       return stat;
+}
+
+static dispc_irq_t dispc_k2g_read_irqenable(struct dispc_device *dispc)
+{
+       dispc_irq_t stat = 0;
+
+       stat |= dispc_k2g_vp_read_irqenable(dispc, 0);
+       stat |= dispc_k2g_vid_read_irqenable(dispc, 0);
+
+       return stat;
+}
+
+static
+void dispc_k2g_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
+{
+       dispc_irq_t old_mask = dispc_k2g_read_irqenable(dispc);
+
+       /* clear the irqstatus for newly enabled irqs */
+       dispc_k2g_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
+
+       dispc_k2g_vp_set_irqenable(dispc, 0, mask);
+       dispc_k2g_vid_set_irqenable(dispc, 0, mask);
+
+       dispc_write(dispc, DISPC_IRQENABLE_SET, (1 << 0) | (1 << 7));
+
+       /* flush posted write */
+       dispc_k2g_read_irqenable(dispc);
+}
+
+static dispc_irq_t dispc_k3_vp_read_irqstatus(struct dispc_device *dispc,
+                                             u32 hw_videoport)
+{
+       u32 stat = dispc_read(dispc, DISPC_VP_IRQSTATUS(hw_videoport));
+
+       return dispc_vp_irq_from_raw(stat, hw_videoport);
+}
+
+static void dispc_k3_vp_write_irqstatus(struct dispc_device *dispc,
+                                       u32 hw_videoport, dispc_irq_t vpstat)
+{
+       u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
+
+       dispc_write(dispc, DISPC_VP_IRQSTATUS(hw_videoport), stat);
+}
+
+static dispc_irq_t dispc_k3_vid_read_irqstatus(struct dispc_device *dispc,
+                                              u32 hw_plane)
+{
+       u32 stat = dispc_read(dispc, DISPC_VID_IRQSTATUS(hw_plane));
+
+       return dispc_vid_irq_from_raw(stat, hw_plane);
+}
+
+static void dispc_k3_vid_write_irqstatus(struct dispc_device *dispc,
+                                        u32 hw_plane, dispc_irq_t vidstat)
+{
+       u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
+
+       dispc_write(dispc, DISPC_VID_IRQSTATUS(hw_plane), stat);
+}
+
+static dispc_irq_t dispc_k3_vp_read_irqenable(struct dispc_device *dispc,
+                                             u32 hw_videoport)
+{
+       u32 stat = dispc_read(dispc, DISPC_VP_IRQENABLE(hw_videoport));
+
+       return dispc_vp_irq_from_raw(stat, hw_videoport);
+}
+
+static void dispc_k3_vp_set_irqenable(struct dispc_device *dispc,
+                                     u32 hw_videoport, dispc_irq_t vpstat)
+{
+       u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
+
+       dispc_write(dispc, DISPC_VP_IRQENABLE(hw_videoport), stat);
+}
+
+static dispc_irq_t dispc_k3_vid_read_irqenable(struct dispc_device *dispc,
+                                              u32 hw_plane)
+{
+       u32 stat = dispc_read(dispc, DISPC_VID_IRQENABLE(hw_plane));
+
+       return dispc_vid_irq_from_raw(stat, hw_plane);
+}
+
+static void dispc_k3_vid_set_irqenable(struct dispc_device *dispc,
+                                      u32 hw_plane, dispc_irq_t vidstat)
+{
+       u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
+
+       dispc_write(dispc, DISPC_VID_IRQENABLE(hw_plane), stat);
+}
+
+static
+void dispc_k3_clear_irqstatus(struct dispc_device *dispc, dispc_irq_t clearmask)
+{
+       unsigned int i;
+       u32 top_clear = 0;
+
+       for (i = 0; i < dispc->feat->num_vps; ++i) {
+               if (clearmask & DSS_IRQ_VP_MASK(i)) {
+                       dispc_k3_vp_write_irqstatus(dispc, i, clearmask);
+                       top_clear |= BIT(i);
+               }
+       }
+       for (i = 0; i < dispc->feat->num_planes; ++i) {
+               if (clearmask & DSS_IRQ_PLANE_MASK(i)) {
+                       dispc_k3_vid_write_irqstatus(dispc, i, clearmask);
+                       top_clear |= BIT(4 + i);
+               }
+       }
+       if (dispc->feat->subrev == DISPC_K2G)
+               return;
+
+       dispc_write(dispc, DISPC_IRQSTATUS, top_clear);
+
+       /* Flush posted writes */
+       dispc_read(dispc, DISPC_IRQSTATUS);
+}
+
+static
+dispc_irq_t dispc_k3_read_and_clear_irqstatus(struct dispc_device *dispc)
+{
+       dispc_irq_t status = 0;
+       unsigned int i;
+
+       for (i = 0; i < dispc->feat->num_vps; ++i)
+               status |= dispc_k3_vp_read_irqstatus(dispc, i);
+
+       for (i = 0; i < dispc->feat->num_planes; ++i)
+               status |= dispc_k3_vid_read_irqstatus(dispc, i);
+
+       dispc_k3_clear_irqstatus(dispc, status);
+
+       return status;
+}
+
+static dispc_irq_t dispc_k3_read_irqenable(struct dispc_device *dispc)
+{
+       dispc_irq_t enable = 0;
+       unsigned int i;
+
+       for (i = 0; i < dispc->feat->num_vps; ++i)
+               enable |= dispc_k3_vp_read_irqenable(dispc, i);
+
+       for (i = 0; i < dispc->feat->num_planes; ++i)
+               enable |= dispc_k3_vid_read_irqenable(dispc, i);
+
+       return enable;
+}
+
+static void dispc_k3_set_irqenable(struct dispc_device *dispc,
+                                  dispc_irq_t mask)
+{
+       unsigned int i;
+       u32 main_enable = 0, main_disable = 0;
+       dispc_irq_t old_mask;
+
+       old_mask = dispc_k3_read_irqenable(dispc);
+
+       /* clear the irqstatus for newly enabled irqs */
+       dispc_k3_clear_irqstatus(dispc, (old_mask ^ mask) & mask);
+
+       for (i = 0; i < dispc->feat->num_vps; ++i) {
+               dispc_k3_vp_set_irqenable(dispc, i, mask);
+               if (mask & DSS_IRQ_VP_MASK(i))
+                       main_enable |= BIT(i);          /* VP IRQ */
+               else
+                       main_disable |= BIT(i);         /* VP IRQ */
+       }
+
+       for (i = 0; i < dispc->feat->num_planes; ++i) {
+               dispc_k3_vid_set_irqenable(dispc, i, mask);
+               if (mask & DSS_IRQ_PLANE_MASK(i))
+                       main_enable |= BIT(i + 4);      /* VID IRQ */
+               else
+                       main_disable |= BIT(i + 4);     /* VID IRQ */
+       }
+
+       if (main_enable)
+               dispc_write(dispc, DISPC_IRQENABLE_SET, main_enable);
+
+       if (main_disable)
+               dispc_write(dispc, DISPC_IRQENABLE_CLR, main_disable);
+
+       /* Flush posted writes */
+       dispc_read(dispc, DISPC_IRQENABLE_SET);
+}
+
+dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc)
+{
+       switch (dispc->feat->subrev) {
+       case DISPC_K2G:
+               return dispc_k2g_read_and_clear_irqstatus(dispc);
+       case DISPC_AM65X:
+       case DISPC_J721E:
+               return dispc_k3_read_and_clear_irqstatus(dispc);
+       default:
+               WARN_ON(1);
+               return 0;
+       }
+}
+
+void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
+{
+       switch (dispc->feat->subrev) {
+       case DISPC_K2G:
+               dispc_k2g_set_irqenable(dispc, mask);
+               break;
+       case DISPC_AM65X:
+       case DISPC_J721E:
+               dispc_k3_set_irqenable(dispc, mask);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+enum dispc_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 };
+
+struct dispc_bus_format {
+       u32 bus_fmt;
+       u32 data_width;
+       bool is_oldi_fmt;
+       enum dispc_oldi_mode_reg_val oldi_mode_reg_val;
+};
+
+static const struct dispc_bus_format dispc_bus_formats[] = {
+       { MEDIA_BUS_FMT_RGB444_1X12,            12, false, 0 },
+       { MEDIA_BUS_FMT_RGB565_1X16,            16, false, 0 },
+       { MEDIA_BUS_FMT_RGB666_1X18,            18, false, 0 },
+       { MEDIA_BUS_FMT_RGB888_1X24,            24, false, 0 },
+       { MEDIA_BUS_FMT_RGB101010_1X30,         30, false, 0 },
+       { MEDIA_BUS_FMT_RGB121212_1X36,         36, false, 0 },
+       { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,      18, true, SPWG_18 },
+       { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,      24, true, SPWG_24 },
+       { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,     24, true, JEIDA_24 },
+};
+
+static const
+struct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc,
+                                              u32 hw_videoport,
+                                              u32 bus_fmt, u32 bus_flags)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(dispc_bus_formats); ++i) {
+               if (dispc_bus_formats[i].bus_fmt == bus_fmt)
+                       return &dispc_bus_formats[i];
+       }
+
+       return NULL;
+}
+
+int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
+                      const struct drm_crtc_state *state)
+{
+       const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
+       const struct dispc_bus_format *fmt;
+
+       fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
+                                   tstate->bus_flags);
+       if (!fmt) {
+               dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n",
+                       __func__, tstate->bus_format);
+               return -EINVAL;
+       }
+
+       if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI &&
+           fmt->is_oldi_fmt) {
+               dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
+                       __func__, dispc->feat->vp_name[hw_videoport]);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void dispc_oldi_tx_power(struct dispc_device *dispc, bool power)
+{
+       u32 val = power ? 0 : OLDI_PWRDN_TX;
+
+       if (WARN_ON(!dispc->oldi_io_ctrl))
+               return;
+
+       regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL,
+                          OLDI_PWRDN_TX, val);
+       regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL,
+                          OLDI_PWRDN_TX, val);
+       regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL,
+                          OLDI_PWRDN_TX, val);
+       regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL,
+                          OLDI_PWRDN_TX, val);
+       regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL,
+                          OLDI_PWRDN_TX, val);
+}
+
+static void dispc_set_num_datalines(struct dispc_device *dispc,
+                                   u32 hw_videoport, int num_lines)
+{
+       int v;
+
+       switch (num_lines) {
+       case 12:
+               v = 0; break;
+       case 16:
+               v = 1; break;
+       case 18:
+               v = 2; break;
+       case 24:
+               v = 3; break;
+       case 30:
+               v = 4; break;
+       case 36:
+               v = 5; break;
+       default:
+               WARN_ON(1);
+               v = 3;
+       }
+
+       VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8);
+}
+
+static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport,
+                             const struct dispc_bus_format *fmt)
+{
+       u32 oldi_cfg = 0;
+       u32 oldi_reset_bit = BIT(5 + hw_videoport);
+       int count = 0;
+
+       /*
+        * For the moment DUALMODESYNC, MASTERSLAVE, MODE, and SRC
+        * bits of DISPC_VP_DSS_OLDI_CFG are set statically to 0.
+        */
+
+       if (fmt->data_width == 24)
+               oldi_cfg |= BIT(8); /* MSB */
+       else if (fmt->data_width != 18)
+               dev_warn(dispc->dev, "%s: %d port width not supported\n",
+                        __func__, fmt->data_width);
+
+       oldi_cfg |= BIT(7); /* DEPOL */
+
+       oldi_cfg = FLD_MOD(oldi_cfg, fmt->oldi_mode_reg_val, 3, 1);
+
+       oldi_cfg |= BIT(12); /* SOFTRST */
+
+       oldi_cfg |= BIT(0); /* ENABLE */
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, oldi_cfg);
+
+       while (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS)) &&
+              count < 10000)
+               count++;
+
+       if (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS)))
+               dev_warn(dispc->dev, "%s: timeout waiting OLDI reset done\n",
+                        __func__);
+}
+
+void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
+                     const struct drm_crtc_state *state)
+{
+       const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
+       const struct dispc_bus_format *fmt;
+
+       fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
+                                   tstate->bus_flags);
+
+       if (WARN_ON(!fmt))
+               return;
+
+       if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
+               dispc_oldi_tx_power(dispc, true);
+
+               dispc_enable_oldi(dispc, hw_videoport, fmt);
+       }
+}
+
+void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
+                    const struct drm_crtc_state *state)
+{
+       const struct drm_display_mode *mode = &state->adjusted_mode;
+       const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
+       bool align, onoff, rf, ieo, ipc, ihs, ivs;
+       const struct dispc_bus_format *fmt;
+       u32 hsw, hfp, hbp, vsw, vfp, vbp;
+
+       fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
+                                   tstate->bus_flags);
+
+       if (WARN_ON(!fmt))
+               return;
+
+       dispc_set_num_datalines(dispc, hw_videoport, fmt->data_width);
+
+       hfp = mode->hsync_start - mode->hdisplay;
+       hsw = mode->hsync_end - mode->hsync_start;
+       hbp = mode->htotal - mode->hsync_end;
+
+       vfp = mode->vsync_start - mode->vdisplay;
+       vsw = mode->vsync_end - mode->vsync_start;
+       vbp = mode->vtotal - mode->vsync_end;
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_H,
+                      FLD_VAL(hsw - 1, 7, 0) |
+                      FLD_VAL(hfp - 1, 19, 8) |
+                      FLD_VAL(hbp - 1, 31, 20));
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_V,
+                      FLD_VAL(vsw - 1, 7, 0) |
+                      FLD_VAL(vfp, 19, 8) |
+                      FLD_VAL(vbp, 31, 20));
+
+       ivs = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+
+       ihs = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+       ieo = !!(tstate->bus_flags & DRM_BUS_FLAG_DE_LOW);
+
+       ipc = !!(tstate->bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE);
+
+       /* always use the 'rf' setting */
+       onoff = true;
+
+       rf = !!(tstate->bus_flags & DRM_BUS_FLAG_SYNC_POSEDGE);
+
+       /* always use aligned syncs */
+       align = true;
+
+       /* always use DE_HIGH for OLDI */
+       if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI)
+               ieo = false;
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ,
+                      FLD_VAL(align, 18, 18) |
+                      FLD_VAL(onoff, 17, 17) |
+                      FLD_VAL(rf, 16, 16) |
+                      FLD_VAL(ieo, 15, 15) |
+                      FLD_VAL(ipc, 14, 14) |
+                      FLD_VAL(ihs, 13, 13) |
+                      FLD_VAL(ivs, 12, 12));
+
+       dispc_vp_write(dispc, hw_videoport, DISPC_VP_SIZE_SCREEN,
+                      FLD_VAL(mode->hdisplay - 1, 11, 0) |
+                      FLD_VAL(mode->vdisplay - 1, 27, 16));
+
+       VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 0, 0);
+}
+
+void dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport)
+{
+       VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 0, 0, 0);
+}
+
+void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport)
+{
+       if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
+               dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0);
+
+               dispc_oldi_tx_power(dispc, false);
+       }
+}
+
+bool dispc_vp_go_busy(struct dispc_device *dispc, u32 hw_videoport)
+{
+       return VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5);
+}
+
+void dispc_vp_go(struct dispc_device *dispc, u32 hw_videoport)
+{
+       WARN_ON(VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5));
+       VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 5, 5);
+}
+
+enum c8_to_c12_mode { C8_TO_C12_REPLICATE, C8_TO_C12_MAX, C8_TO_C12_MIN };
+
+static u16 c8_to_c12(u8 c8, enum c8_to_c12_mode mode)
+{
+       u16 c12;
+
+       c12 = c8 << 4;
+
+       switch (mode) {
+       case C8_TO_C12_REPLICATE:
+               /* Copy c8 4 MSB to 4 LSB for full scale c12 */
+               c12 |= c8 >> 4;
+               break;
+       case C8_TO_C12_MAX:
+               c12 |= 0xF;
+               break;
+       default:
+       case C8_TO_C12_MIN:
+               break;
+       }
+
+       return c12;
+}
+
+static u64 argb8888_to_argb12121212(u32 argb8888, enum c8_to_c12_mode m)
+{
+       u8 a, r, g, b;
+       u64 v;
+
+       a = (argb8888 >> 24) & 0xff;
+       r = (argb8888 >> 16) & 0xff;
+       g = (argb8888 >> 8) & 0xff;
+       b = (argb8888 >> 0) & 0xff;
+
+       v = ((u64)c8_to_c12(a, m) << 36) | ((u64)c8_to_c12(r, m) << 24) |
+               ((u64)c8_to_c12(g, m) << 12) | (u64)c8_to_c12(b, m);
+
+       return v;
+}
+
+static void dispc_vp_set_default_color(struct dispc_device *dispc,
+                                      u32 hw_videoport, u32 default_color)
+{
+       u64 v;
+
+       v = argb8888_to_argb12121212(default_color, C8_TO_C12_REPLICATE);
+
+       dispc_ovr_write(dispc, hw_videoport,
+                       DISPC_OVR_DEFAULT_COLOR, v & 0xffffffff);
+       dispc_ovr_write(dispc, hw_videoport,
+                       DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff);
+}
+
+enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
+                                        u32 hw_videoport,
+                                        const struct drm_display_mode *mode)
+{
+       u32 hsw, hfp, hbp, vsw, vfp, vbp;
+       enum dispc_vp_bus_type bus_type;
+       int max_pclk;
+
+       bus_type = dispc->feat->vp_bus_type[hw_videoport];
+
+       max_pclk = dispc->feat->max_pclk_khz[bus_type];
+
+       if (WARN_ON(max_pclk == 0))
+               return MODE_BAD;
+
+       if (mode->clock < dispc->feat->min_pclk_khz)
+               return MODE_CLOCK_LOW;
+
+       if (mode->clock > max_pclk)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->hdisplay > 4096)
+               return MODE_BAD;
+
+       if (mode->vdisplay > 4096)
+               return MODE_BAD;
+
+       /* TODO: add interlace support */
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               return MODE_NO_INTERLACE;
+
+       /*
+        * Enforce the output width is divisible by 2. Actually this
+        * is only needed in following cases:
+        * - YUV output selected (BT656, BT1120)
+        * - Dithering enabled
+        * - TDM with TDMCycleFormat == 3
+        * But for simplicity we enforce that always.
+        */
+       if ((mode->hdisplay % 2) != 0)
+               return MODE_BAD_HVALUE;
+
+       hfp = mode->hsync_start - mode->hdisplay;
+       hsw = mode->hsync_end - mode->hsync_start;
+       hbp = mode->htotal - mode->hsync_end;
+
+       vfp = mode->vsync_start - mode->vdisplay;
+       vsw = mode->vsync_end - mode->vsync_start;
+       vbp = mode->vtotal - mode->vsync_end;
+
+       if (hsw < 1 || hsw > 256 ||
+           hfp < 1 || hfp > 4096 ||
+           hbp < 1 || hbp > 4096)
+               return MODE_BAD_HVALUE;
+
+       if (vsw < 1 || vsw > 256 ||
+           vfp > 4095 || vbp > 4095)
+               return MODE_BAD_VVALUE;
+
+       if (dispc->memory_bandwidth_limit) {
+               const unsigned int bpp = 4;
+               u64 bandwidth;
+
+               bandwidth = 1000 * mode->clock;
+               bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp;
+               bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal);
+
+               if (dispc->memory_bandwidth_limit < bandwidth)
+                       return MODE_BAD;
+       }
+
+       return MODE_OK;
+}
+
+int dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport)
+{
+       int ret = clk_prepare_enable(dispc->vp_clk[hw_videoport]);
+
+       if (ret)
+               dev_err(dispc->dev, "%s: enabling clk failed: %d\n", __func__,
+                       ret);
+
+       return ret;
+}
+
+void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport)
+{
+       clk_disable_unprepare(dispc->vp_clk[hw_videoport]);
+}
+
+/*
+ * Calculate the percentage difference between the requested pixel clock rate
+ * and the effective rate resulting from calculating the clock divider value.
+ */
+static
+unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
+{
+       int r = rate / 100, rr = real_rate / 100;
+
+       return (unsigned int)(abs(((rr - r) * 100) / r));
+}
+
+int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport,
+                         unsigned long rate)
+{
+       int r;
+       unsigned long new_rate;
+
+       r = clk_set_rate(dispc->vp_clk[hw_videoport], rate);
+       if (r) {
+               dev_err(dispc->dev, "vp%d: failed to set clk rate to %lu\n",
+                       hw_videoport, rate);
+               return r;
+       }
+
+       new_rate = clk_get_rate(dispc->vp_clk[hw_videoport]);
+
+       if (dispc_pclk_diff(rate, new_rate) > 5)
+               dev_warn(dispc->dev,
+                        "vp%d: Clock rate %lu differs over 5%% from requsted %lu\n",
+                        hw_videoport, new_rate, rate);
+
+       dev_dbg(dispc->dev, "vp%d: new rate %lu Hz (requested %lu Hz)\n",
+               hw_videoport, clk_get_rate(dispc->vp_clk[hw_videoport]), rate);
+
+       return 0;
+}
+
+/* OVR */
+static void dispc_k2g_ovr_set_plane(struct dispc_device *dispc,
+                                   u32 hw_plane, u32 hw_videoport,
+                                   u32 x, u32 y, u32 zpos)
+{
+       /* On k2g there is only one plane and no need for ovr */
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_POSITION,
+                       x | (y << 16));
+}
+
+static void dispc_am65x_ovr_set_plane(struct dispc_device *dispc,
+                                     u32 hw_plane, u32 hw_videoport,
+                                     u32 x, u32 y, u32 zpos)
+{
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
+                       hw_plane, 4, 1);
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
+                       x, 17, 6);
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
+                       y, 30, 19);
+}
+
+static void dispc_j721e_ovr_set_plane(struct dispc_device *dispc,
+                                     u32 hw_plane, u32 hw_videoport,
+                                     u32 x, u32 y, u32 zpos)
+{
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
+                       hw_plane, 4, 1);
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(zpos),
+                       x, 13, 0);
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(zpos),
+                       y, 29, 16);
+}
+
+static void dispc_ovr_set_plane(struct dispc_device *dispc,
+                               u32 hw_plane, u32 hw_videoport,
+                               u32 x, u32 y, u32 zpos)
+{
+       switch (dispc->feat->subrev) {
+       case DISPC_K2G:
+               dispc_k2g_ovr_set_plane(dispc, hw_plane, hw_videoport,
+                                       x, y, zpos);
+               break;
+       case DISPC_AM65X:
+               dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport,
+                                         x, y, zpos);
+               break;
+       case DISPC_J721E:
+               dispc_j721e_ovr_set_plane(dispc, hw_plane, hw_videoport,
+                                         x, y, zpos);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+static void dispc_ovr_enable_plane(struct dispc_device *dispc,
+                                  u32 hw_videoport, u32 zpos, bool enable)
+{
+       OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
+                       !!enable, 0, 0);
+}
+
+/* CSC */
+enum csc_ctm {
+       CSC_RR, CSC_RG, CSC_RB,
+       CSC_GR, CSC_GG, CSC_GB,
+       CSC_BR, CSC_BG, CSC_BB,
+};
+
+enum csc_yuv2rgb {
+       CSC_RY, CSC_RCB, CSC_RCR,
+       CSC_GY, CSC_GCB, CSC_GCR,
+       CSC_BY, CSC_BCB, CSC_BCR,
+};
+
+enum csc_rgb2yuv {
+       CSC_YR,  CSC_YG,  CSC_YB,
+       CSC_CBR, CSC_CBG, CSC_CBB,
+       CSC_CRR, CSC_CRG, CSC_CRB,
+};
+
+struct dispc_csc_coef {
+       void (*to_regval)(const struct dispc_csc_coef *csc, u32 *regval);
+       int m[9];
+       int preoffset[3];
+       int postoffset[3];
+       enum { CLIP_LIMITED_RANGE = 0, CLIP_FULL_RANGE = 1, } cliping;
+       const char *name;
+};
+
+#define DISPC_CSC_REGVAL_LEN 8
+
+static
+void dispc_csc_offset_regval(const struct dispc_csc_coef *csc, u32 *regval)
+{
+#define OVAL(x, y) (FLD_VAL(x, 15, 3) | FLD_VAL(y, 31, 19))
+       regval[5] = OVAL(csc->preoffset[0], csc->preoffset[1]);
+       regval[6] = OVAL(csc->preoffset[2], csc->postoffset[0]);
+       regval[7] = OVAL(csc->postoffset[1], csc->postoffset[2]);
+#undef OVAL
+}
+
+#define CVAL(x, y) (FLD_VAL(x, 10, 0) | FLD_VAL(y, 26, 16))
+static
+void dispc_csc_yuv2rgb_regval(const struct dispc_csc_coef *csc, u32 *regval)
+{
+       regval[0] = CVAL(csc->m[CSC_RY], csc->m[CSC_RCR]);
+       regval[1] = CVAL(csc->m[CSC_RCB], csc->m[CSC_GY]);
+       regval[2] = CVAL(csc->m[CSC_GCR], csc->m[CSC_GCB]);
+       regval[3] = CVAL(csc->m[CSC_BY], csc->m[CSC_BCR]);
+       regval[4] = CVAL(csc->m[CSC_BCB], 0);
+
+       dispc_csc_offset_regval(csc, regval);
+}
+
+__maybe_unused static
+void dispc_csc_rgb2yuv_regval(const struct dispc_csc_coef *csc, u32 *regval)
+{
+       regval[0] = CVAL(csc->m[CSC_YR], csc->m[CSC_YG]);
+       regval[1] = CVAL(csc->m[CSC_YB], csc->m[CSC_CRR]);
+       regval[2] = CVAL(csc->m[CSC_CRG], csc->m[CSC_CRB]);
+       regval[3] = CVAL(csc->m[CSC_CBR], csc->m[CSC_CBG]);
+       regval[4] = CVAL(csc->m[CSC_CBB], 0);
+
+       dispc_csc_offset_regval(csc, regval);
+}
+
+static void dispc_csc_cpr_regval(const struct dispc_csc_coef *csc,
+                                u32 *regval)
+{
+       regval[0] = CVAL(csc->m[CSC_RR], csc->m[CSC_RG]);
+       regval[1] = CVAL(csc->m[CSC_RB], csc->m[CSC_GR]);
+       regval[2] = CVAL(csc->m[CSC_GG], csc->m[CSC_GB]);
+       regval[3] = CVAL(csc->m[CSC_BR], csc->m[CSC_BG]);
+       regval[4] = CVAL(csc->m[CSC_BB], 0);
+
+       dispc_csc_offset_regval(csc, regval);
+}
+
+#undef CVAL
+
+static void dispc_k2g_vid_write_csc(struct dispc_device *dispc, u32 hw_plane,
+                                   const struct dispc_csc_coef *csc)
+{
+       static const u16 dispc_vid_csc_coef_reg[] = {
+               DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1),
+               DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3),
+               DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5),
+               DISPC_VID_CSC_COEF(6), /* K2G has no post offset support */
+       };
+       u32 regval[DISPC_CSC_REGVAL_LEN];
+       unsigned int i;
+
+       csc->to_regval(csc, regval);
+
+       if (regval[7] != 0)
+               dev_warn(dispc->dev, "%s: No post offset support for %s\n",
+                        __func__, csc->name);
+
+       for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++)
+               dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i],
+                               regval[i]);
+}
+
+static void dispc_k3_vid_write_csc(struct dispc_device *dispc, u32 hw_plane,
+                                  const struct dispc_csc_coef *csc)
+{
+       static const u16 dispc_vid_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = {
+               DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1),
+               DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3),
+               DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5),
+               DISPC_VID_CSC_COEF(6), DISPC_VID_CSC_COEF7,
+       };
+       u32 regval[DISPC_CSC_REGVAL_LEN];
+       unsigned int i;
+
+       csc->to_regval(csc, regval);
+
+       for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++)
+               dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i],
+                               regval[i]);
+}
+
+/* YUV -> RGB, ITU-R BT.601, full range */
+static const struct dispc_csc_coef csc_yuv2rgb_bt601_full = {
+       dispc_csc_yuv2rgb_regval,
+       { 256,   0,  358,       /* ry, rcb, rcr |1.000  0.000  1.402|*/
+         256, -88, -182,       /* gy, gcb, gcr |1.000 -0.344 -0.714|*/
+         256, 452,    0, },    /* by, bcb, bcr |1.000  1.772  0.000|*/
+       {    0, -2048, -2048, },        /* full range */
+       {    0,     0,     0, },
+       CLIP_FULL_RANGE,
+       "BT.601 Full",
+};
+
+/* YUV -> RGB, ITU-R BT.601, limited range */
+static const struct dispc_csc_coef csc_yuv2rgb_bt601_lim = {
+       dispc_csc_yuv2rgb_regval,
+       { 298,    0,  409,      /* ry, rcb, rcr |1.164  0.000  1.596|*/
+         298, -100, -208,      /* gy, gcb, gcr |1.164 -0.392 -0.813|*/
+         298,  516,    0, },   /* by, bcb, bcr |1.164  2.017  0.000|*/
+       { -256, -2048, -2048, },        /* limited range */
+       {    0,     0,     0, },
+       CLIP_FULL_RANGE,
+       "BT.601 Limited",
+};
+
+/* YUV -> RGB, ITU-R BT.709, full range */
+static const struct dispc_csc_coef csc_yuv2rgb_bt709_full = {
+       dispc_csc_yuv2rgb_regval,
+       { 256,    0,  402,      /* ry, rcb, rcr |1.000  0.000  1.570|*/
+         256,  -48, -120,      /* gy, gcb, gcr |1.000 -0.187 -0.467|*/
+         256,  475,    0, },   /* by, bcb, bcr |1.000  1.856  0.000|*/
+       {    0, -2048, -2048, },        /* full range */
+       {    0,     0,     0, },
+       CLIP_FULL_RANGE,
+       "BT.709 Full",
+};
+
+/* YUV -> RGB, ITU-R BT.709, limited range */
+static const struct dispc_csc_coef csc_yuv2rgb_bt709_lim = {
+       dispc_csc_yuv2rgb_regval,
+       { 298,    0,  459,      /* ry, rcb, rcr |1.164  0.000  1.793|*/
+         298,  -55, -136,      /* gy, gcb, gcr |1.164 -0.213 -0.533|*/
+         298,  541,    0, },   /* by, bcb, bcr |1.164  2.112  0.000|*/
+       { -256, -2048, -2048, },        /* limited range */
+       {    0,     0,     0, },
+       CLIP_FULL_RANGE,
+       "BT.709 Limited",
+};
+
+static const struct {
+       enum drm_color_encoding encoding;
+       enum drm_color_range range;
+       const struct dispc_csc_coef *csc;
+} dispc_csc_table[] = {
+       { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_FULL_RANGE,
+         &csc_yuv2rgb_bt601_full, },
+       { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_LIMITED_RANGE,
+         &csc_yuv2rgb_bt601_lim, },
+       { DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_FULL_RANGE,
+         &csc_yuv2rgb_bt709_full, },
+       { DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE,
+         &csc_yuv2rgb_bt709_lim, },
+};
+
+static const
+struct dispc_csc_coef *dispc_find_csc(enum drm_color_encoding encoding,
+                                     enum drm_color_range range)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(dispc_csc_table); i++) {
+               if (dispc_csc_table[i].encoding == encoding &&
+                   dispc_csc_table[i].range == range) {
+                       return dispc_csc_table[i].csc;
+               }
+       }
+       return NULL;
+}
+
+static void dispc_vid_csc_setup(struct dispc_device *dispc, u32 hw_plane,
+                               const struct drm_plane_state *state)
+{
+       static const struct dispc_csc_coef *coef;
+
+       coef = dispc_find_csc(state->color_encoding, state->color_range);
+       if (!coef) {
+               dev_err(dispc->dev, "%s: CSC (%u,%u) not found\n",
+                       __func__, state->color_encoding, state->color_range);
+               return;
+       }
+
+       if (dispc->feat->subrev == DISPC_K2G)
+               dispc_k2g_vid_write_csc(dispc, hw_plane, coef);
+       else
+               dispc_k3_vid_write_csc(dispc, hw_plane, coef);
+}
+
+static void dispc_vid_csc_enable(struct dispc_device *dispc, u32 hw_plane,
+                                bool enable)
+{
+       VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 9, 9);
+}
+
+/* SCALER */
+
+static u32 dispc_calc_fir_inc(u32 in, u32 out)
+{
+       return (u32)div_u64(0x200000ull * in, out);
+}
+
+enum dispc_vid_fir_coef_set {
+       DISPC_VID_FIR_COEF_HORIZ,
+       DISPC_VID_FIR_COEF_HORIZ_UV,
+       DISPC_VID_FIR_COEF_VERT,
+       DISPC_VID_FIR_COEF_VERT_UV,
+};
+
+static void dispc_vid_write_fir_coefs(struct dispc_device *dispc,
+                                     u32 hw_plane,
+                                     enum dispc_vid_fir_coef_set coef_set,
+                                     const struct tidss_scale_coefs *coefs)
+{
+       static const u16 c0_regs[] = {
+               [DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H0,
+               [DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H0_C,
+               [DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V0,
+               [DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V0_C,
+       };
+
+       static const u16 c12_regs[] = {
+               [DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H12,
+               [DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H12_C,
+               [DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V12,
+               [DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V12_C,
+       };
+
+       const u16 c0_base = c0_regs[coef_set];
+       const u16 c12_base = c12_regs[coef_set];
+       int phase;
+
+       if (!coefs) {
+               dev_err(dispc->dev, "%s: No coefficients given.\n", __func__);
+               return;
+       }
+
+       for (phase = 0; phase <= 8; ++phase) {
+               u16 reg = c0_base + phase * 4;
+               u16 c0 = coefs->c0[phase];
+
+               dispc_vid_write(dispc, hw_plane, reg, c0);
+       }
+
+       for (phase = 0; phase <= 15; ++phase) {
+               u16 reg = c12_base + phase * 4;
+               s16 c1, c2;
+               u32 c12;
+
+               c1 = coefs->c1[phase];
+               c2 = coefs->c2[phase];
+               c12 = FLD_VAL(c1, 19, 10) | FLD_VAL(c2, 29, 20);
+
+               dispc_vid_write(dispc, hw_plane, reg, c12);
+       }
+}
+
+static bool dispc_fourcc_is_yuv(u32 fourcc)
+{
+       switch (fourcc) {
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_NV12:
+               return true;
+       default:
+               return false;
+       }
+}
+
+struct dispc_scaling_params {
+       int xinc, yinc;
+       u32 in_w, in_h, in_w_uv, in_h_uv;
+       u32 fir_xinc, fir_yinc, fir_xinc_uv, fir_yinc_uv;
+       bool scale_x, scale_y;
+       const struct tidss_scale_coefs *xcoef, *ycoef, *xcoef_uv, *ycoef_uv;
+       bool five_taps;
+};
+
+static int dispc_vid_calc_scaling(struct dispc_device *dispc,
+                                 const struct drm_plane_state *state,
+                                 struct dispc_scaling_params *sp,
+                                 bool lite_plane)
+{
+       const struct dispc_features_scaling *f = &dispc->feat->scaling;
+       u32 fourcc = state->fb->format->format;
+       u32 in_width_max_5tap = f->in_width_max_5tap_rgb;
+       u32 in_width_max_3tap = f->in_width_max_3tap_rgb;
+       u32 downscale_limit;
+       u32 in_width_max;
+
+       memset(sp, 0, sizeof(*sp));
+       sp->xinc = 1;
+       sp->yinc = 1;
+       sp->in_w = state->src_w >> 16;
+       sp->in_w_uv = sp->in_w;
+       sp->in_h = state->src_h >> 16;
+       sp->in_h_uv = sp->in_h;
+
+       sp->scale_x = sp->in_w != state->crtc_w;
+       sp->scale_y = sp->in_h != state->crtc_h;
+
+       if (dispc_fourcc_is_yuv(fourcc)) {
+               in_width_max_5tap = f->in_width_max_5tap_yuv;
+               in_width_max_3tap = f->in_width_max_3tap_yuv;
+
+               sp->in_w_uv >>= 1;
+               sp->scale_x = true;
+
+               if (fourcc == DRM_FORMAT_NV12) {
+                       sp->in_h_uv >>= 1;
+                       sp->scale_y = true;
+               }
+       }
+
+       /* Skip the rest if no scaling is used */
+       if ((!sp->scale_x && !sp->scale_y) || lite_plane)
+               return 0;
+
+       if (sp->in_w > in_width_max_5tap) {
+               sp->five_taps = false;
+               in_width_max = in_width_max_3tap;
+               downscale_limit = f->downscale_limit_3tap;
+       } else {
+               sp->five_taps = true;
+               in_width_max = in_width_max_5tap;
+               downscale_limit = f->downscale_limit_5tap;
+       }
+
+       if (sp->scale_x) {
+               sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w);
+
+               if (sp->fir_xinc < dispc_calc_fir_inc(1, f->upscale_limit)) {
+                       dev_dbg(dispc->dev,
+                               "%s: X-scaling factor %u/%u > %u\n",
+                               __func__, state->crtc_w, state->src_w >> 16,
+                               f->upscale_limit);
+                       return -EINVAL;
+               }
+
+               if (sp->fir_xinc >= dispc_calc_fir_inc(downscale_limit, 1)) {
+                       sp->xinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_w,
+                                                            state->crtc_w),
+                                               downscale_limit);
+
+                       if (sp->xinc > f->xinc_max) {
+                               dev_dbg(dispc->dev,
+                                       "%s: X-scaling factor %u/%u < 1/%u\n",
+                                       __func__, state->crtc_w,
+                                       state->src_w >> 16,
+                                       downscale_limit * f->xinc_max);
+                               return -EINVAL;
+                       }
+
+                       sp->in_w = (state->src_w >> 16) / sp->xinc;
+               }
+
+               while (sp->in_w > in_width_max) {
+                       sp->xinc++;
+                       sp->in_w = (state->src_w >> 16) / sp->xinc;
+               }
+
+               if (sp->xinc > f->xinc_max) {
+                       dev_dbg(dispc->dev,
+                               "%s: Too wide input bufer %u > %u\n", __func__,
+                               state->src_w >> 16, in_width_max * f->xinc_max);
+                       return -EINVAL;
+               }
+
+               /*
+                * We need even line length for YUV formats. Decimation
+                * can lead to odd length, so we need to make it even
+                * again.
+                */
+               if (dispc_fourcc_is_yuv(fourcc))
+                       sp->in_w &= ~1;
+
+               sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w);
+       }
+
+       if (sp->scale_y) {
+               sp->fir_yinc = dispc_calc_fir_inc(sp->in_h, state->crtc_h);
+
+               if (sp->fir_yinc < dispc_calc_fir_inc(1, f->upscale_limit)) {
+                       dev_dbg(dispc->dev,
+                               "%s: Y-scaling factor %u/%u > %u\n",
+                               __func__, state->crtc_h, state->src_h >> 16,
+                               f->upscale_limit);
+                       return -EINVAL;
+               }
+
+               if (sp->fir_yinc >= dispc_calc_fir_inc(downscale_limit, 1)) {
+                       sp->yinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_h,
+                                                            state->crtc_h),
+                                               downscale_limit);
+
+                       sp->in_h /= sp->yinc;
+                       sp->fir_yinc = dispc_calc_fir_inc(sp->in_h,
+                                                         state->crtc_h);
+               }
+       }
+
+       dev_dbg(dispc->dev,
+               "%s: %ux%u decim %ux%u -> %ux%u firinc %u.%03ux%u.%03u taps %u -> %ux%u\n",
+               __func__, state->src_w >> 16, state->src_h >> 16,
+               sp->xinc, sp->yinc, sp->in_w, sp->in_h,
+               sp->fir_xinc / 0x200000u,
+               ((sp->fir_xinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu,
+               sp->fir_yinc / 0x200000u,
+               ((sp->fir_yinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu,
+               sp->five_taps ? 5 : 3,
+               state->crtc_w, state->crtc_h);
+
+       if (dispc_fourcc_is_yuv(fourcc)) {
+               if (sp->scale_x) {
+                       sp->in_w_uv /= sp->xinc;
+                       sp->fir_xinc_uv = dispc_calc_fir_inc(sp->in_w_uv,
+                                                            state->crtc_w);
+                       sp->xcoef_uv = tidss_get_scale_coefs(dispc->dev,
+                                                            sp->fir_xinc_uv,
+                                                            true);
+               }
+               if (sp->scale_y) {
+                       sp->in_h_uv /= sp->yinc;
+                       sp->fir_yinc_uv = dispc_calc_fir_inc(sp->in_h_uv,
+                                                            state->crtc_h);
+                       sp->ycoef_uv = tidss_get_scale_coefs(dispc->dev,
+                                                            sp->fir_yinc_uv,
+                                                            sp->five_taps);
+               }
+       }
+
+       if (sp->scale_x)
+               sp->xcoef = tidss_get_scale_coefs(dispc->dev, sp->fir_xinc,
+                                                 true);
+
+       if (sp->scale_y)
+               sp->ycoef = tidss_get_scale_coefs(dispc->dev, sp->fir_yinc,
+                                                 sp->five_taps);
+
+       return 0;
+}
+
+static void dispc_vid_set_scaling(struct dispc_device *dispc,
+                                 u32 hw_plane,
+                                 struct dispc_scaling_params *sp,
+                                 u32 fourcc)
+{
+       /* HORIZONTAL RESIZE ENABLE */
+       VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
+                       sp->scale_x, 7, 7);
+
+       /* VERTICAL RESIZE ENABLE */
+       VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
+                       sp->scale_y, 8, 8);
+
+       /* Skip the rest if no scaling is used */
+       if (!sp->scale_x && !sp->scale_y)
+               return;
+
+       /* VERTICAL 5-TAPS  */
+       VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
+                       sp->five_taps, 21, 21);
+
+       if (dispc_fourcc_is_yuv(fourcc)) {
+               if (sp->scale_x) {
+                       dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH2,
+                                       sp->fir_xinc_uv);
+                       dispc_vid_write_fir_coefs(dispc, hw_plane,
+                                                 DISPC_VID_FIR_COEF_HORIZ_UV,
+                                                 sp->xcoef_uv);
+               }
+               if (sp->scale_y) {
+                       dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV2,
+                                       sp->fir_yinc_uv);
+                       dispc_vid_write_fir_coefs(dispc, hw_plane,
+                                                 DISPC_VID_FIR_COEF_VERT_UV,
+                                                 sp->ycoef_uv);
+               }
+       }
+
+       if (sp->scale_x) {
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH, sp->fir_xinc);
+               dispc_vid_write_fir_coefs(dispc, hw_plane,
+                                         DISPC_VID_FIR_COEF_HORIZ,
+                                         sp->xcoef);
+       }
+
+       if (sp->scale_y) {
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV, sp->fir_yinc);
+               dispc_vid_write_fir_coefs(dispc, hw_plane,
+                                         DISPC_VID_FIR_COEF_VERT, sp->ycoef);
+       }
+}
+
+/* OTHER */
+
+static const struct {
+       u32 fourcc;
+       u8 dss_code;
+} dispc_color_formats[] = {
+       { DRM_FORMAT_ARGB4444, 0x0, },
+       { DRM_FORMAT_ABGR4444, 0x1, },
+       { DRM_FORMAT_RGBA4444, 0x2, },
+
+       { DRM_FORMAT_RGB565, 0x3, },
+       { DRM_FORMAT_BGR565, 0x4, },
+
+       { DRM_FORMAT_ARGB1555, 0x5, },
+       { DRM_FORMAT_ABGR1555, 0x6, },
+
+       { DRM_FORMAT_ARGB8888, 0x7, },
+       { DRM_FORMAT_ABGR8888, 0x8, },
+       { DRM_FORMAT_RGBA8888, 0x9, },
+       { DRM_FORMAT_BGRA8888, 0xa, },
+
+       { DRM_FORMAT_RGB888, 0xb, },
+       { DRM_FORMAT_BGR888, 0xc, },
+
+       { DRM_FORMAT_ARGB2101010, 0xe, },
+       { DRM_FORMAT_ABGR2101010, 0xf, },
+
+       { DRM_FORMAT_XRGB4444, 0x20, },
+       { DRM_FORMAT_XBGR4444, 0x21, },
+       { DRM_FORMAT_RGBX4444, 0x22, },
+
+       { DRM_FORMAT_ARGB1555, 0x25, },
+       { DRM_FORMAT_ABGR1555, 0x26, },
+
+       { DRM_FORMAT_XRGB8888, 0x27, },
+       { DRM_FORMAT_XBGR8888, 0x28, },
+       { DRM_FORMAT_RGBX8888, 0x29, },
+       { DRM_FORMAT_BGRX8888, 0x2a, },
+
+       { DRM_FORMAT_XRGB2101010, 0x2e, },
+       { DRM_FORMAT_XBGR2101010, 0x2f, },
+
+       { DRM_FORMAT_YUYV, 0x3e, },
+       { DRM_FORMAT_UYVY, 0x3f, },
+
+       { DRM_FORMAT_NV12, 0x3d, },
+};
+
+static void dispc_plane_set_pixel_format(struct dispc_device *dispc,
+                                        u32 hw_plane, u32 fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) {
+               if (dispc_color_formats[i].fourcc == fourcc) {
+                       VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
+                                       dispc_color_formats[i].dss_code,
+                                       6, 1);
+                       return;
+               }
+       }
+
+       WARN_ON(1);
+}
+
+const u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len)
+{
+       WARN_ON(!dispc->fourccs);
+
+       *len = dispc->num_fourccs;
+
+       return dispc->fourccs;
+}
+
+static s32 pixinc(int pixels, u8 ps)
+{
+       if (pixels == 1)
+               return 1;
+       else if (pixels > 1)
+               return 1 + (pixels - 1) * ps;
+       else if (pixels < 0)
+               return 1 - (-pixels + 1) * ps;
+
+       WARN_ON(1);
+       return 0;
+}
+
+int dispc_plane_check(struct dispc_device *dispc, u32 hw_plane,
+                     const struct drm_plane_state *state,
+                     u32 hw_videoport)
+{
+       bool lite = dispc->feat->vid_lite[hw_plane];
+       u32 fourcc = state->fb->format->format;
+       bool need_scaling = state->src_w >> 16 != state->crtc_w ||
+               state->src_h >> 16 != state->crtc_h;
+       struct dispc_scaling_params scaling;
+       int ret;
+
+       if (dispc_fourcc_is_yuv(fourcc)) {
+               if (!dispc_find_csc(state->color_encoding,
+                                   state->color_range)) {
+                       dev_dbg(dispc->dev,
+                               "%s: Unsupported CSC (%u,%u) for HW plane %u\n",
+                               __func__, state->color_encoding,
+                               state->color_range, hw_plane);
+                       return -EINVAL;
+               }
+       }
+
+       if (need_scaling) {
+               if (lite) {
+                       dev_dbg(dispc->dev,
+                               "%s: Lite plane %u can't scale %ux%u!=%ux%u\n",
+                               __func__, hw_plane,
+                               state->src_w >> 16, state->src_h >> 16,
+                               state->crtc_w, state->crtc_h);
+                       return -EINVAL;
+               }
+               ret = dispc_vid_calc_scaling(dispc, state, &scaling, false);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static
+dma_addr_t dispc_plane_state_paddr(const struct drm_plane_state *state)
+{
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_gem_cma_object *gem;
+       u32 x = state->src_x >> 16;
+       u32 y = state->src_y >> 16;
+
+       gem = drm_fb_cma_get_gem_obj(state->fb, 0);
+
+       return gem->paddr + fb->offsets[0] + x * fb->format->cpp[0] +
+               y * fb->pitches[0];
+}
+
+static
+dma_addr_t dispc_plane_state_p_uv_addr(const struct drm_plane_state *state)
+{
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_gem_cma_object *gem;
+       u32 x = state->src_x >> 16;
+       u32 y = state->src_y >> 16;
+
+       if (WARN_ON(state->fb->format->num_planes != 2))
+               return 0;
+
+       gem = drm_fb_cma_get_gem_obj(fb, 1);
+
+       return gem->paddr + fb->offsets[1] +
+               (x * fb->format->cpp[1] / fb->format->hsub) +
+               (y * fb->pitches[1] / fb->format->vsub);
+}
+
+int dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane,
+                     const struct drm_plane_state *state,
+                     u32 hw_videoport)
+{
+       bool lite = dispc->feat->vid_lite[hw_plane];
+       u32 fourcc = state->fb->format->format;
+       u16 cpp = state->fb->format->cpp[0];
+       u32 fb_width = state->fb->pitches[0] / cpp;
+       dma_addr_t paddr = dispc_plane_state_paddr(state);
+       struct dispc_scaling_params scale;
+
+       dispc_vid_calc_scaling(dispc, state, &scale, lite);
+
+       dispc_plane_set_pixel_format(dispc, hw_plane, fourcc);
+
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_0, paddr & 0xffffffff);
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_0, (u64)paddr >> 32);
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_1, paddr & 0xffffffff);
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_1, (u64)paddr >> 32);
+
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_PICTURE_SIZE,
+                       (scale.in_w - 1) | ((scale.in_h - 1) << 16));
+
+       /* For YUV422 format we use the macropixel size for pixel inc */
+       if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY)
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC,
+                               pixinc(scale.xinc, cpp * 2));
+       else
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC,
+                               pixinc(scale.xinc, cpp));
+
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC,
+                       pixinc(1 + (scale.yinc * fb_width -
+                                   scale.xinc * scale.in_w),
+                              cpp));
+
+       if (state->fb->format->num_planes == 2) {
+               u16 cpp_uv = state->fb->format->cpp[1];
+               u32 fb_width_uv = state->fb->pitches[1] / cpp_uv;
+               dma_addr_t p_uv_addr = dispc_plane_state_p_uv_addr(state);
+
+               dispc_vid_write(dispc, hw_plane,
+                               DISPC_VID_BA_UV_0, p_uv_addr & 0xffffffff);
+               dispc_vid_write(dispc, hw_plane,
+                               DISPC_VID_BA_UV_EXT_0, (u64)p_uv_addr >> 32);
+               dispc_vid_write(dispc, hw_plane,
+                               DISPC_VID_BA_UV_1, p_uv_addr & 0xffffffff);
+               dispc_vid_write(dispc, hw_plane,
+                               DISPC_VID_BA_UV_EXT_1, (u64)p_uv_addr >> 32);
+
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC_UV,
+                               pixinc(1 + (scale.yinc * fb_width_uv -
+                                           scale.xinc * scale.in_w_uv),
+                                      cpp_uv));
+       }
+
+       if (!lite) {
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_SIZE,
+                               (state->crtc_w - 1) |
+                               ((state->crtc_h - 1) << 16));
+
+               dispc_vid_set_scaling(dispc, hw_plane, &scale, fourcc);
+       }
+
+       /* enable YUV->RGB color conversion */
+       if (dispc_fourcc_is_yuv(fourcc)) {
+               dispc_vid_csc_setup(dispc, hw_plane, state);
+               dispc_vid_csc_enable(dispc, hw_plane, true);
+       } else {
+               dispc_vid_csc_enable(dispc, hw_plane, false);
+       }
+
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_GLOBAL_ALPHA,
+                       0xFF & (state->alpha >> 8));
+
+       if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
+               VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1,
+                               28, 28);
+       else
+               VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0,
+                               28, 28);
+
+       dispc_ovr_set_plane(dispc, hw_plane, hw_videoport,
+                           state->crtc_x, state->crtc_y,
+                           state->normalized_zpos);
+
+       dispc->plane_data[hw_plane].zorder = state->normalized_zpos;
+       dispc->plane_data[hw_plane].hw_videoport = hw_videoport;
+
+       return 0;
+}
+
+int dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable)
+{
+       dispc_ovr_enable_plane(dispc, dispc->plane_data[hw_plane].hw_videoport,
+                              dispc->plane_data[hw_plane].zorder, enable);
+
+       VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 0, 0);
+
+       return 0;
+}
+
+static u32 dispc_vid_get_fifo_size(struct dispc_device *dispc, u32 hw_plane)
+{
+       return VID_REG_GET(dispc, hw_plane, DISPC_VID_BUF_SIZE_STATUS, 15, 0);
+}
+
+static void dispc_vid_set_mflag_threshold(struct dispc_device *dispc,
+                                         u32 hw_plane, u32 low, u32 high)
+{
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_MFLAG_THRESHOLD,
+                       FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
+}
+
+static void dispc_vid_set_buf_threshold(struct dispc_device *dispc,
+                                       u32 hw_plane, u32 low, u32 high)
+{
+       dispc_vid_write(dispc, hw_plane, DISPC_VID_BUF_THRESHOLD,
+                       FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
+}
+
+static void dispc_k2g_plane_init(struct dispc_device *dispc)
+{
+       unsigned int hw_plane;
+
+       dev_dbg(dispc->dev, "%s()\n", __func__);
+
+       /* MFLAG_CTRL = ENABLED */
+       REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0);
+       /* MFLAG_START = MFLAGNORMALSTARTMODE */
+       REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6);
+
+       for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) {
+               u32 size = dispc_vid_get_fifo_size(dispc, hw_plane);
+               u32 thr_low, thr_high;
+               u32 mflag_low, mflag_high;
+               u32 preload;
+
+               thr_high = size - 1;
+               thr_low = size / 2;
+
+               mflag_high = size * 2 / 3;
+               mflag_low = size / 3;
+
+               preload = thr_low;
+
+               dev_dbg(dispc->dev,
+                       "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n",
+                       dispc->feat->vid_name[hw_plane],
+                       size,
+                       thr_high, thr_low,
+                       mflag_high, mflag_low,
+                       preload);
+
+               dispc_vid_set_buf_threshold(dispc, hw_plane,
+                                           thr_low, thr_high);
+               dispc_vid_set_mflag_threshold(dispc, hw_plane,
+                                             mflag_low, mflag_high);
+
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload);
+
+               /*
+                * Prefetch up to fifo high-threshold value to minimize the
+                * possibility of underflows. Note that this means the PRELOAD
+                * register is ignored.
+                */
+               VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1,
+                               19, 19);
+       }
+}
+
+static void dispc_k3_plane_init(struct dispc_device *dispc)
+{
+       unsigned int hw_plane;
+       u32 cba_lo_pri = 1;
+       u32 cba_hi_pri = 0;
+
+       dev_dbg(dispc->dev, "%s()\n", __func__);
+
+       REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_lo_pri, 2, 0);
+       REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_hi_pri, 5, 3);
+
+       /* MFLAG_CTRL = ENABLED */
+       REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0);
+       /* MFLAG_START = MFLAGNORMALSTARTMODE */
+       REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6);
+
+       for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) {
+               u32 size = dispc_vid_get_fifo_size(dispc, hw_plane);
+               u32 thr_low, thr_high;
+               u32 mflag_low, mflag_high;
+               u32 preload;
+
+               thr_high = size - 1;
+               thr_low = size / 2;
+
+               mflag_high = size * 2 / 3;
+               mflag_low = size / 3;
+
+               preload = thr_low;
+
+               dev_dbg(dispc->dev,
+                       "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n",
+                       dispc->feat->vid_name[hw_plane],
+                       size,
+                       thr_high, thr_low,
+                       mflag_high, mflag_low,
+                       preload);
+
+               dispc_vid_set_buf_threshold(dispc, hw_plane,
+                                           thr_low, thr_high);
+               dispc_vid_set_mflag_threshold(dispc, hw_plane,
+                                             mflag_low, mflag_high);
+
+               dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload);
+
+               /* Prefech up to PRELOAD value */
+               VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0,
+                               19, 19);
+       }
+}
+
+static void dispc_plane_init(struct dispc_device *dispc)
+{
+       switch (dispc->feat->subrev) {
+       case DISPC_K2G:
+               dispc_k2g_plane_init(dispc);
+               break;
+       case DISPC_AM65X:
+       case DISPC_J721E:
+               dispc_k3_plane_init(dispc);
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+
+static void dispc_vp_init(struct dispc_device *dispc)
+{
+       unsigned int i;
+
+       dev_dbg(dispc->dev, "%s()\n", __func__);
+
+       /* Enable the gamma Shadow bit-field for all VPs*/
+       for (i = 0; i < dispc->feat->num_vps; i++)
+               VP_REG_FLD_MOD(dispc, i, DISPC_VP_CONFIG, 1, 2, 2);
+}
+
+static void dispc_initial_config(struct dispc_device *dispc)
+{
+       dispc_plane_init(dispc);
+       dispc_vp_init(dispc);
+
+       /* Note: Hardcoded DPI routing on J721E for now */
+       if (dispc->feat->subrev == DISPC_J721E) {
+               dispc_write(dispc, DISPC_CONNECTIONS,
+                           FLD_VAL(2, 3, 0) |          /* VP1 to DPI0 */
+                           FLD_VAL(8, 7, 4)            /* VP3 to DPI1 */
+                       );
+       }
+}
+
+static void dispc_k2g_vp_write_gamma_table(struct dispc_device *dispc,
+                                          u32 hw_videoport)
+{
+       u32 *table = dispc->vp_data[hw_videoport].gamma_table;
+       u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
+       unsigned int i;
+
+       dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport);
+
+       if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT))
+               return;
+
+       for (i = 0; i < hwlen; ++i) {
+               u32 v = table[i];
+
+               v |= i << 24;
+
+               dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_GAMMA_TABLE,
+                              v);
+       }
+}
+
+static void dispc_am65x_vp_write_gamma_table(struct dispc_device *dispc,
+                                            u32 hw_videoport)
+{
+       u32 *table = dispc->vp_data[hw_videoport].gamma_table;
+       u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
+       unsigned int i;
+
+       dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport);
+
+       if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT))
+               return;
+
+       for (i = 0; i < hwlen; ++i) {
+               u32 v = table[i];
+
+               v |= i << 24;
+
+               dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v);
+       }
+}
+
+static void dispc_j721e_vp_write_gamma_table(struct dispc_device *dispc,
+                                            u32 hw_videoport)
+{
+       u32 *table = dispc->vp_data[hw_videoport].gamma_table;
+       u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
+       unsigned int i;
+
+       dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport);
+
+       if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_10BIT))
+               return;
+
+       for (i = 0; i < hwlen; ++i) {
+               u32 v = table[i];
+
+               if (i == 0)
+                       v |= 1 << 31;
+
+               dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v);
+       }
+}
+
+static void dispc_vp_write_gamma_table(struct dispc_device *dispc,
+                                      u32 hw_videoport)
+{
+       switch (dispc->feat->subrev) {
+       case DISPC_K2G:
+               dispc_k2g_vp_write_gamma_table(dispc, hw_videoport);
+               break;
+       case DISPC_AM65X:
+               dispc_am65x_vp_write_gamma_table(dispc, hw_videoport);
+               break;
+       case DISPC_J721E:
+               dispc_j721e_vp_write_gamma_table(dispc, hw_videoport);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+static const struct drm_color_lut dispc_vp_gamma_default_lut[] = {
+       { .red = 0, .green = 0, .blue = 0, },
+       { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
+};
+
+static void dispc_vp_set_gamma(struct dispc_device *dispc,
+                              u32 hw_videoport,
+                              const struct drm_color_lut *lut,
+                              unsigned int length)
+{
+       u32 *table = dispc->vp_data[hw_videoport].gamma_table;
+       u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
+       u32 hwbits;
+       unsigned int i;
+
+       dev_dbg(dispc->dev, "%s: hw_videoport %d, lut len %u, hw len %u\n",
+               __func__, hw_videoport, length, hwlen);
+
+       if (dispc->feat->vp_feat.color.gamma_type == TIDSS_GAMMA_10BIT)
+               hwbits = 10;
+       else
+               hwbits = 8;
+
+       if (!lut || length < 2) {
+               lut = dispc_vp_gamma_default_lut;
+               length = ARRAY_SIZE(dispc_vp_gamma_default_lut);
+       }
+
+       for (i = 0; i < length - 1; ++i) {
+               unsigned int first = i * (hwlen - 1) / (length - 1);
+               unsigned int last = (i + 1) * (hwlen - 1) / (length - 1);
+               unsigned int w = last - first;
+               u16 r, g, b;
+               unsigned int j;
+
+               if (w == 0)
+                       continue;
+
+               for (j = 0; j <= w; j++) {
+                       r = (lut[i].red * (w - j) + lut[i + 1].red * j) / w;
+                       g = (lut[i].green * (w - j) + lut[i + 1].green * j) / w;
+                       b = (lut[i].blue * (w - j) + lut[i + 1].blue * j) / w;
+
+                       r >>= 16 - hwbits;
+                       g >>= 16 - hwbits;
+                       b >>= 16 - hwbits;
+
+                       table[first + j] = (r << (hwbits * 2)) |
+                               (g << hwbits) | b;
+               }
+       }
+
+       dispc_vp_write_gamma_table(dispc, hw_videoport);
+}
+
+static s16 dispc_S31_32_to_s2_8(s64 coef)
+{
+       u64 sign_bit = 1ULL << 63;
+       u64 cbits = (u64)coef;
+       s16 ret;
+
+       if (cbits & sign_bit)
+               ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x200);
+       else
+               ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x1FF);
+
+       return ret;
+}
+
+static void dispc_k2g_cpr_from_ctm(const struct drm_color_ctm *ctm,
+                                  struct dispc_csc_coef *cpr)
+{
+       memset(cpr, 0, sizeof(*cpr));
+
+       cpr->to_regval = dispc_csc_cpr_regval;
+       cpr->m[CSC_RR] = dispc_S31_32_to_s2_8(ctm->matrix[0]);
+       cpr->m[CSC_RG] = dispc_S31_32_to_s2_8(ctm->matrix[1]);
+       cpr->m[CSC_RB] = dispc_S31_32_to_s2_8(ctm->matrix[2]);
+       cpr->m[CSC_GR] = dispc_S31_32_to_s2_8(ctm->matrix[3]);
+       cpr->m[CSC_GG] = dispc_S31_32_to_s2_8(ctm->matrix[4]);
+       cpr->m[CSC_GB] = dispc_S31_32_to_s2_8(ctm->matrix[5]);
+       cpr->m[CSC_BR] = dispc_S31_32_to_s2_8(ctm->matrix[6]);
+       cpr->m[CSC_BG] = dispc_S31_32_to_s2_8(ctm->matrix[7]);
+       cpr->m[CSC_BB] = dispc_S31_32_to_s2_8(ctm->matrix[8]);
+}
+
+#define CVAL(xR, xG, xB) (FLD_VAL(xR, 9, 0) | FLD_VAL(xG, 20, 11) |    \
+                         FLD_VAL(xB, 31, 22))
+
+static void dispc_k2g_vp_csc_cpr_regval(const struct dispc_csc_coef *csc,
+                                       u32 *regval)
+{
+       regval[0] = CVAL(csc->m[CSC_BB], csc->m[CSC_BG], csc->m[CSC_BR]);
+       regval[1] = CVAL(csc->m[CSC_GB], csc->m[CSC_GG], csc->m[CSC_GR]);
+       regval[2] = CVAL(csc->m[CSC_RB], csc->m[CSC_RG], csc->m[CSC_RR]);
+}
+
+#undef CVAL
+
+static void dispc_k2g_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport,
+                                  const struct dispc_csc_coef *csc)
+{
+       static const u16 dispc_vp_cpr_coef_reg[] = {
+               DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2,
+               /* K2G CPR is packed to three registers. */
+       };
+       u32 regval[DISPC_CSC_REGVAL_LEN];
+       unsigned int i;
+
+       dispc_k2g_vp_csc_cpr_regval(csc, regval);
+
+       for (i = 0; i < ARRAY_SIZE(dispc_vp_cpr_coef_reg); i++)
+               dispc_vp_write(dispc, hw_videoport, dispc_vp_cpr_coef_reg[i],
+                              regval[i]);
+}
+
+static void dispc_k2g_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport,
+                                struct drm_color_ctm *ctm)
+{
+       u32 cprenable = 0;
+
+       if (ctm) {
+               struct dispc_csc_coef cpr;
+
+               dispc_k2g_cpr_from_ctm(ctm, &cpr);
+               dispc_k2g_vp_write_csc(dispc, hw_videoport, &cpr);
+               cprenable = 1;
+       }
+
+       VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG,
+                      cprenable, 15, 15);
+}
+
+static s16 dispc_S31_32_to_s3_8(s64 coef)
+{
+       u64 sign_bit = 1ULL << 63;
+       u64 cbits = (u64)coef;
+       s16 ret;
+
+       if (cbits & sign_bit)
+               ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x400);
+       else
+               ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x3FF);
+
+       return ret;
+}
+
+static void dispc_csc_from_ctm(const struct drm_color_ctm *ctm,
+                              struct dispc_csc_coef *cpr)
+{
+       memset(cpr, 0, sizeof(*cpr));
+
+       cpr->to_regval = dispc_csc_cpr_regval;
+       cpr->m[CSC_RR] = dispc_S31_32_to_s3_8(ctm->matrix[0]);
+       cpr->m[CSC_RG] = dispc_S31_32_to_s3_8(ctm->matrix[1]);
+       cpr->m[CSC_RB] = dispc_S31_32_to_s3_8(ctm->matrix[2]);
+       cpr->m[CSC_GR] = dispc_S31_32_to_s3_8(ctm->matrix[3]);
+       cpr->m[CSC_GG] = dispc_S31_32_to_s3_8(ctm->matrix[4]);
+       cpr->m[CSC_GB] = dispc_S31_32_to_s3_8(ctm->matrix[5]);
+       cpr->m[CSC_BR] = dispc_S31_32_to_s3_8(ctm->matrix[6]);
+       cpr->m[CSC_BG] = dispc_S31_32_to_s3_8(ctm->matrix[7]);
+       cpr->m[CSC_BB] = dispc_S31_32_to_s3_8(ctm->matrix[8]);
+}
+
+static void dispc_k3_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport,
+                                 const struct dispc_csc_coef *csc)
+{
+       static const u16 dispc_vp_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = {
+               DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2,
+               DISPC_VP_CSC_COEF3, DISPC_VP_CSC_COEF4, DISPC_VP_CSC_COEF5,
+               DISPC_VP_CSC_COEF6, DISPC_VP_CSC_COEF7,
+       };
+       u32 regval[DISPC_CSC_REGVAL_LEN];
+       unsigned int i;
+
+       csc->to_regval(csc, regval);
+
+       for (i = 0; i < ARRAY_SIZE(regval); i++)
+               dispc_vp_write(dispc, hw_videoport, dispc_vp_csc_coef_reg[i],
+                              regval[i]);
+}
+
+static void dispc_k3_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport,
+                               struct drm_color_ctm *ctm)
+{
+       u32 colorconvenable = 0;
+
+       if (ctm) {
+               struct dispc_csc_coef csc;
+
+               dispc_csc_from_ctm(ctm, &csc);
+               dispc_k3_vp_write_csc(dispc, hw_videoport, &csc);
+               colorconvenable = 1;
+       }
+
+       VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG,
+                      colorconvenable, 24, 24);
+}
+
+static void dispc_vp_set_color_mgmt(struct dispc_device *dispc,
+                                   u32 hw_videoport,
+                                   const struct drm_crtc_state *state,
+                                   bool newmodeset)
+{
+       struct drm_color_lut *lut = NULL;
+       struct drm_color_ctm *ctm = NULL;
+       unsigned int length = 0;
+
+       if (!(state->color_mgmt_changed || newmodeset))
+               return;
+
+       if (state->gamma_lut) {
+               lut = (struct drm_color_lut *)state->gamma_lut->data;
+               length = state->gamma_lut->length / sizeof(*lut);
+       }
+
+       dispc_vp_set_gamma(dispc, hw_videoport, lut, length);
+
+       if (state->ctm)
+               ctm = (struct drm_color_ctm *)state->ctm->data;
+
+       if (dispc->feat->subrev == DISPC_K2G)
+               dispc_k2g_vp_set_ctm(dispc, hw_videoport, ctm);
+       else
+               dispc_k3_vp_set_ctm(dispc, hw_videoport, ctm);
+}
+
+void dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport,
+                   const struct drm_crtc_state *state, bool newmodeset)
+{
+       dispc_vp_set_default_color(dispc, hw_videoport, 0);
+       dispc_vp_set_color_mgmt(dispc, hw_videoport, state, newmodeset);
+}
+
+int dispc_runtime_suspend(struct dispc_device *dispc)
+{
+       dev_dbg(dispc->dev, "suspend\n");
+
+       dispc->is_enabled = false;
+
+       clk_disable_unprepare(dispc->fclk);
+
+       return 0;
+}
+
+int dispc_runtime_resume(struct dispc_device *dispc)
+{
+       dev_dbg(dispc->dev, "resume\n");
+
+       clk_prepare_enable(dispc->fclk);
+
+       if (REG_GET(dispc, DSS_SYSSTATUS, 0, 0) == 0)
+               dev_warn(dispc->dev, "DSS FUNC RESET not done!\n");
+
+       dev_dbg(dispc->dev, "OMAP DSS7 rev 0x%x\n",
+               dispc_read(dispc, DSS_REVISION));
+
+       dev_dbg(dispc->dev, "VP RESETDONE %d,%d,%d\n",
+               REG_GET(dispc, DSS_SYSSTATUS, 1, 1),
+               REG_GET(dispc, DSS_SYSSTATUS, 2, 2),
+               REG_GET(dispc, DSS_SYSSTATUS, 3, 3));
+
+       if (dispc->feat->subrev == DISPC_AM65X)
+               dev_dbg(dispc->dev, "OLDI RESETDONE %d,%d,%d\n",
+                       REG_GET(dispc, DSS_SYSSTATUS, 5, 5),
+                       REG_GET(dispc, DSS_SYSSTATUS, 6, 6),
+                       REG_GET(dispc, DSS_SYSSTATUS, 7, 7));
+
+       dev_dbg(dispc->dev, "DISPC IDLE %d\n",
+               REG_GET(dispc, DSS_SYSSTATUS, 9, 9));
+
+       dispc_initial_config(dispc);
+
+       dispc->is_enabled = true;
+
+       tidss_irq_resume(dispc->tidss);
+
+       return 0;
+}
+
+void dispc_remove(struct tidss_device *tidss)
+{
+       dev_dbg(tidss->dev, "%s\n", __func__);
+
+       tidss->dispc = NULL;
+}
+
+static int dispc_iomap_resource(struct platform_device *pdev, const char *name,
+                               void __iomem **base)
+{
+       struct resource *res;
+       void __iomem *b;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot get mem resource '%s'\n", name);
+               return -EINVAL;
+       }
+
+       b = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(b)) {
+               dev_err(&pdev->dev, "cannot ioremap resource '%s'\n", name);
+               return PTR_ERR(b);
+       }
+
+       *base = b;
+
+       return 0;
+}
+
+static int dispc_init_am65x_oldi_io_ctrl(struct device *dev,
+                                        struct dispc_device *dispc)
+{
+       dispc->oldi_io_ctrl =
+               syscon_regmap_lookup_by_phandle(dev->of_node,
+                                               "ti,am65x-oldi-io-ctrl");
+       if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) {
+               dispc->oldi_io_ctrl = NULL;
+       } else if (IS_ERR(dispc->oldi_io_ctrl)) {
+               dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n",
+                       __func__, PTR_ERR(dispc->oldi_io_ctrl));
+               return PTR_ERR(dispc->oldi_io_ctrl);
+       }
+       return 0;
+}
+
+int dispc_init(struct tidss_device *tidss)
+{
+       struct device *dev = tidss->dev;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct dispc_device *dispc;
+       const struct dispc_features *feat;
+       unsigned int i, num_fourccs;
+       int r = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       feat = tidss->feat;
+
+       if (feat->subrev != DISPC_K2G) {
+               r = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+               if (r)
+                       dev_warn(dev, "cannot set DMA masks to 48-bit\n");
+       }
+
+       dispc = devm_kzalloc(dev, sizeof(*dispc), GFP_KERNEL);
+       if (!dispc)
+               return -ENOMEM;
+
+       dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats),
+                                     sizeof(*dispc->fourccs), GFP_KERNEL);
+       if (!dispc->fourccs)
+               return -ENOMEM;
+
+       num_fourccs = 0;
+       for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) {
+               if (feat->errata.i2000 &&
+                   dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc))
+                       continue;
+               dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc;
+       }
+       dispc->num_fourccs = num_fourccs;
+       dispc->tidss = tidss;
+       dispc->dev = dev;
+       dispc->feat = feat;
+
+       dispc_common_regmap = dispc->feat->common_regs;
+
+       r = dispc_iomap_resource(pdev, dispc->feat->common,
+                                &dispc->base_common);
+       if (r)
+               return r;
+
+       for (i = 0; i < dispc->feat->num_planes; i++) {
+               r = dispc_iomap_resource(pdev, dispc->feat->vid_name[i],
+                                        &dispc->base_vid[i]);
+               if (r)
+                       return r;
+       }
+
+       for (i = 0; i < dispc->feat->num_vps; i++) {
+               u32 gamma_size = dispc->feat->vp_feat.color.gamma_size;
+               u32 *gamma_table;
+               struct clk *clk;
+
+               r = dispc_iomap_resource(pdev, dispc->feat->ovr_name[i],
+                                        &dispc->base_ovr[i]);
+               if (r)
+                       return r;
+
+               r = dispc_iomap_resource(pdev, dispc->feat->vp_name[i],
+                                        &dispc->base_vp[i]);
+               if (r)
+                       return r;
+
+               clk = devm_clk_get(dev, dispc->feat->vpclk_name[i]);
+               if (IS_ERR(clk)) {
+                       dev_err(dev, "%s: Failed to get clk %s:%ld\n", __func__,
+                               dispc->feat->vpclk_name[i], PTR_ERR(clk));
+                       return PTR_ERR(clk);
+               }
+               dispc->vp_clk[i] = clk;
+
+               gamma_table = devm_kmalloc_array(dev, gamma_size,
+                                                sizeof(*gamma_table),
+                                                GFP_KERNEL);
+               if (!gamma_table)
+                       return -ENOMEM;
+               dispc->vp_data[i].gamma_table = gamma_table;
+       }
+
+       if (feat->subrev == DISPC_AM65X) {
+               r = dispc_init_am65x_oldi_io_ctrl(dev, dispc);
+               if (r)
+                       return r;
+       }
+
+       dispc->fclk = devm_clk_get(dev, "fck");
+       if (IS_ERR(dispc->fclk)) {
+               dev_err(dev, "%s: Failed to get fclk: %ld\n",
+                       __func__, PTR_ERR(dispc->fclk));
+               return PTR_ERR(dispc->fclk);
+       }
+       dev_dbg(dev, "DSS fclk %lu Hz\n", clk_get_rate(dispc->fclk));
+
+       of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth",
+                            &dispc->memory_bandwidth_limit);
+
+       tidss->dispc = dispc;
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
new file mode 100644 (file)
index 0000000..e65e6a2
--- /dev/null
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_DISPC_H__
+#define __TIDSS_DISPC_H__
+
+#include "tidss_drv.h"
+
+struct dispc_device;
+
+struct drm_crtc_state;
+
+enum tidss_gamma_type { TIDSS_GAMMA_8BIT, TIDSS_GAMMA_10BIT };
+
+struct tidss_vp_feat {
+       struct tidss_vp_color_feat {
+               u32 gamma_size;
+               enum tidss_gamma_type gamma_type;
+               bool has_ctm;
+       } color;
+};
+
+struct tidss_plane_feat {
+       struct tidss_plane_color_feat {
+               u32 encodings;
+               u32 ranges;
+               enum drm_color_encoding default_encoding;
+               enum drm_color_range default_range;
+       } color;
+       struct tidss_plane_blend_feat {
+               bool global_alpha;
+       } blend;
+};
+
+struct dispc_features_scaling {
+       u32 in_width_max_5tap_rgb;
+       u32 in_width_max_3tap_rgb;
+       u32 in_width_max_5tap_yuv;
+       u32 in_width_max_3tap_yuv;
+       u32 upscale_limit;
+       u32 downscale_limit_5tap;
+       u32 downscale_limit_3tap;
+       u32 xinc_max;
+};
+
+struct dispc_errata {
+       bool i2000; /* DSS Does Not Support YUV Pixel Data Formats */
+};
+
+enum dispc_vp_bus_type {
+       DISPC_VP_DPI,           /* DPI output */
+       DISPC_VP_OLDI,          /* OLDI (LVDS) output */
+       DISPC_VP_INTERNAL,      /* SoC internal routing */
+       DISPC_VP_MAX_BUS_TYPE,
+};
+
+enum dispc_dss_subrevision {
+       DISPC_K2G,
+       DISPC_AM65X,
+       DISPC_J721E,
+};
+
+struct dispc_features {
+       int min_pclk_khz;
+       int max_pclk_khz[DISPC_VP_MAX_BUS_TYPE];
+
+       struct dispc_features_scaling scaling;
+
+       enum dispc_dss_subrevision subrev;
+
+       const char *common;
+       const u16 *common_regs;
+       u32 num_vps;
+       const char *vp_name[TIDSS_MAX_PORTS]; /* Should match dt reg names */
+       const char *ovr_name[TIDSS_MAX_PORTS]; /* Should match dt reg names */
+       const char *vpclk_name[TIDSS_MAX_PORTS]; /* Should match dt clk names */
+       const enum dispc_vp_bus_type vp_bus_type[TIDSS_MAX_PORTS];
+       struct tidss_vp_feat vp_feat;
+       u32 num_planes;
+       const char *vid_name[TIDSS_MAX_PLANES]; /* Should match dt reg names */
+       bool vid_lite[TIDSS_MAX_PLANES];
+       u32 vid_order[TIDSS_MAX_PLANES];
+
+       struct dispc_errata errata;
+};
+
+extern const struct dispc_features dispc_k2g_feats;
+extern const struct dispc_features dispc_am65x_feats;
+extern const struct dispc_features dispc_j721e_feats;
+
+void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask);
+dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc);
+
+void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
+                     const struct drm_crtc_state *state);
+void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
+                    const struct drm_crtc_state *state);
+void dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport);
+void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport);
+bool dispc_vp_go_busy(struct dispc_device *dispc, u32 hw_videoport);
+void dispc_vp_go(struct dispc_device *dispc, u32 hw_videoport);
+int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
+                      const struct drm_crtc_state *state);
+enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
+                                        u32 hw_videoport,
+                                        const struct drm_display_mode *mode);
+int dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport);
+void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport);
+int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport,
+                         unsigned long rate);
+void dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport,
+                   const struct drm_crtc_state *state, bool newmodeset);
+
+int dispc_runtime_suspend(struct dispc_device *dispc);
+int dispc_runtime_resume(struct dispc_device *dispc);
+
+int dispc_plane_check(struct dispc_device *dispc, u32 hw_plane,
+                     const struct drm_plane_state *state,
+                     u32 hw_videoport);
+int dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane,
+                     const struct drm_plane_state *state,
+                     u32 hw_videoport);
+int dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable);
+const u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len);
+
+int dispc_init(struct tidss_device *tidss);
+void dispc_remove(struct tidss_device *tidss);
+
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_dispc_regs.h b/drivers/gpu/drm/tidss/tidss_dispc_regs.h
new file mode 100644 (file)
index 0000000..88a83a4
--- /dev/null
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Jyri Sarha <jsarha@ti.com>
+ */
+
+#ifndef __TIDSS_DISPC_REGS_H
+#define __TIDSS_DISPC_REGS_H
+
+enum dispc_common_regs {
+       NOT_APPLICABLE_OFF = 0,
+       DSS_REVISION_OFF,
+       DSS_SYSCONFIG_OFF,
+       DSS_SYSSTATUS_OFF,
+       DISPC_IRQ_EOI_OFF,
+       DISPC_IRQSTATUS_RAW_OFF,
+       DISPC_IRQSTATUS_OFF,
+       DISPC_IRQENABLE_SET_OFF,
+       DISPC_IRQENABLE_CLR_OFF,
+       DISPC_VID_IRQENABLE_OFF,
+       DISPC_VID_IRQSTATUS_OFF,
+       DISPC_VP_IRQENABLE_OFF,
+       DISPC_VP_IRQSTATUS_OFF,
+       WB_IRQENABLE_OFF,
+       WB_IRQSTATUS_OFF,
+       DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF,
+       DISPC_GLOBAL_OUTPUT_ENABLE_OFF,
+       DISPC_GLOBAL_BUFFER_OFF,
+       DSS_CBA_CFG_OFF,
+       DISPC_DBG_CONTROL_OFF,
+       DISPC_DBG_STATUS_OFF,
+       DISPC_CLKGATING_DISABLE_OFF,
+       DISPC_SECURE_DISABLE_OFF,
+       FBDC_REVISION_1_OFF,
+       FBDC_REVISION_2_OFF,
+       FBDC_REVISION_3_OFF,
+       FBDC_REVISION_4_OFF,
+       FBDC_REVISION_5_OFF,
+       FBDC_REVISION_6_OFF,
+       FBDC_COMMON_CONTROL_OFF,
+       FBDC_CONSTANT_COLOR_0_OFF,
+       FBDC_CONSTANT_COLOR_1_OFF,
+       DISPC_CONNECTIONS_OFF,
+       DISPC_MSS_VP1_OFF,
+       DISPC_MSS_VP3_OFF,
+       DISPC_COMMON_REG_TABLE_LEN,
+};
+
+/*
+ * dispc_common_regmap should be defined as const u16 * and pointing
+ * to a valid dss common register map for the platform, before the
+ * macros bellow can be used.
+ */
+
+#define REG(r) (dispc_common_regmap[r ## _OFF])
+
+#define DSS_REVISION                   REG(DSS_REVISION)
+#define DSS_SYSCONFIG                  REG(DSS_SYSCONFIG)
+#define DSS_SYSSTATUS                  REG(DSS_SYSSTATUS)
+#define DISPC_IRQ_EOI                  REG(DISPC_IRQ_EOI)
+#define DISPC_IRQSTATUS_RAW            REG(DISPC_IRQSTATUS_RAW)
+#define DISPC_IRQSTATUS                        REG(DISPC_IRQSTATUS)
+#define DISPC_IRQENABLE_SET            REG(DISPC_IRQENABLE_SET)
+#define DISPC_IRQENABLE_CLR            REG(DISPC_IRQENABLE_CLR)
+#define DISPC_VID_IRQENABLE(n)         (REG(DISPC_VID_IRQENABLE) + (n) * 4)
+#define DISPC_VID_IRQSTATUS(n)         (REG(DISPC_VID_IRQSTATUS) + (n) * 4)
+#define DISPC_VP_IRQENABLE(n)          (REG(DISPC_VP_IRQENABLE) + (n) * 4)
+#define DISPC_VP_IRQSTATUS(n)          (REG(DISPC_VP_IRQSTATUS) + (n) * 4)
+#define WB_IRQENABLE                   REG(WB_IRQENABLE)
+#define WB_IRQSTATUS                   REG(WB_IRQSTATUS)
+
+#define DISPC_GLOBAL_MFLAG_ATTRIBUTE   REG(DISPC_GLOBAL_MFLAG_ATTRIBUTE)
+#define DISPC_GLOBAL_OUTPUT_ENABLE     REG(DISPC_GLOBAL_OUTPUT_ENABLE)
+#define DISPC_GLOBAL_BUFFER            REG(DISPC_GLOBAL_BUFFER)
+#define DSS_CBA_CFG                    REG(DSS_CBA_CFG)
+#define DISPC_DBG_CONTROL              REG(DISPC_DBG_CONTROL)
+#define DISPC_DBG_STATUS               REG(DISPC_DBG_STATUS)
+#define DISPC_CLKGATING_DISABLE                REG(DISPC_CLKGATING_DISABLE)
+#define DISPC_SECURE_DISABLE           REG(DISPC_SECURE_DISABLE)
+
+#define FBDC_REVISION_1                        REG(FBDC_REVISION_1)
+#define FBDC_REVISION_2                        REG(FBDC_REVISION_2)
+#define FBDC_REVISION_3                        REG(FBDC_REVISION_3)
+#define FBDC_REVISION_4                        REG(FBDC_REVISION_4)
+#define FBDC_REVISION_5                        REG(FBDC_REVISION_5)
+#define FBDC_REVISION_6                        REG(FBDC_REVISION_6)
+#define FBDC_COMMON_CONTROL            REG(FBDC_COMMON_CONTROL)
+#define FBDC_CONSTANT_COLOR_0          REG(FBDC_CONSTANT_COLOR_0)
+#define FBDC_CONSTANT_COLOR_1          REG(FBDC_CONSTANT_COLOR_1)
+#define DISPC_CONNECTIONS              REG(DISPC_CONNECTIONS)
+#define DISPC_MSS_VP1                  REG(DISPC_MSS_VP1)
+#define DISPC_MSS_VP3                  REG(DISPC_MSS_VP3)
+
+/* VID */
+
+#define DISPC_VID_ACCUH_0              0x0
+#define DISPC_VID_ACCUH_1              0x4
+#define DISPC_VID_ACCUH2_0             0x8
+#define DISPC_VID_ACCUH2_1             0xc
+#define DISPC_VID_ACCUV_0              0x10
+#define DISPC_VID_ACCUV_1              0x14
+#define DISPC_VID_ACCUV2_0             0x18
+#define DISPC_VID_ACCUV2_1             0x1c
+#define DISPC_VID_ATTRIBUTES           0x20
+#define DISPC_VID_ATTRIBUTES2          0x24
+#define DISPC_VID_BA_0                 0x28
+#define DISPC_VID_BA_1                 0x2c
+#define DISPC_VID_BA_UV_0              0x30
+#define DISPC_VID_BA_UV_1              0x34
+#define DISPC_VID_BUF_SIZE_STATUS      0x38
+#define DISPC_VID_BUF_THRESHOLD                0x3c
+#define DISPC_VID_CSC_COEF(n)          (0x40 + (n) * 4)
+
+#define DISPC_VID_FIRH                 0x5c
+#define DISPC_VID_FIRH2                        0x60
+#define DISPC_VID_FIRV                 0x64
+#define DISPC_VID_FIRV2                        0x68
+
+#define DISPC_VID_FIR_COEFS_H0         0x6c
+#define DISPC_VID_FIR_COEF_H0(phase)   (0x6c + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_H0_C       0x90
+#define DISPC_VID_FIR_COEF_H0_C(phase) (0x90 + (phase) * 4)
+
+#define DISPC_VID_FIR_COEFS_H12                0xb4
+#define DISPC_VID_FIR_COEF_H12(phase)  (0xb4 + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_H12_C      0xf4
+#define DISPC_VID_FIR_COEF_H12_C(phase)        (0xf4 + (phase) * 4)
+
+#define DISPC_VID_FIR_COEFS_V0         0x134
+#define DISPC_VID_FIR_COEF_V0(phase)   (0x134 + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_V0_C       0x158
+#define DISPC_VID_FIR_COEF_V0_C(phase) (0x158 + (phase) * 4)
+
+#define DISPC_VID_FIR_COEFS_V12                0x17c
+#define DISPC_VID_FIR_COEF_V12(phase)  (0x17c + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_V12_C      0x1bc
+#define DISPC_VID_FIR_COEF_V12_C(phase)        (0x1bc + (phase) * 4)
+
+#define DISPC_VID_GLOBAL_ALPHA         0x1fc
+#define DISPC_VID_K2G_IRQENABLE                0x200 /* K2G */
+#define DISPC_VID_K2G_IRQSTATUS                0x204 /* K2G */
+#define DISPC_VID_MFLAG_THRESHOLD      0x208
+#define DISPC_VID_PICTURE_SIZE         0x20c
+#define DISPC_VID_PIXEL_INC            0x210
+#define DISPC_VID_K2G_POSITION         0x214 /* K2G */
+#define DISPC_VID_PRELOAD              0x218
+#define DISPC_VID_ROW_INC              0x21c
+#define DISPC_VID_SIZE                 0x220
+#define DISPC_VID_BA_EXT_0             0x22c
+#define DISPC_VID_BA_EXT_1             0x230
+#define DISPC_VID_BA_UV_EXT_0          0x234
+#define DISPC_VID_BA_UV_EXT_1          0x238
+#define DISPC_VID_CSC_COEF7            0x23c
+#define DISPC_VID_ROW_INC_UV           0x248
+#define DISPC_VID_CLUT                 0x260
+#define DISPC_VID_SAFETY_ATTRIBUTES    0x2a0
+#define DISPC_VID_SAFETY_CAPT_SIGNATURE        0x2a4
+#define DISPC_VID_SAFETY_POSITION      0x2a8
+#define DISPC_VID_SAFETY_REF_SIGNATURE 0x2ac
+#define DISPC_VID_SAFETY_SIZE          0x2b0
+#define DISPC_VID_SAFETY_LFSR_SEED     0x2b4
+#define DISPC_VID_LUMAKEY              0x2b8
+#define DISPC_VID_DMA_BUFSIZE          0x2bc /* J721E */
+
+/* OVR */
+
+#define DISPC_OVR_CONFIG               0x0
+#define DISPC_OVR_VIRTVP               0x4 /* J721E */
+#define DISPC_OVR_DEFAULT_COLOR                0x8
+#define DISPC_OVR_DEFAULT_COLOR2       0xc
+#define DISPC_OVR_TRANS_COLOR_MAX      0x10
+#define DISPC_OVR_TRANS_COLOR_MAX2     0x14
+#define DISPC_OVR_TRANS_COLOR_MIN      0x18
+#define DISPC_OVR_TRANS_COLOR_MIN2     0x1c
+#define DISPC_OVR_ATTRIBUTES(n)                (0x20 + (n) * 4)
+#define DISPC_OVR_ATTRIBUTES2(n)       (0x34 + (n) * 4) /* J721E */
+/* VP */
+
+#define DISPC_VP_CONFIG                                0x0
+#define DISPC_VP_CONTROL                       0x4
+#define DISPC_VP_CSC_COEF0                     0x8
+#define DISPC_VP_CSC_COEF1                     0xc
+#define DISPC_VP_CSC_COEF2                     0x10
+#define DISPC_VP_DATA_CYCLE_0                  0x14
+#define DISPC_VP_DATA_CYCLE_1                  0x18
+#define DISPC_VP_K2G_GAMMA_TABLE               0x20 /* K2G */
+#define DISPC_VP_K2G_IRQENABLE                 0x3c /* K2G */
+#define DISPC_VP_K2G_IRQSTATUS                 0x40 /* K2G */
+#define DISPC_VP_DATA_CYCLE_2                  0x1c
+#define DISPC_VP_LINE_NUMBER                   0x44
+#define DISPC_VP_POL_FREQ                      0x4c
+#define DISPC_VP_SIZE_SCREEN                   0x50
+#define DISPC_VP_TIMING_H                      0x54
+#define DISPC_VP_TIMING_V                      0x58
+#define DISPC_VP_CSC_COEF3                     0x5c
+#define DISPC_VP_CSC_COEF4                     0x60
+#define DISPC_VP_CSC_COEF5                     0x64
+#define DISPC_VP_CSC_COEF6                     0x68
+#define DISPC_VP_CSC_COEF7                     0x6c
+#define DISPC_VP_SAFETY_ATTRIBUTES_0           0x70
+#define DISPC_VP_SAFETY_ATTRIBUTES_1           0x74
+#define DISPC_VP_SAFETY_ATTRIBUTES_2           0x78
+#define DISPC_VP_SAFETY_ATTRIBUTES_3           0x7c
+#define DISPC_VP_SAFETY_CAPT_SIGNATURE_0       0x90
+#define DISPC_VP_SAFETY_CAPT_SIGNATURE_1       0x94
+#define DISPC_VP_SAFETY_CAPT_SIGNATURE_2       0x98
+#define DISPC_VP_SAFETY_CAPT_SIGNATURE_3       0x9c
+#define DISPC_VP_SAFETY_POSITION_0             0xb0
+#define DISPC_VP_SAFETY_POSITION_1             0xb4
+#define DISPC_VP_SAFETY_POSITION_2             0xb8
+#define DISPC_VP_SAFETY_POSITION_3             0xbc
+#define DISPC_VP_SAFETY_REF_SIGNATURE_0                0xd0
+#define DISPC_VP_SAFETY_REF_SIGNATURE_1                0xd4
+#define DISPC_VP_SAFETY_REF_SIGNATURE_2                0xd8
+#define DISPC_VP_SAFETY_REF_SIGNATURE_3                0xdc
+#define DISPC_VP_SAFETY_SIZE_0                 0xf0
+#define DISPC_VP_SAFETY_SIZE_1                 0xf4
+#define DISPC_VP_SAFETY_SIZE_2                 0xf8
+#define DISPC_VP_SAFETY_SIZE_3                 0xfc
+#define DISPC_VP_SAFETY_LFSR_SEED              0x110
+#define DISPC_VP_GAMMA_TABLE                   0x120
+#define DISPC_VP_DSS_OLDI_CFG                  0x160
+#define DISPC_VP_DSS_OLDI_STATUS               0x164
+#define DISPC_VP_DSS_OLDI_LB                   0x168
+#define DISPC_VP_DSS_MERGE_SPLIT               0x16c /* J721E */
+#define DISPC_VP_DSS_DMA_THREADSIZE            0x170 /* J721E */
+#define DISPC_VP_DSS_DMA_THREADSIZE_STATUS     0x174 /* J721E */
+
+/*
+ * OLDI IO_CTRL register offsets. On AM654 the registers are found
+ * from CTRL_MMR0, there the syscon regmap should map 0x14 bytes from
+ * CTRLMMR0P1_OLDI_DAT0_IO_CTRL to CTRLMMR0P1_OLDI_CLK_IO_CTRL
+ * register range.
+ */
+#define OLDI_DAT0_IO_CTRL                      0x00
+#define OLDI_DAT1_IO_CTRL                      0x04
+#define OLDI_DAT2_IO_CTRL                      0x08
+#define OLDI_DAT3_IO_CTRL                      0x0C
+#define OLDI_CLK_IO_CTRL                       0x10
+
+#define OLDI_PWRDN_TX                          BIT(8)
+
+#endif /* __TIDSS_DISPC_REGS_H */
diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
new file mode 100644 (file)
index 0000000..d95e4be
--- /dev/null
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <linux/console.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_irq.h>
+#include <drm/drm_probe_helper.h>
+
+#include "tidss_dispc.h"
+#include "tidss_drv.h"
+#include "tidss_kms.h"
+#include "tidss_irq.h"
+
+/* Power management */
+
+int tidss_runtime_get(struct tidss_device *tidss)
+{
+       int r;
+
+       dev_dbg(tidss->dev, "%s\n", __func__);
+
+       r = pm_runtime_get_sync(tidss->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+void tidss_runtime_put(struct tidss_device *tidss)
+{
+       int r;
+
+       dev_dbg(tidss->dev, "%s\n", __func__);
+
+       r = pm_runtime_put_sync(tidss->dev);
+       WARN_ON(r < 0);
+}
+
+static int __maybe_unused tidss_pm_runtime_suspend(struct device *dev)
+{
+       struct tidss_device *tidss = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return dispc_runtime_suspend(tidss->dispc);
+}
+
+static int __maybe_unused tidss_pm_runtime_resume(struct device *dev)
+{
+       struct tidss_device *tidss = dev_get_drvdata(dev);
+       int r;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       r = dispc_runtime_resume(tidss->dispc);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static int __maybe_unused tidss_suspend(struct device *dev)
+{
+       struct tidss_device *tidss = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return drm_mode_config_helper_suspend(&tidss->ddev);
+}
+
+static int __maybe_unused tidss_resume(struct device *dev)
+{
+       struct tidss_device *tidss = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return drm_mode_config_helper_resume(&tidss->ddev);
+}
+
+#ifdef CONFIG_PM
+
+static const struct dev_pm_ops tidss_pm_ops = {
+       .runtime_suspend = tidss_pm_runtime_suspend,
+       .runtime_resume = tidss_pm_runtime_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(tidss_suspend, tidss_resume)
+};
+
+#endif /* CONFIG_PM */
+
+/* DRM device Information */
+
+static void tidss_release(struct drm_device *ddev)
+{
+       struct tidss_device *tidss = ddev->dev_private;
+
+       drm_kms_helper_poll_fini(ddev);
+
+       tidss_modeset_cleanup(tidss);
+
+       drm_dev_fini(ddev);
+
+       kfree(tidss);
+}
+
+DEFINE_DRM_GEM_CMA_FOPS(tidss_fops);
+
+static struct drm_driver tidss_driver = {
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+       .fops                   = &tidss_fops,
+       .release                = tidss_release,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
+       .name                   = "tidss",
+       .desc                   = "TI Keystone DSS",
+       .date                   = "20180215",
+       .major                  = 1,
+       .minor                  = 0,
+
+       .irq_preinstall         = tidss_irq_preinstall,
+       .irq_postinstall        = tidss_irq_postinstall,
+       .irq_handler            = tidss_irq_handler,
+       .irq_uninstall          = tidss_irq_uninstall,
+};
+
+static int tidss_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tidss_device *tidss;
+       struct drm_device *ddev;
+       int ret;
+       int irq;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       /* Can't use devm_* since drm_device's lifetime may exceed dev's */
+       tidss = kzalloc(sizeof(*tidss), GFP_KERNEL);
+       if (!tidss)
+               return -ENOMEM;
+
+       ddev = &tidss->ddev;
+
+       ret = devm_drm_dev_init(&pdev->dev, ddev, &tidss_driver);
+       if (ret) {
+               kfree(ddev);
+               return ret;
+       }
+
+       tidss->dev = dev;
+       tidss->feat = of_device_get_match_data(dev);
+
+       platform_set_drvdata(pdev, tidss);
+
+       ddev->dev_private = tidss;
+
+       ret = dispc_init(tidss);
+       if (ret) {
+               dev_err(dev, "failed to initialize dispc: %d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_enable(dev);
+
+#ifndef CONFIG_PM
+       /* If we don't have PM, we need to call resume manually */
+       dispc_runtime_resume(tidss->dispc);
+#endif
+
+       ret = tidss_modeset_init(tidss);
+       if (ret < 0) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to init DRM/KMS (%d)\n", ret);
+               goto err_runtime_suspend;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto err_runtime_suspend;
+       }
+
+       ret = drm_irq_install(ddev, irq);
+       if (ret) {
+               dev_err(dev, "drm_irq_install failed: %d\n", ret);
+               goto err_runtime_suspend;
+       }
+
+       drm_kms_helper_poll_init(ddev);
+
+       drm_mode_config_reset(ddev);
+
+       ret = drm_dev_register(ddev, 0);
+       if (ret) {
+               dev_err(dev, "failed to register DRM device\n");
+               goto err_irq_uninstall;
+       }
+
+       drm_fbdev_generic_setup(ddev, 32);
+
+       dev_dbg(dev, "%s done\n", __func__);
+
+       return 0;
+
+err_irq_uninstall:
+       drm_irq_uninstall(ddev);
+
+err_runtime_suspend:
+#ifndef CONFIG_PM
+       dispc_runtime_suspend(tidss->dispc);
+#endif
+       pm_runtime_disable(dev);
+
+       return ret;
+}
+
+static int tidss_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tidss_device *tidss = platform_get_drvdata(pdev);
+       struct drm_device *ddev = &tidss->ddev;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       drm_dev_unregister(ddev);
+
+       drm_atomic_helper_shutdown(ddev);
+
+       drm_irq_uninstall(ddev);
+
+#ifndef CONFIG_PM
+       /* If we don't have PM, we need to call suspend manually */
+       dispc_runtime_suspend(tidss->dispc);
+#endif
+       pm_runtime_disable(dev);
+
+       /* devm allocated dispc goes away with the dev so mark it NULL */
+       dispc_remove(tidss);
+
+       dev_dbg(dev, "%s done\n", __func__);
+
+       return 0;
+}
+
+static void tidss_shutdown(struct platform_device *pdev)
+{
+       drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
+}
+
+static const struct of_device_id tidss_of_table[] = {
+       { .compatible = "ti,k2g-dss", .data = &dispc_k2g_feats, },
+       { .compatible = "ti,am65x-dss", .data = &dispc_am65x_feats, },
+       { .compatible = "ti,j721e-dss", .data = &dispc_j721e_feats, },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, tidss_of_table);
+
+static struct platform_driver tidss_platform_driver = {
+       .probe          = tidss_probe,
+       .remove         = tidss_remove,
+       .shutdown       = tidss_shutdown,
+       .driver         = {
+               .name   = "tidss",
+#ifdef CONFIG_PM
+               .pm     = &tidss_pm_ops,
+#endif
+               .of_match_table = tidss_of_table,
+               .suppress_bind_attrs = true,
+       },
+};
+
+module_platform_driver(tidss_platform_driver);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("TI Keystone DSS Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/tidss/tidss_drv.h b/drivers/gpu/drm/tidss/tidss_drv.h
new file mode 100644 (file)
index 0000000..e2aa643
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_DRV_H__
+#define __TIDSS_DRV_H__
+
+#include <linux/spinlock.h>
+
+#define TIDSS_MAX_PORTS 4
+#define TIDSS_MAX_PLANES 4
+
+typedef u32 dispc_irq_t;
+
+struct tidss_device {
+       struct drm_device ddev;         /* DRM device for DSS */
+       struct device *dev;             /* Underlying DSS device */
+
+       const struct dispc_features *feat;
+       struct dispc_device *dispc;
+
+       unsigned int num_crtcs;
+       struct drm_crtc *crtcs[TIDSS_MAX_PORTS];
+
+       unsigned int num_planes;
+       struct drm_plane *planes[TIDSS_MAX_PLANES];
+
+       spinlock_t wait_lock;   /* protects the irq masks */
+       dispc_irq_t irq_mask;   /* enabled irqs in addition to wait_list */
+
+       struct drm_atomic_state *saved_state;
+};
+
+int tidss_runtime_get(struct tidss_device *tidss);
+void tidss_runtime_put(struct tidss_device *tidss);
+
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c
new file mode 100644 (file)
index 0000000..f7fe3a4
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <linux/export.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_of.h>
+
+#include "tidss_crtc.h"
+#include "tidss_drv.h"
+#include "tidss_encoder.h"
+
+static int tidss_encoder_atomic_check(struct drm_encoder *encoder,
+                                     struct drm_crtc_state *crtc_state,
+                                     struct drm_connector_state *conn_state)
+{
+       struct drm_device *ddev = encoder->dev;
+       struct tidss_crtc_state *tcrtc_state = to_tidss_crtc_state(crtc_state);
+       struct drm_display_info *di = &conn_state->connector->display_info;
+       struct drm_bridge *bridge;
+       bool bus_flags_set = false;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       /*
+        * Take the bus_flags from the first bridge that defines
+        * bridge timings, or from the connector's display_info if no
+        * bridge defines the timings.
+        */
+       list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+               if (!bridge->timings)
+                       continue;
+
+               tcrtc_state->bus_flags = bridge->timings->input_bus_flags;
+               bus_flags_set = true;
+               break;
+       }
+
+       if (!di->bus_formats || di->num_bus_formats == 0)  {
+               dev_err(ddev->dev, "%s: No bus_formats in connected display\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       // XXX any cleaner way to set bus format and flags?
+       tcrtc_state->bus_format = di->bus_formats[0];
+       if (!bus_flags_set)
+               tcrtc_state->bus_flags = di->bus_flags;
+
+       return 0;
+}
+
+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+       .atomic_check = tidss_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss,
+                                        u32 encoder_type, u32 possible_crtcs)
+{
+       struct drm_encoder *enc;
+       int ret;
+
+       enc = devm_kzalloc(tidss->dev, sizeof(*enc), GFP_KERNEL);
+       if (!enc)
+               return ERR_PTR(-ENOMEM);
+
+       enc->possible_crtcs = possible_crtcs;
+
+       ret = drm_encoder_init(&tidss->ddev, enc, &encoder_funcs,
+                              encoder_type, NULL);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       drm_encoder_helper_add(enc, &encoder_helper_funcs);
+
+       dev_dbg(tidss->dev, "Encoder create done\n");
+
+       return enc;
+}
diff --git a/drivers/gpu/drm/tidss/tidss_encoder.h b/drivers/gpu/drm/tidss/tidss_encoder.h
new file mode 100644 (file)
index 0000000..06854d6
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_ENCODER_H__
+#define __TIDSS_ENCODER_H__
+
+#include <drm/drm_encoder.h>
+
+struct tidss_device;
+
+struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss,
+                                        u32 encoder_type, u32 possible_crtcs);
+
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_irq.c b/drivers/gpu/drm/tidss/tidss_irq.c
new file mode 100644 (file)
index 0000000..612c046
--- /dev/null
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <drm/drm_print.h>
+
+#include "tidss_crtc.h"
+#include "tidss_dispc.h"
+#include "tidss_drv.h"
+#include "tidss_irq.h"
+#include "tidss_plane.h"
+
+/* call with wait_lock and dispc runtime held */
+static void tidss_irq_update(struct tidss_device *tidss)
+{
+       assert_spin_locked(&tidss->wait_lock);
+
+       dispc_set_irqenable(tidss->dispc, tidss->irq_mask);
+}
+
+void tidss_irq_enable_vblank(struct drm_crtc *crtc)
+{
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       u32 hw_videoport = tcrtc->hw_videoport;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tidss->wait_lock, flags);
+       tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
+                          DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
+       tidss_irq_update(tidss);
+       spin_unlock_irqrestore(&tidss->wait_lock, flags);
+}
+
+void tidss_irq_disable_vblank(struct drm_crtc *crtc)
+{
+       struct drm_device *ddev = crtc->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+       u32 hw_videoport = tcrtc->hw_videoport;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tidss->wait_lock, flags);
+       tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
+                            DSS_IRQ_VP_VSYNC_ODD(hw_videoport));
+       tidss_irq_update(tidss);
+       spin_unlock_irqrestore(&tidss->wait_lock, flags);
+}
+
+irqreturn_t tidss_irq_handler(int irq, void *arg)
+{
+       struct drm_device *ddev = (struct drm_device *)arg;
+       struct tidss_device *tidss = ddev->dev_private;
+       unsigned int id;
+       dispc_irq_t irqstatus;
+
+       if (WARN_ON(!ddev->irq_enabled))
+               return IRQ_NONE;
+
+       irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);
+
+       for (id = 0; id < tidss->num_crtcs; id++) {
+               struct drm_crtc *crtc = tidss->crtcs[id];
+               struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
+               u32 hw_videoport = tcrtc->hw_videoport;
+
+               if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
+                                DSS_IRQ_VP_VSYNC_ODD(hw_videoport)))
+                       tidss_crtc_vblank_irq(crtc);
+
+               if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport)))
+                       tidss_crtc_framedone_irq(crtc);
+
+               if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
+                       tidss_crtc_error_irq(crtc, irqstatus);
+       }
+
+       if (irqstatus & DSS_IRQ_DEVICE_OCP_ERR)
+               dev_err_ratelimited(tidss->dev, "OCP error\n");
+
+       return IRQ_HANDLED;
+}
+
+void tidss_irq_resume(struct tidss_device *tidss)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tidss->wait_lock, flags);
+       tidss_irq_update(tidss);
+       spin_unlock_irqrestore(&tidss->wait_lock, flags);
+}
+
+void tidss_irq_preinstall(struct drm_device *ddev)
+{
+       struct tidss_device *tidss = ddev->dev_private;
+
+       spin_lock_init(&tidss->wait_lock);
+
+       tidss_runtime_get(tidss);
+
+       dispc_set_irqenable(tidss->dispc, 0);
+       dispc_read_and_clear_irqstatus(tidss->dispc);
+
+       tidss_runtime_put(tidss);
+}
+
+int tidss_irq_postinstall(struct drm_device *ddev)
+{
+       struct tidss_device *tidss = ddev->dev_private;
+       unsigned long flags;
+       unsigned int i;
+
+       tidss_runtime_get(tidss);
+
+       spin_lock_irqsave(&tidss->wait_lock, flags);
+
+       tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR;
+
+       for (i = 0; i < tidss->num_crtcs; ++i) {
+               struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]);
+
+               tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport);
+
+               tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport);
+       }
+
+       tidss_irq_update(tidss);
+
+       spin_unlock_irqrestore(&tidss->wait_lock, flags);
+
+       tidss_runtime_put(tidss);
+
+       return 0;
+}
+
+void tidss_irq_uninstall(struct drm_device *ddev)
+{
+       struct tidss_device *tidss = ddev->dev_private;
+
+       tidss_runtime_get(tidss);
+       dispc_set_irqenable(tidss->dispc, 0);
+       tidss_runtime_put(tidss);
+}
diff --git a/drivers/gpu/drm/tidss/tidss_irq.h b/drivers/gpu/drm/tidss/tidss_irq.h
new file mode 100644 (file)
index 0000000..aa92db4
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_IRQ_H__
+#define __TIDSS_IRQ_H__
+
+#include <linux/types.h>
+
+#include "tidss_drv.h"
+
+/*
+ * The IRQ status from various DISPC IRQ registers are packed into a single
+ * value, where the bits are defined as follows:
+ *
+ * bit group |dev|wb |mrg0|mrg1|mrg2|mrg3|plane0-3| <unused> |
+ * bit use   |D  |fou|FEOL|FEOL|FEOL|FEOL|  UUUU  |          |
+ * bit number|0  |1-3|4-7 |8-11|  12-19  | 20-23  |  24-31   |
+ *
+ * device bits:        D = OCP error
+ * WB bits:    f = frame done wb, o = wb buffer overflow,
+ *             u = wb buffer uncomplete
+ * vp bits:    F = frame done, E = vsync even, O = vsync odd, L = sync lost
+ * plane bits: U = fifo underflow
+ */
+
+#define DSS_IRQ_DEVICE_OCP_ERR                 BIT(0)
+
+#define DSS_IRQ_DEVICE_FRAMEDONEWB             BIT(1)
+#define DSS_IRQ_DEVICE_WBBUFFEROVERFLOW                BIT(2)
+#define DSS_IRQ_DEVICE_WBUNCOMPLETEERROR       BIT(3)
+#define DSS_IRQ_DEVICE_WB_MASK                 GENMASK(3, 1)
+
+#define DSS_IRQ_VP_BIT_N(ch, bit)      (4 + 4 * (ch) + (bit))
+#define DSS_IRQ_PLANE_BIT_N(plane, bit) \
+       (DSS_IRQ_VP_BIT_N(TIDSS_MAX_PORTS, 0) + 1 * (plane) + (bit))
+
+#define DSS_IRQ_VP_BIT(ch, bit)        BIT(DSS_IRQ_VP_BIT_N((ch), (bit)))
+#define DSS_IRQ_PLANE_BIT(plane, bit) \
+       BIT(DSS_IRQ_PLANE_BIT_N((plane), (bit)))
+
+static inline dispc_irq_t DSS_IRQ_VP_MASK(u32 ch)
+{
+       return GENMASK(DSS_IRQ_VP_BIT_N((ch), 3), DSS_IRQ_VP_BIT_N((ch), 0));
+}
+
+static inline dispc_irq_t DSS_IRQ_PLANE_MASK(u32 plane)
+{
+       return GENMASK(DSS_IRQ_PLANE_BIT_N((plane), 0),
+                      DSS_IRQ_PLANE_BIT_N((plane), 0));
+}
+
+#define DSS_IRQ_VP_FRAME_DONE(ch)      DSS_IRQ_VP_BIT((ch), 0)
+#define DSS_IRQ_VP_VSYNC_EVEN(ch)      DSS_IRQ_VP_BIT((ch), 1)
+#define DSS_IRQ_VP_VSYNC_ODD(ch)       DSS_IRQ_VP_BIT((ch), 2)
+#define DSS_IRQ_VP_SYNC_LOST(ch)       DSS_IRQ_VP_BIT((ch), 3)
+
+#define DSS_IRQ_PLANE_FIFO_UNDERFLOW(plane)    DSS_IRQ_PLANE_BIT((plane), 0)
+
+struct drm_crtc;
+struct drm_device;
+
+struct tidss_device;
+
+void tidss_irq_enable_vblank(struct drm_crtc *crtc);
+void tidss_irq_disable_vblank(struct drm_crtc *crtc);
+
+void tidss_irq_preinstall(struct drm_device *ddev);
+int tidss_irq_postinstall(struct drm_device *ddev);
+void tidss_irq_uninstall(struct drm_device *ddev);
+irqreturn_t tidss_irq_handler(int irq, void *arg);
+
+void tidss_irq_resume(struct tidss_device *tidss);
+
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
new file mode 100644 (file)
index 0000000..5311e0f
--- /dev/null
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_vblank.h>
+
+#include "tidss_crtc.h"
+#include "tidss_dispc.h"
+#include "tidss_drv.h"
+#include "tidss_encoder.h"
+#include "tidss_kms.h"
+#include "tidss_plane.h"
+
+static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
+{
+       struct drm_device *ddev = old_state->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       tidss_runtime_get(tidss);
+
+       drm_atomic_helper_commit_modeset_disables(ddev, old_state);
+       drm_atomic_helper_commit_planes(ddev, old_state, 0);
+       drm_atomic_helper_commit_modeset_enables(ddev, old_state);
+
+       drm_atomic_helper_commit_hw_done(old_state);
+       drm_atomic_helper_wait_for_flip_done(ddev, old_state);
+
+       drm_atomic_helper_cleanup_planes(ddev, old_state);
+
+       tidss_runtime_put(tidss);
+}
+
+static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = {
+       .atomic_commit_tail = tidss_atomic_commit_tail,
+};
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+       .fb_create = drm_gem_fb_create,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = drm_atomic_helper_commit,
+};
+
+static int tidss_dispc_modeset_init(struct tidss_device *tidss)
+{
+       struct device *dev = tidss->dev;
+       unsigned int fourccs_len;
+       const u32 *fourccs = dispc_plane_formats(tidss->dispc, &fourccs_len);
+       unsigned int i;
+
+       struct pipe {
+               u32 hw_videoport;
+               struct drm_bridge *bridge;
+               u32 enc_type;
+       };
+
+       const struct dispc_features *feat = tidss->feat;
+       u32 max_vps = feat->num_vps;
+       u32 max_planes = feat->num_planes;
+
+       struct pipe pipes[TIDSS_MAX_PORTS];
+       u32 num_pipes = 0;
+       u32 crtc_mask;
+
+       /* first find all the connected panels & bridges */
+
+       for (i = 0; i < max_vps; i++) {
+               struct drm_panel *panel;
+               struct drm_bridge *bridge;
+               u32 enc_type = DRM_MODE_ENCODER_NONE;
+               int ret;
+
+               ret = drm_of_find_panel_or_bridge(dev->of_node, i, 0,
+                                                 &panel, &bridge);
+               if (ret == -ENODEV) {
+                       dev_dbg(dev, "no panel/bridge for port %d\n", i);
+                       continue;
+               } else if (ret) {
+                       dev_dbg(dev, "port %d probe returned %d\n", i, ret);
+                       return ret;
+               }
+
+               if (panel) {
+                       u32 conn_type;
+
+                       dev_dbg(dev, "Setting up panel for port %d\n", i);
+
+                       switch (feat->vp_bus_type[i]) {
+                       case DISPC_VP_OLDI:
+                               enc_type = DRM_MODE_ENCODER_LVDS;
+                               conn_type = DRM_MODE_CONNECTOR_LVDS;
+                               break;
+                       case DISPC_VP_DPI:
+                               enc_type = DRM_MODE_ENCODER_DPI;
+                               conn_type = DRM_MODE_CONNECTOR_LVDS;
+                               break;
+                       default:
+                               WARN_ON(1);
+                               return -EINVAL;
+                       }
+
+                       if (panel->connector_type != conn_type) {
+                               dev_err(dev,
+                                       "%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n",
+                                        __func__, dev_name(panel->dev), i,
+                                        panel->connector_type, conn_type);
+                               return -EINVAL;
+                       }
+
+                       bridge = devm_drm_panel_bridge_add(dev, panel);
+                       if (IS_ERR(bridge)) {
+                               dev_err(dev,
+                                       "failed to set up panel bridge for port %d\n",
+                                       i);
+                               return PTR_ERR(bridge);
+                       }
+               }
+
+               pipes[num_pipes].hw_videoport = i;
+               pipes[num_pipes].bridge = bridge;
+               pipes[num_pipes].enc_type = enc_type;
+               num_pipes++;
+       }
+
+       /* all planes can be on any crtc */
+       crtc_mask = (1 << num_pipes) - 1;
+
+       /* then create a plane, a crtc and an encoder for each panel/bridge */
+
+       for (i = 0; i < num_pipes; ++i) {
+               struct tidss_plane *tplane;
+               struct tidss_crtc *tcrtc;
+               struct drm_encoder *enc;
+               u32 hw_plane_id = feat->vid_order[tidss->num_planes];
+               int ret;
+
+               tplane = tidss_plane_create(tidss, hw_plane_id,
+                                           DRM_PLANE_TYPE_PRIMARY, crtc_mask,
+                                           fourccs, fourccs_len);
+               if (IS_ERR(tplane)) {
+                       dev_err(tidss->dev, "plane create failed\n");
+                       return PTR_ERR(tplane);
+               }
+
+               tidss->planes[tidss->num_planes++] = &tplane->plane;
+
+               tcrtc = tidss_crtc_create(tidss, pipes[i].hw_videoport,
+                                         &tplane->plane);
+               if (IS_ERR(tcrtc)) {
+                       dev_err(tidss->dev, "crtc create failed\n");
+                       return PTR_ERR(tcrtc);
+               }
+
+               tidss->crtcs[tidss->num_crtcs++] = &tcrtc->crtc;
+
+               enc = tidss_encoder_create(tidss, pipes[i].enc_type,
+                                          1 << tcrtc->crtc.index);
+               if (IS_ERR(enc)) {
+                       dev_err(tidss->dev, "encoder create failed\n");
+                       return PTR_ERR(enc);
+               }
+
+               ret = drm_bridge_attach(enc, pipes[i].bridge, NULL);
+               if (ret) {
+                       dev_err(tidss->dev, "bridge attach failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* create overlay planes of the leftover planes */
+
+       while (tidss->num_planes < max_planes) {
+               struct tidss_plane *tplane;
+               u32 hw_plane_id = feat->vid_order[tidss->num_planes];
+
+               tplane = tidss_plane_create(tidss, hw_plane_id,
+                                           DRM_PLANE_TYPE_OVERLAY, crtc_mask,
+                                           fourccs, fourccs_len);
+
+               if (IS_ERR(tplane)) {
+                       dev_err(tidss->dev, "plane create failed\n");
+                       return PTR_ERR(tplane);
+               }
+
+               tidss->planes[tidss->num_planes++] = &tplane->plane;
+       }
+
+       return 0;
+}
+
+int tidss_modeset_init(struct tidss_device *tidss)
+{
+       struct drm_device *ddev = &tidss->ddev;
+       unsigned int i;
+       int ret;
+
+       dev_dbg(tidss->dev, "%s\n", __func__);
+
+       drm_mode_config_init(ddev);
+
+       ddev->mode_config.min_width = 8;
+       ddev->mode_config.min_height = 8;
+       ddev->mode_config.max_width = 8096;
+       ddev->mode_config.max_height = 8096;
+       ddev->mode_config.normalize_zpos = true;
+       ddev->mode_config.funcs = &mode_config_funcs;
+       ddev->mode_config.helper_private = &mode_config_helper_funcs;
+
+       ret = tidss_dispc_modeset_init(tidss);
+       if (ret)
+               goto err_mode_config_cleanup;
+
+       ret = drm_vblank_init(ddev, tidss->num_crtcs);
+       if (ret)
+               goto err_mode_config_cleanup;
+
+       /* Start with vertical blanking interrupt reporting disabled. */
+       for (i = 0; i < tidss->num_crtcs; ++i)
+               drm_crtc_vblank_reset(tidss->crtcs[i]);
+
+       drm_mode_config_reset(ddev);
+
+       dev_dbg(tidss->dev, "%s done\n", __func__);
+
+       return 0;
+
+err_mode_config_cleanup:
+       drm_mode_config_cleanup(ddev);
+       return ret;
+}
+
+void tidss_modeset_cleanup(struct tidss_device *tidss)
+{
+       struct drm_device *ddev = &tidss->ddev;
+
+       drm_mode_config_cleanup(ddev);
+}
diff --git a/drivers/gpu/drm/tidss/tidss_kms.h b/drivers/gpu/drm/tidss/tidss_kms.h
new file mode 100644 (file)
index 0000000..dda5625
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_KMS_H__
+#define __TIDSS_KMS_H__
+
+struct tidss_device;
+
+int tidss_modeset_init(struct tidss_device *tidss);
+void tidss_modeset_cleanup(struct tidss_device *tidss);
+
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
new file mode 100644 (file)
index 0000000..ff99b2d
--- /dev/null
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "tidss_crtc.h"
+#include "tidss_dispc.h"
+#include "tidss_drv.h"
+#include "tidss_plane.h"
+
+/* drm_plane_helper_funcs */
+
+static int tidss_plane_atomic_check(struct drm_plane *plane,
+                                   struct drm_plane_state *state)
+{
+       struct drm_device *ddev = plane->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_plane *tplane = to_tidss_plane(plane);
+       const struct drm_format_info *finfo;
+       struct drm_crtc_state *crtc_state;
+       u32 hw_plane = tplane->hw_plane_id;
+       u32 hw_videoport;
+       int ret;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       if (!state->crtc) {
+               /*
+                * The visible field is not reset by the DRM core but only
+                * updated by drm_plane_helper_check_state(), set it manually.
+                */
+               state->visible = false;
+               return 0;
+       }
+
+       crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+       if (IS_ERR(crtc_state))
+               return PTR_ERR(crtc_state);
+
+       ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
+                                                 INT_MAX, true, true);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The HW is only able to start drawing at subpixel boundary
+        * (the two first checks bellow). At the end of a row the HW
+        * can only jump integer number of subpixels forward to the
+        * beginning of the next row. So we can only show picture with
+        * integer subpixel width (the third check). However, after
+        * reaching the end of the drawn picture the drawing starts
+        * again at the absolute memory address where top left corner
+        * position of the drawn picture is (so there is no need to
+        * check for odd height).
+        */
+
+       finfo = drm_format_info(state->fb->format->format);
+
+       if ((state->src_x >> 16) % finfo->hsub != 0) {
+               dev_dbg(ddev->dev,
+                       "%s: x-position %u not divisible subpixel size %u\n",
+                       __func__, (state->src_x >> 16), finfo->hsub);
+               return -EINVAL;
+       }
+
+       if ((state->src_y >> 16) % finfo->vsub != 0) {
+               dev_dbg(ddev->dev,
+                       "%s: y-position %u not divisible subpixel size %u\n",
+                       __func__, (state->src_y >> 16), finfo->vsub);
+               return -EINVAL;
+       }
+
+       if ((state->src_w >> 16) % finfo->hsub != 0) {
+               dev_dbg(ddev->dev,
+                       "%s: src width %u not divisible by subpixel size %u\n",
+                        __func__, (state->src_w >> 16), finfo->hsub);
+               return -EINVAL;
+       }
+
+       if (!state->visible)
+               return 0;
+
+       hw_videoport = to_tidss_crtc(state->crtc)->hw_videoport;
+
+       ret = dispc_plane_check(tidss->dispc, hw_plane, state, hw_videoport);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void tidss_plane_atomic_update(struct drm_plane *plane,
+                                     struct drm_plane_state *old_state)
+{
+       struct drm_device *ddev = plane->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_plane *tplane = to_tidss_plane(plane);
+       struct drm_plane_state *state = plane->state;
+       u32 hw_videoport;
+       int ret;
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       if (!state->visible) {
+               dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
+               return;
+       }
+
+       hw_videoport = to_tidss_crtc(state->crtc)->hw_videoport;
+
+       ret = dispc_plane_setup(tidss->dispc, tplane->hw_plane_id,
+                               state, hw_videoport);
+
+       if (ret) {
+               dev_err(plane->dev->dev, "%s: Failed to setup plane %d\n",
+                       __func__, tplane->hw_plane_id);
+               dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
+               return;
+       }
+
+       dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, true);
+}
+
+static void tidss_plane_atomic_disable(struct drm_plane *plane,
+                                      struct drm_plane_state *old_state)
+{
+       struct drm_device *ddev = plane->dev;
+       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_plane *tplane = to_tidss_plane(plane);
+
+       dev_dbg(ddev->dev, "%s\n", __func__);
+
+       dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
+}
+
+static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = {
+       .atomic_check = tidss_plane_atomic_check,
+       .atomic_update = tidss_plane_atomic_update,
+       .atomic_disable = tidss_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs tidss_plane_funcs = {
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
+       .reset = drm_atomic_helper_plane_reset,
+       .destroy = drm_plane_cleanup,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
+                                      u32 hw_plane_id, u32 plane_type,
+                                      u32 crtc_mask, const u32 *formats,
+                                      u32 num_formats)
+{
+       struct tidss_plane *tplane;
+       enum drm_plane_type type;
+       u32 possible_crtcs;
+       u32 num_planes = tidss->feat->num_planes;
+       u32 color_encodings = (BIT(DRM_COLOR_YCBCR_BT601) |
+                              BIT(DRM_COLOR_YCBCR_BT709));
+       u32 color_ranges = (BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
+                           BIT(DRM_COLOR_YCBCR_LIMITED_RANGE));
+       u32 default_encoding = DRM_COLOR_YCBCR_BT601;
+       u32 default_range = DRM_COLOR_YCBCR_FULL_RANGE;
+       u32 blend_modes = (BIT(DRM_MODE_BLEND_PREMULTI) |
+                          BIT(DRM_MODE_BLEND_COVERAGE));
+       int ret;
+
+       tplane = devm_kzalloc(tidss->dev, sizeof(*tplane), GFP_KERNEL);
+       if (!tplane)
+               return ERR_PTR(-ENOMEM);
+
+       tplane->hw_plane_id = hw_plane_id;
+
+       possible_crtcs = crtc_mask;
+       type = plane_type;
+
+       ret = drm_universal_plane_init(&tidss->ddev, &tplane->plane,
+                                      possible_crtcs,
+                                      &tidss_plane_funcs,
+                                      formats, num_formats,
+                                      NULL, type, NULL);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs);
+
+       drm_plane_create_zpos_property(&tplane->plane, hw_plane_id, 0,
+                                      num_planes - 1);
+
+       ret = drm_plane_create_color_properties(&tplane->plane,
+                                               color_encodings,
+                                               color_ranges,
+                                               default_encoding,
+                                               default_range);
+       if (ret)
+               return ERR_PTR(ret);
+
+       ret = drm_plane_create_alpha_property(&tplane->plane);
+       if (ret)
+               return ERR_PTR(ret);
+
+       ret = drm_plane_create_blend_mode_property(&tplane->plane, blend_modes);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return tplane;
+}
diff --git a/drivers/gpu/drm/tidss/tidss_plane.h b/drivers/gpu/drm/tidss/tidss_plane.h
new file mode 100644 (file)
index 0000000..80ff1c5
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TIDSS_PLANE_H__
+#define __TIDSS_PLANE_H__
+
+#define to_tidss_plane(p) container_of((p), struct tidss_plane, plane)
+
+struct tidss_device;
+
+struct tidss_plane {
+       struct drm_plane plane;
+
+       u32 hw_plane_id;
+};
+
+struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
+                                      u32 hw_plane_id, u32 plane_type,
+                                      u32 crtc_mask, const u32 *formats,
+                                      u32 num_formats);
+
+#endif
diff --git a/drivers/gpu/drm/tidss/tidss_scale_coefs.c b/drivers/gpu/drm/tidss/tidss_scale_coefs.c
new file mode 100644 (file)
index 0000000..5ec6838
--- /dev/null
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Jyri Sarha <jsarha@ti.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#include "tidss_scale_coefs.h"
+
+/*
+ * These are interpolated with a custom python script from DSS5
+ * (drivers/gpu/drm/omapdrm/dss/dispc_coef.c) coefficients.
+ */
+static const struct tidss_scale_coefs coef5_m32 = {
+       .c2 = { 28, 34, 40, 46, 52, 58, 64, 70, 0, 2, 4, 8, 12, 16, 20, 24, },
+       .c1 = { 132, 138, 144, 150, 156, 162, 168, 174, 76, 84, 92, 98, 104, 110, 116, 124, },
+       .c0 = { 192, 192, 192, 190, 188, 186, 184, 182, 180, },
+};
+
+static const struct tidss_scale_coefs coef5_m26 = {
+       .c2 = { 24, 28, 32, 38, 44, 50, 56, 64, 0, 2, 4, 6, 8, 12, 16, 20, },
+       .c1 = { 132, 138, 144, 152, 160, 166, 172, 178, 72, 80, 88, 94, 100, 108, 116, 124, },
+       .c0 = { 200, 202, 204, 202, 200, 196, 192, 188, 184, },
+};
+
+static const struct tidss_scale_coefs coef5_m22 = {
+       .c2 = { 16, 20, 24, 30, 36, 42, 48, 56, 0, 0, 0, 2, 4, 8, 12, 14, },
+       .c1 = { 132, 140, 148, 156, 164, 172, 180, 186, 64, 72, 80, 88, 96, 104, 112, 122, },
+       .c0 = { 216, 216, 216, 214, 212, 208, 204, 198, 192, },
+};
+
+static const struct tidss_scale_coefs coef5_m19 = {
+       .c2 = { 12, 14, 16, 22, 28, 34, 40, 48, 0, 0, 0, 2, 4, 4, 4, 8, },
+       .c1 = { 128, 140, 152, 160, 168, 176, 184, 192, 56, 64, 72, 82, 92, 100, 108, 118, },
+       .c0 = { 232, 232, 232, 226, 220, 218, 216, 208, 200, },
+};
+
+static const struct tidss_scale_coefs coef5_m16 = {
+       .c2 = { 0, 2, 4, 8, 12, 18, 24, 32, 0, 0, 0, -2, -4, -4, -4, -2, },
+       .c1 = { 124, 138, 152, 164, 176, 186, 196, 206, 40, 48, 56, 68, 80, 90, 100, 112, },
+       .c0 = { 264, 262, 260, 254, 248, 242, 236, 226, 216, },
+};
+
+static const struct tidss_scale_coefs coef5_m14 = {
+       .c2 = { -8, -6, -4, -2, 0, 6, 12, 18, 0, -2, -4, -6, -8, -8, -8, -8, },
+       .c1 = { 120, 134, 148, 164, 180, 194, 208, 220, 24, 32, 40, 52, 64, 78, 92, 106, },
+       .c0 = { 288, 286, 284, 280, 276, 266, 256, 244, 232, },
+};
+
+static const struct tidss_scale_coefs coef5_m13 = {
+       .c2 = { -12, -12, -12, -10, -8, -4, 0, 6, 0, -2, -4, -6, -8, -10, -12, -12, },
+       .c1 = { 112, 130, 148, 164, 180, 196, 212, 228, 12, 22, 32, 44, 56, 70, 84, 98, },
+       .c0 = { 312, 308, 304, 298, 292, 282, 272, 258, 244, },
+};
+
+static const struct tidss_scale_coefs coef5_m12 = {
+       .c2 = { -16, -18, -20, -18, -16, -14, -12, -6, 0, -2, -4, -6, -8, -10, -12, -14, },
+       .c1 = { 104, 124, 144, 164, 184, 202, 220, 238, 0, 10, 20, 30, 40, 56, 72, 88, },
+       .c0 = { 336, 332, 328, 320, 312, 300, 288, 272, 256, },
+};
+
+static const struct tidss_scale_coefs coef5_m11 = {
+       .c2 = { -20, -22, -24, -24, -24, -24, -24, -20, 0, -2, -4, -6, -8, -10, -12, -16, },
+       .c1 = { 92, 114, 136, 158, 180, 204, 228, 250, -16, -8, 0, 12, 24, 38, 52, 72, },
+       .c0 = { 368, 364, 360, 350, 340, 326, 312, 292, 272, },
+};
+
+static const struct tidss_scale_coefs coef5_m10 = {
+       .c2 = { -16, -20, -24, -28, -32, -34, -36, -34, 0, 0, 0, -2, -4, -8, -12, -14, },
+       .c1 = { 72, 96, 120, 148, 176, 204, 232, 260, -32, -26, -20, -10, 0, 16, 32, 52, },
+       .c0 = { 400, 398, 396, 384, 372, 354, 336, 312, 288, },
+};
+
+static const struct tidss_scale_coefs coef5_m9 = {
+       .c2 = { -12, -18, -24, -28, -32, -38, -44, -46, 0, 2, 4, 2, 0, -2, -4, -8, },
+       .c1 = { 40, 68, 96, 128, 160, 196, 232, 268, -48, -46, -44, -36, -28, -14, 0, 20, },
+       .c0 = { 456, 450, 444, 428, 412, 388, 364, 334, 304, },
+};
+
+static const struct tidss_scale_coefs coef5_m8 = {
+       .c2 = { 0, -4, -8, -16, -24, -32, -40, -48, 0, 2, 4, 6, 8, 6, 4, 2, },
+       .c1 = { 0, 28, 56, 94, 132, 176, 220, 266, -56, -60, -64, -62, -60, -50, -40, -20, },
+       .c0 = { 512, 506, 500, 478, 456, 424, 392, 352, 312, },
+};
+
+static const struct tidss_scale_coefs coef3_m32 = {
+       .c1 = { 108, 92, 76, 62, 48, 36, 24, 140, 256, 236, 216, 198, 180, 162, 144, 126, },
+       .c0 = { 296, 294, 292, 288, 284, 278, 272, 136, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m26 = {
+       .c1 = { 104, 90, 76, 60, 44, 32, 20, 138, 256, 236, 216, 198, 180, 160, 140, 122, },
+       .c0 = { 304, 300, 296, 292, 288, 282, 276, 138, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m22 = {
+       .c1 = { 100, 84, 68, 54, 40, 30, 20, 138, 256, 236, 216, 196, 176, 156, 136, 118, },
+       .c0 = { 312, 310, 308, 302, 296, 286, 276, 138, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m19 = {
+       .c1 = { 96, 80, 64, 50, 36, 26, 16, 136, 256, 236, 216, 194, 172, 152, 132, 114, },
+       .c0 = { 320, 318, 316, 310, 304, 292, 280, 140, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m16 = {
+       .c1 = { 88, 72, 56, 44, 32, 22, 12, 134, 256, 234, 212, 190, 168, 148, 128, 108, },
+       .c0 = { 336, 332, 328, 320, 312, 300, 288, 144, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m14 = {
+       .c1 = { 80, 64, 48, 36, 24, 16, 8, 132, 256, 232, 208, 186, 164, 142, 120, 100, },
+       .c0 = { 352, 348, 344, 334, 324, 310, 296, 148, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m13 = {
+       .c1 = { 72, 56, 40, 30, 20, 12, 4, 130, 256, 232, 208, 184, 160, 136, 112, 92, },
+       .c0 = { 368, 364, 360, 346, 332, 316, 300, 150, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m12 = {
+       .c1 = { 64, 50, 36, 26, 16, 10, 4, 130, 256, 230, 204, 178, 152, 128, 104, 84, },
+       .c0 = { 384, 378, 372, 358, 344, 324, 304, 152, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m11 = {
+       .c1 = { 56, 40, 24, 16, 8, 4, 0, 128, 256, 228, 200, 172, 144, 120, 96, 76, },
+       .c0 = { 400, 396, 392, 376, 360, 336, 312, 156, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m10 = {
+       .c1 = { 40, 26, 12, 6, 0, -2, -4, 126, 256, 226, 196, 166, 136, 110, 84, 62, },
+       .c0 = { 432, 424, 416, 396, 376, 348, 320, 160, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m9 = {
+       .c1 = { 24, 12, 0, -4, -8, -8, -8, 124, 256, 222, 188, 154, 120, 92, 64, 44, },
+       .c0 = { 464, 456, 448, 424, 400, 366, 332, 166, 256, },
+};
+
+static const struct tidss_scale_coefs coef3_m8 = {
+       .c1 = { 0, -8, -16, -16, -16, -12, -8, 124, 256, 214, 172, 134, 96, 66, 36, 18, },
+       .c0 = { 512, 502, 492, 462, 432, 390, 348, 174, 256, },
+};
+
+const struct tidss_scale_coefs *tidss_get_scale_coefs(struct device *dev,
+                                                     u32 firinc,
+                                                     bool five_taps)
+{
+       int i;
+       int inc;
+       static const struct {
+               int mmin;
+               int mmax;
+               const struct tidss_scale_coefs *coef3;
+               const struct tidss_scale_coefs *coef5;
+               const char *name;
+       } coefs[] = {
+               { 27, 32, &coef3_m32, &coef5_m32, "M32" },
+               { 23, 26, &coef3_m26, &coef5_m26, "M26" },
+               { 20, 22, &coef3_m22, &coef5_m22, "M22" },
+               { 17, 19, &coef3_m19, &coef5_m19, "M19" },
+               { 15, 16, &coef3_m16, &coef5_m16, "M16" },
+               { 14, 14, &coef3_m14, &coef5_m14, "M14" },
+               { 13, 13, &coef3_m13, &coef5_m13, "M13" },
+               { 12, 12, &coef3_m12, &coef5_m12, "M12" },
+               { 11, 11, &coef3_m11, &coef5_m11, "M11" },
+               { 10, 10, &coef3_m10, &coef5_m10, "M10" },
+               {  9,  9, &coef3_m9, &coef5_m9, "M9" },
+               {  4,  8, &coef3_m8, &coef5_m8, "M8" },
+               /*
+                * When upscaling more than two times, blockiness and outlines
+                * around the image are observed when M8 tables are used. M11,
+                * M16 and M19 tables are used to prevent this.
+                */
+               {  3,  3, &coef3_m11, &coef5_m11, "M11" },
+               {  2,  2, &coef3_m16, &coef5_m16, "M16" },
+               {  0,  1, &coef3_m19, &coef5_m19, "M19" },
+       };
+
+       /*
+        * inc is result of 0x200000 * in_size / out_size. This dividing
+        * by 0x40000 scales it down to 8 * in_size / out_size. After
+        * division the actual scaling factor is 8/inc.
+        */
+       inc = firinc / 0x40000;
+       for (i = 0; i < ARRAY_SIZE(coefs); ++i) {
+               if (inc >= coefs[i].mmin && inc <= coefs[i].mmax) {
+                       if (five_taps)
+                               return coefs[i].coef5;
+                       else
+                               return coefs[i].coef3;
+               }
+       }
+
+       dev_err(dev, "%s: Coefficients not found for firinc 0x%08x, inc %d\n",
+               __func__, firinc, inc);
+
+       return NULL;
+}
diff --git a/drivers/gpu/drm/tidss/tidss_scale_coefs.h b/drivers/gpu/drm/tidss/tidss_scale_coefs.h
new file mode 100644 (file)
index 0000000..64b5af5
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Jyri Sarha <jsarha@ti.com>
+ */
+
+#ifndef __TIDSS_DISPC_COEF_H__
+#define __TIDSS_DISPC_COEF_H__
+
+#include <linux/types.h>
+
+struct tidss_scale_coefs {
+       s16 c2[16];
+       s16 c1[16];
+       u16 c0[9];
+};
+
+const struct tidss_scale_coefs *tidss_get_scale_coefs(struct device *dev,
+                                                     u32 firinc,
+                                                     bool five_taps);
+
+#endif
index a46ac28..4160e74 100644 (file)
@@ -47,6 +47,20 @@ config TINYDRM_ILI9341
 
          If M is selected the module will be called ili9341.
 
+config TINYDRM_ILI9486
+       tristate "DRM support for ILI9486 display panels"
+       depends on DRM && SPI
+       select DRM_KMS_HELPER
+       select DRM_KMS_CMA_HELPER
+       select DRM_MIPI_DBI
+       select BACKLIGHT_CLASS_DEVICE
+       help
+         DRM driver for the following Ilitek ILI9486 panels:
+         * PISCREEN 3.5" 320x480 TFT (Ozzmaker 3.5")
+         * RPILCD 3.5" 320x480 TFT (Waveshare 3.5")
+
+         If M is selected the module will be called ili9486.
+
 config TINYDRM_MI0283QT
        tristate "DRM support for MI0283QT"
        depends on DRM && SPI
@@ -85,14 +99,16 @@ config TINYDRM_ST7586
          If M is selected the module will be called st7586.
 
 config TINYDRM_ST7735R
-       tristate "DRM support for Sitronix ST7735R display panels"
+       tristate "DRM support for Sitronix ST7715R/ST7735R display panels"
        depends on DRM && SPI
        select DRM_KMS_HELPER
        select DRM_KMS_CMA_HELPER
        select DRM_MIPI_DBI
        select BACKLIGHT_CLASS_DEVICE
        help
-         DRM driver Sitronix ST7735R with one of the following LCDs:
-         * JD-T18003-T01 1.8" 128x160 TFT
+         DRM driver for Sitronix ST7715R/ST7735R with one of the following
+         LCDs:
+         * Jianda JD-T18003-T01 1.8" 128x160 TFT
+         * Okaya RH128128T 1.44" 128x128 TFT
 
          If M is selected the module will be called st7735r.
index 896cf31..c96ceee 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_GM12U320)              += gm12u320.o
 obj-$(CONFIG_TINYDRM_HX8357D)          += hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)          += ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)          += ili9341.o
+obj-$(CONFIG_TINYDRM_ILI9486)          += ili9486.o
 obj-$(CONFIG_TINYDRM_MI0283QT)         += mi0283qt.o
 obj-$(CONFIG_TINYDRM_REPAPER)          += repaper.o
 obj-$(CONFIG_TINYDRM_ST7586)           += st7586.o
index 94fb1f5..a481734 100644 (file)
@@ -22,7 +22,6 @@
 #include <drm/drm_modeset_helper_vtables.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
-#include <drm/drm_vblank.h>
 
 static bool eco_mode;
 module_param(eco_mode, bool, 0644);
@@ -610,18 +609,10 @@ static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe,
                                 struct drm_plane_state *old_state)
 {
        struct drm_plane_state *state = pipe->plane.state;
-       struct drm_crtc *crtc = &pipe->crtc;
        struct drm_rect rect;
 
        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
                gm12u320_fb_mark_dirty(pipe->plane.state->fb, &rect);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               crtc->state->event = NULL;
-               spin_unlock_irq(&crtc->dev->event_lock);
-       }
 }
 
 static const struct drm_simple_display_pipe_funcs gm12u320_pipe_funcs = {
index c66acc5..802fb8d 100644 (file)
@@ -26,7 +26,6 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_mipi_dbi.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_vblank.h>
 
 #define ILI9225_DRIVER_READ_CODE       0x00
 #define ILI9225_DRIVER_OUTPUT_CONTROL  0x01
@@ -165,18 +164,10 @@ static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe,
                                struct drm_plane_state *old_state)
 {
        struct drm_plane_state *state = pipe->plane.state;
-       struct drm_crtc *crtc = &pipe->crtc;
        struct drm_rect rect;
 
        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
                ili9225_fb_dirty(state->fb, &rect);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-               crtc->state->event = NULL;
-       }
 }
 
 static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c
new file mode 100644 (file)
index 0000000..5084b38
--- /dev/null
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DRM driver for Ilitek ILI9486 panels
+ *
+ * Copyright 2020 Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_atomic_helper.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_mipi_dbi.h>
+#include <drm/drm_modeset_helper.h>
+
+#define ILI9486_ITFCTR1         0xb0
+#define ILI9486_PWCTRL1         0xc2
+#define ILI9486_VMCTRL1         0xc5
+#define ILI9486_PGAMCTRL        0xe0
+#define ILI9486_NGAMCTRL        0xe1
+#define ILI9486_DGAMCTRL        0xe2
+#define ILI9486_MADCTL_BGR      BIT(3)
+#define ILI9486_MADCTL_MV       BIT(5)
+#define ILI9486_MADCTL_MX       BIT(6)
+#define ILI9486_MADCTL_MY       BIT(7)
+
+/*
+ * The PiScreen/waveshare rpi-lcd-35 has a SPI to 16-bit parallel bus converter
+ * in front of the  display controller. This means that 8-bit values have to be
+ * transferred as 16-bit.
+ */
+static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par,
+                            size_t num)
+{
+       struct spi_device *spi = mipi->spi;
+       void *data = par;
+       u32 speed_hz;
+       int i, ret;
+       u16 *buf;
+
+       buf = kmalloc(32 * sizeof(u16), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /*
+        * The displays are Raspberry Pi HATs and connected to the 8-bit only
+        * SPI controller, so 16-bit command and parameters need byte swapping
+        * before being transferred as 8-bit on the big endian SPI bus.
+        * Pixel data bytes have already been swapped before this function is
+        * called.
+        */
+       buf[0] = cpu_to_be16(*cmd);
+       gpiod_set_value_cansleep(mipi->dc, 0);
+       speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 2);
+       ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, buf, 2);
+       if (ret || !num)
+               goto free;
+
+       /* 8-bit configuration data, not 16-bit pixel data */
+       if (num <= 32) {
+               for (i = 0; i < num; i++)
+                       buf[i] = cpu_to_be16(par[i]);
+               num *= 2;
+               speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
+               data = buf;
+       }
+
+       gpiod_set_value_cansleep(mipi->dc, 1);
+       ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, data, num);
+ free:
+       kfree(buf);
+
+       return ret;
+}
+
+static void waveshare_enable(struct drm_simple_display_pipe *pipe,
+                            struct drm_crtc_state *crtc_state,
+                            struct drm_plane_state *plane_state)
+{
+       struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
+       struct mipi_dbi *dbi = &dbidev->dbi;
+       u8 addr_mode;
+       int ret, idx;
+
+       if (!drm_dev_enter(pipe->crtc.dev, &idx))
+               return;
+
+       DRM_DEBUG_KMS("\n");
+
+       ret = mipi_dbi_poweron_conditional_reset(dbidev);
+       if (ret < 0)
+               goto out_exit;
+       if (ret == 1)
+               goto out_enable;
+
+       mipi_dbi_command(dbi, ILI9486_ITFCTR1);
+       mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
+       msleep(250);
+
+       mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
+
+       mipi_dbi_command(dbi, ILI9486_PWCTRL1, 0x44);
+
+       mipi_dbi_command(dbi, ILI9486_VMCTRL1, 0x00, 0x00, 0x00, 0x00);
+
+       mipi_dbi_command(dbi, ILI9486_PGAMCTRL,
+                        0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98,
+                        0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x0);
+       mipi_dbi_command(dbi, ILI9486_NGAMCTRL,
+                        0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
+                        0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
+       mipi_dbi_command(dbi, ILI9486_DGAMCTRL,
+                        0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
+                        0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
+
+       mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
+       msleep(100);
+
+ out_enable:
+       switch (dbidev->rotation) {
+       case 90:
+               addr_mode = ILI9486_MADCTL_MY;
+               break;
+       case 180:
+               addr_mode = ILI9486_MADCTL_MV;
+               break;
+       case 270:
+               addr_mode = ILI9486_MADCTL_MX;
+               break;
+       default:
+               addr_mode = ILI9486_MADCTL_MV | ILI9486_MADCTL_MY |
+                       ILI9486_MADCTL_MX;
+               break;
+       }
+       addr_mode |= ILI9486_MADCTL_BGR;
+       mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
+       mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
+ out_exit:
+       drm_dev_exit(idx);
+}
+
+static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = {
+       .enable = waveshare_enable,
+       .disable = mipi_dbi_pipe_disable,
+       .update = mipi_dbi_pipe_update,
+       .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+};
+
+static const struct drm_display_mode waveshare_mode = {
+       DRM_SIMPLE_MODE(480, 320, 73, 49),
+};
+
+DEFINE_DRM_GEM_CMA_FOPS(ili9486_fops);
+
+static struct drm_driver ili9486_driver = {
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+       .fops                   = &ili9486_fops,
+       .release                = mipi_dbi_release,
+       DRM_GEM_CMA_VMAP_DRIVER_OPS,
+       .debugfs_init           = mipi_dbi_debugfs_init,
+       .name                   = "ili9486",
+       .desc                   = "Ilitek ILI9486",
+       .date                   = "20200118",
+       .major                  = 1,
+       .minor                  = 0,
+};
+
+static const struct of_device_id ili9486_of_match[] = {
+       { .compatible = "waveshare,rpi-lcd-35" },
+       { .compatible = "ozzmaker,piscreen" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ili9486_of_match);
+
+static const struct spi_device_id ili9486_id[] = {
+       { "ili9486", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ili9486_id);
+
+static int ili9486_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct mipi_dbi_dev *dbidev;
+       struct drm_device *drm;
+       struct mipi_dbi *dbi;
+       struct gpio_desc *dc;
+       u32 rotation = 0;
+       int ret;
+
+       dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL);
+       if (!dbidev)
+               return -ENOMEM;
+
+       dbi = &dbidev->dbi;
+       drm = &dbidev->drm;
+       ret = devm_drm_dev_init(dev, drm, &ili9486_driver);
+       if (ret) {
+               kfree(dbidev);
+               return ret;
+       }
+
+       drm_mode_config_init(drm);
+
+       dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(dbi->reset)) {
+               DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
+               return PTR_ERR(dbi->reset);
+       }
+
+       dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+       if (IS_ERR(dc)) {
+               DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
+               return PTR_ERR(dc);
+       }
+
+       dbidev->backlight = devm_of_find_backlight(dev);
+       if (IS_ERR(dbidev->backlight))
+               return PTR_ERR(dbidev->backlight);
+
+       device_property_read_u32(dev, "rotation", &rotation);
+
+       ret = mipi_dbi_spi_init(spi, dbi, dc);
+       if (ret)
+               return ret;
+
+       dbi->command = waveshare_command;
+       dbi->read_commands = NULL;
+
+       ret = mipi_dbi_dev_init(dbidev, &waveshare_pipe_funcs,
+                               &waveshare_mode, rotation);
+       if (ret)
+               return ret;
+
+       drm_mode_config_reset(drm);
+
+       ret = drm_dev_register(drm, 0);
+       if (ret)
+               return ret;
+
+       spi_set_drvdata(spi, drm);
+
+       drm_fbdev_generic_setup(drm, 0);
+
+       return 0;
+}
+
+static int ili9486_remove(struct spi_device *spi)
+{
+       struct drm_device *drm = spi_get_drvdata(spi);
+
+       drm_dev_unplug(drm);
+       drm_atomic_helper_shutdown(drm);
+
+       return 0;
+}
+
+static void ili9486_shutdown(struct spi_device *spi)
+{
+       drm_atomic_helper_shutdown(spi_get_drvdata(spi));
+}
+
+static struct spi_driver ili9486_spi_driver = {
+       .driver = {
+               .name = "ili9486",
+               .of_match_table = ili9486_of_match,
+       },
+       .id_table = ili9486_id,
+       .probe = ili9486_probe,
+       .remove = ili9486_remove,
+       .shutdown = ili9486_shutdown,
+};
+module_spi_driver(ili9486_spi_driver);
+
+MODULE_DESCRIPTION("Ilitek ILI9486 DRM driver");
+MODULE_AUTHOR("Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>");
+MODULE_LICENSE("GPL");
index 76d1792..f5ebcaf 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/dma-buf.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
 #include <linux/sched/clock.h>
 #include <linux/spi/spi.h>
 #include <linux/thermal.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_vblank.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 
 #define REPAPER_RID_G2_COG_ID  0x12
 
 enum repaper_model {
+       /* 0 is reserved to avoid clashing with NULL */
        E1144CS021 = 1,
        E1190CS021,
        E2200CS021,
@@ -856,18 +856,10 @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe,
                                struct drm_plane_state *old_state)
 {
        struct drm_plane_state *state = pipe->plane.state;
-       struct drm_crtc *crtc = &pipe->crtc;
        struct drm_rect rect;
 
        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
                repaper_fb_dirty(state->fb);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-               crtc->state->event = NULL;
-       }
 }
 
 static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = {
@@ -995,21 +987,21 @@ static int repaper_probe(struct spi_device *spi)
 {
        const struct drm_display_mode *mode;
        const struct spi_device_id *spi_id;
-       const struct of_device_id *match;
        struct device *dev = &spi->dev;
        enum repaper_model model;
        const char *thermal_zone;
        struct repaper_epd *epd;
        size_t line_buffer_size;
        struct drm_device *drm;
+       const void *match;
        int ret;
 
-       match = of_match_device(repaper_of_match, dev);
+       match = device_get_match_data(dev);
        if (match) {
-               model = (enum repaper_model)match->data;
+               model = (enum repaper_model)match;
        } else {
                spi_id = spi_get_device_id(spi);
-               model = spi_id->driver_data;
+               model = (enum repaper_model)spi_id->driver_data;
        }
 
        /* The SPI device is used to allocate dma memory */
@@ -1197,7 +1189,6 @@ static void repaper_shutdown(struct spi_device *spi)
 static struct spi_driver repaper_spi_driver = {
        .driver = {
                .name = "repaper",
-               .owner = THIS_MODULE,
                .of_match_table = repaper_of_match,
        },
        .id_table = repaper_id,
index 060cc75..9ef559d 100644 (file)
@@ -23,7 +23,6 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_mipi_dbi.h>
 #include <drm/drm_rect.h>
-#include <drm/drm_vblank.h>
 
 /* controller-specific commands */
 #define ST7586_DISP_MODE_GRAY  0x38
@@ -159,18 +158,10 @@ static void st7586_pipe_update(struct drm_simple_display_pipe *pipe,
                               struct drm_plane_state *old_state)
 {
        struct drm_plane_state *state = pipe->plane.state;
-       struct drm_crtc *crtc = &pipe->crtc;
        struct drm_rect rect;
 
        if (drm_atomic_helper_damage_merged(old_state, state, &rect))
                st7586_fb_dirty(state->fb, &rect);
-
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-               crtc->state->event = NULL;
-       }
 }
 
 static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
index 3f4487c..3cd9b8d 100644 (file)
@@ -1,8 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * DRM driver for Sitronix ST7735R panels
+ * DRM driver for display panels connected to a Sitronix ST7715R or ST7735R
+ * display controller in SPI mode.
  *
  * Copyright 2017 David Lechner <david@lechnology.com>
+ * Copyright (C) 2019 Glider bvba
  */
 
 #include <linux/backlight.h>
 #define ST7735R_MY     BIT(7)
 #define ST7735R_MX     BIT(6)
 #define ST7735R_MV     BIT(5)
+#define ST7735R_RGB    BIT(3)
+
+struct st7735r_cfg {
+       const struct drm_display_mode mode;
+       unsigned int left_offset;
+       unsigned int top_offset;
+       unsigned int write_only:1;
+       unsigned int rgb:1;             /* RGB (vs. BGR) */
+};
+
+struct st7735r_priv {
+       struct mipi_dbi_dev dbidev;     /* Must be first for .release() */
+       const struct st7735r_cfg *cfg;
+};
 
-static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe,
-                                     struct drm_crtc_state *crtc_state,
-                                     struct drm_plane_state *plane_state)
+static void st7735r_pipe_enable(struct drm_simple_display_pipe *pipe,
+                               struct drm_crtc_state *crtc_state,
+                               struct drm_plane_state *plane_state)
 {
        struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
+       struct st7735r_priv *priv = container_of(dbidev, struct st7735r_priv,
+                                                dbidev);
        struct mipi_dbi *dbi = &dbidev->dbi;
        int ret, idx;
        u8 addr_mode;
@@ -87,6 +105,10 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe,
                addr_mode = ST7735R_MY | ST7735R_MV;
                break;
        }
+
+       if (priv->cfg->rgb)
+               addr_mode |= ST7735R_RGB;
+
        mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
        mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
                         MIPI_DCS_PIXEL_FMT_16BIT);
@@ -109,15 +131,24 @@ out_exit:
        drm_dev_exit(idx);
 }
 
-static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = {
-       .enable         = jd_t18003_t01_pipe_enable,
+static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = {
+       .enable         = st7735r_pipe_enable,
        .disable        = mipi_dbi_pipe_disable,
        .update         = mipi_dbi_pipe_update,
        .prepare_fb     = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
 
-static const struct drm_display_mode jd_t18003_t01_mode = {
-       DRM_SIMPLE_MODE(128, 160, 28, 35),
+static const struct st7735r_cfg jd_t18003_t01_cfg = {
+       .mode           = { DRM_SIMPLE_MODE(128, 160, 28, 35) },
+       /* Cannot read from Adafruit 1.8" display via SPI */
+       .write_only     = true,
+};
+
+static const struct st7735r_cfg rh128128t_cfg = {
+       .mode           = { DRM_SIMPLE_MODE(128, 128, 25, 26) },
+       .left_offset    = 2,
+       .top_offset     = 3,
+       .rgb            = true,
 };
 
 DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops);
@@ -136,13 +167,14 @@ static struct drm_driver st7735r_driver = {
 };
 
 static const struct of_device_id st7735r_of_match[] = {
-       { .compatible = "jianda,jd-t18003-t01" },
+       { .compatible = "jianda,jd-t18003-t01", .data = &jd_t18003_t01_cfg },
+       { .compatible = "okaya,rh128128t", .data = &rh128128t_cfg },
        { },
 };
 MODULE_DEVICE_TABLE(of, st7735r_of_match);
 
 static const struct spi_device_id st7735r_id[] = {
-       { "jd-t18003-t01", 0 },
+       { "jd-t18003-t01", (uintptr_t)&jd_t18003_t01_cfg },
        { },
 };
 MODULE_DEVICE_TABLE(spi, st7735r_id);
@@ -150,17 +182,26 @@ MODULE_DEVICE_TABLE(spi, st7735r_id);
 static int st7735r_probe(struct spi_device *spi)
 {
        struct device *dev = &spi->dev;
+       const struct st7735r_cfg *cfg;
        struct mipi_dbi_dev *dbidev;
+       struct st7735r_priv *priv;
        struct drm_device *drm;
        struct mipi_dbi *dbi;
        struct gpio_desc *dc;
        u32 rotation = 0;
        int ret;
 
-       dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL);
-       if (!dbidev)
+       cfg = device_get_match_data(&spi->dev);
+       if (!cfg)
+               cfg = (void *)spi_get_device_id(spi)->driver_data;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
                return -ENOMEM;
 
+       dbidev = &priv->dbidev;
+       priv->cfg = cfg;
+
        dbi = &dbidev->dbi;
        drm = &dbidev->drm;
        ret = devm_drm_dev_init(dev, drm, &st7735r_driver);
@@ -193,10 +234,14 @@ static int st7735r_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       /* Cannot read from Adafruit 1.8" display via SPI */
-       dbi->read_commands = NULL;
+       if (cfg->write_only)
+               dbi->read_commands = NULL;
+
+       dbidev->left_offset = cfg->left_offset;
+       dbidev->top_offset = cfg->top_offset;
 
-       ret = mipi_dbi_dev_init(dbidev, &jd_t18003_t01_pipe_funcs, &jd_t18003_t01_mode, rotation);
+       ret = mipi_dbi_dev_init(dbidev, &st7735r_pipe_funcs, &cfg->mode,
+                               rotation);
        if (ret)
                return ret;
 
@@ -231,7 +276,6 @@ static void st7735r_shutdown(struct spi_device *spi)
 static struct spi_driver st7735r_spi_driver = {
        .driver = {
                .name = "st7735r",
-               .owner = THIS_MODULE,
                .of_match_table = st7735r_of_match,
        },
        .id_table = st7735r_id,
index 5df596f..1fbc36f 100644 (file)
@@ -372,14 +372,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
        }
 
 moved:
-       if (bo->evicted) {
-               if (bdev->driver->invalidate_caches) {
-                       ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
-                       if (ret)
-                               pr_err("Can not flush read caches\n");
-               }
-               bo->evicted = false;
-       }
+       bo->evicted = false;
 
        if (bo->mem.mm_node)
                bo->offset = (bo->mem.start << PAGE_SHIFT) +
@@ -498,8 +491,10 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
 
                dma_resv_unlock(bo->base.resv);
        }
-       if (bo->base.resv != &bo->base._resv)
+       if (bo->base.resv != &bo->base._resv) {
+               ttm_bo_flush_all_fences(bo);
                dma_resv_unlock(&bo->base._resv);
+       }
 
 error:
        kref_get(&bo->list_kref);
index e9671d3..0afdfb0 100644 (file)
@@ -109,7 +109,6 @@ static const struct drm_connector_helper_funcs udl_connector_helper_funcs = {
 };
 
 static const struct drm_connector_funcs udl_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
        .reset = drm_atomic_helper_connector_reset,
        .detect = udl_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
index 22af179..d59ebac 100644 (file)
@@ -375,8 +375,6 @@ udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
        char *wrptr;
        int color_depth = UDL_COLOR_DEPTH_16BPP;
 
-       crtc_state->no_vblank = true;
-
        buf = (char *)udl->mode_buf;
 
        /* This first section has to do with setting the base address on the
@@ -428,14 +426,6 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
        udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer);
 }
 
-static int
-udl_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
-                             struct drm_plane_state *plane_state,
-                             struct drm_crtc_state *crtc_state)
-{
-       return 0;
-}
-
 static void
 udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
                               struct drm_plane_state *old_plane_state)
@@ -457,7 +447,6 @@ struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = {
        .mode_valid = udl_simple_display_pipe_mode_valid,
        .enable = udl_simple_display_pipe_enable,
        .disable = udl_simple_display_pipe_disable,
-       .check = udl_simple_display_pipe_check,
        .update = udl_simple_display_pipe_update,
        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 };
index 1961213..0883a43 100644 (file)
@@ -18,7 +18,6 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_vblank.h>
 
 #include "hgsmi_channels.h"
 #include "vbox_drv.h"
@@ -226,17 +225,6 @@ static void vbox_crtc_atomic_disable(struct drm_crtc *crtc,
 static void vbox_crtc_atomic_flush(struct drm_crtc *crtc,
                                   struct drm_crtc_state *old_crtc_state)
 {
-       struct drm_pending_vblank_event *event;
-       unsigned long flags;
-
-       if (crtc->state && crtc->state->event) {
-               event = crtc->state->event;
-               crtc->state->event = NULL;
-
-               spin_lock_irqsave(&crtc->dev->event_lock, flags);
-               drm_crtc_send_vblank_event(crtc, event);
-               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
-       }
 }
 
 static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
@@ -838,6 +826,7 @@ static int vbox_connector_init(struct drm_device *dev,
 
 static const struct drm_mode_config_funcs vbox_mode_funcs = {
        .fb_create = drm_gem_fb_create_with_dirty,
+       .mode_valid = drm_vram_helper_mode_valid,
        .atomic_check = drm_atomic_helper_check,
        .atomic_commit = drm_atomic_helper_commit,
 };
index 4934127..91e408f 100644 (file)
@@ -139,7 +139,7 @@ static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
 
 static bool plane_enabled(struct drm_plane_state *state)
 {
-       return state->fb && state->crtc;
+       return state->fb && !WARN_ON(!state->crtc);
 }
 
 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
index 5156e6b..e27120d 100644 (file)
@@ -47,6 +47,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_int(m, "cap sets", vgdev->num_capsets);
        virtio_add_int(m, "scanouts", vgdev->num_scanouts);
        return 0;
index 0966208..7b0f064 100644 (file)
@@ -30,7 +30,6 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_vblank.h>
 
 #include "virtgpu_drv.h"
 
@@ -121,13 +120,6 @@ static int virtio_gpu_crtc_atomic_check(struct drm_crtc *crtc,
 static void virtio_gpu_crtc_atomic_flush(struct drm_crtc *crtc,
                                         struct drm_crtc_state *old_state)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&crtc->dev->event_lock, flags);
-       if (crtc->state->event)
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-       crtc->state->event = NULL;
-       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 }
 
 static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
@@ -332,6 +324,7 @@ static void vgdev_atomic_commit_tail(struct drm_atomic_state *state)
        drm_atomic_helper_commit_modeset_enables(dev, state);
        drm_atomic_helper_commit_planes(dev, state, 0);
 
+       drm_atomic_helper_fake_vblank(state);
        drm_atomic_helper_commit_hw_done(state);
 
        drm_atomic_helper_wait_for_vblanks(dev, state);
index 7e69c06..d278c8c 100644 (file)
@@ -193,6 +193,7 @@ struct virtio_gpu_device {
 
        bool has_virgl_3d;
        bool has_edid;
+       bool has_indirect;
 
        struct work_struct config_changed_work;
 
index 2f5773e..c1086df 100644 (file)
@@ -159,6 +159,9 @@ int virtio_gpu_init(struct drm_device *dev)
        if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_EDID)) {
                vgdev->has_edid = true;
        }
+       if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) {
+               vgdev->has_indirect = true;
+       }
 
        DRM_INFO("features: %cvirgl %cedid\n",
                 vgdev->has_virgl_3d ? '+' : '-',
index 5914e79..cc02fc4 100644 (file)
@@ -95,7 +95,8 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
        if (!vbuf)
                return ERR_PTR(-ENOMEM);
 
-       BUG_ON(size > MAX_INLINE_CMD_SIZE);
+       BUG_ON(size > MAX_INLINE_CMD_SIZE ||
+              size < sizeof(struct virtio_gpu_ctrl_hdr));
        vbuf->buf = (void *)vbuf + sizeof(*vbuf);
        vbuf->size = size;
 
@@ -109,6 +110,16 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
        return vbuf;
 }
 
+static struct virtio_gpu_ctrl_hdr *
+virtio_gpu_vbuf_ctrl_hdr(struct virtio_gpu_vbuffer *vbuf)
+{
+       /* this assumes a vbuf contains a command that starts with a
+        * virtio_gpu_ctrl_hdr, which is true for both ctrl and cursor
+        * virtqueues.
+        */
+       return (struct virtio_gpu_ctrl_hdr *)vbuf->buf;
+}
+
 static void *virtio_gpu_alloc_cmd(struct virtio_gpu_device *vgdev,
                                  struct virtio_gpu_vbuffer **vbuffer_p,
                                  int size)
@@ -211,10 +222,10 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work)
                if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) {
                        if (resp->type >= cpu_to_le32(VIRTIO_GPU_RESP_ERR_UNSPEC)) {
                                struct virtio_gpu_ctrl_hdr *cmd;
-                               cmd = (struct virtio_gpu_ctrl_hdr *)entry->buf;
-                               DRM_ERROR("response 0x%x (command 0x%x)\n",
-                                         le32_to_cpu(resp->type),
-                                         le32_to_cpu(cmd->type));
+                               cmd = virtio_gpu_vbuf_ctrl_hdr(entry);
+                               DRM_ERROR_RATELIMITED("response 0x%x (command 0x%x)\n",
+                                                     le32_to_cpu(resp->type),
+                                                     le32_to_cpu(cmd->type));
                        } else
                                DRM_DEBUG("response 0x%x\n", le32_to_cpu(resp->type));
                }
@@ -307,109 +318,113 @@ static struct sg_table *vmalloc_to_sgt(char *data, uint32_t size, int *sg_ents)
        return sgt;
 }
 
-static bool virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev,
-                                               struct virtio_gpu_vbuffer *vbuf,
-                                               struct scatterlist *vout)
-               __releases(&vgdev->ctrlq.qlock)
-               __acquires(&vgdev->ctrlq.qlock)
+static void virtio_gpu_queue_ctrl_sgs(struct virtio_gpu_device *vgdev,
+                                     struct virtio_gpu_vbuffer *vbuf,
+                                     struct virtio_gpu_fence *fence,
+                                     int elemcnt,
+                                     struct scatterlist **sgs,
+                                     int outcnt,
+                                     int incnt)
 {
        struct virtqueue *vq = vgdev->ctrlq.vq;
-       struct scatterlist *sgs[3], vcmd, vresp;
-       int outcnt = 0, incnt = 0;
        bool notify = false;
        int ret;
 
-       if (!vgdev->vqs_ready)
-               return notify;
+       if (vgdev->has_indirect)
+               elemcnt = 1;
 
-       sg_init_one(&vcmd, vbuf->buf, vbuf->size);
-       sgs[outcnt + incnt] = &vcmd;
-       outcnt++;
+again:
+       spin_lock(&vgdev->ctrlq.qlock);
 
-       if (vout) {
-               sgs[outcnt + incnt] = vout;
-               outcnt++;
+       if (!vgdev->vqs_ready) {
+               spin_unlock(&vgdev->ctrlq.qlock);
+
+               if (fence && vbuf->objs)
+                       virtio_gpu_array_unlock_resv(vbuf->objs);
+               return;
        }
 
-       if (vbuf->resp_size) {
-               sg_init_one(&vresp, vbuf->resp_buf, vbuf->resp_size);
-               sgs[outcnt + incnt] = &vresp;
-               incnt++;
+       if (vq->num_free < elemcnt) {
+               spin_unlock(&vgdev->ctrlq.qlock);
+               wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= elemcnt);
+               goto again;
+       }
+
+       /* now that the position of the vbuf in the virtqueue is known, we can
+        * finally set the fence id
+        */
+       if (fence) {
+               virtio_gpu_fence_emit(vgdev, virtio_gpu_vbuf_ctrl_hdr(vbuf),
+                                     fence);
+               if (vbuf->objs) {
+                       virtio_gpu_array_add_fence(vbuf->objs, &fence->f);
+                       virtio_gpu_array_unlock_resv(vbuf->objs);
+               }
        }
 
-retry:
        ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC);
-       if (ret == -ENOSPC) {
-               spin_unlock(&vgdev->ctrlq.qlock);
-               wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= outcnt + incnt);
-               spin_lock(&vgdev->ctrlq.qlock);
-               goto retry;
-       } else {
-               trace_virtio_gpu_cmd_queue(vq,
-                       (struct virtio_gpu_ctrl_hdr *)vbuf->buf);
+       WARN_ON(ret);
 
-               notify = virtqueue_kick_prepare(vq);
+       trace_virtio_gpu_cmd_queue(vq, virtio_gpu_vbuf_ctrl_hdr(vbuf));
+
+       notify = virtqueue_kick_prepare(vq);
+
+       spin_unlock(&vgdev->ctrlq.qlock);
+
+       if (notify) {
+               if (vgdev->disable_notify)
+                       vgdev->pending_notify = true;
+               else
+                       virtqueue_notify(vq);
        }
-       return notify;
 }
 
 static void virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev,
                                                struct virtio_gpu_vbuffer *vbuf,
-                                               struct virtio_gpu_ctrl_hdr *hdr,
                                                struct virtio_gpu_fence *fence)
 {
-       struct virtqueue *vq = vgdev->ctrlq.vq;
-       struct scatterlist *vout = NULL, sg;
+       struct scatterlist *sgs[3], vcmd, vout, vresp;
        struct sg_table *sgt = NULL;
-       bool notify;
-       int outcnt = 0;
+       int elemcnt = 0, outcnt = 0, incnt = 0;
 
+       /* set up vcmd */
+       sg_init_one(&vcmd, vbuf->buf, vbuf->size);
+       elemcnt++;
+       sgs[outcnt] = &vcmd;
+       outcnt++;
+
+       /* set up vout */
        if (vbuf->data_size) {
                if (is_vmalloc_addr(vbuf->data_buf)) {
+                       int sg_ents;
                        sgt = vmalloc_to_sgt(vbuf->data_buf, vbuf->data_size,
-                                            &outcnt);
-                       if (!sgt)
+                                            &sg_ents);
+                       if (!sgt) {
+                               if (fence && vbuf->objs)
+                                       virtio_gpu_array_unlock_resv(vbuf->objs);
                                return;
-                       vout = sgt->sgl;
+                       }
+
+                       elemcnt += sg_ents;
+                       sgs[outcnt] = sgt->sgl;
                } else {
-                       sg_init_one(&sg, vbuf->data_buf, vbuf->data_size);
-                       vout = &sg;
-                       outcnt = 1;
+                       sg_init_one(&vout, vbuf->data_buf, vbuf->data_size);
+                       elemcnt++;
+                       sgs[outcnt] = &vout;
                }
+               outcnt++;
        }
 
-again:
-       spin_lock(&vgdev->ctrlq.qlock);
-
-       /*
-        * Make sure we have enouth space in the virtqueue.  If not
-        * wait here until we have.
-        *
-        * Without that virtio_gpu_queue_ctrl_buffer_nolock might have
-        * to wait for free space, which can result in fence ids being
-        * submitted out-of-order.
-        */
-       if (vq->num_free < 2 + outcnt) {
-               spin_unlock(&vgdev->ctrlq.qlock);
-               wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= 3);
-               goto again;
+       /* set up vresp */
+       if (vbuf->resp_size) {
+               sg_init_one(&vresp, vbuf->resp_buf, vbuf->resp_size);
+               elemcnt++;
+               sgs[outcnt + incnt] = &vresp;
+               incnt++;
        }
 
-       if (hdr && fence) {
-               virtio_gpu_fence_emit(vgdev, hdr, fence);
-               if (vbuf->objs) {
-                       virtio_gpu_array_add_fence(vbuf->objs, &fence->f);
-                       virtio_gpu_array_unlock_resv(vbuf->objs);
-               }
-       }
-       notify = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf, vout);
-       spin_unlock(&vgdev->ctrlq.qlock);
-       if (notify) {
-               if (vgdev->disable_notify)
-                       vgdev->pending_notify = true;
-               else
-                       virtqueue_notify(vgdev->ctrlq.vq);
-       }
+       virtio_gpu_queue_ctrl_sgs(vgdev, vbuf, fence, elemcnt, sgs, outcnt,
+                                 incnt);
 
        if (sgt) {
                sg_free_table(sgt);
@@ -435,7 +450,7 @@ void virtio_gpu_enable_notify(struct virtio_gpu_device *vgdev)
 static void virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev,
                                         struct virtio_gpu_vbuffer *vbuf)
 {
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, NULL, NULL);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, NULL);
 }
 
 static void virtio_gpu_queue_cursor(struct virtio_gpu_device *vgdev,
@@ -464,7 +479,7 @@ retry:
                goto retry;
        } else {
                trace_virtio_gpu_cmd_queue(vq,
-                       (struct virtio_gpu_ctrl_hdr *)vbuf->buf);
+                       virtio_gpu_vbuf_ctrl_hdr(vbuf));
 
                notify = virtqueue_kick_prepare(vq);
        }
@@ -499,7 +514,7 @@ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
        cmd_p->width = cpu_to_le32(params->width);
        cmd_p->height = cpu_to_le32(params->height);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
        bo->created = true;
 }
 
@@ -531,7 +546,7 @@ static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgde
        cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING);
        cmd_p->resource_id = cpu_to_le32(resource_id);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
 void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
@@ -606,7 +621,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev,
        cmd_p->r.x = cpu_to_le32(x);
        cmd_p->r.y = cpu_to_le32(y);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
 static void
@@ -629,7 +644,7 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev,
        vbuf->data_buf = ents;
        vbuf->data_size = sizeof(*ents) * nents;
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
 static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
@@ -988,7 +1003,7 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
        cmd_p->nr_samples = cpu_to_le32(params->nr_samples);
        cmd_p->flags = cpu_to_le32(params->flags);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
        bo->created = true;
 }
 
@@ -1021,7 +1036,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
        cmd_p->offset = cpu_to_le64(offset);
        cmd_p->level = cpu_to_le32(level);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
 void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev,
@@ -1047,7 +1062,7 @@ void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev,
        cmd_p->offset = cpu_to_le64(offset);
        cmd_p->level = cpu_to_le32(level);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
 void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
@@ -1070,7 +1085,7 @@ void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
        cmd_p->hdr.ctx_id = cpu_to_le32(ctx_id);
        cmd_p->size = cpu_to_le32(data_size);
 
-       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+       virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
 int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
index 5fc8f85..6d31265 100644 (file)
@@ -117,7 +117,7 @@ static int vkms_plane_atomic_check(struct drm_plane *plane,
        bool can_position = false;
        int ret;
 
-       if (!state->fb | !state->crtc)
+       if (!state->fb || WARN_ON(!state->crtc))
                return 0;
 
        crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
index d8ea3dd..3f3b2c7 100644 (file)
@@ -736,11 +736,6 @@ out_no_init:
        return NULL;
 }
 
-static int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
-{
-       return 0;
-}
-
 static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                      struct ttm_mem_type_manager *man)
 {
@@ -866,7 +861,6 @@ struct ttm_bo_driver vmw_bo_driver = {
        .ttm_tt_create = &vmw_ttm_tt_create,
        .ttm_tt_populate = &vmw_ttm_populate,
        .ttm_tt_unpopulate = &vmw_ttm_unpopulate,
-       .invalidate_caches = vmw_invalidate_caches,
        .init_mem_type = vmw_init_mem_type,
        .eviction_valuable = ttm_bo_eviction_valuable,
        .evict_flags = vmw_evict_flags,
index 4f34c52..78096bb 100644 (file)
@@ -220,6 +220,24 @@ static bool display_send_page_flip(struct drm_simple_display_pipe *pipe,
        return false;
 }
 
+static int display_check(struct drm_simple_display_pipe *pipe,
+                        struct drm_plane_state *plane_state,
+                        struct drm_crtc_state *crtc_state)
+{
+       /*
+        * Xen doesn't initialize vblanking via drm_vblank_init(), so
+        * DRM helpers assume that it doesn't handle vblanking and start
+        * sending out fake VBLANK events automatically.
+        *
+        * As xen contains it's own logic for sending out VBLANK events
+        * in send_pending_event(), disable no_vblank (i.e., the xen
+        * driver has vblanking support).
+        */
+       crtc_state->no_vblank = false;
+
+       return 0;
+}
+
 static void display_update(struct drm_simple_display_pipe *pipe,
                           struct drm_plane_state *old_plane_state)
 {
@@ -284,6 +302,7 @@ static const struct drm_simple_display_pipe_funcs display_funcs = {
        .enable = display_enable,
        .disable = display_disable,
        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+       .check = display_check,
        .update = display_update,
 };
 
index 086c50f..c8f7b21 100644 (file)
@@ -54,7 +54,7 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane,
        int min_scale = FRAC_16_16(1, 8);
        int max_scale = FRAC_16_16(8, 1);
 
-       if (!crtc || !fb)
+       if (!crtc || WARN_ON(!fb))
                return 0;
 
        crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
@@ -281,7 +281,7 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane,
        struct drm_crtc *crtc = plane_state->crtc;
        struct drm_crtc_state *crtc_state;
 
-       if (!crtc || !fb)
+       if (!crtc || WARN_ON(!fb))
                return 0;
 
        crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
index 403707a..95e2000 100644 (file)
@@ -9,7 +9,7 @@ menu "Backlight & LCD device support"
 # LCD
 #
 config LCD_CLASS_DEVICE
-        tristate "Lowlevel LCD controls"
+       tristate "Lowlevel LCD controls"
        help
          This framework adds support for low-level control of LCD.
          Some framebuffer devices connect to platform-specific LCD modules
@@ -141,10 +141,10 @@ endif # LCD_CLASS_DEVICE
 # Backlight
 #
 config BACKLIGHT_CLASS_DEVICE
-        tristate "Lowlevel Backlight controls"
+       tristate "Lowlevel Backlight controls"
        help
          This framework adds support for low-level control of the LCD
-          backlight. This includes support for brightness and power.
+         backlight. This includes support for brightness and power.
 
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
@@ -272,7 +272,7 @@ config BACKLIGHT_APPLE
        tristate "Apple Backlight Driver"
        depends on X86 && ACPI
        help
-         If you have an Intel-based Apple say Y to enable a driver for its
+        If you have an Intel-based Apple say Y to enable a driver for its
         backlight.
 
 config BACKLIGHT_TOSA
index 70c10ea..3c01b0d 100644 (file)
@@ -27,7 +27,7 @@ config VGACON_SOFT_SCROLLBACK
        depends on VGA_CONSOLE
        default n
        help
-         The scrollback buffer of the standard VGA console is located in
+        The scrollback buffer of the standard VGA console is located in
         the VGA RAM.  The size of this RAM is fixed and is quite small.
         If you require a larger scrollback buffer, this can be placed in
         System RAM which is dynamically allocated during initialization.
@@ -84,36 +84,36 @@ config MDA_CONSOLE
          If unsure, say N.
 
 config SGI_NEWPORT_CONSOLE
-        tristate "SGI Newport Console support"
+       tristate "SGI Newport Console support"
        depends on SGI_IP22 && HAS_IOMEM
-        select FONT_SUPPORT
-        help
-          Say Y here if you want the console on the Newport aka XL graphics
-          card of your Indy.  Most people say Y here.
+       select FONT_SUPPORT
+       help
+         Say Y here if you want the console on the Newport aka XL graphics
+         card of your Indy.  Most people say Y here.
 
 config DUMMY_CONSOLE
        bool
        default y
 
 config DUMMY_CONSOLE_COLUMNS
-        int "Initial number of console screen columns"
-        depends on DUMMY_CONSOLE && !ARM
-        default 160 if PARISC
-        default 80
-        help
-          On PA-RISC, the default value is 160, which should fit a 1280x1024
-          monitor.
-          Select 80 if you use a 640x480 resolution by default.
+       int "Initial number of console screen columns"
+       depends on DUMMY_CONSOLE && !ARM
+       default 160 if PARISC
+       default 80
+       help
+         On PA-RISC, the default value is 160, which should fit a 1280x1024
+         monitor.
+         Select 80 if you use a 640x480 resolution by default.
 
 config DUMMY_CONSOLE_ROWS
-        int "Initial number of console screen rows"
-        depends on DUMMY_CONSOLE && !ARM
-        default 64 if PARISC
-        default 25
-        help
-          On PA-RISC, the default value is 64, which should fit a 1280x1024
-          monitor.
-          Select 25 if you use a 640x480 resolution by default.
+       int "Initial number of console screen rows"
+       depends on DUMMY_CONSOLE && !ARM
+       default 64 if PARISC
+       default 25
+       help
+         On PA-RISC, the default value is 64, which should fit a 1280x1024
+         monitor.
+         Select 25 if you use a 640x480 resolution by default.
 
 config FRAMEBUFFER_CONSOLE
        bool "Framebuffer Console support"
@@ -129,11 +129,11 @@ config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
        depends on FRAMEBUFFER_CONSOLE
        default n
        ---help---
-         If this option is selected, the framebuffer console will
-         automatically select the primary display device (if the architecture
+        If this option is selected, the framebuffer console will
+        automatically select the primary display device (if the architecture
         supports this feature).  Otherwise, the framebuffer console will
-         always select the first framebuffer driver that is loaded. The latter
-         is the default behavior.
+        always select the first framebuffer driver that is loaded. The latter
+        is the default behavior.
 
         You can always override the automatic selection of the primary device
         by using the fbcon=map: boot option.
@@ -144,11 +144,11 @@ config FRAMEBUFFER_CONSOLE_ROTATION
        bool "Framebuffer Console Rotation"
        depends on FRAMEBUFFER_CONSOLE
        help
-         Enable display rotation for the framebuffer console.  This is done
-         in software and may be significantly slower than a normally oriented
-         display.  Note that the rotation is done at the console level only
-         such that other users of the framebuffer will remain normally
-         oriented.
+        Enable display rotation for the framebuffer console.  This is done
+        in software and may be significantly slower than a normally oriented
+        display.  Note that the rotation is done at the console level only
+        such that other users of the framebuffer will remain normally
+        oriented.
 
 config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
        bool "Framebuffer Console Deferred Takeover"
@@ -162,14 +162,14 @@ config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
          black screen as soon as fbcon loads.
 
 config STI_CONSOLE
-        bool "STI text console"
+       bool "STI text console"
        depends on PARISC && HAS_IOMEM
-        select FONT_SUPPORT
-        default y
-        help
-          The STI console is the builtin display/keyboard on HP-PARISC
-          machines.  Say Y here to build support for it into your kernel.
-          The alternative is to use your primary serial port as a console.
+       select FONT_SUPPORT
+       default y
+       help
+         The STI console is the builtin display/keyboard on HP-PARISC
+         machines.  Say Y here to build support for it into your kernel.
+         The alternative is to use your primary serial port as a console.
 
 endmenu
 
index a620b51..6a745eb 100644 (file)
@@ -509,8 +509,7 @@ static int cg14_probe(struct platform_device *op)
        if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
                goto out_unmap_regs;
 
-       is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) ==
-                 (8 * 1024 * 1024));
+       is_8mb = (resource_size(&op->resource[1]) == (8 * 1024 * 1024));
 
        BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map));
                
index 3771031..26cbc96 100644 (file)
@@ -16,7 +16,6 @@ fb-y                            += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
                                     fbcon_ccw.o
 endif
 endif
-fb-objs                           := $(fb-y)
 
 obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
 obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
index bb6ae99..2833578 100644 (file)
@@ -873,7 +873,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
        int oldidx = con2fb_map[unit];
        struct fb_info *info = registered_fb[newidx];
        struct fb_info *oldinfo = NULL;
-       int found, err = 0;
+       int found, err = 0;
 
        WARN_CONSOLE_UNLOCKED();
 
@@ -895,31 +895,30 @@ static int set_con2fb_map(int unit, int newidx, int user)
 
        con2fb_map[unit] = newidx;
        if (!err && !found)
-               err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
-
+               err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
 
        /*
         * If old fb is not mapped to any of the consoles,
         * fbcon should release it.
         */
-       if (!err && oldinfo && !search_fb_in_map(oldidx))
-               err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx,
-                                            found);
+       if (!err && oldinfo && !search_fb_in_map(oldidx))
+               err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx,
+                                            found);
 
-       if (!err) {
-               int show_logo = (fg_console == 0 && !user &&
-                                logo_shown != FBCON_LOGO_DONTSHOW);
+       if (!err) {
+               int show_logo = (fg_console == 0 && !user &&
+                                logo_shown != FBCON_LOGO_DONTSHOW);
 
-               if (!found)
-                       fbcon_add_cursor_timer(info);
-               con2fb_map_boot[unit] = newidx;
-               con2fb_init_display(vc, info, unit, show_logo);
+               if (!found)
+                       fbcon_add_cursor_timer(info);
+               con2fb_map_boot[unit] = newidx;
+               con2fb_init_display(vc, info, unit, show_logo);
        }
 
        if (!search_fb_in_map(info_idx))
                info_idx = newidx;
 
-       return err;
+       return err;
 }
 
 /*
index d045549..30e73ec 100644 (file)
@@ -663,20 +663,20 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
                fb_logo.depth = 1;
 
 
-       if (fb_logo.depth > 4 && depth > 4) {
-               switch (info->fix.visual) {
-               case FB_VISUAL_TRUECOLOR:
-                       fb_logo.needs_truepalette = 1;
-                       break;
-               case FB_VISUAL_DIRECTCOLOR:
-                       fb_logo.needs_directpalette = 1;
-                       fb_logo.needs_cmapreset = 1;
-                       break;
-               case FB_VISUAL_PSEUDOCOLOR:
-                       fb_logo.needs_cmapreset = 1;
-                       break;
-               }
-       }
+       if (fb_logo.depth > 4 && depth > 4) {
+               switch (info->fix.visual) {
+               case FB_VISUAL_TRUECOLOR:
+                       fb_logo.needs_truepalette = 1;
+                       break;
+               case FB_VISUAL_DIRECTCOLOR:
+                       fb_logo.needs_directpalette = 1;
+                       fb_logo.needs_cmapreset = 1;
+                       break;
+               case FB_VISUAL_PSEUDOCOLOR:
+                       fb_logo.needs_cmapreset = 1;
+                       break;
+               }
+       }
 
        height = fb_logo.logo->height;
        if (fb_center_logo)
@@ -1065,19 +1065,19 @@ fb_blank(struct fb_info *info, int blank)
        struct fb_event event;
        int ret = -EINVAL;
 
-       if (blank > FB_BLANK_POWERDOWN)
-               blank = FB_BLANK_POWERDOWN;
+       if (blank > FB_BLANK_POWERDOWN)
+               blank = FB_BLANK_POWERDOWN;
 
        event.info = info;
        event.data = &blank;
 
        if (info->fbops->fb_blank)
-               ret = info->fbops->fb_blank(blank, info);
+               ret = info->fbops->fb_blank(blank, info);
 
        if (!ret)
                fb_notifier_call_chain(FB_EVENT_BLANK, &event);
 
-       return ret;
+       return ret;
 }
 EXPORT_SYMBOL(fb_blank);
 
@@ -1115,7 +1115,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                break;
        case FBIOGET_FSCREENINFO:
                lock_fb_info(info);
-               fix = info->fix;
+               memcpy(&fix, &info->fix, sizeof(fix));
                if (info->flags & FBINFO_HIDE_SMEM_START)
                        fix.smem_start = 0;
                unlock_fb_info(info);
index f47d50e..e4c3c8b 100644 (file)
@@ -594,8 +594,8 @@ static int synthvid_get_supported_resolution(struct hv_device *hdev)
        t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
        if (!t) {
                pr_err("Time out on waiting resolution response\n");
-                       ret = -ETIMEDOUT;
-                       goto out;
+               ret = -ETIMEDOUT;
+               goto out;
        }
 
        if (msg->resolution_resp.resolution_count == 0) {
index c583c01..c24de91 100644 (file)
@@ -168,27 +168,26 @@ static int nvidia_panel_tweak(struct nvidia_par *par,
 {
        int tweak = 0;
 
-   if (par->paneltweak) {
-          tweak = par->paneltweak;
-   } else {
-          /* begin flat panel hacks */
-          /* This is unfortunate, but some chips need this register
-             tweaked or else you get artifacts where adjacent pixels are
-             swapped.  There are no hard rules for what to set here so all
-             we can do is experiment and apply hacks. */
-
-          if(((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
-                  /* At least one NV34 laptop needs this workaround. */
-                  tweak = -1;
-          }
-
-          if((par->Chipset & 0xfff0) == 0x0310) {
-                  tweak = 1;
-          }
-          /* end flat panel hacks */
-   }
-
-   return tweak;
+       if (par->paneltweak) {
+               tweak = par->paneltweak;
+       } else {
+               /* Begin flat panel hacks.
+                * This is unfortunate, but some chips need this register
+                * tweaked or else you get artifacts where adjacent pixels are
+                * swapped.  There are no hard rules for what to set here so all
+                * we can do is experiment and apply hacks.
+                */
+               if (((par->Chipset & 0xffff) == 0x0328) && (state->bpp == 32)) {
+                       /* At least one NV34 laptop needs this workaround. */
+                       tweak = -1;
+               }
+
+               if ((par->Chipset & 0xfff0) == 0x0310)
+                       tweak = 1;
+               /* end flat panel hacks */
+       }
+
+       return tweak;
 }
 
 static void nvidia_screen_off(struct nvidia_par *par, int on)
index 8dfa915..836e7b1 100644 (file)
@@ -1154,16 +1154,12 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
                   r = fbdev->ctrl->setcolreg(regno, red, green, blue,
                   transp, update_hw_pal);
                   */
-               /* Fallthrough */
                r = -EINVAL;
                break;
        case OMAPFB_COLOR_RGB565:
        case OMAPFB_COLOR_RGB444:
        case OMAPFB_COLOR_RGB24P:
        case OMAPFB_COLOR_RGB24U:
-               if (r != 0)
-                       break;
-
                if (regno < 16) {
                        u32 pal;
                        pal = ((red >> (16 - var->red.length)) <<
index 9b9ec14..706c694 100644 (file)
@@ -769,7 +769,7 @@ failed_free_fbmem:
        dma_free_wc(fbi->dev, info->fix.smem_len,
                    info->screen_base, fbi->fb_start_dma);
 failed_free_info:
-       kfree(info);
+       framebuffer_release(info);
 
        dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
        return ret;
index 8048499..eaea8c3 100644 (file)
@@ -746,9 +746,9 @@ s1d13xxxfb_remove(struct platform_device *pdev)
        }
 
        release_mem_region(pdev->resource[0].start,
-                       pdev->resource[0].end - pdev->resource[0].start +1);
+                          resource_size(&pdev->resource[0]));
        release_mem_region(pdev->resource[1].start,
-                       pdev->resource[1].end - pdev->resource[1].start +1);
+                          resource_size(&pdev->resource[1]));
        return 0;
 }
 
@@ -788,14 +788,14 @@ static int s1d13xxxfb_probe(struct platform_device *pdev)
        }
 
        if (!request_mem_region(pdev->resource[0].start,
-               pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) {
+               resource_size(&pdev->resource[0]), "s1d13xxxfb mem")) {
                dev_dbg(&pdev->dev, "request_mem_region failed\n");
                ret = -EBUSY;
                goto bail;
        }
 
        if (!request_mem_region(pdev->resource[1].start,
-               pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) {
+               resource_size(&pdev->resource[1]), "s1d13xxxfb regs")) {
                dev_dbg(&pdev->dev, "request_mem_region failed\n");
                ret = -EBUSY;
                goto bail;
@@ -810,7 +810,7 @@ static int s1d13xxxfb_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, info);
        default_par = info->par;
        default_par->regs = ioremap(pdev->resource[1].start,
-                       pdev->resource[1].end - pdev->resource[1].start +1);
+                                   resource_size(&pdev->resource[1]));
        if (!default_par->regs) {
                printk(KERN_ERR PFX "unable to map registers\n");
                ret = -ENOMEM;
@@ -819,7 +819,7 @@ static int s1d13xxxfb_probe(struct platform_device *pdev)
        info->pseudo_palette = default_par->pseudo_palette;
 
        info->screen_base = ioremap(pdev->resource[0].start,
-                       pdev->resource[0].end - pdev->resource[0].start +1);
+                                   resource_size(&pdev->resource[0]));
 
        if (!info->screen_base) {
                printk(KERN_ERR PFX "unable to map framebuffer\n");
@@ -857,9 +857,9 @@ static int s1d13xxxfb_probe(struct platform_device *pdev)
 
        info->fix = s1d13xxxfb_fix;
        info->fix.mmio_start = pdev->resource[1].start;
-       info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start + 1;
+       info->fix.mmio_len = resource_size(&pdev->resource[1]);
        info->fix.smem_start = pdev->resource[0].start;
-       info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+       info->fix.smem_len = resource_size(&pdev->resource[0]);
 
        printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
               default_par->regs, info->fix.smem_len / 1024, info->screen_base);
index 5bb653d..2d285cc 100644 (file)
@@ -1053,7 +1053,7 @@ static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 }
 
 /* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs = {
+static const struct fb_monspecs monspecs = {
        .hfmin  = 30000,
        .hfmax  = 70000,
        .vfmin  = 50,
index 1425352..1a0bd78 100644 (file)
@@ -791,6 +791,8 @@ static int ssd1307fb_remove(struct i2c_client *client)
                pwm_disable(par->pwm);
                pwm_put(par->pwm);
        }
+       if (par->vbat_reg)
+               regulator_disable(par->vbat_reg);
        fb_deferred_io_cleanup(info);
        __free_pages(__va(info->fix.smem_start), get_order(info->fix.smem_len));
        framebuffer_release(info);
index 951dfb1..52d65a0 100644 (file)
@@ -670,6 +670,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
 }
 
 int __must_check
+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
+                              struct drm_encoder *encoder);
+int __must_check
 drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
                                   struct drm_crtc *crtc);
 int __must_check
@@ -992,4 +995,77 @@ drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
        return state->active || state->self_refresh_active;
 }
 
+/**
+ * struct drm_bus_cfg - bus configuration
+ *
+ * This structure stores the configuration of a physical bus between two
+ * components in an output pipeline, usually between two bridges, an encoder
+ * and a bridge, or a bridge and a connector.
+ *
+ * The bus configuration is stored in &drm_bridge_state separately for the
+ * input and output buses, as seen from the point of view of each bridge. The
+ * bus configuration of a bridge output is usually identical to the
+ * configuration of the next bridge's input, but may differ if the signals are
+ * modified between the two bridges, for instance by an inverter on the board.
+ * The input and output configurations of a bridge may differ if the bridge
+ * modifies the signals internally, for instance by performing format
+ * conversion, or modifying signals polarities.
+ */
+struct drm_bus_cfg {
+       /**
+        * @format: format used on this bus (one of the MEDIA_BUS_FMT_* format)
+        *
+        * This field should not be directly modified by drivers
+        * (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus
+        * format negotiation).
+        */
+       u32 format;
+
+       /**
+        * @flags: DRM_BUS_* flags used on this bus
+        */
+       u32 flags;
+};
+
+/**
+ * struct drm_bridge_state - Atomic bridge state object
+ */
+struct drm_bridge_state {
+       /**
+        * @base: inherit from &drm_private_state
+        */
+       struct drm_private_state base;
+
+       /**
+        * @bridge: the bridge this state refers to
+        */
+       struct drm_bridge *bridge;
+
+       /**
+        * @input_bus_cfg: input bus configuration
+        */
+       struct drm_bus_cfg input_bus_cfg;
+
+       /**
+        * @output_bus_cfg: input bus configuration
+        */
+       struct drm_bus_cfg output_bus_cfg;
+};
+
+static inline struct drm_bridge_state *
+drm_priv_to_bridge_state(struct drm_private_state *priv)
+{
+       return container_of(priv, struct drm_bridge_state, base);
+}
+
+struct drm_bridge_state *
+drm_atomic_get_bridge_state(struct drm_atomic_state *state,
+                           struct drm_bridge *bridge);
+struct drm_bridge_state *
+drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
+                               struct drm_bridge *bridge);
+struct drm_bridge_state *
+drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
+                               struct drm_bridge *bridge);
+
 #endif /* DRM_ATOMIC_H_ */
index 9db3cac..b268180 100644 (file)
@@ -224,4 +224,12 @@ drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state,
        return old_plane_state->crtc && !new_plane_state->crtc;
 }
 
+u32 *
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
+                                       struct drm_bridge_state *bridge_state,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state,
+                                       u32 output_fmt,
+                                       unsigned int *num_input_fmts);
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
index 8171dea..3f8f1d6 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <linux/types.h>
 
+struct drm_bridge;
+struct drm_bridge_state;
 struct drm_crtc;
 struct drm_crtc_state;
 struct drm_plane;
@@ -80,3 +82,14 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state);
 void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
                                                     struct drm_private_state *state);
+
+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
+                                               struct drm_bridge_state *state);
+struct drm_bridge_state *
+drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge);
+void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
+                                           struct drm_bridge_state *state);
+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
+                                     struct drm_bridge_state *state);
+struct drm_bridge_state *
+drm_atomic_helper_bridge_reset(struct drm_bridge *bridge);
index 694e153..45626ec 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <linux/list.h>
 #include <linux/ctype.h>
+
+#include <drm/drm_atomic.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_mode_object.h>
 #include <drm/drm_modes.h>
@@ -109,7 +111,9 @@ struct drm_bridge_funcs {
         * this function passes all other callbacks must succeed for this
         * configuration.
         *
-        * The @mode_fixup callback is optional.
+        * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup()
+        * is not called when &drm_bridge_funcs.atomic_check() is implemented,
+        * so only one of them should be provided.
         *
         * NOTE:
         *
@@ -263,7 +267,7 @@ struct drm_bridge_funcs {
         * The @atomic_pre_enable callback is optional.
         */
        void (*atomic_pre_enable)(struct drm_bridge *bridge,
-                                 struct drm_atomic_state *old_state);
+                                 struct drm_bridge_state *old_bridge_state);
 
        /**
         * @atomic_enable:
@@ -288,7 +292,7 @@ struct drm_bridge_funcs {
         * The @atomic_enable callback is optional.
         */
        void (*atomic_enable)(struct drm_bridge *bridge,
-                             struct drm_atomic_state *old_state);
+                             struct drm_bridge_state *old_bridge_state);
        /**
         * @atomic_disable:
         *
@@ -311,7 +315,7 @@ struct drm_bridge_funcs {
         * The @atomic_disable callback is optional.
         */
        void (*atomic_disable)(struct drm_bridge *bridge,
-                              struct drm_atomic_state *old_state);
+                              struct drm_bridge_state *old_bridge_state);
 
        /**
         * @atomic_post_disable:
@@ -337,7 +341,153 @@ struct drm_bridge_funcs {
         * The @atomic_post_disable callback is optional.
         */
        void (*atomic_post_disable)(struct drm_bridge *bridge,
-                                   struct drm_atomic_state *old_state);
+                                   struct drm_bridge_state *old_bridge_state);
+
+       /**
+        * @atomic_duplicate_state:
+        *
+        * Duplicate the current bridge state object (which is guaranteed to be
+        * non-NULL).
+        *
+        * The atomic_duplicate_state() is optional. When not implemented the
+        * core allocates a drm_bridge_state object and calls
+        * &__drm_atomic_helper_bridge_duplicate_state() to initialize it.
+        *
+        * RETURNS:
+        * A valid drm_bridge_state object or NULL if the allocation fails.
+        */
+       struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge);
+
+       /**
+        * @atomic_destroy_state:
+        *
+        * Destroy a bridge state object previously allocated by
+        * &drm_bridge_funcs.atomic_duplicate_state().
+        *
+        * The atomic_destroy_state hook is optional. When not implemented the
+        * core calls kfree() on the state.
+        */
+       void (*atomic_destroy_state)(struct drm_bridge *bridge,
+                                    struct drm_bridge_state *state);
+
+       /**
+        * @atomic_get_output_bus_fmts:
+        *
+        * Return the supported bus formats on the output end of a bridge.
+        * The returned array must be allocated with kmalloc() and will be
+        * freed by the caller. If the allocation fails, NULL should be
+        * returned. num_output_fmts must be set to the returned array size.
+        * Formats listed in the returned array should be listed in decreasing
+        * preference order (the core will try all formats until it finds one
+        * that works).
+        *
+        * This method is only called on the last element of the bridge chain
+        * as part of the bus format negotiation process that happens in
+        * &drm_atomic_bridge_chain_select_bus_fmts().
+        * This method is optional. When not implemented, the core will
+        * fall back to &drm_connector.display_info.bus_formats[0] if
+        * &drm_connector.display_info.num_bus_formats > 0,
+        * or to MEDIA_BUS_FMT_FIXED otherwise.
+        */
+       u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge,
+                                          struct drm_bridge_state *bridge_state,
+                                          struct drm_crtc_state *crtc_state,
+                                          struct drm_connector_state *conn_state,
+                                          unsigned int *num_output_fmts);
+
+       /**
+        * @atomic_get_input_bus_fmts:
+        *
+        * Return the supported bus formats on the input end of a bridge for
+        * a specific output bus format.
+        *
+        * The returned array must be allocated with kmalloc() and will be
+        * freed by the caller. If the allocation fails, NULL should be
+        * returned. num_output_fmts must be set to the returned array size.
+        * Formats listed in the returned array should be listed in decreasing
+        * preference order (the core will try all formats until it finds one
+        * that works). When the format is not supported NULL should be
+        * returned and *num_output_fmts should be set to 0.
+        *
+        * This method is called on all elements of the bridge chain as part of
+        * the bus format negotiation process that happens in
+        * &drm_atomic_bridge_chain_select_bus_fmts().
+        * This method is optional. When not implemented, the core will bypass
+        * bus format negotiation on this element of the bridge without
+        * failing, and the previous element in the chain will be passed
+        * MEDIA_BUS_FMT_FIXED as its output bus format.
+        *
+        * Bridge drivers that need to support being linked to bridges that are
+        * not supporting bus format negotiation should handle the
+        * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a
+        * sensible default value or extracting this information from somewhere
+        * else (FW property, &drm_display_mode, &drm_display_info, ...)
+        *
+        * Note: Even if input format selection on the first bridge has no
+        * impact on the negotiation process (bus format negotiation stops once
+        * we reach the first element of the chain), drivers are expected to
+        * return accurate input formats as the input format may be used to
+        * configure the CRTC output appropriately.
+        */
+       u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge,
+                                         struct drm_bridge_state *bridge_state,
+                                         struct drm_crtc_state *crtc_state,
+                                         struct drm_connector_state *conn_state,
+                                         u32 output_fmt,
+                                         unsigned int *num_input_fmts);
+
+       /**
+        * @atomic_check:
+        *
+        * This method is responsible for checking bridge state correctness.
+        * It can also check the state of the surrounding components in chain
+        * to make sure the whole pipeline can work properly.
+        *
+        * &drm_bridge_funcs.atomic_check() hooks are called in reverse
+        * order (from the last to the first bridge).
+        *
+        * This method is optional. &drm_bridge_funcs.mode_fixup() is not
+        * called when &drm_bridge_funcs.atomic_check() is implemented, so only
+        * one of them should be provided.
+        *
+        * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or
+        * &drm_bridge_state.output_bus_cfg.flags it should should happen in
+        * this function. By default the &drm_bridge_state.output_bus_cfg.flags
+        * field is set to the next bridge
+        * &drm_bridge_state.input_bus_cfg.flags value or
+        * &drm_connector.display_info.bus_flags if the bridge is the last
+        * element in the chain.
+        *
+        * RETURNS:
+        * zero if the check passed, a negative error code otherwise.
+        */
+       int (*atomic_check)(struct drm_bridge *bridge,
+                           struct drm_bridge_state *bridge_state,
+                           struct drm_crtc_state *crtc_state,
+                           struct drm_connector_state *conn_state);
+
+       /**
+        * @atomic_reset:
+        *
+        * Reset the bridge to a predefined state (or retrieve its current
+        * state) and return a &drm_bridge_state object matching this state.
+        * This function is called at attach time.
+        *
+        * The atomic_reset hook is mandatory if the bridge implements any of
+        * the atomic hooks, and should be left unassigned otherwise.
+        *
+        * Note that the atomic_reset() semantics is not exactly matching the
+        * reset() semantics found on other components (connector, plane, ...).
+        * 1/ The reset operation happens when the bridge is attached, not when
+        *    drm_mode_config_reset() is called
+        * 2/ It's meant to be used exclusively on bridges that have been
+        *    converted to the ATOMIC API
+        *
+        * RETURNS:
+        * A valid drm_bridge_state object in case of success, an ERR_PTR()
+        * giving the reason of the failure otherwise.
+        */
+       struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge);
 };
 
 /**
@@ -380,6 +530,8 @@ struct drm_bridge_timings {
  * struct drm_bridge - central DRM bridge control structure
  */
 struct drm_bridge {
+       /** @base: inherit from &drm_private_object */
+       struct drm_private_obj base;
        /** @dev: DRM device this bridge belongs to */
        struct drm_device *dev;
        /** @encoder: encoder to which this bridge is connected */
@@ -404,6 +556,12 @@ struct drm_bridge {
        void *driver_private;
 };
 
+static inline struct drm_bridge *
+drm_priv_to_bridge(struct drm_private_obj *priv)
+{
+       return container_of(priv, struct drm_bridge, base);
+}
+
 void drm_bridge_add(struct drm_bridge *bridge);
 void drm_bridge_remove(struct drm_bridge *bridge);
 struct drm_bridge *of_drm_find_bridge(struct device_node *np);
@@ -482,6 +640,9 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
 void drm_bridge_chain_pre_enable(struct drm_bridge *bridge);
 void drm_bridge_chain_enable(struct drm_bridge *bridge);
 
+int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
+                                 struct drm_crtc_state *crtc_state,
+                                 struct drm_connector_state *conn_state);
 void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
                                     struct drm_atomic_state *state);
 void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
@@ -491,6 +652,14 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
 void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
                                    struct drm_atomic_state *state);
 
+u32 *
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
+                                       struct drm_bridge_state *bridge_state,
+                                       struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state,
+                                       u32 output_fmt,
+                                       unsigned int *num_input_fmts);
+
 #ifdef CONFIG_DRM_PANEL_BRIDGE
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel);
 struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
index 2219109..2113500 100644 (file)
@@ -1552,8 +1552,13 @@ void drm_connector_set_link_status_property(struct drm_connector *connector,
                                            uint64_t link_status);
 void drm_connector_set_vrr_capable_property(
                struct drm_connector *connector, bool capable);
-int drm_connector_init_panel_orientation_property(
-       struct drm_connector *connector, int width, int height);
+int drm_connector_set_panel_orientation(
+       struct drm_connector *connector,
+       enum drm_panel_orientation panel_orientation);
+int drm_connector_set_panel_orientation_with_quirk(
+       struct drm_connector *connector,
+       enum drm_panel_orientation panel_orientation,
+       int width, int height);
 int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
                                          int min, int max);
 
index 5e9b15a..6bef2f4 100644 (file)
@@ -174,12 +174,25 @@ struct drm_crtc_state {
         * @no_vblank:
         *
         * Reflects the ability of a CRTC to send VBLANK events. This state
-        * usually depends on the pipeline configuration, and the main usuage
-        * is CRTCs feeding a writeback connector operating in oneshot mode.
-        * In this case the VBLANK event is only generated when a job is queued
-        * to the writeback connector, and we want the core to fake VBLANK
-        * events when this part of the pipeline hasn't changed but others had
-        * or when the CRTC and connectors are being disabled.
+        * usually depends on the pipeline configuration. If set to true, DRM
+        * atomic helpers will send out a fake VBLANK event during display
+        * updates after all hardware changes have been committed. This is
+        * implemented in drm_atomic_helper_fake_vblank().
+        *
+        * One usage is for drivers and/or hardware without support for VBLANK
+        * interrupts. Such drivers typically do not initialize vblanking
+        * (i.e., call drm_vblank_init() with the number of CRTCs). For CRTCs
+        * without initialized vblanking, this field is set to true in
+        * drm_atomic_helper_check_modeset(), and a fake VBLANK event will be
+        * send out on each update of the display pipeline by
+        * drm_atomic_helper_fake_vblank().
+        *
+        * Another usage is CRTCs feeding a writeback connector operating in
+        * oneshot mode. In this case the fake VBLANK event is only generated
+        * when a job is queued to the writeback connector, and we want the
+        * core to fake VBLANK events when this part of the pipeline hasn't
+        * changed but others had or when the CRTC and connectors are being
+        * disabled.
         *
         * __drm_atomic_helper_crtc_duplicate_state() will not reset the value
         * from the current state, the CRTC driver is then responsible for
@@ -335,7 +348,14 @@ struct drm_crtc_state {
         *  - Events for disabled CRTCs are not allowed, and drivers can ignore
         *    that case.
         *
-        * This can be handled by the drm_crtc_send_vblank_event() function,
+        * For very simple hardware without VBLANK interrupt, enabling
+        * &struct drm_crtc_state.no_vblank makes DRM's atomic commit helpers
+        * send a fake VBLANK event at the end of the display update after all
+        * hardware changes have been applied. See
+        * drm_atomic_helper_fake_vblank().
+        *
+        * For more complex hardware this
+        * can be handled by the drm_crtc_send_vblank_event() function,
         * which the driver should call on the provided event upon completion of
         * the atomic commit. Note that if the driver supports vblank signalling
         * and timestamping the vblank counters and timestamps must agree with
index 1acfc3b..bb60a94 100644 (file)
@@ -144,7 +144,7 @@ struct drm_device {
         * Usage counter for outstanding files open,
         * protected by drm_global_mutex
         */
-       int open_count;
+       atomic_t open_count;
 
        /** @filelist_mutex: Protects @filelist. */
        struct mutex filelist_mutex;
index bc04467..262faf9 100644 (file)
 # define DP_DS_12BPC                       2
 # define DP_DS_16BPC                       3
 
+#define DP_MAX_DOWNSTREAM_PORTS                    0x10
+
 /* DP Forward error Correction Registers */
 #define DP_FEC_CAPABILITY                  0x090    /* 1.4 */
 # define DP_FEC_CAPABLE                            (1 << 0)
index bcb39da..5483f88 100644 (file)
@@ -635,11 +635,13 @@ struct drm_dp_mst_topology_mgr {
        struct mutex payload_lock;
        /**
         * @proposed_vcpis: Array of pointers for the new VCPI allocation. The
-        * VCPI structure itself is &drm_dp_mst_port.vcpi.
+        * VCPI structure itself is &drm_dp_mst_port.vcpi, and the size of
+        * this array is determined by @max_payloads.
         */
        struct drm_dp_vcpi **proposed_vcpis;
        /**
-        * @payloads: Array of payloads.
+        * @payloads: Array of payloads. The size of this array is determined
+        * by @max_payloads.
         */
        struct drm_dp_payload *payloads;
        /**
index cf13470..77685ed 100644 (file)
@@ -458,20 +458,6 @@ struct drm_driver {
        void (*irq_uninstall) (struct drm_device *dev);
 
        /**
-        * @master_create:
-        *
-        * Called whenever a new master is created. Only used by vmwgfx.
-        */
-       int (*master_create)(struct drm_device *dev, struct drm_master *master);
-
-       /**
-        * @master_destroy:
-        *
-        * Called whenever a master is destroyed. Only used by vmwgfx.
-        */
-       void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
-
-       /**
         * @master_set:
         *
         * Called whenever the minor master is set. Only used by vmwgfx.
@@ -824,6 +810,25 @@ static inline bool drm_dev_is_unplugged(struct drm_device *dev)
 }
 
 /**
+ * drm_core_check_all_features - check driver feature flags mask
+ * @dev: DRM device to check
+ * @features: feature flag(s) mask
+ *
+ * This checks @dev for driver features, see &drm_driver.driver_features,
+ * &drm_device.driver_features, and the various &enum drm_driver_feature flags.
+ *
+ * Returns true if all features in the @features mask are supported, false
+ * otherwise.
+ */
+static inline bool drm_core_check_all_features(const struct drm_device *dev,
+                                              u32 features)
+{
+       u32 supported = dev->driver->driver_features & dev->driver_features;
+
+       return features && (supported & features) == features;
+}
+
+/**
  * drm_core_check_feature - check driver feature flags
  * @dev: DRM device to check
  * @feature: feature flag
@@ -833,9 +838,10 @@ static inline bool drm_dev_is_unplugged(struct drm_device *dev)
  *
  * Returns true if the @feature is supported, false otherwise.
  */
-static inline bool drm_core_check_feature(const struct drm_device *dev, u32 feature)
+static inline bool drm_core_check_feature(const struct drm_device *dev,
+                                         enum drm_driver_feature feature)
 {
-       return dev->driver->driver_features & dev->driver_features & feature;
+       return drm_core_check_all_features(dev, feature);
 }
 
 /**
index 8b099b3..19df802 100644 (file)
@@ -374,6 +374,7 @@ int drm_open(struct inode *inode, struct file *filp);
 ssize_t drm_read(struct file *filp, char __user *buffer,
                 size_t count, loff_t *offset);
 int drm_release(struct inode *inode, struct file *filp);
+int drm_release_noglobal(struct inode *inode, struct file *filp);
 __poll_t drm_poll(struct file *filp, struct poll_table_struct *wait);
 int drm_event_reserve_init_locked(struct drm_device *dev,
                                  struct drm_file *file_priv,
index 573e9fd..0f6e472 100644 (file)
@@ -6,6 +6,7 @@
 #include <drm/drm_file.h>
 #include <drm/drm_gem.h>
 #include <drm/drm_ioctl.h>
+#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>
@@ -205,4 +206,12 @@ struct drm_vram_mm *drm_vram_helper_alloc_mm(
        struct drm_device *dev, uint64_t vram_base, size_t vram_size);
 void drm_vram_helper_release_mm(struct drm_device *dev);
 
+/*
+ * Mode-config helpers
+ */
+
+enum drm_mode_status
+drm_vram_helper_mode_valid(struct drm_device *dev,
+                          const struct drm_display_mode *mode);
+
 #endif
index 5745710..dcef359 100644 (file)
@@ -194,17 +194,11 @@ void drm_legacy_idlelock_release(struct drm_lock_data *lock);
 
 #ifdef CONFIG_PCI
 
-void __drm_legacy_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
 int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
 void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
 
 #else
 
-static inline void __drm_legacy_pci_free(struct drm_device *dev,
-                                        drm_dma_handle_t *dmah)
-{
-}
-
 static inline int drm_legacy_pci_init(struct drm_driver *driver,
                                      struct pci_driver *pdriver)
 {
index 67c66f5..33f325f 100644 (file)
@@ -110,6 +110,18 @@ struct mipi_dbi_dev {
        unsigned int rotation;
 
        /**
+        * @left_offset: Horizontal offset of the display relative to the
+        *               controller's driver array
+        */
+       unsigned int left_offset;
+
+       /**
+        * @top_offset: Vertical offset of the display relative to the
+        *              controller's driver array
+        */
+       unsigned int top_offset;
+
+       /**
         * @backlight: backlight device (optional)
         */
        struct backlight_device *backlight;
index 121f7aa..6193cb5 100644 (file)
@@ -198,7 +198,8 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
 }
 #endif
 
-#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
+#if IS_ENABLED(CONFIG_DRM_PANEL) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
+       (IS_MODULE(CONFIG_DRM) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE)))
 int drm_panel_of_backlight(struct drm_panel *panel);
 #else
 static inline int drm_panel_of_backlight(struct drm_panel *panel)
index 8f99d38..894a0b9 100644 (file)
@@ -553,4 +553,33 @@ void __drm_err(const char *format, ...);
 #define DRM_DEBUG_PRIME_RATELIMITED(fmt, ...)                          \
        DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
 
+/*
+ * struct drm_device based WARNs
+ *
+ * drm_WARN*() acts like WARN*(), but with the key difference of
+ * using device specific information so that we know from which device
+ * warning is originating from.
+ *
+ * Prefer drm_device based drm_WARN* over regular WARN*
+ */
+
+/* Helper for struct drm_device based WARNs */
+#define drm_WARN(drm, condition, format, arg...)                       \
+       WARN(condition, "%s %s: " format,                               \
+                       dev_driver_string((drm)->dev),                  \
+                       dev_name((drm)->dev), ## arg)
+
+#define drm_WARN_ONCE(drm, condition, format, arg...)                  \
+       WARN_ONCE(condition, "%s %s: " format,                          \
+                       dev_driver_string((drm)->dev),                  \
+                       dev_name((drm)->dev), ## arg)
+
+#define drm_WARN_ON(drm, x)                                            \
+       drm_WARN((drm), (x), "%s",                                      \
+                "drm_WARN_ON(" __stringify(x) ")")
+
+#define drm_WARN_ON_ONCE(drm, x)                                       \
+       drm_WARN_ONCE((drm), (x), "%s",                                 \
+                     "drm_WARN_ON_ONCE(" __stringify(x) ")")
+
 #endif /* DRM_PRINT_H_ */
index 15afee9..e253ba7 100644 (file)
@@ -100,8 +100,11 @@ struct drm_simple_display_pipe_funcs {
         * This is the function drivers should submit the
         * &drm_pending_vblank_event from. Using either
         * drm_crtc_arm_vblank_event(), when the driver supports vblank
-        * interrupt handling, or drm_crtc_send_vblank_event() directly in case
-        * the hardware lacks vblank support entirely.
+        * interrupt handling, or drm_crtc_send_vblank_event() for more
+        * complex case. In case the hardware lacks vblank support entirely,
+        * drivers can set &struct drm_crtc_state.no_vblank in
+        * &struct drm_simple_display_pipe_funcs.check and let DRM's
+        * atomic helper fake a vblank event.
         */
        void (*update)(struct drm_simple_display_pipe *pipe,
                       struct drm_plane_state *old_plane_state);
index c16c440..94275e9 100644 (file)
@@ -206,6 +206,7 @@ struct drm_vblank_crtc {
 };
 
 int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
+bool drm_dev_has_vblank(const struct drm_device *dev);
 u64 drm_crtc_vblank_count(struct drm_crtc *crtc);
 u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
                                   ktime_t *vblanktime);
index cac7a8a..c9e0fd0 100644 (file)
@@ -210,8 +210,6 @@ struct ttm_mem_type_manager {
  * struct ttm_bo_driver
  *
  * @create_ttm_backend_entry: Callback to create a struct ttm_backend.
- * @invalidate_caches: Callback to invalidate read caches when a buffer object
- * has been evicted.
  * @init_mem_type: Callback to initialize a struct ttm_mem_type_manager
  * structure.
  * @evict_flags: Callback to obtain placement flags when a buffer is evicted.
@@ -256,19 +254,6 @@ struct ttm_bo_driver {
         */
        void (*ttm_tt_unpopulate)(struct ttm_tt *ttm);
 
-       /**
-        * struct ttm_bo_driver member invalidate_caches
-        *
-        * @bdev: the buffer object device.
-        * @flags: new placement of the rebound buffer object.
-        *
-        * A previosly evicted buffer has been rebound in a
-        * potentially new location. Tell the driver that it might
-        * consider invalidating read (texture) caches on the next command
-        * submission as a consequence.
-        */
-
-       int (*invalidate_caches)(struct ttm_bo_device *bdev, uint32_t flags);
        int (*init_mem_type)(struct ttm_bo_device *bdev, uint32_t type,
                             struct ttm_mem_type_manager *man);
 
index 868bf79..808b48a 100644 (file)
@@ -948,6 +948,8 @@ extern "C" {
 #define DRM_IOCTL_SYNCOBJ_TRANSFER     DRM_IOWR(0xCC, struct drm_syncobj_transfer)
 #define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL      DRM_IOWR(0xCD, struct drm_syncobj_timeline_array)
 
+#define DRM_IOCTL_MODE_GETFB2          DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.
index 95a00fb..1ec58d6 100644 (file)
@@ -32,12 +32,19 @@ struct drm_lima_get_param {
        __u64 value; /* out, parameter value */
 };
 
+/*
+ * heap buffer dynamically increase backup memory size when GP task fail
+ * due to lack of heap memory. size field of heap buffer is an up bound of
+ * the backup memory which can be set to a fairly large value.
+ */
+#define LIMA_BO_FLAG_HEAP  (1 << 0)
+
 /**
  * create a buffer for used by GPU
  */
 struct drm_lima_gem_create {
        __u32 size;    /* in, buffer size */
-       __u32 flags;   /* in, currently no flags, must be zero */
+       __u32 flags;   /* in, buffer flags */
        __u32 handle;  /* out, GEM buffer handle */
        __u32 pad;     /* pad, must be zero */
 };
index b6571c3..c4a93ce 100644 (file)
@@ -10,7 +10,7 @@
  *
  * This is the register set for the fimd and new style framebuffer interface
  * found from the S3C2443 onwards into the S3C2416, S3C2450, the
- * S3C64XX series such as the S3C6400 and S3C6410, and EXYNOS series.
+ * S3C64XX series such as the S3C6400 and S3C6410, and Exynos series.
 */
 
 /* VIDCON0 */