浏览代码

Merge tag 'drm-for-v4.10' of git://people.freedesktop.org/~airlied/linux into drm-misc-next

Main pull request for drm for 4.10 kernel - resync drm-misc with full
4.10 state (2 new drivers) so that we can start pulling in all the
refactorings for 4.11!

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Daniel Vetter 8 年之前
父节点
当前提交
010f5b9f0d
共有 100 个文件被更改,包括 5926 次插入509 次删除
  1. 112 0
      Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
  2. 14 0
      Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
  3. 45 8
      Documentation/devicetree/bindings/display/mxsfb.txt
  4. 7 0
      Documentation/devicetree/bindings/display/panel/auo,g133han01.txt
  5. 7 0
      Documentation/devicetree/bindings/display/panel/auo,g185han01.txt
  6. 7 0
      Documentation/devicetree/bindings/display/panel/auo,t215hvn01.txt
  7. 7 0
      Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt
  8. 7 0
      Documentation/devicetree/bindings/display/panel/nvd,9128.txt
  9. 36 0
      Documentation/devicetree/bindings/display/panel/sharp,lq150x1lg11.txt
  10. 1 0
      Documentation/devicetree/bindings/vendor-prefixes.txt
  11. 15 0
      MAINTAINERS
  12. 4 0
      drivers/gpu/drm/Kconfig
  13. 2 0
      drivers/gpu/drm/Makefile
  14. 3 2
      drivers/gpu/drm/amd/amdgpu/amdgpu.h
  15. 6 0
      drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
  16. 4 2
      drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
  17. 1 1
      drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
  18. 80 7
      drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
  19. 1 1
      drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
  20. 1 1
      drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
  21. 12 2
      drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
  22. 26 0
      drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
  23. 5 7
      drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
  24. 1 1
      drivers/gpu/drm/amd/amdgpu/ci_dpm.c
  25. 17 8
      drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
  26. 17 8
      drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
  27. 22 11
      drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
  28. 19 8
      drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
  29. 25 0
      drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
  30. 25 0
      drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
  31. 61 302
      drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
  32. 1 6
      drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
  33. 1 6
      drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
  34. 1 6
      drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
  35. 2 0
      drivers/gpu/drm/amd/amdgpu/si_dpm.c
  36. 4 2
      drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
  37. 95 20
      drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
  38. 1 1
      drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
  39. 4 2
      drivers/gpu/drm/amd/amdgpu/vi.c
  40. 2 2
      drivers/gpu/drm/amd/powerplay/amd_powerplay.c
  41. 1 1
      drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c
  42. 1 1
      drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c
  43. 13 0
      drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
  44. 1 0
      drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h
  45. 6 0
      drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c
  46. 6 0
      drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c
  47. 6 0
      drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c
  48. 17 4
      drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c
  49. 6 0
      drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c
  50. 50 0
      drivers/gpu/drm/drm_atomic.c
  51. 62 0
      drivers/gpu/drm/drm_drv.c
  52. 2 2
      drivers/gpu/drm/drm_plane.c
  53. 0 1
      drivers/gpu/drm/fsl-dcu/Makefile
  54. 18 8
      drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
  55. 0 1
      drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
  56. 0 23
      drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c
  57. 2 0
      drivers/gpu/drm/i915/gvt/gvt.h
  58. 6 4
      drivers/gpu/drm/i915/gvt/scheduler.c
  59. 1 0
      drivers/gpu/drm/i915/gvt/vgpu.c
  60. 1 26
      drivers/gpu/drm/i915/i915_debugfs.c
  61. 2 0
      drivers/gpu/drm/i915/i915_gem.c
  62. 27 7
      drivers/gpu/drm/i915/i915_gem_request.c
  63. 5 0
      drivers/gpu/drm/i915/i915_sw_fence.h
  64. 5 2
      drivers/gpu/drm/i915/intel_audio.c
  65. 7 4
      drivers/gpu/drm/i915/intel_display.c
  66. 7 7
      drivers/gpu/drm/i915/intel_pm.c
  67. 9 0
      drivers/gpu/drm/meson/Kconfig
  68. 4 0
      drivers/gpu/drm/meson/Makefile
  69. 68 0
      drivers/gpu/drm/meson/meson_canvas.c
  70. 42 0
      drivers/gpu/drm/meson/meson_canvas.h
  71. 208 0
      drivers/gpu/drm/meson/meson_crtc.c
  72. 32 0
      drivers/gpu/drm/meson/meson_crtc.h
  73. 343 0
      drivers/gpu/drm/meson/meson_drv.c
  74. 59 0
      drivers/gpu/drm/meson/meson_drv.h
  75. 230 0
      drivers/gpu/drm/meson/meson_plane.c
  76. 30 0
      drivers/gpu/drm/meson/meson_plane.h
  77. 1395 0
      drivers/gpu/drm/meson/meson_registers.h
  78. 167 0
      drivers/gpu/drm/meson/meson_vclk.c
  79. 34 0
      drivers/gpu/drm/meson/meson_vclk.h
  80. 254 0
      drivers/gpu/drm/meson/meson_venc.c
  81. 72 0
      drivers/gpu/drm/meson/meson_venc.h
  82. 293 0
      drivers/gpu/drm/meson/meson_venc_cvbs.c
  83. 41 0
      drivers/gpu/drm/meson/meson_venc_cvbs.h
  84. 331 0
      drivers/gpu/drm/meson/meson_viu.c
  85. 64 0
      drivers/gpu/drm/meson/meson_viu.h
  86. 162 0
      drivers/gpu/drm/meson/meson_vpp.c
  87. 35 0
      drivers/gpu/drm/meson/meson_vpp.h
  88. 19 0
      drivers/gpu/drm/mxsfb/Kconfig
  89. 2 0
      drivers/gpu/drm/mxsfb/Makefile
  90. 241 0
      drivers/gpu/drm/mxsfb/mxsfb_crtc.c
  91. 444 0
      drivers/gpu/drm/mxsfb/mxsfb_drv.c
  92. 54 0
      drivers/gpu/drm/mxsfb/mxsfb_drv.h
  93. 131 0
      drivers/gpu/drm/mxsfb/mxsfb_out.c
  94. 114 0
      drivers/gpu/drm/mxsfb/mxsfb_regs.h
  95. 76 4
      drivers/gpu/drm/nouveau/nouveau_backlight.c
  96. 1 0
      drivers/gpu/drm/nouveau/nouveau_bo.c
  97. 10 0
      drivers/gpu/drm/nouveau/nouveau_display.h
  98. 2 0
      drivers/gpu/drm/nouveau/nouveau_drm.c
  99. 1 0
      drivers/gpu/drm/nouveau/nouveau_drv.h
  100. 5 0
      drivers/gpu/drm/nouveau/nv50_display.c

+ 112 - 0
Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt

@@ -0,0 +1,112 @@
+Amlogic Meson Display Controller
+================================
+
+The Amlogic Meson Display controller is composed of several components
+that are going to be documented below:
+
+DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
+   | vd1   _______     _____________    _________________     |               |
+D  |-------|      |----|            |   |                |    |   HDMI PLL    |
+D  | vd2   | VIU  |    | Video Post |   | Video Encoders |<---|-----VCLK      |
+R  |-------|      |----| Processing |   |                |    |               |
+   | osd2  |      |    |            |---| Enci ----------|----|-----VDAC------|
+R  |-------| CSC  |----| Scalers    |   | Encp ----------|----|----HDMI-TX----|
+A  | osd1  |      |    | Blenders   |   | Encl ----------|----|---------------|
+M  |-------|______|----|____________|   |________________|    |               |
+___|__________________________________________________________|_______________|
+
+
+VIU: Video Input Unit
+---------------------
+
+The Video Input Unit is in charge of the pixel scanout from the DDR memory.
+It fetches the frames addresses, stride and parameters from the "Canvas" memory.
+This part is also in charge of the CSC (Colorspace Conversion).
+It can handle 2 OSD Planes and 2 Video Planes.
+
+VPP: Video Post Processing
+--------------------------
+
+The Video Post Processing is in charge of the scaling and blending of the
+various planes into a single pixel stream.
+There is a special "pre-blending" used by the video planes with a dedicated
+scaler and a "post-blending" to merge with the OSD Planes.
+The OSD planes also have a dedicated scaler for one of the OSD.
+
+VENC: Video Encoders
+--------------------
+
+The VENC is composed of the multiple pixel encoders :
+ - ENCI : Interlace Video encoder for CVBS and Interlace HDMI
+ - ENCP : Progressive Video Encoder for HDMI
+ - ENCL : LCD LVDS Encoder
+The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock
+tree and provides the scanout clock to the VPP and VIU.
+The ENCI is connected to a single VDAC for Composite Output.
+The ENCI and ENCP are connected to an on-chip HDMI Transceiver.
+
+Device Tree Bindings:
+---------------------
+
+VPU: Video Processing Unit
+--------------------------
+
+Required properties:
+- compatible: value should be different for each SoC family as :
+	- GXBB (S905) : "amlogic,meson-gxbb-vpu"
+	- GXL (S905X, S905D) : "amlogic,meson-gxl-vpu"
+	- GXM (S912) : "amlogic,meson-gxm-vpu"
+	followed by the common "amlogic,meson-gx-vpu"
+- reg: base address and size of he following memory-mapped regions :
+	- vpu
+	- hhi
+	- dmc
+- reg-names: should contain the names of the previous memory regions
+- interrupts: should contain the VENC Vsync interrupt number
+
+Required nodes:
+
+The connections to the VPU output video ports are modeled using the OF graph
+bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+The following table lists for each supported model the port number
+corresponding to each VPU output.
+
+		Port 0		Port 1
+-----------------------------------------
+ S905 (GXBB)	CVBS VDAC	HDMI-TX
+ S905X (GXL)	CVBS VDAC	HDMI-TX
+ S905D (GXL)	CVBS VDAC	HDMI-TX
+ S912 (GXM)	CVBS VDAC	HDMI-TX
+
+Example:
+
+tv-connector {
+	compatible = "composite-video-connector";
+
+	port {
+		tv_connector_in: endpoint {
+			remote-endpoint = <&cvbs_vdac_out>;
+		};
+	};
+};
+
+vpu: vpu@d0100000 {
+	compatible = "amlogic,meson-gxbb-vpu";
+	reg = <0x0 0xd0100000 0x0 0x100000>,
+	      <0x0 0xc883c000 0x0 0x1000>,
+	      <0x0 0xc8838000 0x0 0x1000>;
+	reg-names = "vpu", "hhi", "dmc";
+	interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* CVBS VDAC output port */
+	port@0 {
+		reg = <0>;
+
+		cvbs_vdac_out: endpoint {
+			remote-endpoint = <&tv_connector_in>;
+		};
+	};
+};

+ 14 - 0
Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt

@@ -43,6 +43,13 @@ Required properties for DPI:
 - port:		Port node with a single endpoint connecting to the panel
 - port:		Port node with a single endpoint connecting to the panel
 		  device, as defined in [1]
 		  device, as defined in [1]
 
 
+Required properties for VEC:
+- compatible:	Should be "brcm,bcm2835-vec"
+- reg:		Physical base address and length of the registers
+- clocks:	The core clock the unit runs on
+- interrupts:	The interrupt number
+		  See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
 Required properties for V3D:
 Required properties for V3D:
 - compatible:	Should be "brcm,bcm2835-v3d"
 - compatible:	Should be "brcm,bcm2835-v3d"
 - reg:		Physical base address and length of the V3D's registers
 - reg:		Physical base address and length of the V3D's registers
@@ -92,6 +99,13 @@ dpi: dpi@7e208000 {
 	};
 	};
 };
 };
 
 
+vec: vec@7e806000 {
+	compatible = "brcm,bcm2835-vec";
+	reg = <0x7e806000 0x1000>;
+	clocks = <&clocks BCM2835_CLOCK_VEC>;
+	interrupts = <2 27>;
+};
+
 v3d: v3d@7ec00000 {
 v3d: v3d@7ec00000 {
 	compatible = "brcm,bcm2835-v3d";
 	compatible = "brcm,bcm2835-v3d";
 	reg = <0x7ec00000 0x1000>;
 	reg = <0x7ec00000 0x1000>;

+ 45 - 8
Documentation/devicetree/bindings/display/mxsfb.txt

@@ -1,20 +1,57 @@
 * Freescale MXS LCD Interface (LCDIF)
 * Freescale MXS LCD Interface (LCDIF)
 
 
+New bindings:
+=============
 Required properties:
 Required properties:
-- compatible: Should be "fsl,<chip>-lcdif".  Supported chips include
-  imx23 and imx28.
-- reg: Address and length of the register set for lcdif
-- interrupts: Should contain lcdif interrupts
-- display : phandle to display node (see below for details)
+- compatible:	Should be "fsl,imx23-lcdif" for i.MX23.
+		Should be "fsl,imx28-lcdif" for i.MX28.
+		Should be "fsl,imx6sx-lcdif" for i.MX6SX.
+- reg:		Address and length of the register set for LCDIF
+- interrupts:	Should contain LCDIF interrupt
+- clocks:	A list of phandle + clock-specifier pairs, one for each
+		entry in 'clock-names'.
+- clock-names:	A list of clock names. For MXSFB it should contain:
+    - "pix" for the LCDIF block clock
+    - (MX6SX-only) "axi", "disp_axi" for the bus interface clock
+
+Required sub-nodes:
+  - port: The connection to an encoder chip.
+
+Example:
+
+	lcdif1: display-controller@2220000 {
+		compatible = "fsl,imx6sx-lcdif", "fsl,imx28-lcdif";
+		reg = <0x02220000 0x4000>;
+		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX6SX_CLK_LCDIF1_PIX>,
+			 <&clks IMX6SX_CLK_LCDIF_APB>,
+			 <&clks IMX6SX_CLK_DISPLAY_AXI>;
+		clock-names = "pix", "axi", "disp_axi";
+
+		port {
+			parallel_out: endpoint {
+				remote-endpoint = <&panel_in_parallel>;
+			};
+		};
+	};
+
+Deprecated bindings:
+====================
+Required properties:
+- compatible:	Should be "fsl,imx23-lcdif" for i.MX23.
+		Should be "fsl,imx28-lcdif" for i.MX28.
+- reg:		Address and length of the register set for LCDIF
+- interrupts:	Should contain LCDIF interrupts
+- display:	phandle to display node (see below for details)
 
 
 * display node
 * display node
 
 
 Required properties:
 Required properties:
-- bits-per-pixel : <16> for RGB565, <32> for RGB888/666.
-- bus-width : number of data lines.  Could be <8>, <16>, <18> or <24>.
+- bits-per-pixel:	<16> for RGB565, <32> for RGB888/666.
+- bus-width:		number of data lines.  Could be <8>, <16>, <18> or <24>.
 
 
 Required sub-node:
 Required sub-node:
-- display-timings : Refer to binding doc display-timing.txt for details.
+- display-timings:	Refer to binding doc display-timing.txt for details.
 
 
 Examples:
 Examples:
 
 

+ 7 - 0
Documentation/devicetree/bindings/display/panel/auo,g133han01.txt

@@ -0,0 +1,7 @@
+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.

+ 7 - 0
Documentation/devicetree/bindings/display/panel/auo,g185han01.txt

@@ -0,0 +1,7 @@
+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.

+ 7 - 0
Documentation/devicetree/bindings/display/panel/auo,t215hvn01.txt

@@ -0,0 +1,7 @@
+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.

+ 7 - 0
Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt

@@ -0,0 +1,7 @@
+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.

+ 7 - 0
Documentation/devicetree/bindings/display/panel/nvd,9128.txt

@@ -0,0 +1,7 @@
+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.

+ 36 - 0
Documentation/devicetree/bindings/display/panel/sharp,lq150x1lg11.txt

@@ -0,0 +1,36 @@
+Sharp 15" LQ150X1LG11 XGA TFT LCD panel
+
+Required properties:
+- compatible: should be "sharp,lq150x1lg11"
+- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
+
+Optional properties:
+- backlight: phandle of the backlight device
+- rlud-gpios: a single GPIO for the RL/UD (rotate 180 degrees) pin.
+- sellvds-gpios: a single GPIO for the SELLVDS pin.
+
+If rlud-gpios and/or sellvds-gpios are not specified, the RL/UD and/or SELLVDS
+pins are assumed to be handled appropriately by the hardware.
+
+Example:
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 100000>;                      /* VBR */
+
+		brightness-levels = <0 20 40 60 80 100>;
+		default-brightness-level = <2>;
+
+		power-supply = <&vdd_12v_reg>;               /* VDD */
+		enable-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;  /* XSTABY */
+	};
+
+	panel {
+		compatible = "sharp,lq150x1lg11";
+
+		power-supply = <&vcc_3v3_reg>;               /* VCC */
+
+		backlight = <&backlight>;
+		rlud-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;    /* RL/UD */
+		sellvds-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; /* SELLVDS */
+	};

+ 1 - 0
Documentation/devicetree/bindings/vendor-prefixes.txt

@@ -187,6 +187,7 @@ netgear	NETGEAR
 netlogic	Broadcom Corporation (formerly NetLogic Microsystems)
 netlogic	Broadcom Corporation (formerly NetLogic Microsystems)
 netxeon		Shenzhen Netxeon Technology CO., LTD
 netxeon		Shenzhen Netxeon Technology CO., LTD
 newhaven	Newhaven Display International
 newhaven	Newhaven Display International
+nvd	New Vision Display
 nintendo	Nintendo
 nintendo	Nintendo
 nokia	Nokia
 nokia	Nokia
 nuvoton	Nuvoton Technology Corporation
 nuvoton	Nuvoton Technology Corporation

+ 15 - 0
MAINTAINERS

@@ -4121,6 +4121,15 @@ S:	Supported
 F:	drivers/gpu/drm/sun4i/
 F:	drivers/gpu/drm/sun4i/
 F:	Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
 F:	Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
 
 
+DRM DRIVERS FOR AMLOGIC SOCS
+M:	Neil Armstrong <narmstrong@baylibre.com>
+L:	dri-devel@lists.freedesktop.org
+L:	linux-amlogic@lists.infradead.org
+W:	http://linux-meson.com/
+S:	Supported
+F:	drivers/gpu/drm/meson/
+F:	Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
+
 DRM DRIVERS FOR EXYNOS
 DRM DRIVERS FOR EXYNOS
 M:	Inki Dae <inki.dae@samsung.com>
 M:	Inki Dae <inki.dae@samsung.com>
 M:	Joonyoung Shim <jy0922.shim@samsung.com>
 M:	Joonyoung Shim <jy0922.shim@samsung.com>
@@ -8319,6 +8328,12 @@ T:	git git://linuxtv.org/mkrufky/tuners.git
 S:	Maintained
 S:	Maintained
 F:	drivers/media/tuners/mxl5007t.*
 F:	drivers/media/tuners/mxl5007t.*
 
 
+MXSFB DRM DRIVER
+M:	Marek Vasut <marex@denx.de>
+S:	Supported
+F:	drivers/gpu/drm/mxsfb/
+F:	Documentation/devicetree/bindings/display/mxsfb-drm.txt
+
 MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 M:	Hyong-Youb Kim <hykim@myri.com>
 M:	Hyong-Youb Kim <hykim@myri.com>
 L:	netdev@vger.kernel.org
 L:	netdev@vger.kernel.org

+ 4 - 0
drivers/gpu/drm/Kconfig

@@ -240,6 +240,10 @@ source "drivers/gpu/drm/mediatek/Kconfig"
 
 
 source "drivers/gpu/drm/zte/Kconfig"
 source "drivers/gpu/drm/zte/Kconfig"
 
 
+source "drivers/gpu/drm/mxsfb/Kconfig"
+
+source "drivers/gpu/drm/meson/Kconfig"
+
 # Keep legacy drivers last
 # Keep legacy drivers last
 
 
 menuconfig DRM_LEGACY
 menuconfig DRM_LEGACY

+ 2 - 0
drivers/gpu/drm/Makefile

@@ -81,6 +81,7 @@ obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STI) += sti/
 obj-$(CONFIG_DRM_STI) += sti/
 obj-$(CONFIG_DRM_IMX) += imx/
 obj-$(CONFIG_DRM_IMX) += imx/
 obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
 obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
+obj-$(CONFIG_DRM_MESON)	+= meson/
 obj-y			+= i2c/
 obj-y			+= i2c/
 obj-y			+= panel/
 obj-y			+= panel/
 obj-y			+= bridge/
 obj-y			+= bridge/
@@ -89,3 +90,4 @@ obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
 obj-$(CONFIG_DRM_ARCPGU)+= arc/
 obj-$(CONFIG_DRM_ARCPGU)+= arc/
 obj-y			+= hisilicon/
 obj-y			+= hisilicon/
 obj-$(CONFIG_DRM_ZTE)	+= zte/
 obj-$(CONFIG_DRM_ZTE)	+= zte/
+obj-$(CONFIG_DRM_MXSFB)	+= mxsfb/

+ 3 - 2
drivers/gpu/drm/amd/amdgpu/amdgpu.h

@@ -842,6 +842,8 @@ struct amdgpu_gfx_funcs {
 	uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev);
 	uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev);
 	void (*select_se_sh)(struct amdgpu_device *adev, u32 se_num, u32 sh_num, u32 instance);
 	void (*select_se_sh)(struct amdgpu_device *adev, u32 se_num, u32 sh_num, u32 instance);
 	void (*read_wave_data)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields);
 	void (*read_wave_data)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields);
+	void (*read_wave_vgprs)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t thread, uint32_t start, uint32_t size, uint32_t *dst);
+	void (*read_wave_sgprs)(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t start, uint32_t size, uint32_t *dst);
 };
 };
 
 
 struct amdgpu_gfx {
 struct amdgpu_gfx {
@@ -1330,6 +1332,7 @@ struct amdgpu_device {
 
 
 	/* BIOS */
 	/* BIOS */
 	uint8_t				*bios;
 	uint8_t				*bios;
+	uint32_t			bios_size;
 	bool				is_atom_bios;
 	bool				is_atom_bios;
 	struct amdgpu_bo		*stollen_vga_memory;
 	struct amdgpu_bo		*stollen_vga_memory;
 	uint32_t			bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
 	uint32_t			bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
@@ -1679,8 +1682,6 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
 void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base);
 void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base);
 void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc);
 void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc);
 void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size);
 void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size);
-u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev);
-int amdgpu_ttm_global_init(struct amdgpu_device *adev);
 int amdgpu_ttm_init(struct amdgpu_device *adev);
 int amdgpu_ttm_init(struct amdgpu_device *adev);
 void amdgpu_ttm_fini(struct amdgpu_device *adev);
 void amdgpu_ttm_fini(struct amdgpu_device *adev);
 void amdgpu_program_register_sequence(struct amdgpu_device *adev,
 void amdgpu_program_register_sequence(struct amdgpu_device *adev,

+ 6 - 0
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c

@@ -74,6 +74,7 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
 		iounmap(bios);
 		iounmap(bios);
 		return false;
 		return false;
 	}
 	}
+	adev->bios_size = size;
 	memcpy_fromio(adev->bios, bios, size);
 	memcpy_fromio(adev->bios, bios, size);
 	iounmap(bios);
 	iounmap(bios);
 	return true;
 	return true;
@@ -103,6 +104,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
 		pci_unmap_rom(adev->pdev, bios);
 		pci_unmap_rom(adev->pdev, bios);
 		return false;
 		return false;
 	}
 	}
+	adev->bios_size = size;
 	memcpy_fromio(adev->bios, bios, size);
 	memcpy_fromio(adev->bios, bios, size);
 	pci_unmap_rom(adev->pdev, bios);
 	pci_unmap_rom(adev->pdev, bios);
 	return true;
 	return true;
@@ -135,6 +137,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
 		DRM_ERROR("no memory to allocate for BIOS\n");
 		DRM_ERROR("no memory to allocate for BIOS\n");
 		return false;
 		return false;
 	}
 	}
+	adev->bios_size = len;
 
 
 	/* read complete BIOS */
 	/* read complete BIOS */
 	return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
 	return amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
@@ -159,6 +162,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
 	if (adev->bios == NULL) {
 	if (adev->bios == NULL) {
 		return false;
 		return false;
 	}
 	}
+	adev->bios_size = size;
 
 
 	return true;
 	return true;
 }
 }
@@ -273,6 +277,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
 		kfree(adev->bios);
 		kfree(adev->bios);
 		return false;
 		return false;
 	}
 	}
+	adev->bios_size = size;
 	return true;
 	return true;
 }
 }
 #else
 #else
@@ -334,6 +339,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
 	}
 	}
 
 
 	adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
 	adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
+	adev->bios_size = vhdr->ImageLength;
 	ret = !!adev->bios;
 	ret = !!adev->bios;
 
 
 out_unmap:
 out_unmap:

+ 4 - 2
drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c

@@ -723,7 +723,7 @@ static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
 					enum cgs_ucode_id type)
 					enum cgs_ucode_id type)
 {
 {
 	CGS_FUNC_ADEV;
 	CGS_FUNC_ADEV;
-	uint16_t fw_version;
+	uint16_t fw_version = 0;
 
 
 	switch (type) {
 	switch (type) {
 		case CGS_UCODE_ID_SDMA0:
 		case CGS_UCODE_ID_SDMA0:
@@ -753,9 +753,11 @@ static uint16_t amdgpu_get_firmware_version(struct cgs_device *cgs_device,
 		case CGS_UCODE_ID_RLC_G:
 		case CGS_UCODE_ID_RLC_G:
 			fw_version = adev->gfx.rlc_fw_version;
 			fw_version = adev->gfx.rlc_fw_version;
 			break;
 			break;
+		case CGS_UCODE_ID_STORAGE:
+			break;
 		default:
 		default:
 			DRM_ERROR("firmware type %d do not have version\n", type);
 			DRM_ERROR("firmware type %d do not have version\n", type);
-			fw_version = 0;
+			break;
 	}
 	}
 	return fw_version;
 	return fw_version;
 }
 }

+ 1 - 1
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c

@@ -451,7 +451,7 @@ static int amdgpu_cs_validate(void *param, struct amdgpu_bo *bo)
 		return r;
 		return r;
 
 
 	if (bo->shadow)
 	if (bo->shadow)
-		r = amdgpu_cs_bo_validate(p, bo);
+		r = amdgpu_cs_bo_validate(p, bo->shadow);
 
 
 	return r;
 	return r;
 }
 }

+ 80 - 7
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c

@@ -1470,20 +1470,26 @@ static int amdgpu_fini(struct amdgpu_device *adev)
 			amdgpu_wb_fini(adev);
 			amdgpu_wb_fini(adev);
 			amdgpu_vram_scratch_fini(adev);
 			amdgpu_vram_scratch_fini(adev);
 		}
 		}
-		/* ungate blocks before hw fini so that we can shutdown the blocks safely */
-		r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev,
-									     AMD_CG_STATE_UNGATE);
-		if (r) {
-			DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n",
-				  adev->ip_blocks[i].version->funcs->name, r);
-			return r;
+
+		if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
+			adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) {
+			/* ungate blocks before hw fini so that we can shutdown the blocks safely */
+			r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev,
+										     AMD_CG_STATE_UNGATE);
+			if (r) {
+				DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n",
+					  adev->ip_blocks[i].version->funcs->name, r);
+				return r;
+			}
 		}
 		}
+
 		r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev);
 		r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev);
 		/* XXX handle errors */
 		/* XXX handle errors */
 		if (r) {
 		if (r) {
 			DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
 			DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
 				  adev->ip_blocks[i].version->funcs->name, r);
 				  adev->ip_blocks[i].version->funcs->name, r);
 		}
 		}
+
 		adev->ip_blocks[i].status.hw = false;
 		adev->ip_blocks[i].status.hw = false;
 	}
 	}
 
 
@@ -2973,6 +2979,66 @@ static ssize_t amdgpu_debugfs_wave_read(struct file *f, char __user *buf,
 	return result;
 	return result;
 }
 }
 
 
+static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
+					size_t size, loff_t *pos)
+{
+	struct amdgpu_device *adev = f->f_inode->i_private;
+	int r;
+	ssize_t result = 0;
+	uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;
+
+	if (size & 3 || *pos & 3)
+		return -EINVAL;
+
+	/* decode offset */
+	offset = (*pos & 0xFFF);       /* in dwords */
+	se = ((*pos >> 12) & 0xFF);
+	sh = ((*pos >> 20) & 0xFF);
+	cu = ((*pos >> 28) & 0xFF);
+	wave = ((*pos >> 36) & 0xFF);
+	simd = ((*pos >> 44) & 0xFF);
+	thread = ((*pos >> 52) & 0xFF);
+	bank = ((*pos >> 60) & 1);
+
+	data = kmalloc_array(1024, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* switch to the specific se/sh/cu */
+	mutex_lock(&adev->grbm_idx_mutex);
+	amdgpu_gfx_select_se_sh(adev, se, sh, cu);
+
+	if (bank == 0) {
+		if (adev->gfx.funcs->read_wave_vgprs)
+			adev->gfx.funcs->read_wave_vgprs(adev, simd, wave, thread, offset, size>>2, data);
+	} else {
+		if (adev->gfx.funcs->read_wave_sgprs)
+			adev->gfx.funcs->read_wave_sgprs(adev, simd, wave, offset, size>>2, data);
+	}
+
+	amdgpu_gfx_select_se_sh(adev, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+	mutex_unlock(&adev->grbm_idx_mutex);
+
+	while (size) {
+		uint32_t value;
+
+		value = data[offset++];
+		r = put_user(value, (uint32_t *)buf);
+		if (r) {
+			result = r;
+			goto err;
+		}
+
+		result += 4;
+		buf += 4;
+		size -= 4;
+	}
+
+err:
+	kfree(data);
+	return result;
+}
+
 static const struct file_operations amdgpu_debugfs_regs_fops = {
 static const struct file_operations amdgpu_debugfs_regs_fops = {
 	.owner = THIS_MODULE,
 	.owner = THIS_MODULE,
 	.read = amdgpu_debugfs_regs_read,
 	.read = amdgpu_debugfs_regs_read,
@@ -3015,6 +3081,11 @@ static const struct file_operations amdgpu_debugfs_wave_fops = {
 	.read = amdgpu_debugfs_wave_read,
 	.read = amdgpu_debugfs_wave_read,
 	.llseek = default_llseek
 	.llseek = default_llseek
 };
 };
+static const struct file_operations amdgpu_debugfs_gpr_fops = {
+	.owner = THIS_MODULE,
+	.read = amdgpu_debugfs_gpr_read,
+	.llseek = default_llseek
+};
 
 
 static const struct file_operations *debugfs_regs[] = {
 static const struct file_operations *debugfs_regs[] = {
 	&amdgpu_debugfs_regs_fops,
 	&amdgpu_debugfs_regs_fops,
@@ -3024,6 +3095,7 @@ static const struct file_operations *debugfs_regs[] = {
 	&amdgpu_debugfs_gca_config_fops,
 	&amdgpu_debugfs_gca_config_fops,
 	&amdgpu_debugfs_sensors_fops,
 	&amdgpu_debugfs_sensors_fops,
 	&amdgpu_debugfs_wave_fops,
 	&amdgpu_debugfs_wave_fops,
+	&amdgpu_debugfs_gpr_fops,
 };
 };
 
 
 static const char *debugfs_regs_names[] = {
 static const char *debugfs_regs_names[] = {
@@ -3034,6 +3106,7 @@ static const char *debugfs_regs_names[] = {
 	"amdgpu_gca_config",
 	"amdgpu_gca_config",
 	"amdgpu_sensors",
 	"amdgpu_sensors",
 	"amdgpu_wave",
 	"amdgpu_wave",
+	"amdgpu_gpr",
 };
 };
 
 
 static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
 static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)

+ 1 - 1
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c

@@ -187,7 +187,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
 		goto cleanup;
 		goto cleanup;
 	}
 	}
 
 
-	r = amdgpu_bo_pin_restricted(new_abo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base);
+	r = amdgpu_bo_pin(new_abo, AMDGPU_GEM_DOMAIN_VRAM, &base);
 	if (unlikely(r != 0)) {
 	if (unlikely(r != 0)) {
 		r = -EINVAL;
 		r = -EINVAL;
 		DRM_ERROR("failed to pin new abo buffer before flip\n");
 		DRM_ERROR("failed to pin new abo buffer before flip\n");

+ 1 - 1
drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c

@@ -171,7 +171,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
 	}
 	}
 
 
 
 
-	ret = amdgpu_bo_pin_restricted(abo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, NULL);
+	ret = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, NULL);
 	if (ret) {
 	if (ret) {
 		amdgpu_bo_unreserve(abo);
 		amdgpu_bo_unreserve(abo);
 		goto out_unref;
 		goto out_unref;

+ 12 - 2
drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c

@@ -164,8 +164,10 @@ static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
 	spin_unlock(&mgr->lock);
 	spin_unlock(&mgr->lock);
 
 
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
-	if (!node)
-		return -ENOMEM;
+	if (!node) {
+		r = -ENOMEM;
+		goto err_out;
+	}
 
 
 	node->start = AMDGPU_BO_INVALID_OFFSET;
 	node->start = AMDGPU_BO_INVALID_OFFSET;
 	node->size = mem->num_pages;
 	node->size = mem->num_pages;
@@ -176,12 +178,20 @@ static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man,
 		if (unlikely(r)) {
 		if (unlikely(r)) {
 			kfree(node);
 			kfree(node);
 			mem->mm_node = NULL;
 			mem->mm_node = NULL;
+			r = 0;
+			goto err_out;
 		}
 		}
 	} else {
 	} else {
 		mem->start = node->start;
 		mem->start = node->start;
 	}
 	}
 
 
 	return 0;
 	return 0;
+err_out:
+	spin_lock(&mgr->lock);
+	mgr->available += mem->num_pages;
+	spin_unlock(&mgr->lock);
+
+	return r;
 }
 }
 
 
 /**
 /**

+ 26 - 0
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c

@@ -544,6 +544,32 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
 		return copy_to_user(out, &vce_clk_table,
 		return copy_to_user(out, &vce_clk_table,
 				    min((size_t)size, sizeof(vce_clk_table))) ? -EFAULT : 0;
 				    min((size_t)size, sizeof(vce_clk_table))) ? -EFAULT : 0;
 	}
 	}
+	case AMDGPU_INFO_VBIOS: {
+		uint32_t bios_size = adev->bios_size;
+
+		switch (info->vbios_info.type) {
+		case AMDGPU_INFO_VBIOS_SIZE:
+			return copy_to_user(out, &bios_size,
+					min((size_t)size, sizeof(bios_size)))
+					? -EFAULT : 0;
+		case AMDGPU_INFO_VBIOS_IMAGE: {
+			uint8_t *bios;
+			uint32_t bios_offset = info->vbios_info.offset;
+
+			if (bios_offset >= bios_size)
+				return -EINVAL;
+
+			bios = adev->bios + bios_offset;
+			return copy_to_user(out, bios,
+					    min((size_t)size, (size_t)(bios_size - bios_offset)))
+					? -EFAULT : 0;
+		}
+		default:
+			DRM_DEBUG_KMS("Invalid request %d\n",
+					info->vbios_info.type);
+			return -EINVAL;
+		}
+	}
 	default:
 	default:
 		DRM_DEBUG_KMS("Invalid request %d\n", info->query);
 		DRM_DEBUG_KMS("Invalid request %d\n", info->query);
 		return -EINVAL;
 		return -EINVAL;

+ 5 - 7
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c

@@ -34,7 +34,6 @@
 #include <ttm/ttm_placement.h>
 #include <ttm/ttm_placement.h>
 #include <ttm/ttm_module.h>
 #include <ttm/ttm_module.h>
 #include <ttm/ttm_page_alloc.h>
 #include <ttm/ttm_page_alloc.h>
-#include <ttm/ttm_memory.h>
 #include <drm/drmP.h>
 #include <drm/drmP.h>
 #include <drm/amdgpu_drm.h>
 #include <drm/amdgpu_drm.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
@@ -65,7 +64,7 @@ static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref)
 	ttm_mem_global_release(ref->object);
 	ttm_mem_global_release(ref->object);
 }
 }
 
 
-int amdgpu_ttm_global_init(struct amdgpu_device *adev)
+static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
 {
 {
 	struct drm_global_reference *global_ref;
 	struct drm_global_reference *global_ref;
 	struct amdgpu_ring *ring;
 	struct amdgpu_ring *ring;
@@ -1151,6 +1150,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 	unsigned i, j;
 	unsigned i, j;
 	int r;
 	int r;
 
 
+	r = amdgpu_ttm_global_init(adev);
+	if (r) {
+		return r;
+	}
 	/* No others user of address space so set it to 0 */
 	/* No others user of address space so set it to 0 */
 	r = ttm_bo_device_init(&adev->mman.bdev,
 	r = ttm_bo_device_init(&adev->mman.bdev,
 			       adev->mman.bo_global_ref.ref.object,
 			       adev->mman.bo_global_ref.ref.object,
@@ -1650,8 +1653,3 @@ static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev)
 
 
 #endif
 #endif
 }
 }
-
-u64 amdgpu_ttm_get_gtt_mem_size(struct amdgpu_device *adev)
-{
-	return ttm_get_kernel_zone_memory_size(adev->mman.mem_global_ref.object);
-}

+ 1 - 1
drivers/gpu/drm/amd/amdgpu/ci_dpm.c

@@ -6083,7 +6083,7 @@ ci_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
 		activity_percent = activity_percent > 100 ? 100 : activity_percent;
 		activity_percent = activity_percent > 100 ? 100 : activity_percent;
 	}
 	}
 
 
-	seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis");
+	seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en");
 	seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
 	seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis");
 	seq_printf(m, "power level avg    sclk: %u mclk: %u\n",
 	seq_printf(m, "power level avg    sclk: %u mclk: %u\n",
 		   sclk, mclk);
 		   sclk, mclk);

+ 17 - 8
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c

@@ -2493,6 +2493,9 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc,
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	int xorigin = 0, yorigin = 0;
 	int xorigin = 0, yorigin = 0;
 
 
+	amdgpu_crtc->cursor_x = x;
+	amdgpu_crtc->cursor_y = y;
+
 	/* avivo cursor are offset into the total surface */
 	/* avivo cursor are offset into the total surface */
 	x += crtc->x;
 	x += crtc->x;
 	y += crtc->y;
 	y += crtc->y;
@@ -2509,11 +2512,6 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc,
 
 
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
-	WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
-	       ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
-
-	amdgpu_crtc->cursor_x = x;
-	amdgpu_crtc->cursor_y = y;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2539,6 +2537,7 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
 				      int32_t hot_y)
 				      int32_t hot_y)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_gem_object *obj;
 	struct amdgpu_bo *aobj;
 	struct amdgpu_bo *aobj;
 	int ret;
 	int ret;
@@ -2577,9 +2576,6 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
 		return ret;
 		return ret;
 	}
 	}
 
 
-	amdgpu_crtc->cursor_width = width;
-	amdgpu_crtc->cursor_height = height;
-
 	dce_v10_0_lock_cursor(crtc, true);
 	dce_v10_0_lock_cursor(crtc, true);
 
 
 	if (hot_x != amdgpu_crtc->cursor_hot_x ||
 	if (hot_x != amdgpu_crtc->cursor_hot_x ||
@@ -2595,6 +2591,14 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc,
 		amdgpu_crtc->cursor_hot_y = hot_y;
 		amdgpu_crtc->cursor_hot_y = hot_y;
 	}
 	}
 
 
+	if (width != amdgpu_crtc->cursor_width ||
+	    height != amdgpu_crtc->cursor_height) {
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (width - 1) << 16 | (height - 1));
+		amdgpu_crtc->cursor_width = width;
+		amdgpu_crtc->cursor_height = height;
+	}
+
 	dce_v10_0_show_cursor(crtc);
 	dce_v10_0_show_cursor(crtc);
 	dce_v10_0_lock_cursor(crtc, false);
 	dce_v10_0_lock_cursor(crtc, false);
 
 
@@ -2616,6 +2620,7 @@ unpin:
 static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
 static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 
 
 	if (amdgpu_crtc->cursor_bo) {
 	if (amdgpu_crtc->cursor_bo) {
 		dce_v10_0_lock_cursor(crtc, true);
 		dce_v10_0_lock_cursor(crtc, true);
@@ -2623,6 +2628,10 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
 		dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 		dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 					     amdgpu_crtc->cursor_y);
 					     amdgpu_crtc->cursor_y);
 
 
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (amdgpu_crtc->cursor_width - 1) << 16 |
+		       (amdgpu_crtc->cursor_height - 1));
+
 		dce_v10_0_show_cursor(crtc);
 		dce_v10_0_show_cursor(crtc);
 
 
 		dce_v10_0_lock_cursor(crtc, false);
 		dce_v10_0_lock_cursor(crtc, false);

+ 17 - 8
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c

@@ -2509,6 +2509,9 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc,
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	int xorigin = 0, yorigin = 0;
 	int xorigin = 0, yorigin = 0;
 
 
+	amdgpu_crtc->cursor_x = x;
+	amdgpu_crtc->cursor_y = y;
+
 	/* avivo cursor are offset into the total surface */
 	/* avivo cursor are offset into the total surface */
 	x += crtc->x;
 	x += crtc->x;
 	y += crtc->y;
 	y += crtc->y;
@@ -2525,11 +2528,6 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc,
 
 
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
-	WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
-	       ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
-
-	amdgpu_crtc->cursor_x = x;
-	amdgpu_crtc->cursor_y = y;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2555,6 +2553,7 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
 				      int32_t hot_y)
 				      int32_t hot_y)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_gem_object *obj;
 	struct amdgpu_bo *aobj;
 	struct amdgpu_bo *aobj;
 	int ret;
 	int ret;
@@ -2593,9 +2592,6 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
 		return ret;
 		return ret;
 	}
 	}
 
 
-	amdgpu_crtc->cursor_width = width;
-	amdgpu_crtc->cursor_height = height;
-
 	dce_v11_0_lock_cursor(crtc, true);
 	dce_v11_0_lock_cursor(crtc, true);
 
 
 	if (hot_x != amdgpu_crtc->cursor_hot_x ||
 	if (hot_x != amdgpu_crtc->cursor_hot_x ||
@@ -2611,6 +2607,14 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc,
 		amdgpu_crtc->cursor_hot_y = hot_y;
 		amdgpu_crtc->cursor_hot_y = hot_y;
 	}
 	}
 
 
+	if (width != amdgpu_crtc->cursor_width ||
+	    height != amdgpu_crtc->cursor_height) {
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (width - 1) << 16 | (height - 1));
+		amdgpu_crtc->cursor_width = width;
+		amdgpu_crtc->cursor_height = height;
+	}
+
 	dce_v11_0_show_cursor(crtc);
 	dce_v11_0_show_cursor(crtc);
 	dce_v11_0_lock_cursor(crtc, false);
 	dce_v11_0_lock_cursor(crtc, false);
 
 
@@ -2632,6 +2636,7 @@ unpin:
 static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
 static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 
 
 	if (amdgpu_crtc->cursor_bo) {
 	if (amdgpu_crtc->cursor_bo) {
 		dce_v11_0_lock_cursor(crtc, true);
 		dce_v11_0_lock_cursor(crtc, true);
@@ -2639,6 +2644,10 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
 		dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 		dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 					     amdgpu_crtc->cursor_y);
 					     amdgpu_crtc->cursor_y);
 
 
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (amdgpu_crtc->cursor_width - 1) << 16 |
+		       (amdgpu_crtc->cursor_height - 1));
+
 		dce_v11_0_show_cursor(crtc);
 		dce_v11_0_show_cursor(crtc);
 
 
 		dce_v11_0_lock_cursor(crtc, false);
 		dce_v11_0_lock_cursor(crtc, false);

+ 22 - 11
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c

@@ -460,9 +460,8 @@ static void dce_v6_0_resume_mc_access(struct amdgpu_device *adev,
 	for (i = 0; i < adev->mode_info.num_crtc; i++) {
 	for (i = 0; i < adev->mode_info.num_crtc; i++) {
 		if (save->crtc_enabled[i]) {
 		if (save->crtc_enabled[i]) {
 			tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]);
 			tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]);
-			if ((tmp & 0x7) != 3) {
+			if ((tmp & 0x7) != 0) {
 				tmp &= ~0x7;
 				tmp &= ~0x7;
-				tmp |= 0x3;
 				WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp);
 				WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp);
 			}
 			}
 			tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
 			tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
@@ -1860,7 +1859,8 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	int xorigin = 0, yorigin = 0;
 	int xorigin = 0, yorigin = 0;
 
 
-	int w = amdgpu_crtc->cursor_width;
+	amdgpu_crtc->cursor_x = x;
+	amdgpu_crtc->cursor_y = y;
 
 
 	/* avivo cursor are offset into the total surface */
 	/* avivo cursor are offset into the total surface */
 	x += crtc->x;
 	x += crtc->x;
@@ -1878,11 +1878,7 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc,
 
 
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
-	WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
-	       ((w - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
 
 
-	amdgpu_crtc->cursor_x = x;
-	amdgpu_crtc->cursor_y = y;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1907,6 +1903,7 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
 				     int32_t hot_y)
 				     int32_t hot_y)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_gem_object *obj;
 	struct amdgpu_bo *aobj;
 	struct amdgpu_bo *aobj;
 	int ret;
 	int ret;
@@ -1945,12 +1942,11 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
 		return ret;
 		return ret;
 	}
 	}
 
 
-	amdgpu_crtc->cursor_width = width;
-	amdgpu_crtc->cursor_height = height;
-
 	dce_v6_0_lock_cursor(crtc, true);
 	dce_v6_0_lock_cursor(crtc, true);
 
 
-	if (hot_x != amdgpu_crtc->cursor_hot_x ||
+	if (width != amdgpu_crtc->cursor_width ||
+	    height != amdgpu_crtc->cursor_height ||
+	    hot_x != amdgpu_crtc->cursor_hot_x ||
 	    hot_y != amdgpu_crtc->cursor_hot_y) {
 	    hot_y != amdgpu_crtc->cursor_hot_y) {
 		int x, y;
 		int x, y;
 
 
@@ -1959,10 +1955,20 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc,
 
 
 		dce_v6_0_cursor_move_locked(crtc, x, y);
 		dce_v6_0_cursor_move_locked(crtc, x, y);
 
 
+		amdgpu_crtc->cursor_width = width;
+		amdgpu_crtc->cursor_height = height;
 		amdgpu_crtc->cursor_hot_x = hot_x;
 		amdgpu_crtc->cursor_hot_x = hot_x;
 		amdgpu_crtc->cursor_hot_y = hot_y;
 		amdgpu_crtc->cursor_hot_y = hot_y;
 	}
 	}
 
 
+	if (width != amdgpu_crtc->cursor_width ||
+	    height != amdgpu_crtc->cursor_height) {
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (width - 1) << 16 | (height - 1));
+		amdgpu_crtc->cursor_width = width;
+		amdgpu_crtc->cursor_height = height;
+	}
+
 	dce_v6_0_show_cursor(crtc);
 	dce_v6_0_show_cursor(crtc);
 	dce_v6_0_lock_cursor(crtc, false);
 	dce_v6_0_lock_cursor(crtc, false);
 
 
@@ -1984,6 +1990,7 @@ unpin:
 static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
 static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 
 
 	if (amdgpu_crtc->cursor_bo) {
 	if (amdgpu_crtc->cursor_bo) {
 		dce_v6_0_lock_cursor(crtc, true);
 		dce_v6_0_lock_cursor(crtc, true);
@@ -1991,6 +1998,10 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
 		dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 		dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 					    amdgpu_crtc->cursor_y);
 					    amdgpu_crtc->cursor_y);
 
 
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (amdgpu_crtc->cursor_width - 1) << 16 |
+		       (amdgpu_crtc->cursor_height - 1));
+
 		dce_v6_0_show_cursor(crtc);
 		dce_v6_0_show_cursor(crtc);
 		dce_v6_0_lock_cursor(crtc, false);
 		dce_v6_0_lock_cursor(crtc, false);
 	}
 	}

+ 19 - 8
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c

@@ -2344,6 +2344,9 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc,
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct amdgpu_device *adev = crtc->dev->dev_private;
 	int xorigin = 0, yorigin = 0;
 	int xorigin = 0, yorigin = 0;
 
 
+	amdgpu_crtc->cursor_x = x;
+	amdgpu_crtc->cursor_y = y;
+
 	/* avivo cursor are offset into the total surface */
 	/* avivo cursor are offset into the total surface */
 	x += crtc->x;
 	x += crtc->x;
 	y += crtc->y;
 	y += crtc->y;
@@ -2360,11 +2363,6 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc,
 
 
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
 	WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
-	WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
-	       ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
-
-	amdgpu_crtc->cursor_x = x;
-	amdgpu_crtc->cursor_y = y;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2390,6 +2388,7 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
 				     int32_t hot_y)
 				     int32_t hot_y)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_gem_object *obj;
 	struct amdgpu_bo *aobj;
 	struct amdgpu_bo *aobj;
 	int ret;
 	int ret;
@@ -2428,9 +2427,6 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
 		return ret;
 		return ret;
 	}
 	}
 
 
-	amdgpu_crtc->cursor_width = width;
-	amdgpu_crtc->cursor_height = height;
-
 	dce_v8_0_lock_cursor(crtc, true);
 	dce_v8_0_lock_cursor(crtc, true);
 
 
 	if (hot_x != amdgpu_crtc->cursor_hot_x ||
 	if (hot_x != amdgpu_crtc->cursor_hot_x ||
@@ -2442,10 +2438,20 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc,
 
 
 		dce_v8_0_cursor_move_locked(crtc, x, y);
 		dce_v8_0_cursor_move_locked(crtc, x, y);
 
 
+		amdgpu_crtc->cursor_width = width;
+		amdgpu_crtc->cursor_height = height;
 		amdgpu_crtc->cursor_hot_x = hot_x;
 		amdgpu_crtc->cursor_hot_x = hot_x;
 		amdgpu_crtc->cursor_hot_y = hot_y;
 		amdgpu_crtc->cursor_hot_y = hot_y;
 	}
 	}
 
 
+	if (width != amdgpu_crtc->cursor_width ||
+	    height != amdgpu_crtc->cursor_height) {
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (width - 1) << 16 | (height - 1));
+		amdgpu_crtc->cursor_width = width;
+		amdgpu_crtc->cursor_height = height;
+	}
+
 	dce_v8_0_show_cursor(crtc);
 	dce_v8_0_show_cursor(crtc);
 	dce_v8_0_lock_cursor(crtc, false);
 	dce_v8_0_lock_cursor(crtc, false);
 
 
@@ -2467,6 +2473,7 @@ unpin:
 static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
 static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
 {
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = crtc->dev->dev_private;
 
 
 	if (amdgpu_crtc->cursor_bo) {
 	if (amdgpu_crtc->cursor_bo) {
 		dce_v8_0_lock_cursor(crtc, true);
 		dce_v8_0_lock_cursor(crtc, true);
@@ -2474,6 +2481,10 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
 		dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 		dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
 					    amdgpu_crtc->cursor_y);
 					    amdgpu_crtc->cursor_y);
 
 
+		WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+		       (amdgpu_crtc->cursor_width - 1) << 16 |
+		       (amdgpu_crtc->cursor_height - 1));
+
 		dce_v8_0_show_cursor(crtc);
 		dce_v8_0_show_cursor(crtc);
 
 
 		dce_v8_0_lock_cursor(crtc, false);
 		dce_v8_0_lock_cursor(crtc, false);

+ 25 - 0
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c

@@ -2827,6 +2827,21 @@ static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_
 	return RREG32(mmSQ_IND_DATA);
 	return RREG32(mmSQ_IND_DATA);
 }
 }
 
 
+static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd,
+			   uint32_t wave, uint32_t thread,
+			   uint32_t regno, uint32_t num, uint32_t *out)
+{
+	WREG32(mmSQ_IND_INDEX,
+		(wave << SQ_IND_INDEX__WAVE_ID__SHIFT) |
+		(simd << SQ_IND_INDEX__SIMD_ID__SHIFT) |
+		(regno << SQ_IND_INDEX__INDEX__SHIFT) |
+		(thread << SQ_IND_INDEX__THREAD_ID__SHIFT) |
+		(SQ_IND_INDEX__FORCE_READ_MASK) |
+		(SQ_IND_INDEX__AUTO_INCR_MASK));
+	while (num--)
+		*(out++) = RREG32(mmSQ_IND_DATA);
+}
+
 static void gfx_v6_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
 static void gfx_v6_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
 {
 {
 	/* type 0 wave data */
 	/* type 0 wave data */
@@ -2851,10 +2866,20 @@ static void gfx_v6_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, u
 	dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
 	dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
 }
 }
 
 
+static void gfx_v6_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
+				     uint32_t wave, uint32_t start,
+				     uint32_t size, uint32_t *dst)
+{
+	wave_read_regs(
+		adev, simd, wave, 0,
+		start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
+}
+
 static const struct amdgpu_gfx_funcs gfx_v6_0_gfx_funcs = {
 static const struct amdgpu_gfx_funcs gfx_v6_0_gfx_funcs = {
 	.get_gpu_clock_counter = &gfx_v6_0_get_gpu_clock_counter,
 	.get_gpu_clock_counter = &gfx_v6_0_get_gpu_clock_counter,
 	.select_se_sh = &gfx_v6_0_select_se_sh,
 	.select_se_sh = &gfx_v6_0_select_se_sh,
 	.read_wave_data = &gfx_v6_0_read_wave_data,
 	.read_wave_data = &gfx_v6_0_read_wave_data,
+	.read_wave_sgprs = &gfx_v6_0_read_wave_sgprs,
 };
 };
 
 
 static int gfx_v6_0_early_init(void *handle)
 static int gfx_v6_0_early_init(void *handle)

+ 25 - 0
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c

@@ -4380,6 +4380,21 @@ static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_
 	return RREG32(mmSQ_IND_DATA);
 	return RREG32(mmSQ_IND_DATA);
 }
 }
 
 
+static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd,
+			   uint32_t wave, uint32_t thread,
+			   uint32_t regno, uint32_t num, uint32_t *out)
+{
+	WREG32(mmSQ_IND_INDEX,
+		(wave << SQ_IND_INDEX__WAVE_ID__SHIFT) |
+		(simd << SQ_IND_INDEX__SIMD_ID__SHIFT) |
+		(regno << SQ_IND_INDEX__INDEX__SHIFT) |
+		(thread << SQ_IND_INDEX__THREAD_ID__SHIFT) |
+		(SQ_IND_INDEX__FORCE_READ_MASK) |
+		(SQ_IND_INDEX__AUTO_INCR_MASK));
+	while (num--)
+		*(out++) = RREG32(mmSQ_IND_DATA);
+}
+
 static void gfx_v7_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
 static void gfx_v7_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
 {
 {
 	/* type 0 wave data */
 	/* type 0 wave data */
@@ -4404,10 +4419,20 @@ static void gfx_v7_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, u
 	dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
 	dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
 }
 }
 
 
+static void gfx_v7_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
+				     uint32_t wave, uint32_t start,
+				     uint32_t size, uint32_t *dst)
+{
+	wave_read_regs(
+		adev, simd, wave, 0,
+		start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
+}
+
 static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
 static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
 	.get_gpu_clock_counter = &gfx_v7_0_get_gpu_clock_counter,
 	.get_gpu_clock_counter = &gfx_v7_0_get_gpu_clock_counter,
 	.select_se_sh = &gfx_v7_0_select_se_sh,
 	.select_se_sh = &gfx_v7_0_select_se_sh,
 	.read_wave_data = &gfx_v7_0_read_wave_data,
 	.read_wave_data = &gfx_v7_0_read_wave_data,
+	.read_wave_sgprs = &gfx_v7_0_read_wave_sgprs,
 };
 };
 
 
 static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = {
 static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = {

+ 61 - 302
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c

@@ -25,6 +25,7 @@
 #include "amdgpu.h"
 #include "amdgpu.h"
 #include "amdgpu_gfx.h"
 #include "amdgpu_gfx.h"
 #include "vi.h"
 #include "vi.h"
+#include "vi_structs.h"
 #include "vid.h"
 #include "vid.h"
 #include "amdgpu_ucode.h"
 #include "amdgpu_ucode.h"
 #include "amdgpu_atombios.h"
 #include "amdgpu_atombios.h"
@@ -167,6 +168,7 @@ static const u32 golden_settings_tonga_a11[] =
 	mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
 	mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
 	mmPA_SC_FIFO_DEPTH_CNTL, 0x000003ff, 0x000000fc,
 	mmPA_SC_FIFO_DEPTH_CNTL, 0x000003ff, 0x000000fc,
 	mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
 	mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+	mmRLC_CGCG_CGLS_CTRL, 0x00000003, 0x0000003c,
 	mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
 	mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
 	mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
 	mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
 	mmTCC_CTRL, 0x00100000, 0xf31fff7f,
 	mmTCC_CTRL, 0x00100000, 0xf31fff7f,
@@ -1371,7 +1373,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
 
 
 	if (adev->gfx.mec.hpd_eop_obj == NULL) {
 	if (adev->gfx.mec.hpd_eop_obj == NULL) {
 		r = amdgpu_bo_create(adev,
 		r = amdgpu_bo_create(adev,
-				     adev->gfx.mec.num_mec *adev->gfx.mec.num_pipe * MEC_HPD_SIZE * 2,
+				     adev->gfx.mec.num_queue * MEC_HPD_SIZE,
 				     PAGE_SIZE, true,
 				     PAGE_SIZE, true,
 				     AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL,
 				     AMDGPU_GEM_DOMAIN_GTT, 0, NULL, NULL,
 				     &adev->gfx.mec.hpd_eop_obj);
 				     &adev->gfx.mec.hpd_eop_obj);
@@ -1400,7 +1402,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
 		return r;
 		return r;
 	}
 	}
 
 
-	memset(hpd, 0, adev->gfx.mec.num_mec *adev->gfx.mec.num_pipe * MEC_HPD_SIZE * 2);
+	memset(hpd, 0, adev->gfx.mec.num_queue * MEC_HPD_SIZE);
 
 
 	amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj);
 	amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj);
 	amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj);
 	amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj);
@@ -4469,267 +4471,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 	return 0;
 	return 0;
 }
 }
 
 
-struct vi_mqd {
-	uint32_t header;  /* ordinal0 */
-	uint32_t compute_dispatch_initiator;  /* ordinal1 */
-	uint32_t compute_dim_x;  /* ordinal2 */
-	uint32_t compute_dim_y;  /* ordinal3 */
-	uint32_t compute_dim_z;  /* ordinal4 */
-	uint32_t compute_start_x;  /* ordinal5 */
-	uint32_t compute_start_y;  /* ordinal6 */
-	uint32_t compute_start_z;  /* ordinal7 */
-	uint32_t compute_num_thread_x;  /* ordinal8 */
-	uint32_t compute_num_thread_y;  /* ordinal9 */
-	uint32_t compute_num_thread_z;  /* ordinal10 */
-	uint32_t compute_pipelinestat_enable;  /* ordinal11 */
-	uint32_t compute_perfcount_enable;  /* ordinal12 */
-	uint32_t compute_pgm_lo;  /* ordinal13 */
-	uint32_t compute_pgm_hi;  /* ordinal14 */
-	uint32_t compute_tba_lo;  /* ordinal15 */
-	uint32_t compute_tba_hi;  /* ordinal16 */
-	uint32_t compute_tma_lo;  /* ordinal17 */
-	uint32_t compute_tma_hi;  /* ordinal18 */
-	uint32_t compute_pgm_rsrc1;  /* ordinal19 */
-	uint32_t compute_pgm_rsrc2;  /* ordinal20 */
-	uint32_t compute_vmid;  /* ordinal21 */
-	uint32_t compute_resource_limits;  /* ordinal22 */
-	uint32_t compute_static_thread_mgmt_se0;  /* ordinal23 */
-	uint32_t compute_static_thread_mgmt_se1;  /* ordinal24 */
-	uint32_t compute_tmpring_size;  /* ordinal25 */
-	uint32_t compute_static_thread_mgmt_se2;  /* ordinal26 */
-	uint32_t compute_static_thread_mgmt_se3;  /* ordinal27 */
-	uint32_t compute_restart_x;  /* ordinal28 */
-	uint32_t compute_restart_y;  /* ordinal29 */
-	uint32_t compute_restart_z;  /* ordinal30 */
-	uint32_t compute_thread_trace_enable;  /* ordinal31 */
-	uint32_t compute_misc_reserved;  /* ordinal32 */
-	uint32_t compute_dispatch_id;  /* ordinal33 */
-	uint32_t compute_threadgroup_id;  /* ordinal34 */
-	uint32_t compute_relaunch;  /* ordinal35 */
-	uint32_t compute_wave_restore_addr_lo;  /* ordinal36 */
-	uint32_t compute_wave_restore_addr_hi;  /* ordinal37 */
-	uint32_t compute_wave_restore_control;  /* ordinal38 */
-	uint32_t reserved9;  /* ordinal39 */
-	uint32_t reserved10;  /* ordinal40 */
-	uint32_t reserved11;  /* ordinal41 */
-	uint32_t reserved12;  /* ordinal42 */
-	uint32_t reserved13;  /* ordinal43 */
-	uint32_t reserved14;  /* ordinal44 */
-	uint32_t reserved15;  /* ordinal45 */
-	uint32_t reserved16;  /* ordinal46 */
-	uint32_t reserved17;  /* ordinal47 */
-	uint32_t reserved18;  /* ordinal48 */
-	uint32_t reserved19;  /* ordinal49 */
-	uint32_t reserved20;  /* ordinal50 */
-	uint32_t reserved21;  /* ordinal51 */
-	uint32_t reserved22;  /* ordinal52 */
-	uint32_t reserved23;  /* ordinal53 */
-	uint32_t reserved24;  /* ordinal54 */
-	uint32_t reserved25;  /* ordinal55 */
-	uint32_t reserved26;  /* ordinal56 */
-	uint32_t reserved27;  /* ordinal57 */
-	uint32_t reserved28;  /* ordinal58 */
-	uint32_t reserved29;  /* ordinal59 */
-	uint32_t reserved30;  /* ordinal60 */
-	uint32_t reserved31;  /* ordinal61 */
-	uint32_t reserved32;  /* ordinal62 */
-	uint32_t reserved33;  /* ordinal63 */
-	uint32_t reserved34;  /* ordinal64 */
-	uint32_t compute_user_data_0;  /* ordinal65 */
-	uint32_t compute_user_data_1;  /* ordinal66 */
-	uint32_t compute_user_data_2;  /* ordinal67 */
-	uint32_t compute_user_data_3;  /* ordinal68 */
-	uint32_t compute_user_data_4;  /* ordinal69 */
-	uint32_t compute_user_data_5;  /* ordinal70 */
-	uint32_t compute_user_data_6;  /* ordinal71 */
-	uint32_t compute_user_data_7;  /* ordinal72 */
-	uint32_t compute_user_data_8;  /* ordinal73 */
-	uint32_t compute_user_data_9;  /* ordinal74 */
-	uint32_t compute_user_data_10;  /* ordinal75 */
-	uint32_t compute_user_data_11;  /* ordinal76 */
-	uint32_t compute_user_data_12;  /* ordinal77 */
-	uint32_t compute_user_data_13;  /* ordinal78 */
-	uint32_t compute_user_data_14;  /* ordinal79 */
-	uint32_t compute_user_data_15;  /* ordinal80 */
-	uint32_t cp_compute_csinvoc_count_lo;  /* ordinal81 */
-	uint32_t cp_compute_csinvoc_count_hi;  /* ordinal82 */
-	uint32_t reserved35;  /* ordinal83 */
-	uint32_t reserved36;  /* ordinal84 */
-	uint32_t reserved37;  /* ordinal85 */
-	uint32_t cp_mqd_query_time_lo;  /* ordinal86 */
-	uint32_t cp_mqd_query_time_hi;  /* ordinal87 */
-	uint32_t cp_mqd_connect_start_time_lo;  /* ordinal88 */
-	uint32_t cp_mqd_connect_start_time_hi;  /* ordinal89 */
-	uint32_t cp_mqd_connect_end_time_lo;  /* ordinal90 */
-	uint32_t cp_mqd_connect_end_time_hi;  /* ordinal91 */
-	uint32_t cp_mqd_connect_end_wf_count;  /* ordinal92 */
-	uint32_t cp_mqd_connect_end_pq_rptr;  /* ordinal93 */
-	uint32_t cp_mqd_connect_end_pq_wptr;  /* ordinal94 */
-	uint32_t cp_mqd_connect_end_ib_rptr;  /* ordinal95 */
-	uint32_t reserved38;  /* ordinal96 */
-	uint32_t reserved39;  /* ordinal97 */
-	uint32_t cp_mqd_save_start_time_lo;  /* ordinal98 */
-	uint32_t cp_mqd_save_start_time_hi;  /* ordinal99 */
-	uint32_t cp_mqd_save_end_time_lo;  /* ordinal100 */
-	uint32_t cp_mqd_save_end_time_hi;  /* ordinal101 */
-	uint32_t cp_mqd_restore_start_time_lo;  /* ordinal102 */
-	uint32_t cp_mqd_restore_start_time_hi;  /* ordinal103 */
-	uint32_t cp_mqd_restore_end_time_lo;  /* ordinal104 */
-	uint32_t cp_mqd_restore_end_time_hi;  /* ordinal105 */
-	uint32_t reserved40;  /* ordinal106 */
-	uint32_t reserved41;  /* ordinal107 */
-	uint32_t gds_cs_ctxsw_cnt0;  /* ordinal108 */
-	uint32_t gds_cs_ctxsw_cnt1;  /* ordinal109 */
-	uint32_t gds_cs_ctxsw_cnt2;  /* ordinal110 */
-	uint32_t gds_cs_ctxsw_cnt3;  /* ordinal111 */
-	uint32_t reserved42;  /* ordinal112 */
-	uint32_t reserved43;  /* ordinal113 */
-	uint32_t cp_pq_exe_status_lo;  /* ordinal114 */
-	uint32_t cp_pq_exe_status_hi;  /* ordinal115 */
-	uint32_t cp_packet_id_lo;  /* ordinal116 */
-	uint32_t cp_packet_id_hi;  /* ordinal117 */
-	uint32_t cp_packet_exe_status_lo;  /* ordinal118 */
-	uint32_t cp_packet_exe_status_hi;  /* ordinal119 */
-	uint32_t gds_save_base_addr_lo;  /* ordinal120 */
-	uint32_t gds_save_base_addr_hi;  /* ordinal121 */
-	uint32_t gds_save_mask_lo;  /* ordinal122 */
-	uint32_t gds_save_mask_hi;  /* ordinal123 */
-	uint32_t ctx_save_base_addr_lo;  /* ordinal124 */
-	uint32_t ctx_save_base_addr_hi;  /* ordinal125 */
-	uint32_t reserved44;  /* ordinal126 */
-	uint32_t reserved45;  /* ordinal127 */
-	uint32_t cp_mqd_base_addr_lo;  /* ordinal128 */
-	uint32_t cp_mqd_base_addr_hi;  /* ordinal129 */
-	uint32_t cp_hqd_active;  /* ordinal130 */
-	uint32_t cp_hqd_vmid;  /* ordinal131 */
-	uint32_t cp_hqd_persistent_state;  /* ordinal132 */
-	uint32_t cp_hqd_pipe_priority;  /* ordinal133 */
-	uint32_t cp_hqd_queue_priority;  /* ordinal134 */
-	uint32_t cp_hqd_quantum;  /* ordinal135 */
-	uint32_t cp_hqd_pq_base_lo;  /* ordinal136 */
-	uint32_t cp_hqd_pq_base_hi;  /* ordinal137 */
-	uint32_t cp_hqd_pq_rptr;  /* ordinal138 */
-	uint32_t cp_hqd_pq_rptr_report_addr_lo;  /* ordinal139 */
-	uint32_t cp_hqd_pq_rptr_report_addr_hi;  /* ordinal140 */
-	uint32_t cp_hqd_pq_wptr_poll_addr;  /* ordinal141 */
-	uint32_t cp_hqd_pq_wptr_poll_addr_hi;  /* ordinal142 */
-	uint32_t cp_hqd_pq_doorbell_control;  /* ordinal143 */
-	uint32_t cp_hqd_pq_wptr;  /* ordinal144 */
-	uint32_t cp_hqd_pq_control;  /* ordinal145 */
-	uint32_t cp_hqd_ib_base_addr_lo;  /* ordinal146 */
-	uint32_t cp_hqd_ib_base_addr_hi;  /* ordinal147 */
-	uint32_t cp_hqd_ib_rptr;  /* ordinal148 */
-	uint32_t cp_hqd_ib_control;  /* ordinal149 */
-	uint32_t cp_hqd_iq_timer;  /* ordinal150 */
-	uint32_t cp_hqd_iq_rptr;  /* ordinal151 */
-	uint32_t cp_hqd_dequeue_request;  /* ordinal152 */
-	uint32_t cp_hqd_dma_offload;  /* ordinal153 */
-	uint32_t cp_hqd_sema_cmd;  /* ordinal154 */
-	uint32_t cp_hqd_msg_type;  /* ordinal155 */
-	uint32_t cp_hqd_atomic0_preop_lo;  /* ordinal156 */
-	uint32_t cp_hqd_atomic0_preop_hi;  /* ordinal157 */
-	uint32_t cp_hqd_atomic1_preop_lo;  /* ordinal158 */
-	uint32_t cp_hqd_atomic1_preop_hi;  /* ordinal159 */
-	uint32_t cp_hqd_hq_status0;  /* ordinal160 */
-	uint32_t cp_hqd_hq_control0;  /* ordinal161 */
-	uint32_t cp_mqd_control;  /* ordinal162 */
-	uint32_t cp_hqd_hq_status1;  /* ordinal163 */
-	uint32_t cp_hqd_hq_control1;  /* ordinal164 */
-	uint32_t cp_hqd_eop_base_addr_lo;  /* ordinal165 */
-	uint32_t cp_hqd_eop_base_addr_hi;  /* ordinal166 */
-	uint32_t cp_hqd_eop_control;  /* ordinal167 */
-	uint32_t cp_hqd_eop_rptr;  /* ordinal168 */
-	uint32_t cp_hqd_eop_wptr;  /* ordinal169 */
-	uint32_t cp_hqd_eop_done_events;  /* ordinal170 */
-	uint32_t cp_hqd_ctx_save_base_addr_lo;  /* ordinal171 */
-	uint32_t cp_hqd_ctx_save_base_addr_hi;  /* ordinal172 */
-	uint32_t cp_hqd_ctx_save_control;  /* ordinal173 */
-	uint32_t cp_hqd_cntl_stack_offset;  /* ordinal174 */
-	uint32_t cp_hqd_cntl_stack_size;  /* ordinal175 */
-	uint32_t cp_hqd_wg_state_offset;  /* ordinal176 */
-	uint32_t cp_hqd_ctx_save_size;  /* ordinal177 */
-	uint32_t cp_hqd_gds_resource_state;  /* ordinal178 */
-	uint32_t cp_hqd_error;  /* ordinal179 */
-	uint32_t cp_hqd_eop_wptr_mem;  /* ordinal180 */
-	uint32_t cp_hqd_eop_dones;  /* ordinal181 */
-	uint32_t reserved46;  /* ordinal182 */
-	uint32_t reserved47;  /* ordinal183 */
-	uint32_t reserved48;  /* ordinal184 */
-	uint32_t reserved49;  /* ordinal185 */
-	uint32_t reserved50;  /* ordinal186 */
-	uint32_t reserved51;  /* ordinal187 */
-	uint32_t reserved52;  /* ordinal188 */
-	uint32_t reserved53;  /* ordinal189 */
-	uint32_t reserved54;  /* ordinal190 */
-	uint32_t reserved55;  /* ordinal191 */
-	uint32_t iqtimer_pkt_header;  /* ordinal192 */
-	uint32_t iqtimer_pkt_dw0;  /* ordinal193 */
-	uint32_t iqtimer_pkt_dw1;  /* ordinal194 */
-	uint32_t iqtimer_pkt_dw2;  /* ordinal195 */
-	uint32_t iqtimer_pkt_dw3;  /* ordinal196 */
-	uint32_t iqtimer_pkt_dw4;  /* ordinal197 */
-	uint32_t iqtimer_pkt_dw5;  /* ordinal198 */
-	uint32_t iqtimer_pkt_dw6;  /* ordinal199 */
-	uint32_t iqtimer_pkt_dw7;  /* ordinal200 */
-	uint32_t iqtimer_pkt_dw8;  /* ordinal201 */
-	uint32_t iqtimer_pkt_dw9;  /* ordinal202 */
-	uint32_t iqtimer_pkt_dw10;  /* ordinal203 */
-	uint32_t iqtimer_pkt_dw11;  /* ordinal204 */
-	uint32_t iqtimer_pkt_dw12;  /* ordinal205 */
-	uint32_t iqtimer_pkt_dw13;  /* ordinal206 */
-	uint32_t iqtimer_pkt_dw14;  /* ordinal207 */
-	uint32_t iqtimer_pkt_dw15;  /* ordinal208 */
-	uint32_t iqtimer_pkt_dw16;  /* ordinal209 */
-	uint32_t iqtimer_pkt_dw17;  /* ordinal210 */
-	uint32_t iqtimer_pkt_dw18;  /* ordinal211 */
-	uint32_t iqtimer_pkt_dw19;  /* ordinal212 */
-	uint32_t iqtimer_pkt_dw20;  /* ordinal213 */
-	uint32_t iqtimer_pkt_dw21;  /* ordinal214 */
-	uint32_t iqtimer_pkt_dw22;  /* ordinal215 */
-	uint32_t iqtimer_pkt_dw23;  /* ordinal216 */
-	uint32_t iqtimer_pkt_dw24;  /* ordinal217 */
-	uint32_t iqtimer_pkt_dw25;  /* ordinal218 */
-	uint32_t iqtimer_pkt_dw26;  /* ordinal219 */
-	uint32_t iqtimer_pkt_dw27;  /* ordinal220 */
-	uint32_t iqtimer_pkt_dw28;  /* ordinal221 */
-	uint32_t iqtimer_pkt_dw29;  /* ordinal222 */
-	uint32_t iqtimer_pkt_dw30;  /* ordinal223 */
-	uint32_t iqtimer_pkt_dw31;  /* ordinal224 */
-	uint32_t reserved56;  /* ordinal225 */
-	uint32_t reserved57;  /* ordinal226 */
-	uint32_t reserved58;  /* ordinal227 */
-	uint32_t set_resources_header;  /* ordinal228 */
-	uint32_t set_resources_dw1;  /* ordinal229 */
-	uint32_t set_resources_dw2;  /* ordinal230 */
-	uint32_t set_resources_dw3;  /* ordinal231 */
-	uint32_t set_resources_dw4;  /* ordinal232 */
-	uint32_t set_resources_dw5;  /* ordinal233 */
-	uint32_t set_resources_dw6;  /* ordinal234 */
-	uint32_t set_resources_dw7;  /* ordinal235 */
-	uint32_t reserved59;  /* ordinal236 */
-	uint32_t reserved60;  /* ordinal237 */
-	uint32_t reserved61;  /* ordinal238 */
-	uint32_t reserved62;  /* ordinal239 */
-	uint32_t reserved63;  /* ordinal240 */
-	uint32_t reserved64;  /* ordinal241 */
-	uint32_t reserved65;  /* ordinal242 */
-	uint32_t reserved66;  /* ordinal243 */
-	uint32_t reserved67;  /* ordinal244 */
-	uint32_t reserved68;  /* ordinal245 */
-	uint32_t reserved69;  /* ordinal246 */
-	uint32_t reserved70;  /* ordinal247 */
-	uint32_t reserved71;  /* ordinal248 */
-	uint32_t reserved72;  /* ordinal249 */
-	uint32_t reserved73;  /* ordinal250 */
-	uint32_t reserved74;  /* ordinal251 */
-	uint32_t reserved75;  /* ordinal252 */
-	uint32_t reserved76;  /* ordinal253 */
-	uint32_t reserved77;  /* ordinal254 */
-	uint32_t reserved78;  /* ordinal255 */
-
-	uint32_t reserved_t[256]; /* Reserve 256 dword buffer used by ucode */
-};
-
 static void gfx_v8_0_cp_compute_fini(struct amdgpu_device *adev)
 static void gfx_v8_0_cp_compute_fini(struct amdgpu_device *adev)
 {
 {
 	int i, r;
 	int i, r;
@@ -4763,34 +4504,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
 	u32 *buf;
 	u32 *buf;
 	struct vi_mqd *mqd;
 	struct vi_mqd *mqd;
 
 
-	/* init the pipes */
-	mutex_lock(&adev->srbm_mutex);
-	for (i = 0; i < (adev->gfx.mec.num_pipe * adev->gfx.mec.num_mec); i++) {
-		int me = (i < 4) ? 1 : 2;
-		int pipe = (i < 4) ? i : (i - 4);
-
-		eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE);
-		eop_gpu_addr >>= 8;
-
-		vi_srbm_select(adev, me, pipe, 0, 0);
-
-		/* write the EOP addr */
-		WREG32(mmCP_HQD_EOP_BASE_ADDR, eop_gpu_addr);
-		WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr));
-
-		/* set the VMID assigned */
-		WREG32(mmCP_HQD_VMID, 0);
-
-		/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
-		tmp = RREG32(mmCP_HQD_EOP_CONTROL);
-		tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
-				    (order_base_2(MEC_HPD_SIZE / 4) - 1));
-		WREG32(mmCP_HQD_EOP_CONTROL, tmp);
-	}
-	vi_srbm_select(adev, 0, 0, 0, 0);
-	mutex_unlock(&adev->srbm_mutex);
-
-	/* init the queues.  Just two for now. */
+	/* init the queues.  */
 	for (i = 0; i < adev->gfx.num_compute_rings; i++) {
 	for (i = 0; i < adev->gfx.num_compute_rings; i++) {
 		struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
 		struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
 
 
@@ -4842,6 +4556,22 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
 			       ring->pipe,
 			       ring->pipe,
 			       ring->queue, 0);
 			       ring->queue, 0);
 
 
+		eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE);
+		eop_gpu_addr >>= 8;
+
+		/* write the EOP addr */
+		WREG32(mmCP_HQD_EOP_BASE_ADDR, eop_gpu_addr);
+		WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr));
+
+		/* set the VMID assigned */
+		WREG32(mmCP_HQD_VMID, 0);
+
+		/* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+		tmp = RREG32(mmCP_HQD_EOP_CONTROL);
+		tmp = REG_SET_FIELD(tmp, CP_HQD_EOP_CONTROL, EOP_SIZE,
+				    (order_base_2(MEC_HPD_SIZE / 4) - 1));
+		WREG32(mmCP_HQD_EOP_CONTROL, tmp);
+
 		/* disable wptr polling */
 		/* disable wptr polling */
 		tmp = RREG32(mmCP_PQ_WPTR_POLL_CNTL);
 		tmp = RREG32(mmCP_PQ_WPTR_POLL_CNTL);
 		tmp = REG_SET_FIELD(tmp, CP_PQ_WPTR_POLL_CNTL, EN, 0);
 		tmp = REG_SET_FIELD(tmp, CP_PQ_WPTR_POLL_CNTL, EN, 0);
@@ -4925,9 +4655,9 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
 
 
 		/* only used if CP_PQ_WPTR_POLL_CNTL.CP_PQ_WPTR_POLL_CNTL__EN_MASK=1 */
 		/* only used if CP_PQ_WPTR_POLL_CNTL.CP_PQ_WPTR_POLL_CNTL__EN_MASK=1 */
 		wb_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
 		wb_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
-		mqd->cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
+		mqd->cp_hqd_pq_wptr_poll_addr_lo = wb_gpu_addr & 0xfffffffc;
 		mqd->cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
 		mqd->cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
-		WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, mqd->cp_hqd_pq_wptr_poll_addr);
+		WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, mqd->cp_hqd_pq_wptr_poll_addr_lo);
 		WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR_HI,
 		WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR_HI,
 		       mqd->cp_hqd_pq_wptr_poll_addr_hi);
 		       mqd->cp_hqd_pq_wptr_poll_addr_hi);
 
 
@@ -5098,6 +4828,10 @@ static int gfx_v8_0_hw_fini(void *handle)
 
 
 	amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
 	amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
 	amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
 	amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
+	if (amdgpu_sriov_vf(adev)) {
+		pr_debug("For SRIOV client, shouldn't do anything.\n");
+		return 0;
+	}
 	gfx_v8_0_cp_enable(adev, false);
 	gfx_v8_0_cp_enable(adev, false);
 	gfx_v8_0_rlc_stop(adev);
 	gfx_v8_0_rlc_stop(adev);
 	gfx_v8_0_cp_compute_fini(adev);
 	gfx_v8_0_cp_compute_fini(adev);
@@ -5450,6 +5184,21 @@ static uint32_t wave_read_ind(struct amdgpu_device *adev, uint32_t simd, uint32_
 	return RREG32(mmSQ_IND_DATA);
 	return RREG32(mmSQ_IND_DATA);
 }
 }
 
 
+static void wave_read_regs(struct amdgpu_device *adev, uint32_t simd,
+			   uint32_t wave, uint32_t thread,
+			   uint32_t regno, uint32_t num, uint32_t *out)
+{
+	WREG32(mmSQ_IND_INDEX,
+		(wave << SQ_IND_INDEX__WAVE_ID__SHIFT) |
+		(simd << SQ_IND_INDEX__SIMD_ID__SHIFT) |
+		(regno << SQ_IND_INDEX__INDEX__SHIFT) |
+		(thread << SQ_IND_INDEX__THREAD_ID__SHIFT) |
+		(SQ_IND_INDEX__FORCE_READ_MASK) |
+		(SQ_IND_INDEX__AUTO_INCR_MASK));
+	while (num--)
+		*(out++) = RREG32(mmSQ_IND_DATA);
+}
+
 static void gfx_v8_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
 static void gfx_v8_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields)
 {
 {
 	/* type 0 wave data */
 	/* type 0 wave data */
@@ -5474,11 +5223,21 @@ static void gfx_v8_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd, u
 	dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
 	dst[(*no_fields)++] = wave_read_ind(adev, simd, wave, ixSQ_WAVE_M0);
 }
 }
 
 
+static void gfx_v8_0_read_wave_sgprs(struct amdgpu_device *adev, uint32_t simd,
+				     uint32_t wave, uint32_t start,
+				     uint32_t size, uint32_t *dst)
+{
+	wave_read_regs(
+		adev, simd, wave, 0,
+		start + SQIND_WAVE_SGPRS_OFFSET, size, dst);
+}
+
 
 
 static const struct amdgpu_gfx_funcs gfx_v8_0_gfx_funcs = {
 static const struct amdgpu_gfx_funcs gfx_v8_0_gfx_funcs = {
 	.get_gpu_clock_counter = &gfx_v8_0_get_gpu_clock_counter,
 	.get_gpu_clock_counter = &gfx_v8_0_get_gpu_clock_counter,
 	.select_se_sh = &gfx_v8_0_select_se_sh,
 	.select_se_sh = &gfx_v8_0_select_se_sh,
 	.read_wave_data = &gfx_v8_0_read_wave_data,
 	.read_wave_data = &gfx_v8_0_read_wave_data,
+	.read_wave_sgprs = &gfx_v8_0_read_wave_sgprs,
 };
 };
 
 
 static int gfx_v8_0_early_init(void *handle)
 static int gfx_v8_0_early_init(void *handle)
@@ -5930,29 +5689,24 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
 	adev->gfx.rlc.funcs->enter_safe_mode(adev);
 	adev->gfx.rlc.funcs->enter_safe_mode(adev);
 
 
 	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
 	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
-		/* 1 enable cntx_empty_int_enable/cntx_busy_int_enable/
-		 * Cmp_busy/GFX_Idle interrupts
-		 */
-		gfx_v8_0_enable_gui_idle_interrupt(adev, true);
-
 		temp1 = data1 =	RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
 		temp1 = data1 =	RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
 		data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK;
 		data1 &= ~RLC_CGTT_MGCG_OVERRIDE__CGCG_MASK;
 		if (temp1 != data1)
 		if (temp1 != data1)
 			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
 			WREG32(mmRLC_CGTT_MGCG_OVERRIDE, data1);
 
 
-		/* 2 wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
+		/* : wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
 		gfx_v8_0_wait_for_rlc_serdes(adev);
 		gfx_v8_0_wait_for_rlc_serdes(adev);
 
 
-		/* 3 - clear cgcg override */
+		/* 2 - clear cgcg override */
 		gfx_v8_0_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
 		gfx_v8_0_send_serdes_cmd(adev, BPM_REG_CGCG_OVERRIDE, CLE_BPM_SERDES_CMD);
 
 
 		/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
 		/* wait for RLC_SERDES_CU_MASTER & RLC_SERDES_NONCU_MASTER idle */
 		gfx_v8_0_wait_for_rlc_serdes(adev);
 		gfx_v8_0_wait_for_rlc_serdes(adev);
 
 
-		/* 4 - write cmd to set CGLS */
+		/* 3 - write cmd to set CGLS */
 		gfx_v8_0_send_serdes_cmd(adev, BPM_REG_CGLS_EN, SET_BPM_SERDES_CMD);
 		gfx_v8_0_send_serdes_cmd(adev, BPM_REG_CGLS_EN, SET_BPM_SERDES_CMD);
 
 
-		/* 5 - enable cgcg */
+		/* 4 - enable cgcg */
 		data |= RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
 		data |= RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
 
 
 		if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) {
 		if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) {
@@ -5970,6 +5724,11 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
 
 
 		if (temp != data)
 		if (temp != data)
 			WREG32(mmRLC_CGCG_CGLS_CTRL, data);
 			WREG32(mmRLC_CGCG_CGLS_CTRL, data);
+
+		/* 5 enable cntx_empty_int_enable/cntx_busy_int_enable/
+		 * Cmp_busy/GFX_Idle interrupts
+		 */
+		gfx_v8_0_enable_gui_idle_interrupt(adev, true);
 	} else {
 	} else {
 		/* disable cntx_empty_int_enable & GFX Idle interrupt */
 		/* disable cntx_empty_int_enable & GFX Idle interrupt */
 		gfx_v8_0_enable_gui_idle_interrupt(adev, false);
 		gfx_v8_0_enable_gui_idle_interrupt(adev, false);

+ 1 - 6
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c

@@ -335,7 +335,7 @@ static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
 	 * size equal to the 1024 or vram, whichever is larger.
 	 * size equal to the 1024 or vram, whichever is larger.
 	 */
 	 */
 	if (amdgpu_gart_size == -1)
 	if (amdgpu_gart_size == -1)
-		adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
+		adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
 	else
 	else
 		adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 		adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 
 
@@ -795,11 +795,6 @@ static int gmc_v6_0_sw_init(void *handle)
 		return r;
 		return r;
 	}
 	}
 
 
-	r = amdgpu_ttm_global_init(adev);
-	if (r) {
-		return r;
-	}
-
 	r = gmc_v6_0_mc_init(adev);
 	r = gmc_v6_0_mc_init(adev);
 	if (r)
 	if (r)
 		return r;
 		return r;

+ 1 - 6
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c

@@ -385,7 +385,7 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
 	 * size equal to the 1024 or vram, whichever is larger.
 	 * size equal to the 1024 or vram, whichever is larger.
 	 */
 	 */
 	if (amdgpu_gart_size == -1)
 	if (amdgpu_gart_size == -1)
-		adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
+		adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
 	else
 	else
 		adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 		adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 
 
@@ -945,11 +945,6 @@ static int gmc_v7_0_sw_init(void *handle)
 		return r;
 		return r;
 	}
 	}
 
 
-	r = amdgpu_ttm_global_init(adev);
-	if (r) {
-		return r;
-	}
-
 	r = gmc_v7_0_mc_init(adev);
 	r = gmc_v7_0_mc_init(adev);
 	if (r)
 	if (r)
 		return r;
 		return r;

+ 1 - 6
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c

@@ -472,7 +472,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
 	 * size equal to the 1024 or vram, whichever is larger.
 	 * size equal to the 1024 or vram, whichever is larger.
 	 */
 	 */
 	if (amdgpu_gart_size == -1)
 	if (amdgpu_gart_size == -1)
-		adev->mc.gtt_size = amdgpu_ttm_get_gtt_mem_size(adev);
+		adev->mc.gtt_size = max((1024ULL << 20), adev->mc.mc_vram_size);
 	else
 	else
 		adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 		adev->mc.gtt_size = (uint64_t)amdgpu_gart_size << 20;
 
 
@@ -952,11 +952,6 @@ static int gmc_v8_0_sw_init(void *handle)
 		return r;
 		return r;
 	}
 	}
 
 
-	r = amdgpu_ttm_global_init(adev);
-	if (r) {
-		return r;
-	}
-
 	r = gmc_v8_0_mc_init(adev);
 	r = gmc_v8_0_mc_init(adev);
 	if (r)
 	if (r)
 		return r;
 		return r;

+ 2 - 0
drivers/gpu/drm/amd/amdgpu/si_dpm.c

@@ -3506,6 +3506,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
 		    (adev->pdev->revision == 0x80) ||
 		    (adev->pdev->revision == 0x80) ||
 		    (adev->pdev->revision == 0x81) ||
 		    (adev->pdev->revision == 0x81) ||
 		    (adev->pdev->revision == 0x83) ||
 		    (adev->pdev->revision == 0x83) ||
+		    (adev->pdev->revision == 0x87) ||
 		    (adev->pdev->device == 0x6604) ||
 		    (adev->pdev->device == 0x6604) ||
 		    (adev->pdev->device == 0x6605)) {
 		    (adev->pdev->device == 0x6605)) {
 			max_sclk = 75000;
 			max_sclk = 75000;
@@ -7715,6 +7716,7 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev)
 		    (adev->pdev->revision == 0x80) ||
 		    (adev->pdev->revision == 0x80) ||
 		    (adev->pdev->revision == 0x81) ||
 		    (adev->pdev->revision == 0x81) ||
 		    (adev->pdev->revision == 0x83) ||
 		    (adev->pdev->revision == 0x83) ||
+		    (adev->pdev->revision == 0x87) ||
 		    (adev->pdev->device == 0x6604) ||
 		    (adev->pdev->device == 0x6604) ||
 		    (adev->pdev->device == 0x6605))
 		    (adev->pdev->device == 0x6605))
 			chip_name = "oland_k";
 			chip_name = "oland_k";

+ 4 - 2
drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c

@@ -640,7 +640,7 @@ static void uvd_v5_0_enable_clock_gating(struct amdgpu_device *adev, bool enable
 		     UVD_SUVD_CGC_GATE__SDB_MASK;
 		     UVD_SUVD_CGC_GATE__SDB_MASK;
 
 
 	if (enable) {
 	if (enable) {
-		data3 |= (UVD_CGC_GATE__SYS_MASK       |
+		data3 |= (UVD_CGC_GATE__SYS_MASK     |
 			UVD_CGC_GATE__UDEC_MASK      |
 			UVD_CGC_GATE__UDEC_MASK      |
 			UVD_CGC_GATE__MPEG2_MASK     |
 			UVD_CGC_GATE__MPEG2_MASK     |
 			UVD_CGC_GATE__RBC_MASK       |
 			UVD_CGC_GATE__RBC_MASK       |
@@ -656,9 +656,11 @@ static void uvd_v5_0_enable_clock_gating(struct amdgpu_device *adev, bool enable
 			UVD_CGC_GATE__UDEC_DB_MASK   |
 			UVD_CGC_GATE__UDEC_DB_MASK   |
 			UVD_CGC_GATE__UDEC_MP_MASK   |
 			UVD_CGC_GATE__UDEC_MP_MASK   |
 			UVD_CGC_GATE__WCB_MASK       |
 			UVD_CGC_GATE__WCB_MASK       |
-			UVD_CGC_GATE__VCPU_MASK      |
 			UVD_CGC_GATE__JPEG_MASK      |
 			UVD_CGC_GATE__JPEG_MASK      |
 			UVD_CGC_GATE__SCPU_MASK);
 			UVD_CGC_GATE__SCPU_MASK);
+		/* only in pg enabled, we can gate clock to vcpu*/
+		if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
+			data3 |= UVD_CGC_GATE__VCPU_MASK;
 		data3 &= ~UVD_CGC_GATE__REGS_MASK;
 		data3 &= ~UVD_CGC_GATE__REGS_MASK;
 		data1 |= suvd_flags;
 		data1 |= suvd_flags;
 	} else {
 	} else {

+ 95 - 20
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c

@@ -42,6 +42,10 @@ static void uvd_v6_0_set_irq_funcs(struct amdgpu_device *adev);
 static int uvd_v6_0_start(struct amdgpu_device *adev);
 static int uvd_v6_0_start(struct amdgpu_device *adev);
 static void uvd_v6_0_stop(struct amdgpu_device *adev);
 static void uvd_v6_0_stop(struct amdgpu_device *adev);
 static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev);
 static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev);
+static int uvd_v6_0_set_clockgating_state(void *handle,
+					  enum amd_clockgating_state state);
+static void uvd_v6_0_enable_mgcg(struct amdgpu_device *adev,
+				 bool enable);
 
 
 /**
 /**
  * uvd_v6_0_ring_get_rptr - get read pointer
  * uvd_v6_0_ring_get_rptr - get read pointer
@@ -151,8 +155,6 @@ static int uvd_v6_0_hw_init(void *handle)
 	uint32_t tmp;
 	uint32_t tmp;
 	int r;
 	int r;
 
 
-	amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
-
 	r = uvd_v6_0_start(adev);
 	r = uvd_v6_0_start(adev);
 	if (r)
 	if (r)
 		goto done;
 		goto done;
@@ -395,11 +397,11 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
 	lmi_swap_cntl = 0;
 	lmi_swap_cntl = 0;
 	mp_swap_cntl = 0;
 	mp_swap_cntl = 0;
 
 
+	amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
+	uvd_v6_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
+	uvd_v6_0_enable_mgcg(adev, true);
 	uvd_v6_0_mc_resume(adev);
 	uvd_v6_0_mc_resume(adev);
 
 
-	/* disable clock gating */
-	WREG32_FIELD(UVD_CGC_CTRL, DYN_CLOCK_MODE, 0);
-
 	/* disable interupt */
 	/* disable interupt */
 	WREG32_FIELD(UVD_MASTINT_EN, VCPU_EN, 0);
 	WREG32_FIELD(UVD_MASTINT_EN, VCPU_EN, 0);
 
 
@@ -838,22 +840,72 @@ static int uvd_v6_0_process_interrupt(struct amdgpu_device *adev,
 	return 0;
 	return 0;
 }
 }
 
 
+static void uvd_v6_0_enable_clock_gating(struct amdgpu_device *adev, bool enable)
+{
+	uint32_t data1, data3;
+
+	data1 = RREG32(mmUVD_SUVD_CGC_GATE);
+	data3 = RREG32(mmUVD_CGC_GATE);
+
+	data1 |= UVD_SUVD_CGC_GATE__SRE_MASK |
+		     UVD_SUVD_CGC_GATE__SIT_MASK |
+		     UVD_SUVD_CGC_GATE__SMP_MASK |
+		     UVD_SUVD_CGC_GATE__SCM_MASK |
+		     UVD_SUVD_CGC_GATE__SDB_MASK |
+		     UVD_SUVD_CGC_GATE__SRE_H264_MASK |
+		     UVD_SUVD_CGC_GATE__SRE_HEVC_MASK |
+		     UVD_SUVD_CGC_GATE__SIT_H264_MASK |
+		     UVD_SUVD_CGC_GATE__SIT_HEVC_MASK |
+		     UVD_SUVD_CGC_GATE__SCM_H264_MASK |
+		     UVD_SUVD_CGC_GATE__SCM_HEVC_MASK |
+		     UVD_SUVD_CGC_GATE__SDB_H264_MASK |
+		     UVD_SUVD_CGC_GATE__SDB_HEVC_MASK;
+
+	if (enable) {
+		data3 |= (UVD_CGC_GATE__SYS_MASK       |
+			UVD_CGC_GATE__UDEC_MASK      |
+			UVD_CGC_GATE__MPEG2_MASK     |
+			UVD_CGC_GATE__RBC_MASK       |
+			UVD_CGC_GATE__LMI_MC_MASK    |
+			UVD_CGC_GATE__LMI_UMC_MASK   |
+			UVD_CGC_GATE__IDCT_MASK      |
+			UVD_CGC_GATE__MPRD_MASK      |
+			UVD_CGC_GATE__MPC_MASK       |
+			UVD_CGC_GATE__LBSI_MASK      |
+			UVD_CGC_GATE__LRBBM_MASK     |
+			UVD_CGC_GATE__UDEC_RE_MASK   |
+			UVD_CGC_GATE__UDEC_CM_MASK   |
+			UVD_CGC_GATE__UDEC_IT_MASK   |
+			UVD_CGC_GATE__UDEC_DB_MASK   |
+			UVD_CGC_GATE__UDEC_MP_MASK   |
+			UVD_CGC_GATE__WCB_MASK       |
+			UVD_CGC_GATE__JPEG_MASK      |
+			UVD_CGC_GATE__SCPU_MASK      |
+			UVD_CGC_GATE__JPEG2_MASK);
+		/* only in pg enabled, we can gate clock to vcpu*/
+		if (adev->pg_flags & AMD_PG_SUPPORT_UVD)
+			data3 |= UVD_CGC_GATE__VCPU_MASK;
+
+		data3 &= ~UVD_CGC_GATE__REGS_MASK;
+	} else {
+		data3 = 0;
+	}
+
+	WREG32(mmUVD_SUVD_CGC_GATE, data1);
+	WREG32(mmUVD_CGC_GATE, data3);
+}
+
 static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev)
 static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev)
 {
 {
-	uint32_t data, data1, data2, suvd_flags;
+	uint32_t data, data2;
 
 
 	data = RREG32(mmUVD_CGC_CTRL);
 	data = RREG32(mmUVD_CGC_CTRL);
-	data1 = RREG32(mmUVD_SUVD_CGC_GATE);
 	data2 = RREG32(mmUVD_SUVD_CGC_CTRL);
 	data2 = RREG32(mmUVD_SUVD_CGC_CTRL);
 
 
+
 	data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |
 	data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK |
 		  UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
 		  UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK);
 
 
-	suvd_flags = UVD_SUVD_CGC_GATE__SRE_MASK |
-		     UVD_SUVD_CGC_GATE__SIT_MASK |
-		     UVD_SUVD_CGC_GATE__SMP_MASK |
-		     UVD_SUVD_CGC_GATE__SCM_MASK |
-		     UVD_SUVD_CGC_GATE__SDB_MASK;
 
 
 	data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
 	data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK |
 		(1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER)) |
 		(1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER)) |
@@ -886,11 +938,8 @@ static void uvd_v6_0_set_sw_clock_gating(struct amdgpu_device *adev)
 			UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
 			UVD_SUVD_CGC_CTRL__SMP_MODE_MASK |
 			UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
 			UVD_SUVD_CGC_CTRL__SCM_MODE_MASK |
 			UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);
 			UVD_SUVD_CGC_CTRL__SDB_MODE_MASK);
-	data1 |= suvd_flags;
 
 
 	WREG32(mmUVD_CGC_CTRL, data);
 	WREG32(mmUVD_CGC_CTRL, data);
-	WREG32(mmUVD_CGC_GATE, 0);
-	WREG32(mmUVD_SUVD_CGC_GATE, data1);
 	WREG32(mmUVD_SUVD_CGC_CTRL, data2);
 	WREG32(mmUVD_SUVD_CGC_CTRL, data2);
 }
 }
 
 
@@ -937,6 +986,32 @@ static void uvd_v6_0_set_hw_clock_gating(struct amdgpu_device *adev)
 }
 }
 #endif
 #endif
 
 
+static void uvd_v6_0_enable_mgcg(struct amdgpu_device *adev,
+				 bool enable)
+{
+	u32 orig, data;
+
+	if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {
+		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
+		data |= 0xfff;
+		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
+
+		orig = data = RREG32(mmUVD_CGC_CTRL);
+		data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
+		if (orig != data)
+			WREG32(mmUVD_CGC_CTRL, data);
+	} else {
+		data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
+		data &= ~0xfff;
+		WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
+
+		orig = data = RREG32(mmUVD_CGC_CTRL);
+		data &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
+		if (orig != data)
+			WREG32(mmUVD_CGC_CTRL, data);
+	}
+}
+
 static int uvd_v6_0_set_clockgating_state(void *handle,
 static int uvd_v6_0_set_clockgating_state(void *handle,
 					  enum amd_clockgating_state state)
 					  enum amd_clockgating_state state)
 {
 {
@@ -947,17 +1022,17 @@ static int uvd_v6_0_set_clockgating_state(void *handle,
 		return 0;
 		return 0;
 
 
 	if (enable) {
 	if (enable) {
-		/* disable HW gating and enable Sw gating */
-		uvd_v6_0_set_sw_clock_gating(adev);
-	} else {
 		/* wait for STATUS to clear */
 		/* wait for STATUS to clear */
 		if (uvd_v6_0_wait_for_idle(handle))
 		if (uvd_v6_0_wait_for_idle(handle))
 			return -EBUSY;
 			return -EBUSY;
-
+		uvd_v6_0_enable_clock_gating(adev, true);
 		/* enable HW gates because UVD is idle */
 		/* enable HW gates because UVD is idle */
 /*		uvd_v6_0_set_hw_clock_gating(adev); */
 /*		uvd_v6_0_set_hw_clock_gating(adev); */
+	} else {
+		/* disable HW gating and enable Sw gating */
+		uvd_v6_0_enable_clock_gating(adev, false);
 	}
 	}
-
+	uvd_v6_0_set_sw_clock_gating(adev);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c

@@ -134,7 +134,7 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
 	   accessible but the firmware will throttle the clocks on the
 	   accessible but the firmware will throttle the clocks on the
 	   fly as necessary.
 	   fly as necessary.
 	*/
 	*/
-	if (gated) {
+	if (!gated) {
 		data = RREG32(mmVCE_CLOCK_GATING_B);
 		data = RREG32(mmVCE_CLOCK_GATING_B);
 		data |= 0x1ff;
 		data |= 0x1ff;
 		data &= ~0xef0000;
 		data &= ~0xef0000;

+ 4 - 2
drivers/gpu/drm/amd/amdgpu/vi.c

@@ -937,12 +937,14 @@ static int vi_common_early_init(void *handle)
 		adev->external_rev_id = adev->rev_id + 0x14;
 		adev->external_rev_id = adev->rev_id + 0x14;
 		break;
 		break;
 	case CHIP_POLARIS11:
 	case CHIP_POLARIS11:
-		adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
+		adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
+			AMD_CG_SUPPORT_VCE_MGCG;
 		adev->pg_flags = 0;
 		adev->pg_flags = 0;
 		adev->external_rev_id = adev->rev_id + 0x5A;
 		adev->external_rev_id = adev->rev_id + 0x5A;
 		break;
 		break;
 	case CHIP_POLARIS10:
 	case CHIP_POLARIS10:
-		adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
+		adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
+			AMD_CG_SUPPORT_VCE_MGCG;
 		adev->pg_flags = 0;
 		adev->pg_flags = 0;
 		adev->external_rev_id = adev->rev_id + 0x50;
 		adev->external_rev_id = adev->rev_id + 0x50;
 		break;
 		break;

+ 2 - 2
drivers/gpu/drm/amd/powerplay/amd_powerplay.c

@@ -1004,12 +1004,12 @@ int amd_powerplay_reset(void *handle)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	hw_init_power_state_table(instance->hwmgr);
-
 	if ((amdgpu_dpm == 0)
 	if ((amdgpu_dpm == 0)
 		|| cgs_is_virtualization_enabled(instance->smu_mgr->device))
 		|| cgs_is_virtualization_enabled(instance->smu_mgr->device))
 		return 0;
 		return 0;
 
 
+	hw_init_power_state_table(instance->hwmgr);
+
 	if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
 	if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
 		return -EINVAL;
 		return -EINVAL;
 
 

+ 1 - 1
drivers/gpu/drm/amd/powerplay/eventmgr/eventtasks.c

@@ -154,7 +154,7 @@ int pem_task_powerdown_vce_tasks(struct pp_eventmgr *eventmgr, struct pem_event_
 
 
 int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
 int pem_task_disable_clock_power_gatings_tasks(struct pp_eventmgr *eventmgr, struct pem_event_data *event_data)
 {
 {
-	/* TODO */
+	phm_disable_clock_power_gatings(eventmgr->hwmgr);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c

@@ -35,7 +35,7 @@ static int phm_run_table(struct pp_hwmgr *hwmgr,
 	phm_table_function *function;
 	phm_table_function *function;
 
 
 	if (rt_table->function_list == NULL) {
 	if (rt_table->function_list == NULL) {
-		printk(KERN_INFO "[ powerplay ] this function not implement!\n");
+		pr_debug("[ powerplay ] this function not implement!\n");
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 13 - 0
drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c

@@ -209,6 +209,19 @@ int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr)
 	return 0;
 	return 0;
 }
 }
 
 
+int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr)
+{
+	PHM_FUNC_CHECK(hwmgr);
+
+	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+		PHM_PlatformCaps_TablelessHardwareInterface)) {
+		if (NULL != hwmgr->hwmgr_func->disable_clock_power_gating)
+			return hwmgr->hwmgr_func->disable_clock_power_gating(hwmgr);
+	}
+	return 0;
+}
+
+
 int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
 int phm_display_configuration_changed(struct pp_hwmgr *hwmgr)
 {
 {
 	PHM_FUNC_CHECK(hwmgr);
 	PHM_FUNC_CHECK(hwmgr);

+ 1 - 0
drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h

@@ -334,6 +334,7 @@ struct phm_clocks {
 	uint32_t clock[MAX_NUM_CLOCKS];
 	uint32_t clock[MAX_NUM_CLOCKS];
 };
 };
 
 
+extern int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr);
 extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr);
 extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr);
 extern int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate);
 extern int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate);
 extern int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate);
 extern int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate);

+ 6 - 0
drivers/gpu/drm/amd/powerplay/smumgr/fiji_smc.c

@@ -1958,6 +1958,12 @@ int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
 	int res;
 	int res;
 	uint64_t tmp64;
 	uint64_t tmp64;
 
 
+	if (hwmgr->thermal_controller.fanInfo.bNoFan) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
 	if (smu_data->smu7_data.fan_table_start == 0) {
 	if (smu_data->smu7_data.fan_table_start == 0) {
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 				PHM_PlatformCaps_MicrocodeFanControl);
 				PHM_PlatformCaps_MicrocodeFanControl);

+ 6 - 0
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c

@@ -2006,6 +2006,12 @@ int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
 	if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
 	if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
 		return 0;
 		return 0;
 
 
+	if (hwmgr->thermal_controller.fanInfo.bNoFan) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
 	if (0 == smu7_data->fan_table_start) {
 	if (0 == smu7_data->fan_table_start) {
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
 		return 0;
 		return 0;

+ 6 - 0
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c

@@ -1885,6 +1885,12 @@ int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
 	int res;
 	int res;
 	uint64_t tmp64;
 	uint64_t tmp64;
 
 
+	if (hwmgr->thermal_controller.fanInfo.bNoFan) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
 	if (smu_data->smu7_data.fan_table_start == 0) {
 	if (smu_data->smu7_data.fan_table_start == 0) {
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 				PHM_PlatformCaps_MicrocodeFanControl);
 				PHM_PlatformCaps_MicrocodeFanControl);

+ 17 - 4
drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c

@@ -366,12 +366,16 @@ static int smu7_populate_single_firmware_entry(struct pp_smumgr *smumgr,
 				&info);
 				&info);
 
 
 	if (!result) {
 	if (!result) {
-		entry->version = info.version;
+		entry->version = info.fw_version;
 		entry->id = (uint16_t)fw_type;
 		entry->id = (uint16_t)fw_type;
 		entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
 		entry->image_addr_high = smu_upper_32_bits(info.mc_addr);
 		entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
 		entry->image_addr_low = smu_lower_32_bits(info.mc_addr);
 		entry->meta_data_addr_high = 0;
 		entry->meta_data_addr_high = 0;
 		entry->meta_data_addr_low = 0;
 		entry->meta_data_addr_low = 0;
+
+		/* digest need be excluded out */
+		if (cgs_is_virtualization_enabled(smumgr->device))
+			info.image_size -= 20;
 		entry->data_size_byte = info.image_size;
 		entry->data_size_byte = info.image_size;
 		entry->num_register_entries = 0;
 		entry->num_register_entries = 0;
 	}
 	}
@@ -403,8 +407,14 @@ int smu7_request_smu_load_fw(struct pp_smumgr *smumgr)
 					0x0);
 					0x0);
 
 
 	if (smumgr->chip_id > CHIP_TOPAZ) { /* add support for Topaz */
 	if (smumgr->chip_id > CHIP_TOPAZ) { /* add support for Topaz */
-		smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, smu_data->smu_buffer.mc_addr_high);
-		smu7_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, smu_data->smu_buffer.mc_addr_low);
+		if (!cgs_is_virtualization_enabled(smumgr->device)) {
+			smu7_send_msg_to_smc_with_parameter(smumgr,
+						PPSMC_MSG_SMU_DRAM_ADDR_HI,
+						smu_data->smu_buffer.mc_addr_high);
+			smu7_send_msg_to_smc_with_parameter(smumgr,
+						PPSMC_MSG_SMU_DRAM_ADDR_LO,
+						smu_data->smu_buffer.mc_addr_low);
+		}
 		fw_to_load = UCODE_ID_RLC_G_MASK
 		fw_to_load = UCODE_ID_RLC_G_MASK
 			   + UCODE_ID_SDMA0_MASK
 			   + UCODE_ID_SDMA0_MASK
 			   + UCODE_ID_SDMA1_MASK
 			   + UCODE_ID_SDMA1_MASK
@@ -539,7 +549,6 @@ int smu7_init(struct pp_smumgr *smumgr)
 	smu_data = (struct smu7_smumgr *)(smumgr->backend);
 	smu_data = (struct smu7_smumgr *)(smumgr->backend);
 	smu_data->header_buffer.data_size =
 	smu_data->header_buffer.data_size =
 			((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
 			((sizeof(struct SMU_DRAMData_TOC) / 4096) + 1) * 4096;
-	smu_data->smu_buffer.data_size = 200*4096;
 
 
 /* Allocate FW image data structure and header buffer and
 /* Allocate FW image data structure and header buffer and
  * send the header buffer address to SMU */
  * send the header buffer address to SMU */
@@ -562,6 +571,10 @@ int smu7_init(struct pp_smumgr *smumgr)
 		(cgs_handle_t)smu_data->header_buffer.handle);
 		(cgs_handle_t)smu_data->header_buffer.handle);
 		return -EINVAL);
 		return -EINVAL);
 
 
+	if (cgs_is_virtualization_enabled(smumgr->device))
+		return 0;
+
+	smu_data->smu_buffer.data_size = 200*4096;
 	smu_allocate_memory(smumgr->device,
 	smu_allocate_memory(smumgr->device,
 		smu_data->smu_buffer.data_size,
 		smu_data->smu_buffer.data_size,
 		CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,
 		CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB,

+ 6 - 0
drivers/gpu/drm/amd/powerplay/smumgr/tonga_smc.c

@@ -2496,6 +2496,12 @@ int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
 					PHM_PlatformCaps_MicrocodeFanControl))
 					PHM_PlatformCaps_MicrocodeFanControl))
 		return 0;
 		return 0;
 
 
+	if (hwmgr->thermal_controller.fanInfo.bNoFan) {
+		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+			PHM_PlatformCaps_MicrocodeFanControl);
+		return 0;
+	}
+
 	if (0 == smu_data->smu7_data.fan_table_start) {
 	if (0 == smu_data->smu7_data.fan_table_start) {
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
 					PHM_PlatformCaps_MicrocodeFanControl);
 					PHM_PlatformCaps_MicrocodeFanControl);

+ 50 - 0
drivers/gpu/drm/drm_atomic.c

@@ -1087,12 +1087,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
 		 * now?) atomic writes to DPMS property:
 		 * now?) atomic writes to DPMS property:
 		 */
 		 */
 		return -EINVAL;
 		return -EINVAL;
+	} else if (property == config->tv_select_subconnector_property) {
+		state->tv.subconnector = val;
+	} else if (property == config->tv_left_margin_property) {
+		state->tv.margins.left = val;
+	} else if (property == config->tv_right_margin_property) {
+		state->tv.margins.right = val;
+	} else if (property == config->tv_top_margin_property) {
+		state->tv.margins.top = val;
+	} else if (property == config->tv_bottom_margin_property) {
+		state->tv.margins.bottom = val;
+	} else if (property == config->tv_mode_property) {
+		state->tv.mode = val;
+	} else if (property == config->tv_brightness_property) {
+		state->tv.brightness = val;
+	} else if (property == config->tv_contrast_property) {
+		state->tv.contrast = val;
+	} else if (property == config->tv_flicker_reduction_property) {
+		state->tv.flicker_reduction = val;
+	} else if (property == config->tv_overscan_property) {
+		state->tv.overscan = val;
+	} else if (property == config->tv_saturation_property) {
+		state->tv.saturation = val;
+	} else if (property == config->tv_hue_property) {
+		state->tv.hue = val;
 	} else if (connector->funcs->atomic_set_property) {
 	} else if (connector->funcs->atomic_set_property) {
 		return connector->funcs->atomic_set_property(connector,
 		return connector->funcs->atomic_set_property(connector,
 				state, property, val);
 				state, property, val);
 	} else {
 	} else {
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+
+	return 0;
 }
 }
 EXPORT_SYMBOL(drm_atomic_connector_set_property);
 EXPORT_SYMBOL(drm_atomic_connector_set_property);
 
 
@@ -1135,6 +1161,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = (state->crtc) ? state->crtc->base.id : 0;
 		*val = (state->crtc) ? state->crtc->base.id : 0;
 	} else if (property == config->dpms_property) {
 	} else if (property == config->dpms_property) {
 		*val = connector->dpms;
 		*val = connector->dpms;
+	} else if (property == config->tv_select_subconnector_property) {
+		*val = state->tv.subconnector;
+	} else if (property == config->tv_left_margin_property) {
+		*val = state->tv.margins.left;
+	} else if (property == config->tv_right_margin_property) {
+		*val = state->tv.margins.right;
+	} else if (property == config->tv_top_margin_property) {
+		*val = state->tv.margins.top;
+	} else if (property == config->tv_bottom_margin_property) {
+		*val = state->tv.margins.bottom;
+	} else if (property == config->tv_mode_property) {
+		*val = state->tv.mode;
+	} else if (property == config->tv_brightness_property) {
+		*val = state->tv.brightness;
+	} else if (property == config->tv_contrast_property) {
+		*val = state->tv.contrast;
+	} else if (property == config->tv_flicker_reduction_property) {
+		*val = state->tv.flicker_reduction;
+	} else if (property == config->tv_overscan_property) {
+		*val = state->tv.overscan;
+	} else if (property == config->tv_saturation_property) {
+		*val = state->tv.saturation;
+	} else if (property == config->tv_hue_property) {
+		*val = state->tv.hue;
 	} else if (connector->funcs->atomic_get_property) {
 	} else if (connector->funcs->atomic_get_property) {
 		return connector->funcs->atomic_get_property(connector,
 		return connector->funcs->atomic_get_property(connector,
 				state, property, val);
 				state, property, val);

+ 62 - 0
drivers/gpu/drm/drm_drv.c

@@ -650,6 +650,62 @@ void drm_dev_unref(struct drm_device *dev)
 }
 }
 EXPORT_SYMBOL(drm_dev_unref);
 EXPORT_SYMBOL(drm_dev_unref);
 
 
+static int create_compat_control_link(struct drm_device *dev)
+{
+	struct drm_minor *minor;
+	char *name;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return 0;
+
+	minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
+	if (!minor)
+		return 0;
+
+	/*
+	 * Some existing userspace out there uses the existing of the controlD*
+	 * sysfs files to figure out whether it's a modeset driver. It only does
+	 * readdir, hence a symlink is sufficient (and the least confusing
+	 * option). Otherwise controlD* is entirely unused.
+	 *
+	 * Old controlD chardev have been allocated in the range
+	 * 64-127.
+	 */
+	name = kasprintf(GFP_KERNEL, "controlD%d", minor->index + 64);
+	if (!name)
+		return -ENOMEM;
+
+	ret = sysfs_create_link(minor->kdev->kobj.parent,
+				&minor->kdev->kobj,
+				name);
+
+	kfree(name);
+
+	return ret;
+}
+
+static void remove_compat_control_link(struct drm_device *dev)
+{
+	struct drm_minor *minor;
+	char *name;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return;
+
+	minor = *drm_minor_get_slot(dev, DRM_MINOR_PRIMARY);
+	if (!minor)
+		return;
+
+	name = kasprintf(GFP_KERNEL, "controlD%d", minor->index);
+	if (!name)
+		return;
+
+	sysfs_remove_link(minor->kdev->kobj.parent, name);
+
+	kfree(name);
+}
+
 /**
 /**
  * drm_dev_register - Register DRM device
  * drm_dev_register - Register DRM device
  * @dev: Device to register
  * @dev: Device to register
@@ -688,6 +744,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 	if (ret)
 	if (ret)
 		goto err_minors;
 		goto err_minors;
 
 
+	ret = create_compat_control_link(dev);
+	if (ret)
+		goto err_minors;
+
 	if (dev->driver->load) {
 	if (dev->driver->load) {
 		ret = dev->driver->load(dev, flags);
 		ret = dev->driver->load(dev, flags);
 		if (ret)
 		if (ret)
@@ -701,6 +761,7 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 	goto out_unlock;
 	goto out_unlock;
 
 
 err_minors:
 err_minors:
+	remove_compat_control_link(dev);
 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
@@ -741,6 +802,7 @@ void drm_dev_unregister(struct drm_device *dev)
 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
 		drm_legacy_rmmap(dev, r_list->map);
 		drm_legacy_rmmap(dev, r_list->map);
 
 
+	remove_compat_control_link(dev);
 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
 	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);

+ 2 - 2
drivers/gpu/drm/drm_plane.c

@@ -79,7 +79,7 @@ static unsigned int drm_num_planes(struct drm_device *dev)
  * Zero on success, error code on failure.
  * Zero on success, error code on failure.
  */
  */
 int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
-			     unsigned long possible_crtcs,
+			     uint32_t possible_crtcs,
 			     const struct drm_plane_funcs *funcs,
 			     const struct drm_plane_funcs *funcs,
 			     const uint32_t *formats, unsigned int format_count,
 			     const uint32_t *formats, unsigned int format_count,
 			     enum drm_plane_type type,
 			     enum drm_plane_type type,
@@ -196,7 +196,7 @@ void drm_plane_unregister_all(struct drm_device *dev)
  * Zero on success, error code on failure.
  * Zero on success, error code on failure.
  */
  */
 int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
-		   unsigned long possible_crtcs,
+		   uint32_t possible_crtcs,
 		   const struct drm_plane_funcs *funcs,
 		   const struct drm_plane_funcs *funcs,
 		   const uint32_t *formats, unsigned int format_count,
 		   const uint32_t *formats, unsigned int format_count,
 		   bool is_primary)
 		   bool is_primary)

+ 0 - 1
drivers/gpu/drm/fsl-dcu/Makefile

@@ -3,6 +3,5 @@ fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
 		 fsl_dcu_drm_rgb.o \
 		 fsl_dcu_drm_rgb.o \
 		 fsl_dcu_drm_plane.o \
 		 fsl_dcu_drm_plane.o \
 		 fsl_dcu_drm_crtc.o \
 		 fsl_dcu_drm_crtc.o \
-		 fsl_dcu_drm_fbdev.o \
 		 fsl_tcon.o
 		 fsl_tcon.o
 obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
 obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o

+ 18 - 8
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c

@@ -32,6 +32,9 @@
 #include "fsl_dcu_drm_drv.h"
 #include "fsl_dcu_drm_drv.h"
 #include "fsl_tcon.h"
 #include "fsl_tcon.h"
 
 
+static int legacyfb_depth = 24;
+module_param(legacyfb_depth, int, 0444);
+
 static bool fsl_dcu_drm_is_volatile_reg(struct device *dev, unsigned int reg)
 static bool fsl_dcu_drm_is_volatile_reg(struct device *dev, unsigned int reg)
 {
 {
 	if (reg == DCU_INT_STATUS || reg == DCU_UPDATE_MODE)
 	if (reg == DCU_INT_STATUS || reg == DCU_UPDATE_MODE)
@@ -85,7 +88,18 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
 		goto done;
 		goto done;
 	dev->irq_enabled = true;
 	dev->irq_enabled = true;
 
 
-	fsl_dcu_fbdev_init(dev);
+	if (legacyfb_depth != 16 && legacyfb_depth != 24 &&
+	    legacyfb_depth != 32) {
+		dev_warn(dev->dev,
+			"Invalid legacyfb_depth.  Defaulting to 24bpp\n");
+		legacyfb_depth = 24;
+	}
+	fsl_dev->fbdev = drm_fbdev_cma_init(dev, legacyfb_depth, 1, 1);
+	if (IS_ERR(fsl_dev->fbdev)) {
+		ret = PTR_ERR(fsl_dev->fbdev);
+		fsl_dev->fbdev = NULL;
+		goto done;
+	}
 
 
 	return 0;
 	return 0;
 done:
 done:
@@ -106,6 +120,7 @@ static int fsl_dcu_unload(struct drm_device *dev)
 {
 {
 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 
 
+	drm_crtc_force_disable_all(dev);
 	drm_kms_helper_poll_fini(dev);
 	drm_kms_helper_poll_fini(dev);
 
 
 	if (fsl_dev->fbdev)
 	if (fsl_dev->fbdev)
@@ -332,11 +347,6 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
 	fsl_dev->soc = id->data;
 	fsl_dev->soc = id->data;
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(dev, "could not get memory IO resource\n");
-		return -ENODEV;
-	}
-
 	base = devm_ioremap_resource(dev, res);
 	base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(base)) {
 	if (IS_ERR(base)) {
 		ret = PTR_ERR(base);
 		ret = PTR_ERR(base);
@@ -346,7 +356,7 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
 	fsl_dev->irq = platform_get_irq(pdev, 0);
 	fsl_dev->irq = platform_get_irq(pdev, 0);
 	if (fsl_dev->irq < 0) {
 	if (fsl_dev->irq < 0) {
 		dev_err(dev, "failed to get irq\n");
 		dev_err(dev, "failed to get irq\n");
-		return -ENXIO;
+		return fsl_dev->irq;
 	}
 	}
 
 
 	fsl_dev->regmap = devm_regmap_init_mmio(dev, base,
 	fsl_dev->regmap = devm_regmap_init_mmio(dev, base,
@@ -424,9 +434,9 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev)
 {
 {
 	struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
 	struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
 
 
+	drm_put_dev(fsl_dev->drm);
 	clk_disable_unprepare(fsl_dev->clk);
 	clk_disable_unprepare(fsl_dev->clk);
 	clk_unregister(fsl_dev->pix_clk);
 	clk_unregister(fsl_dev->pix_clk);
-	drm_put_dev(fsl_dev->drm);
 
 
 	return 0;
 	return 0;
 }
 }

+ 0 - 1
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h

@@ -197,7 +197,6 @@ struct fsl_dcu_drm_device {
 	struct drm_atomic_state *state;
 	struct drm_atomic_state *state;
 };
 };
 
 
-void fsl_dcu_fbdev_init(struct drm_device *dev);
 int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
 int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
 
 
 #endif /* __FSL_DCU_DRM_DRV_H__ */
 #endif /* __FSL_DCU_DRM_DRV_H__ */

+ 0 - 23
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c

@@ -1,23 +0,0 @@
-/*
- * Copyright 2015 Freescale Semiconductor, Inc.
- *
- * Freescale DCU drm device driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "fsl_dcu_drm_drv.h"
-
-/* initialize fbdev helper */
-void fsl_dcu_fbdev_init(struct drm_device *dev)
-{
-	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
-
-	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
-}

+ 2 - 0
drivers/gpu/drm/i915/gvt/gvt.h

@@ -361,6 +361,8 @@ static inline void intel_vgpu_write_pci_bar(struct intel_vgpu *vgpu,
 		 * leave the bit 3 - bit 0 unchanged.
 		 * leave the bit 3 - bit 0 unchanged.
 		 */
 		 */
 		*pval = (val & GENMASK(31, 4)) | (*pval & GENMASK(3, 0));
 		*pval = (val & GENMASK(31, 4)) | (*pval & GENMASK(3, 0));
+	} else {
+		*pval = val;
 	}
 	}
 }
 }
 
 

+ 6 - 4
drivers/gpu/drm/i915/gvt/scheduler.c

@@ -177,8 +177,8 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
 	rq = i915_gem_request_alloc(dev_priv->engine[ring_id], shadow_ctx);
 	rq = i915_gem_request_alloc(dev_priv->engine[ring_id], shadow_ctx);
 	if (IS_ERR(rq)) {
 	if (IS_ERR(rq)) {
 		gvt_err("fail to allocate gem request\n");
 		gvt_err("fail to allocate gem request\n");
-		workload->status = PTR_ERR(rq);
-		return workload->status;
+		ret = PTR_ERR(rq);
+		goto out;
 	}
 	}
 
 
 	gvt_dbg_sched("ring id %d get i915 gem request %p\n", ring_id, rq);
 	gvt_dbg_sched("ring id %d get i915 gem request %p\n", ring_id, rq);
@@ -212,7 +212,8 @@ out:
 	if (ret)
 	if (ret)
 		workload->status = ret;
 		workload->status = ret;
 
 
-	i915_add_request_no_flush(rq);
+	if (!IS_ERR_OR_NULL(rq))
+		i915_add_request_no_flush(rq);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
 	return ret;
 	return ret;
 }
 }
@@ -460,7 +461,8 @@ complete:
 
 
 		complete_current_workload(gvt, ring_id);
 		complete_current_workload(gvt, ring_id);
 
 
-		i915_gem_request_put(fetch_and_zero(&workload->req));
+		if (workload->req)
+			i915_gem_request_put(fetch_and_zero(&workload->req));
 
 
 		if (need_force_wake)
 		if (need_force_wake)
 			intel_uncore_forcewake_put(gvt->dev_priv,
 			intel_uncore_forcewake_put(gvt->dev_priv,

+ 1 - 0
drivers/gpu/drm/i915/gvt/vgpu.c

@@ -378,6 +378,7 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
 	struct intel_vgpu *vgpu;
 	struct intel_vgpu *vgpu;
 
 
 	param.handle = 0;
 	param.handle = 0;
+	param.primary = 1;
 	param.low_gm_sz = type->low_gm_size;
 	param.low_gm_sz = type->low_gm_size;
 	param.high_gm_sz = type->high_gm_size;
 	param.high_gm_sz = type->high_gm_size;
 	param.fence_sz = type->fence;
 	param.fence_sz = type->fence;

+ 1 - 26
drivers/gpu/drm/i915/i915_debugfs.c

@@ -935,27 +935,6 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
 	return 0;
 	return 0;
 }
 }
 
 
-static int i915_hws_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = m->private;
-	struct drm_i915_private *dev_priv = node_to_i915(node);
-	struct intel_engine_cs *engine;
-	const u32 *hws;
-	int i;
-
-	engine = dev_priv->engine[(uintptr_t)node->info_ent->data];
-	hws = engine->status_page.page_addr;
-	if (hws == NULL)
-		return 0;
-
-	for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
-		seq_printf(m, "0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-			   i * 4,
-			   hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
-	}
-	return 0;
-}
-
 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
 
 
 static ssize_t
 static ssize_t
@@ -1047,7 +1026,7 @@ i915_next_seqno_get(void *data, u64 *val)
 {
 {
 	struct drm_i915_private *dev_priv = data;
 	struct drm_i915_private *dev_priv = data;
 
 
-	*val = atomic_read(&dev_priv->gt.global_timeline.next_seqno);
+	*val = 1 + atomic_read(&dev_priv->gt.global_timeline.next_seqno);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5403,10 +5382,6 @@ static const struct drm_info_list i915_debugfs_list[] = {
 	{"i915_gem_seqno", i915_gem_seqno_info, 0},
 	{"i915_gem_seqno", i915_gem_seqno_info, 0},
 	{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
 	{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
 	{"i915_gem_interrupt", i915_interrupt_info, 0},
 	{"i915_gem_interrupt", i915_interrupt_info, 0},
-	{"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
-	{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
-	{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
-	{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
 	{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
 	{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
 	{"i915_guc_info", i915_guc_info, 0},
 	{"i915_guc_info", i915_guc_info, 0},
 	{"i915_guc_load_status", i915_guc_load_status_info, 0},
 	{"i915_guc_load_status", i915_guc_load_status_info, 0},

+ 2 - 0
drivers/gpu/drm/i915/i915_gem.c

@@ -2764,6 +2764,8 @@ void i915_gem_reset(struct drm_i915_private *dev_priv)
 
 
 static void nop_submit_request(struct drm_i915_gem_request *request)
 static void nop_submit_request(struct drm_i915_gem_request *request)
 {
 {
+	i915_gem_request_submit(request);
+	intel_engine_init_global_seqno(request->engine, request->global_seqno);
 }
 }
 
 
 static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
 static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)

+ 27 - 7
drivers/gpu/drm/i915/i915_gem_request.c

@@ -200,8 +200,8 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
 	struct i915_gem_active *active, *next;
 	struct i915_gem_active *active, *next;
 
 
 	lockdep_assert_held(&request->i915->drm.struct_mutex);
 	lockdep_assert_held(&request->i915->drm.struct_mutex);
-	GEM_BUG_ON(!i915_sw_fence_done(&request->submit));
-	GEM_BUG_ON(!i915_sw_fence_done(&request->execute));
+	GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit));
+	GEM_BUG_ON(!i915_sw_fence_signaled(&request->execute));
 	GEM_BUG_ON(!i915_gem_request_completed(request));
 	GEM_BUG_ON(!i915_gem_request_completed(request));
 	GEM_BUG_ON(!request->i915->gt.active_requests);
 	GEM_BUG_ON(!request->i915->gt.active_requests);
 
 
@@ -445,11 +445,17 @@ void i915_gem_request_submit(struct drm_i915_gem_request *request)
 static int __i915_sw_fence_call
 static int __i915_sw_fence_call
 submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 {
 {
-	if (state == FENCE_COMPLETE) {
-		struct drm_i915_gem_request *request =
-			container_of(fence, typeof(*request), submit);
+	struct drm_i915_gem_request *request =
+		container_of(fence, typeof(*request), submit);
 
 
+	switch (state) {
+	case FENCE_COMPLETE:
 		request->engine->submit_request(request);
 		request->engine->submit_request(request);
+		break;
+
+	case FENCE_FREE:
+		i915_gem_request_put(request);
+		break;
 	}
 	}
 
 
 	return NOTIFY_DONE;
 	return NOTIFY_DONE;
@@ -458,6 +464,18 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 static int __i915_sw_fence_call
 static int __i915_sw_fence_call
 execute_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 execute_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 {
 {
+	struct drm_i915_gem_request *request =
+		container_of(fence, typeof(*request), execute);
+
+	switch (state) {
+	case FENCE_COMPLETE:
+		break;
+
+	case FENCE_FREE:
+		i915_gem_request_put(request);
+		break;
+	}
+
 	return NOTIFY_DONE;
 	return NOTIFY_DONE;
 }
 }
 
 
@@ -545,8 +563,10 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
 		       req->timeline->fence_context,
 		       req->timeline->fence_context,
 		       __timeline_get_seqno(req->timeline->common));
 		       __timeline_get_seqno(req->timeline->common));
 
 
-	i915_sw_fence_init(&req->submit, submit_notify);
-	i915_sw_fence_init(&req->execute, execute_notify);
+	/* We bump the ref for the fence chain */
+	i915_sw_fence_init(&i915_gem_request_get(req)->submit, submit_notify);
+	i915_sw_fence_init(&i915_gem_request_get(req)->execute, execute_notify);
+
 	/* Ensure that the execute fence completes after the submit fence -
 	/* Ensure that the execute fence completes after the submit fence -
 	 * as we complete the execute fence from within the submit fence
 	 * as we complete the execute fence from within the submit fence
 	 * callback, its completion would otherwise be visible first.
 	 * callback, its completion would otherwise be visible first.

+ 5 - 0
drivers/gpu/drm/i915/i915_sw_fence.h

@@ -75,6 +75,11 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
 				    unsigned long timeout,
 				    unsigned long timeout,
 				    gfp_t gfp);
 				    gfp_t gfp);
 
 
+static inline bool i915_sw_fence_signaled(const struct i915_sw_fence *fence)
+{
+	return atomic_read(&fence->pending) <= 0;
+}
+
 static inline bool i915_sw_fence_done(const struct i915_sw_fence *fence)
 static inline bool i915_sw_fence_done(const struct i915_sw_fence *fence)
 {
 {
 	return atomic_read(&fence->pending) < 0;
 	return atomic_read(&fence->pending) < 0;

+ 5 - 2
drivers/gpu/drm/i915/intel_audio.c

@@ -351,10 +351,13 @@ hsw_hdmi_audio_config_update(struct intel_crtc *intel_crtc, enum port port,
 
 
 	I915_WRITE(HSW_AUD_CFG(pipe), tmp);
 	I915_WRITE(HSW_AUD_CFG(pipe), tmp);
 
 
+	/*
+	 * Let's disable "Enable CTS or M Prog bit"
+	 * and let HW calculate the value
+	 */
 	tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
 	tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
-	tmp &= ~AUD_CONFIG_M_MASK;
+	tmp &= ~AUD_M_CTS_M_PROG_ENABLE;
 	tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
 	tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
-	tmp |= AUD_M_CTS_M_PROG_ENABLE;
 	I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
 	I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
 }
 }
 
 

+ 7 - 4
drivers/gpu/drm/i915/intel_display.c

@@ -12028,7 +12028,6 @@ static void intel_mmio_flip_work_func(struct work_struct *w)
 		to_intel_framebuffer(crtc->base.primary->fb);
 		to_intel_framebuffer(crtc->base.primary->fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 	struct drm_i915_gem_object *obj = intel_fb->obj;
 
 
-	i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
 	WARN_ON(i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT, NULL) < 0);
 	WARN_ON(i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT, NULL) < 0);
 
 
 	intel_pipe_update_start(crtc);
 	intel_pipe_update_start(crtc);
@@ -12284,6 +12283,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 		i915_add_request_no_flush(request);
 		i915_add_request_no_flush(request);
 	}
 	}
 
 
+	i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
 	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
 	i915_gem_track_fb(intel_fb_obj(old_fb), obj,
 			  to_intel_plane(primary)->frontbuffer_bit);
 			  to_intel_plane(primary)->frontbuffer_bit);
 	mutex_unlock(&dev->struct_mutex);
 	mutex_unlock(&dev->struct_mutex);
@@ -13995,8 +13995,9 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
 
 
 		DRM_DEBUG_KMS("New cdclk calculated to be atomic %u, actual %u\n",
 		DRM_DEBUG_KMS("New cdclk calculated to be atomic %u, actual %u\n",
 			      intel_state->cdclk, intel_state->dev_cdclk);
 			      intel_state->cdclk, intel_state->dev_cdclk);
-	} else
+	} else {
 		to_intel_atomic_state(state)->cdclk = dev_priv->atomic_cdclk_freq;
 		to_intel_atomic_state(state)->cdclk = dev_priv->atomic_cdclk_freq;
+	}
 
 
 	intel_modeset_clear_plls(state);
 	intel_modeset_clear_plls(state);
 
 
@@ -14097,8 +14098,9 @@ static int intel_atomic_check(struct drm_device *dev,
 
 
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
-	} else
-		intel_state->cdclk = dev_priv->cdclk_freq;
+	} else {
+		intel_state->cdclk = dev_priv->atomic_cdclk_freq;
+	}
 
 
 	ret = drm_atomic_helper_check_planes(dev, state);
 	ret = drm_atomic_helper_check_planes(dev, state);
 	if (ret)
 	if (ret)
@@ -16485,6 +16487,7 @@ int intel_modeset_init(struct drm_device *dev)
 
 
 	intel_update_czclk(dev_priv);
 	intel_update_czclk(dev_priv);
 	intel_update_cdclk(dev_priv);
 	intel_update_cdclk(dev_priv);
+	dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
 
 
 	intel_shared_dpll_init(dev);
 	intel_shared_dpll_init(dev);
 
 

+ 7 - 7
drivers/gpu/drm/i915/intel_pm.c

@@ -3851,10 +3851,10 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv,
 	I915_WRITE(reg, val);
 	I915_WRITE(reg, val);
 }
 }
 
 
-void skl_write_plane_wm(struct intel_crtc *intel_crtc,
-			const struct skl_plane_wm *wm,
-			const struct skl_ddb_allocation *ddb,
-			int plane)
+static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+			       const struct skl_plane_wm *wm,
+			       const struct skl_ddb_allocation *ddb,
+			       int plane)
 {
 {
 	struct drm_crtc *crtc = &intel_crtc->base;
 	struct drm_crtc *crtc = &intel_crtc->base;
 	struct drm_device *dev = crtc->dev;
 	struct drm_device *dev = crtc->dev;
@@ -3875,9 +3875,9 @@ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
 			    &ddb->y_plane[pipe][plane]);
 			    &ddb->y_plane[pipe][plane]);
 }
 }
 
 
-void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
-			 const struct skl_plane_wm *wm,
-			 const struct skl_ddb_allocation *ddb)
+static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+				const struct skl_plane_wm *wm,
+				const struct skl_ddb_allocation *ddb)
 {
 {
 	struct drm_crtc *crtc = &intel_crtc->base;
 	struct drm_crtc *crtc = &intel_crtc->base;
 	struct drm_device *dev = crtc->dev;
 	struct drm_device *dev = crtc->dev;

+ 9 - 0
drivers/gpu/drm/meson/Kconfig

@@ -0,0 +1,9 @@
+config DRM_MESON
+	tristate "DRM Support for Amlogic Meson Display Controller"
+	depends on DRM && OF && (ARM || ARM64)
+	depends on ARCH_MESON || COMPILE_TEST
+	select DRM_KMS_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_GEM_CMA_HELPER
+	select VIDEOMODE_HELPERS
+	select REGMAP_MMIO

+ 4 - 0
drivers/gpu/drm/meson/Makefile

@@ -0,0 +1,4 @@
+meson-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
+meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
+
+obj-$(CONFIG_DRM_MESON) += meson.o

+ 68 - 0
drivers/gpu/drm/meson/meson_canvas.c

@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "meson_drv.h"
+#include "meson_canvas.h"
+#include "meson_registers.h"
+
+/*
+ * CANVAS is a memory zone where physical memory frames information
+ * are stored for the VIU to scanout.
+ */
+
+/* DMC Registers */
+#define DMC_CAV_LUT_DATAL	0x48 /* 0x12 offset in data sheet */
+#define CANVAS_WIDTH_LBIT	29
+#define CANVAS_WIDTH_LWID       3
+#define DMC_CAV_LUT_DATAH	0x4c /* 0x13 offset in data sheet */
+#define CANVAS_WIDTH_HBIT       0
+#define CANVAS_HEIGHT_BIT       9
+#define CANVAS_BLKMODE_BIT      24
+#define DMC_CAV_LUT_ADDR	0x50 /* 0x14 offset in data sheet */
+#define CANVAS_LUT_WR_EN        (0x2 << 8)
+#define CANVAS_LUT_RD_EN        (0x1 << 8)
+
+void meson_canvas_setup(struct meson_drm *priv,
+			uint32_t canvas_index, uint32_t addr,
+			uint32_t stride, uint32_t height,
+			unsigned int wrap,
+			unsigned int blkmode)
+{
+	unsigned int val;
+
+	regmap_write(priv->dmc, DMC_CAV_LUT_DATAL,
+		(((addr + 7) >> 3)) |
+		(((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
+
+	regmap_write(priv->dmc, DMC_CAV_LUT_DATAH,
+		((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
+						CANVAS_WIDTH_HBIT) |
+		(height << CANVAS_HEIGHT_BIT) |
+		(wrap << 22) |
+		(blkmode << CANVAS_BLKMODE_BIT));
+
+	regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
+			CANVAS_LUT_WR_EN | canvas_index);
+
+	/* Force a read-back to make sure everything is flushed. */
+	regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val);
+}

+ 42 - 0
drivers/gpu/drm/meson/meson_canvas.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Canvas LUT Memory */
+
+#ifndef __MESON_CANVAS_H
+#define __MESON_CANVAS_H
+
+#define MESON_CANVAS_ID_OSD1	0x4e
+
+/* Canvas configuration. */
+#define MESON_CANVAS_WRAP_NONE	0x00
+#define	MESON_CANVAS_WRAP_X	0x01
+#define	MESON_CANVAS_WRAP_Y	0x02
+
+#define	MESON_CANVAS_BLKMODE_LINEAR	0x00
+#define	MESON_CANVAS_BLKMODE_32x32	0x01
+#define	MESON_CANVAS_BLKMODE_64x64	0x02
+
+void meson_canvas_setup(struct meson_drm *priv,
+			uint32_t canvas_index, uint32_t addr,
+			uint32_t stride, uint32_t height,
+			unsigned int wrap,
+			unsigned int blkmode);
+
+#endif /* __MESON_CANVAS_H */

+ 208 - 0
drivers/gpu/drm/meson/meson_crtc.c

@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "meson_crtc.h"
+#include "meson_plane.h"
+#include "meson_vpp.h"
+#include "meson_viu.h"
+#include "meson_registers.h"
+
+/* CRTC definition */
+
+struct meson_crtc {
+	struct drm_crtc base;
+	struct drm_pending_vblank_event *event;
+	struct meson_drm *priv;
+};
+#define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
+
+/* CRTC */
+
+static const struct drm_crtc_funcs meson_crtc_funcs = {
+	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.destroy		= drm_crtc_cleanup,
+	.page_flip		= drm_atomic_helper_page_flip,
+	.reset			= drm_atomic_helper_crtc_reset,
+	.set_config             = drm_atomic_helper_set_config,
+};
+
+static void meson_crtc_enable(struct drm_crtc *crtc)
+{
+	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+	struct drm_plane *plane = meson_crtc->priv->primary_plane;
+	struct meson_drm *priv = meson_crtc->priv;
+
+	/* Enable VPP Postblend */
+	writel(plane->state->crtc_w,
+	       priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
+
+	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
+			    priv->io_base + _REG(VPP_MISC));
+
+	priv->viu.osd1_enabled = true;
+}
+
+static void meson_crtc_disable(struct drm_crtc *crtc)
+{
+	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+	struct meson_drm *priv = meson_crtc->priv;
+
+	priv->viu.osd1_enabled = false;
+
+	/* Disable VPP Postblend */
+	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
+			    priv->io_base + _REG(VPP_MISC));
+
+	if (crtc->state->event && !crtc->state->active) {
+		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 meson_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+	unsigned long flags;
+
+	if (crtc->state->event) {
+		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+		spin_lock_irqsave(&crtc->dev->event_lock, flags);
+		meson_crtc->event = crtc->state->event;
+		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+		crtc->state->event = NULL;
+	}
+}
+
+static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_crtc_state)
+{
+	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+	struct meson_drm *priv = meson_crtc->priv;
+
+	if (priv->viu.osd1_enabled)
+		priv->viu.osd1_commit = true;
+}
+
+static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
+	.enable		= meson_crtc_enable,
+	.disable	= meson_crtc_disable,
+	.atomic_begin	= meson_crtc_atomic_begin,
+	.atomic_flush	= meson_crtc_atomic_flush,
+};
+
+void meson_crtc_irq(struct meson_drm *priv)
+{
+	struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc);
+	unsigned long flags;
+
+	/* Update the OSD registers */
+	if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {
+		writel_relaxed(priv->viu.osd1_ctrl_stat,
+				priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
+		writel_relaxed(priv->viu.osd1_blk0_cfg[0],
+				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));
+		writel_relaxed(priv->viu.osd1_blk0_cfg[1],
+				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1));
+		writel_relaxed(priv->viu.osd1_blk0_cfg[2],
+				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2));
+		writel_relaxed(priv->viu.osd1_blk0_cfg[3],
+				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
+		writel_relaxed(priv->viu.osd1_blk0_cfg[4],
+				priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
+
+		/* If output is interlace, make use of the Scaler */
+		if (priv->viu.osd1_interlace) {
+			struct drm_plane *plane = priv->primary_plane;
+			struct drm_plane_state *state = plane->state;
+			struct drm_rect dest = {
+				.x1 = state->crtc_x,
+				.y1 = state->crtc_y,
+				.x2 = state->crtc_x + state->crtc_w,
+				.y2 = state->crtc_y + state->crtc_h,
+			};
+
+			meson_vpp_setup_interlace_vscaler_osd1(priv, &dest);
+		} else
+			meson_vpp_disable_interlace_vscaler_osd1(priv);
+
+		/* Enable OSD1 */
+		writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
+				    priv->io_base + _REG(VPP_MISC));
+
+		priv->viu.osd1_commit = false;
+	}
+
+	drm_crtc_handle_vblank(priv->crtc);
+
+	spin_lock_irqsave(&priv->drm->event_lock, flags);
+	if (meson_crtc->event) {
+		drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
+		drm_crtc_vblank_put(priv->crtc);
+		meson_crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+}
+
+int meson_crtc_create(struct meson_drm *priv)
+{
+	struct meson_crtc *meson_crtc;
+	struct drm_crtc *crtc;
+	int ret;
+
+	meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
+				  GFP_KERNEL);
+	if (!meson_crtc)
+		return -ENOMEM;
+
+	meson_crtc->priv = priv;
+	crtc = &meson_crtc->base;
+	ret = drm_crtc_init_with_planes(priv->drm, crtc,
+					priv->primary_plane, NULL,
+					&meson_crtc_funcs, "meson_crtc");
+	if (ret) {
+		dev_err(priv->drm->dev, "Failed to init CRTC\n");
+		return ret;
+	}
+
+	drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);
+
+	priv->crtc = crtc;
+
+	return 0;
+}

+ 32 - 0
drivers/gpu/drm/meson/meson_crtc.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#ifndef __MESON_CRTC_H
+#define __MESON_CRTC_H
+
+#include "meson_drv.h"
+
+int meson_crtc_create(struct meson_drm *priv);
+
+void meson_crtc_irq(struct meson_drm *priv);
+
+#endif /* __MESON_CRTC_H */

+ 343 - 0
drivers/gpu/drm/meson/meson_drv.c

@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/of_graph.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_rect.h>
+#include <drm/drm_fb_helper.h>
+
+#include "meson_drv.h"
+#include "meson_plane.h"
+#include "meson_crtc.h"
+#include "meson_venc_cvbs.h"
+
+#include "meson_vpp.h"
+#include "meson_viu.h"
+#include "meson_venc.h"
+#include "meson_canvas.h"
+#include "meson_registers.h"
+
+#define DRIVER_NAME "meson"
+#define DRIVER_DESC "Amlogic Meson DRM driver"
+
+/*
+ * Video Processing Unit
+ *
+ * VPU Handles the Global Video Processing, it includes management of the
+ * clocks gates, blocks reset lines and power domains.
+ *
+ * What is missing :
+ * - Full reset of entire video processing HW blocks
+ * - Scaling and setup of the VPU clock
+ * - Bus clock gates
+ * - Powering up video processing HW blocks
+ * - Powering Up HDMI controller and PHY
+ */
+
+static void meson_fb_output_poll_changed(struct drm_device *dev)
+{
+	struct meson_drm *priv = dev->dev_private;
+
+	drm_fbdev_cma_hotplug_event(priv->fbdev);
+}
+
+static const struct drm_mode_config_funcs meson_mode_config_funcs = {
+	.output_poll_changed = meson_fb_output_poll_changed,
+	.atomic_check        = drm_atomic_helper_check,
+	.atomic_commit       = drm_atomic_helper_commit,
+	.fb_create           = drm_fb_cma_create,
+};
+
+static int meson_enable_vblank(struct drm_device *dev, unsigned int crtc)
+{
+	struct meson_drm *priv = dev->dev_private;
+
+	meson_venc_enable_vsync(priv);
+
+	return 0;
+}
+
+static void meson_disable_vblank(struct drm_device *dev, unsigned int crtc)
+{
+	struct meson_drm *priv = dev->dev_private;
+
+	meson_venc_disable_vsync(priv);
+}
+
+static irqreturn_t meson_irq(int irq, void *arg)
+{
+	struct drm_device *dev = arg;
+	struct meson_drm *priv = dev->dev_private;
+
+	(void)readl_relaxed(priv->io_base + _REG(VENC_INTFLAG));
+
+	meson_crtc_irq(priv);
+
+	return IRQ_HANDLED;
+}
+
+static const struct file_operations fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct drm_driver meson_driver = {
+	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM |
+				  DRIVER_MODESET | DRIVER_PRIME |
+				  DRIVER_ATOMIC,
+
+	/* Vblank */
+	.enable_vblank		= meson_enable_vblank,
+	.disable_vblank		= meson_disable_vblank,
+	.get_vblank_counter	= drm_vblank_no_hw_counter,
+
+	/* IRQ */
+	.irq_handler		= meson_irq,
+
+	/* PRIME Ops */
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_export	= drm_gem_prime_export,
+	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+
+	/* GEM Ops */
+	.dumb_create		= drm_gem_cma_dumb_create,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.gem_free_object_unlocked = drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+
+	/* Misc */
+	.fops			= &fops,
+	.name			= DRIVER_NAME,
+	.desc			= DRIVER_DESC,
+	.date			= "20161109",
+	.major			= 1,
+	.minor			= 0,
+};
+
+static bool meson_vpu_has_available_connectors(struct device *dev)
+{
+	struct device_node *ep, *remote;
+
+	/* Parses each endpoint and check if remote exists */
+	for_each_endpoint_of_node(dev->of_node, ep) {
+		/* If the endpoint node exists, consider it enabled */
+		remote = of_graph_get_remote_port(ep);
+		if (remote)
+			return true;
+	}
+
+	return false;
+}
+
+static struct regmap_config meson_regmap_config = {
+	.reg_bits       = 32,
+	.val_bits       = 32,
+	.reg_stride     = 4,
+	.max_register   = 0x1000,
+};
+
+static int meson_drv_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct meson_drm *priv;
+	struct drm_device *drm;
+	struct resource *res;
+	void __iomem *regs;
+	int ret;
+
+	/* Checks if an output connector is available */
+	if (!meson_vpu_has_available_connectors(dev)) {
+		dev_err(dev, "No output connector available\n");
+		return -ENODEV;
+	}
+
+	drm = drm_dev_alloc(&meson_driver, dev);
+	if (IS_ERR(drm))
+		return PTR_ERR(drm);
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto free_drm;
+	}
+	drm->dev_private = priv;
+	priv->drm = drm;
+	priv->dev = dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	priv->io_base = regs;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
+	/* Simply ioremap since it may be a shared register zone */
+	regs = devm_ioremap(dev, res->start, resource_size(res));
+	if (!regs)
+		return -EADDRNOTAVAIL;
+
+	priv->hhi = devm_regmap_init_mmio(dev, regs,
+					  &meson_regmap_config);
+	if (IS_ERR(priv->hhi)) {
+		dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
+		return PTR_ERR(priv->hhi);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
+	/* Simply ioremap since it may be a shared register zone */
+	regs = devm_ioremap(dev, res->start, resource_size(res));
+	if (!regs)
+		return -EADDRNOTAVAIL;
+
+	priv->dmc = devm_regmap_init_mmio(dev, regs,
+					  &meson_regmap_config);
+	if (IS_ERR(priv->dmc)) {
+		dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
+		return PTR_ERR(priv->dmc);
+	}
+
+	priv->vsync_irq = platform_get_irq(pdev, 0);
+
+	drm_vblank_init(drm, 1);
+	drm_mode_config_init(drm);
+
+	/* Encoder Initialization */
+
+	ret = meson_venc_cvbs_create(priv);
+	if (ret)
+		goto free_drm;
+
+	/* Hardware Initialization */
+
+	meson_venc_init(priv);
+	meson_vpp_init(priv);
+	meson_viu_init(priv);
+
+	ret = meson_plane_create(priv);
+	if (ret)
+		goto free_drm;
+
+	ret = meson_crtc_create(priv);
+	if (ret)
+		goto free_drm;
+
+	ret = drm_irq_install(drm, priv->vsync_irq);
+	if (ret)
+		goto free_drm;
+
+	drm_mode_config_reset(drm);
+	drm->mode_config.max_width = 8192;
+	drm->mode_config.max_height = 8192;
+	drm->mode_config.funcs = &meson_mode_config_funcs;
+
+	priv->fbdev = drm_fbdev_cma_init(drm, 32,
+					 drm->mode_config.num_crtc,
+					 drm->mode_config.num_connector);
+	if (IS_ERR(priv->fbdev)) {
+		ret = PTR_ERR(priv->fbdev);
+		goto free_drm;
+	}
+
+	drm_kms_helper_poll_init(drm);
+
+	platform_set_drvdata(pdev, priv);
+
+	ret = drm_dev_register(drm, 0);
+	if (ret)
+		goto free_drm;
+
+	return 0;
+
+free_drm:
+	drm_dev_unref(drm);
+
+	return ret;
+}
+
+static int meson_drv_remove(struct platform_device *pdev)
+{
+	struct drm_device *drm = dev_get_drvdata(&pdev->dev);
+	struct meson_drm *priv = drm->dev_private;
+
+	drm_dev_unregister(drm);
+	drm_kms_helper_poll_fini(drm);
+	drm_fbdev_cma_fini(priv->fbdev);
+	drm_mode_config_cleanup(drm);
+	drm_vblank_cleanup(drm);
+	drm_dev_unref(drm);
+
+	return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+	{ .compatible = "amlogic,meson-gxbb-vpu" },
+	{ .compatible = "amlogic,meson-gxl-vpu" },
+	{ .compatible = "amlogic,meson-gxm-vpu" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
+static struct platform_driver meson_drm_platform_driver = {
+	.probe      = meson_drv_probe,
+	.remove     = meson_drv_remove,
+	.driver     = {
+		.owner  = THIS_MODULE,
+		.name   = DRIVER_NAME,
+		.of_match_table = dt_match,
+	},
+};
+
+module_platform_driver(meson_drm_platform_driver);
+
+MODULE_AUTHOR("Jasper St. Pierre <jstpierre@mecheye.net>");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");

+ 59 - 0
drivers/gpu/drm/meson/meson_drv.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MESON_DRV_H
+#define __MESON_DRV_H
+
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <drm/drmP.h>
+
+struct meson_drm {
+	struct device *dev;
+	void __iomem *io_base;
+	struct regmap *hhi;
+	struct regmap *dmc;
+	int vsync_irq;
+
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	struct drm_fbdev_cma *fbdev;
+	struct drm_plane *primary_plane;
+
+	/* Components Data */
+	struct {
+		bool osd1_enabled;
+		bool osd1_interlace;
+		bool osd1_commit;
+		uint32_t osd1_ctrl_stat;
+		uint32_t osd1_blk0_cfg[5];
+	} viu;
+
+	struct {
+		unsigned int current_mode;
+	} venc;
+};
+
+static inline int meson_vpu_is_compatible(struct meson_drm *priv,
+					  const char *compat)
+{
+	return of_device_is_compatible(priv->dev->of_node, compat);
+}
+
+#endif /* __MESON_DRV_H */

+ 230 - 0
drivers/gpu/drm/meson/meson_plane.c

@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_rect.h>
+
+#include "meson_plane.h"
+#include "meson_vpp.h"
+#include "meson_viu.h"
+#include "meson_canvas.h"
+#include "meson_registers.h"
+
+struct meson_plane {
+	struct drm_plane base;
+	struct meson_drm *priv;
+};
+#define to_meson_plane(x) container_of(x, struct meson_plane, base)
+
+static int meson_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct drm_crtc_state *crtc_state;
+	struct drm_rect clip = { 0, };
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	clip.x2 = crtc_state->mode.hdisplay;
+	clip.y2 = crtc_state->mode.vdisplay;
+
+	return drm_plane_helper_check_state(state, &clip,
+					    DRM_PLANE_HELPER_NO_SCALING,
+					    DRM_PLANE_HELPER_NO_SCALING,
+					    true, true);
+}
+
+/* Takes a fixed 16.16 number and converts it to integer. */
+static inline int64_t fixed16_to_int(int64_t value)
+{
+	return value >> 16;
+}
+
+static void meson_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct meson_plane *meson_plane = to_meson_plane(plane);
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct meson_drm *priv = meson_plane->priv;
+	struct drm_gem_cma_object *gem;
+	struct drm_rect src = {
+		.x1 = (state->src_x),
+		.y1 = (state->src_y),
+		.x2 = (state->src_x + state->src_w),
+		.y2 = (state->src_y + state->src_h),
+	};
+	struct drm_rect dest = {
+		.x1 = state->crtc_x,
+		.y1 = state->crtc_y,
+		.x2 = state->crtc_x + state->crtc_w,
+		.y2 = state->crtc_y + state->crtc_h,
+	};
+	unsigned long flags;
+
+	/*
+	 * Update Coordinates
+	 * Update Formats
+	 * Update Buffer
+	 * Enable Plane
+	 */
+	spin_lock_irqsave(&priv->drm->event_lock, flags);
+
+	/* Enable OSD and BLK0, set max global alpha */
+	priv->viu.osd1_ctrl_stat = OSD_ENABLE |
+				   (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
+				   OSD_BLK0_ENABLE;
+
+	/* Set up BLK0 to point to the right canvas */
+	priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
+				      OSD_ENDIANNESS_LE);
+
+	/* On GXBB, Use the old non-HDR RGB2YUV converter */
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
+		priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
+
+	switch (fb->pixel_format) {
+	case DRM_FORMAT_XRGB8888:
+		/* For XRGB, replace the pixel's alpha by 0xFF */
+		writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN,
+				    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
+		priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
+					      OSD_COLOR_MATRIX_32_ARGB;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		/* For ARGB, use the pixel's alpha */
+		writel_bits_relaxed(OSD_REPLACE_EN, 0,
+				    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
+		priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
+					      OSD_COLOR_MATRIX_32_ARGB;
+		break;
+	case DRM_FORMAT_RGB888:
+		priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 |
+					      OSD_COLOR_MATRIX_24_RGB;
+		break;
+	case DRM_FORMAT_RGB565:
+		priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 |
+					      OSD_COLOR_MATRIX_16_RGB565;
+		break;
+	};
+
+	if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
+		priv->viu.osd1_interlace = true;
+
+		dest.y1 /= 2;
+		dest.y2 /= 2;
+	} else
+		priv->viu.osd1_interlace = false;
+
+	/*
+	 * The format of these registers is (x2 << 16 | x1),
+	 * where x2 is exclusive.
+	 * e.g. +30x1920 would be (1919 << 16) | 30
+	 */
+	priv->viu.osd1_blk0_cfg[1] = ((fixed16_to_int(src.x2) - 1) << 16) |
+					fixed16_to_int(src.x1);
+	priv->viu.osd1_blk0_cfg[2] = ((fixed16_to_int(src.y2) - 1) << 16) |
+					fixed16_to_int(src.y1);
+	priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
+	priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
+
+	/* Update Canvas with buffer address */
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
+			   gem->paddr, fb->pitches[0],
+			   fb->height, MESON_CANVAS_WRAP_NONE,
+			   MESON_CANVAS_BLKMODE_LINEAR);
+
+	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+}
+
+static void meson_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+	struct meson_plane *meson_plane = to_meson_plane(plane);
+	struct meson_drm *priv = meson_plane->priv;
+
+	/* Disable OSD1 */
+	writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
+			    priv->io_base + _REG(VPP_MISC));
+
+}
+
+static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
+	.atomic_check	= meson_plane_atomic_check,
+	.atomic_disable	= meson_plane_atomic_disable,
+	.atomic_update	= meson_plane_atomic_update,
+};
+
+static const struct drm_plane_funcs meson_plane_funcs = {
+	.update_plane		= drm_atomic_helper_update_plane,
+	.disable_plane		= drm_atomic_helper_disable_plane,
+	.destroy		= drm_plane_cleanup,
+	.reset			= drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
+};
+
+static const uint32_t supported_drm_formats[] = {
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_RGB565,
+};
+
+int meson_plane_create(struct meson_drm *priv)
+{
+	struct meson_plane *meson_plane;
+	struct drm_plane *plane;
+
+	meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
+				   GFP_KERNEL);
+	if (!meson_plane)
+		return -ENOMEM;
+
+	meson_plane->priv = priv;
+	plane = &meson_plane->base;
+
+	drm_universal_plane_init(priv->drm, plane, 0xFF,
+				 &meson_plane_funcs,
+				 supported_drm_formats,
+				 ARRAY_SIZE(supported_drm_formats),
+				 DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
+
+	drm_plane_helper_add(plane, &meson_plane_helper_funcs);
+
+	priv->primary_plane = plane;
+
+	return 0;
+}

+ 30 - 0
drivers/gpu/drm/meson/meson_plane.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#ifndef __MESON_PLANE_H
+#define __MESON_PLANE_H
+
+#include "meson_drv.h"
+
+int meson_plane_create(struct meson_drm *priv);
+
+#endif /* __MESON_PLANE_H */

+ 1395 - 0
drivers/gpu/drm/meson/meson_registers.h

@@ -0,0 +1,1395 @@
+/*
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __MESON_REGISTERS_H
+#define __MESON_REGISTERS_H
+
+/* Shift all registers by 2 */
+#define _REG(reg)	((reg) << 2)
+
+#define writel_bits_relaxed(mask, val, addr) \
+	writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)
+
+/* vpp2 */
+#define VPP2_DUMMY_DATA 0x1900
+#define VPP2_LINE_IN_LENGTH 0x1901
+#define VPP2_PIC_IN_HEIGHT 0x1902
+#define VPP2_SCALE_COEF_IDX 0x1903
+#define VPP2_SCALE_COEF 0x1904
+#define VPP2_VSC_REGION12_STARTP 0x1905
+#define VPP2_VSC_REGION34_STARTP 0x1906
+#define VPP2_VSC_REGION4_ENDP 0x1907
+#define VPP2_VSC_START_PHASE_STEP 0x1908
+#define VPP2_VSC_REGION0_PHASE_SLOPE 0x1909
+#define VPP2_VSC_REGION1_PHASE_SLOPE 0x190a
+#define VPP2_VSC_REGION3_PHASE_SLOPE 0x190b
+#define VPP2_VSC_REGION4_PHASE_SLOPE 0x190c
+#define VPP2_VSC_PHASE_CTRL 0x190d
+#define VPP2_VSC_INI_PHASE 0x190e
+#define VPP2_HSC_REGION12_STARTP 0x1910
+#define VPP2_HSC_REGION34_STARTP 0x1911
+#define VPP2_HSC_REGION4_ENDP 0x1912
+#define VPP2_HSC_START_PHASE_STEP 0x1913
+#define VPP2_HSC_REGION0_PHASE_SLOPE 0x1914
+#define VPP2_HSC_REGION1_PHASE_SLOPE 0x1915
+#define VPP2_HSC_REGION3_PHASE_SLOPE 0x1916
+#define VPP2_HSC_REGION4_PHASE_SLOPE 0x1917
+#define VPP2_HSC_PHASE_CTRL 0x1918
+#define VPP2_SC_MISC 0x1919
+#define VPP2_PREBLEND_VD1_H_START_END 0x191a
+#define VPP2_PREBLEND_VD1_V_START_END 0x191b
+#define VPP2_POSTBLEND_VD1_H_START_END 0x191c
+#define VPP2_POSTBLEND_VD1_V_START_END 0x191d
+#define VPP2_PREBLEND_H_SIZE 0x1920
+#define VPP2_POSTBLEND_H_SIZE 0x1921
+#define VPP2_HOLD_LINES 0x1922
+#define VPP2_BLEND_ONECOLOR_CTRL 0x1923
+#define VPP2_PREBLEND_CURRENT_XY 0x1924
+#define VPP2_POSTBLEND_CURRENT_XY 0x1925
+#define VPP2_MISC 0x1926
+#define VPP2_OFIFO_SIZE 0x1927
+#define VPP2_FIFO_STATUS 0x1928
+#define VPP2_SMOKE_CTRL 0x1929
+#define VPP2_SMOKE1_VAL 0x192a
+#define VPP2_SMOKE2_VAL 0x192b
+#define VPP2_SMOKE1_H_START_END 0x192d
+#define VPP2_SMOKE1_V_START_END 0x192e
+#define VPP2_SMOKE2_H_START_END 0x192f
+#define VPP2_SMOKE2_V_START_END 0x1930
+#define VPP2_SCO_FIFO_CTRL 0x1933
+#define VPP2_HSC_PHASE_CTRL1 0x1934
+#define VPP2_HSC_INI_PAT_CTRL 0x1935
+#define VPP2_VADJ_CTRL 0x1940
+#define VPP2_VADJ1_Y 0x1941
+#define VPP2_VADJ1_MA_MB 0x1942
+#define VPP2_VADJ1_MC_MD 0x1943
+#define VPP2_VADJ2_Y 0x1944
+#define VPP2_VADJ2_MA_MB 0x1945
+#define VPP2_VADJ2_MC_MD 0x1946
+#define VPP2_MATRIX_PROBE_COLOR 0x195c
+#define VPP2_MATRIX_HL_COLOR 0x195d
+#define VPP2_MATRIX_PROBE_POS 0x195e
+#define VPP2_MATRIX_CTRL 0x195f
+#define VPP2_MATRIX_COEF00_01 0x1960
+#define VPP2_MATRIX_COEF02_10 0x1961
+#define VPP2_MATRIX_COEF11_12 0x1962
+#define VPP2_MATRIX_COEF20_21 0x1963
+#define VPP2_MATRIX_COEF22 0x1964
+#define VPP2_MATRIX_OFFSET0_1 0x1965
+#define VPP2_MATRIX_OFFSET2 0x1966
+#define VPP2_MATRIX_PRE_OFFSET0_1 0x1967
+#define VPP2_MATRIX_PRE_OFFSET2 0x1968
+#define VPP2_DUMMY_DATA1 0x1969
+#define VPP2_GAINOFF_CTRL0 0x196a
+#define VPP2_GAINOFF_CTRL1 0x196b
+#define VPP2_GAINOFF_CTRL2 0x196c
+#define VPP2_GAINOFF_CTRL3 0x196d
+#define VPP2_GAINOFF_CTRL4 0x196e
+#define VPP2_CHROMA_ADDR_PORT 0x1970
+#define VPP2_CHROMA_DATA_PORT 0x1971
+#define VPP2_GCLK_CTRL0 0x1972
+#define VPP2_GCLK_CTRL1 0x1973
+#define VPP2_SC_GCLK_CTRL 0x1974
+#define VPP2_MISC1 0x1976
+#define VPP2_DNLP_CTRL_00 0x1981
+#define VPP2_DNLP_CTRL_01 0x1982
+#define VPP2_DNLP_CTRL_02 0x1983
+#define VPP2_DNLP_CTRL_03 0x1984
+#define VPP2_DNLP_CTRL_04 0x1985
+#define VPP2_DNLP_CTRL_05 0x1986
+#define VPP2_DNLP_CTRL_06 0x1987
+#define VPP2_DNLP_CTRL_07 0x1988
+#define VPP2_DNLP_CTRL_08 0x1989
+#define VPP2_DNLP_CTRL_09 0x198a
+#define VPP2_DNLP_CTRL_10 0x198b
+#define VPP2_DNLP_CTRL_11 0x198c
+#define VPP2_DNLP_CTRL_12 0x198d
+#define VPP2_DNLP_CTRL_13 0x198e
+#define VPP2_DNLP_CTRL_14 0x198f
+#define VPP2_DNLP_CTRL_15 0x1990
+#define VPP2_VE_ENABLE_CTRL 0x19a1
+#define VPP2_VE_DEMO_LEFT_TOP_SCREEN_WIDTH 0x19a2
+#define VPP2_VE_DEMO_CENTER_BAR 0x19a3
+#define VPP2_VE_H_V_SIZE 0x19a4
+#define VPP2_VDO_MEAS_CTRL 0x19a8
+#define VPP2_VDO_MEAS_VS_COUNT_HI 0x19a9
+#define VPP2_VDO_MEAS_VS_COUNT_LO 0x19aa
+#define VPP2_OSD_VSC_PHASE_STEP 0x19c0
+#define VPP2_OSD_VSC_INI_PHASE 0x19c1
+#define VPP2_OSD_VSC_CTRL0 0x19c2
+#define VPP2_OSD_HSC_PHASE_STEP 0x19c3
+#define VPP2_OSD_HSC_INI_PHASE 0x19c4
+#define VPP2_OSD_HSC_CTRL0 0x19c5
+#define VPP2_OSD_HSC_INI_PAT_CTRL 0x19c6
+#define VPP2_OSD_SC_DUMMY_DATA 0x19c7
+#define VPP2_OSD_SC_CTRL0 0x19c8
+#define VPP2_OSD_SCI_WH_M1 0x19c9
+#define VPP2_OSD_SCO_H_START_END 0x19ca
+#define VPP2_OSD_SCO_V_START_END 0x19cb
+#define VPP2_OSD_SCALE_COEF_IDX 0x19cc
+#define VPP2_OSD_SCALE_COEF 0x19cd
+#define VPP2_INT_LINE_NUM 0x19ce
+
+/* viu */
+#define VIU_ADDR_START 0x1a00
+#define VIU_ADDR_END 0x1aff
+#define VIU_SW_RESET 0x1a01
+#define VIU_MISC_CTRL0 0x1a06
+#define VIU_MISC_CTRL1 0x1a07
+#define D2D3_INTF_LENGTH 0x1a08
+#define D2D3_INTF_CTRL0 0x1a09
+#define VIU_OSD1_CTRL_STAT 0x1a10
+#define VIU_OSD1_CTRL_STAT2 0x1a2d
+#define VIU_OSD1_COLOR_ADDR 0x1a11
+#define VIU_OSD1_COLOR 0x1a12
+#define VIU_OSD1_TCOLOR_AG0 0x1a17
+#define VIU_OSD1_TCOLOR_AG1 0x1a18
+#define VIU_OSD1_TCOLOR_AG2 0x1a19
+#define VIU_OSD1_TCOLOR_AG3 0x1a1a
+#define VIU_OSD1_BLK0_CFG_W0 0x1a1b
+#define VIU_OSD1_BLK1_CFG_W0 0x1a1f
+#define VIU_OSD1_BLK2_CFG_W0 0x1a23
+#define VIU_OSD1_BLK3_CFG_W0 0x1a27
+#define VIU_OSD1_BLK0_CFG_W1 0x1a1c
+#define VIU_OSD1_BLK1_CFG_W1 0x1a20
+#define VIU_OSD1_BLK2_CFG_W1 0x1a24
+#define VIU_OSD1_BLK3_CFG_W1 0x1a28
+#define VIU_OSD1_BLK0_CFG_W2 0x1a1d
+#define VIU_OSD1_BLK1_CFG_W2 0x1a21
+#define VIU_OSD1_BLK2_CFG_W2 0x1a25
+#define VIU_OSD1_BLK3_CFG_W2 0x1a29
+#define VIU_OSD1_BLK0_CFG_W3 0x1a1e
+#define VIU_OSD1_BLK1_CFG_W3 0x1a22
+#define VIU_OSD1_BLK2_CFG_W3 0x1a26
+#define VIU_OSD1_BLK3_CFG_W3 0x1a2a
+#define VIU_OSD1_BLK0_CFG_W4 0x1a13
+#define VIU_OSD1_BLK1_CFG_W4 0x1a14
+#define VIU_OSD1_BLK2_CFG_W4 0x1a15
+#define VIU_OSD1_BLK3_CFG_W4 0x1a16
+#define VIU_OSD1_FIFO_CTRL_STAT 0x1a2b
+#define VIU_OSD1_TEST_RDDATA 0x1a2c
+#define VIU_OSD1_PROT_CTRL 0x1a2e
+#define VIU_OSD2_CTRL_STAT 0x1a30
+#define VIU_OSD2_CTRL_STAT2 0x1a4d
+#define VIU_OSD2_COLOR_ADDR 0x1a31
+#define VIU_OSD2_COLOR 0x1a32
+#define VIU_OSD2_HL1_H_START_END 0x1a33
+#define VIU_OSD2_HL1_V_START_END 0x1a34
+#define VIU_OSD2_HL2_H_START_END 0x1a35
+#define VIU_OSD2_HL2_V_START_END 0x1a36
+#define VIU_OSD2_TCOLOR_AG0 0x1a37
+#define VIU_OSD2_TCOLOR_AG1 0x1a38
+#define VIU_OSD2_TCOLOR_AG2 0x1a39
+#define VIU_OSD2_TCOLOR_AG3 0x1a3a
+#define VIU_OSD2_BLK0_CFG_W0 0x1a3b
+#define VIU_OSD2_BLK1_CFG_W0 0x1a3f
+#define VIU_OSD2_BLK2_CFG_W0 0x1a43
+#define VIU_OSD2_BLK3_CFG_W0 0x1a47
+#define VIU_OSD2_BLK0_CFG_W1 0x1a3c
+#define VIU_OSD2_BLK1_CFG_W1 0x1a40
+#define VIU_OSD2_BLK2_CFG_W1 0x1a44
+#define VIU_OSD2_BLK3_CFG_W1 0x1a48
+#define VIU_OSD2_BLK0_CFG_W2 0x1a3d
+#define VIU_OSD2_BLK1_CFG_W2 0x1a41
+#define VIU_OSD2_BLK2_CFG_W2 0x1a45
+#define VIU_OSD2_BLK3_CFG_W2 0x1a49
+#define VIU_OSD2_BLK0_CFG_W3 0x1a3e
+#define VIU_OSD2_BLK1_CFG_W3 0x1a42
+#define VIU_OSD2_BLK2_CFG_W3 0x1a46
+#define VIU_OSD2_BLK3_CFG_W3 0x1a4a
+#define VIU_OSD2_BLK0_CFG_W4 0x1a64
+#define VIU_OSD2_BLK1_CFG_W4 0x1a65
+#define VIU_OSD2_BLK2_CFG_W4 0x1a66
+#define VIU_OSD2_BLK3_CFG_W4 0x1a67
+#define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b
+#define VIU_OSD2_TEST_RDDATA 0x1a4c
+#define VIU_OSD2_PROT_CTRL 0x1a4e
+
+#define VD1_IF0_GEN_REG 0x1a50
+#define VD1_IF0_CANVAS0 0x1a51
+#define VD1_IF0_CANVAS1 0x1a52
+#define VD1_IF0_LUMA_X0 0x1a53
+#define VD1_IF0_LUMA_Y0 0x1a54
+#define VD1_IF0_CHROMA_X0 0x1a55
+#define VD1_IF0_CHROMA_Y0 0x1a56
+#define VD1_IF0_LUMA_X1 0x1a57
+#define VD1_IF0_LUMA_Y1 0x1a58
+#define VD1_IF0_CHROMA_X1 0x1a59
+#define VD1_IF0_CHROMA_Y1 0x1a5a
+#define VD1_IF0_RPT_LOOP 0x1a5b
+#define VD1_IF0_LUMA0_RPT_PAT 0x1a5c
+#define VD1_IF0_CHROMA0_RPT_PAT 0x1a5d
+#define VD1_IF0_LUMA1_RPT_PAT 0x1a5e
+#define VD1_IF0_CHROMA1_RPT_PAT 0x1a5f
+#define VD1_IF0_LUMA_PSEL 0x1a60
+#define VD1_IF0_CHROMA_PSEL 0x1a61
+#define VD1_IF0_DUMMY_PIXEL 0x1a62
+#define VD1_IF0_LUMA_FIFO_SIZE 0x1a63
+#define VD1_IF0_RANGE_MAP_Y 0x1a6a
+#define VD1_IF0_RANGE_MAP_CB 0x1a6b
+#define VD1_IF0_RANGE_MAP_CR 0x1a6c
+#define VD1_IF0_GEN_REG2 0x1a6d
+#define VD1_IF0_PROT_CNTL 0x1a6e
+#define VIU_VD1_FMT_CTRL 0x1a68
+#define VIU_VD1_FMT_W 0x1a69
+#define VD2_IF0_GEN_REG 0x1a70
+#define VD2_IF0_CANVAS0 0x1a71
+#define VD2_IF0_CANVAS1 0x1a72
+#define VD2_IF0_LUMA_X0 0x1a73
+#define VD2_IF0_LUMA_Y0 0x1a74
+#define VD2_IF0_CHROMA_X0 0x1a75
+#define VD2_IF0_CHROMA_Y0 0x1a76
+#define VD2_IF0_LUMA_X1 0x1a77
+#define VD2_IF0_LUMA_Y1 0x1a78
+#define VD2_IF0_CHROMA_X1 0x1a79
+#define VD2_IF0_CHROMA_Y1 0x1a7a
+#define VD2_IF0_RPT_LOOP 0x1a7b
+#define VD2_IF0_LUMA0_RPT_PAT 0x1a7c
+#define VD2_IF0_CHROMA0_RPT_PAT 0x1a7d
+#define VD2_IF0_LUMA1_RPT_PAT 0x1a7e
+#define VD2_IF0_CHROMA1_RPT_PAT 0x1a7f
+#define VD2_IF0_LUMA_PSEL 0x1a80
+#define VD2_IF0_CHROMA_PSEL 0x1a81
+#define VD2_IF0_DUMMY_PIXEL 0x1a82
+#define VD2_IF0_LUMA_FIFO_SIZE 0x1a83
+#define VD2_IF0_RANGE_MAP_Y 0x1a8a
+#define VD2_IF0_RANGE_MAP_CB 0x1a8b
+#define VD2_IF0_RANGE_MAP_CR 0x1a8c
+#define VD2_IF0_GEN_REG2 0x1a8d
+#define VD2_IF0_PROT_CNTL 0x1a8e
+#define VIU_VD2_FMT_CTRL 0x1a88
+#define VIU_VD2_FMT_W 0x1a89
+
+/* VIU Matrix Registers */
+#define VIU_OSD1_MATRIX_CTRL 0x1a90
+#define VIU_OSD1_MATRIX_COEF00_01 0x1a91
+#define VIU_OSD1_MATRIX_COEF02_10 0x1a92
+#define VIU_OSD1_MATRIX_COEF11_12 0x1a93
+#define VIU_OSD1_MATRIX_COEF20_21 0x1a94
+#define VIU_OSD1_MATRIX_COLMOD_COEF42 0x1a95
+#define VIU_OSD1_MATRIX_OFFSET0_1 0x1a96
+#define VIU_OSD1_MATRIX_OFFSET2 0x1a97
+#define VIU_OSD1_MATRIX_PRE_OFFSET0_1 0x1a98
+#define VIU_OSD1_MATRIX_PRE_OFFSET2 0x1a99
+#define VIU_OSD1_MATRIX_COEF22_30 0x1a9d
+#define VIU_OSD1_MATRIX_COEF31_32 0x1a9e
+#define VIU_OSD1_MATRIX_COEF40_41 0x1a9f
+#define VIU_OSD1_EOTF_CTL 0x1ad4
+#define VIU_OSD1_EOTF_COEF00_01 0x1ad5
+#define VIU_OSD1_EOTF_COEF02_10 0x1ad6
+#define VIU_OSD1_EOTF_COEF11_12 0x1ad7
+#define VIU_OSD1_EOTF_COEF20_21 0x1ad8
+#define VIU_OSD1_EOTF_COEF22_RS 0x1ad9
+#define VIU_OSD1_EOTF_LUT_ADDR_PORT 0x1ada
+#define VIU_OSD1_EOTF_LUT_DATA_PORT 0x1adb
+#define VIU_OSD1_OETF_CTL 0x1adc
+#define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add
+#define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade
+
+/* vpp */
+#define VPP_DUMMY_DATA 0x1d00
+#define VPP_LINE_IN_LENGTH 0x1d01
+#define VPP_PIC_IN_HEIGHT 0x1d02
+#define VPP_SCALE_COEF_IDX 0x1d03
+#define VPP_SCALE_COEF 0x1d04
+#define VPP_VSC_REGION12_STARTP 0x1d05
+#define VPP_VSC_REGION34_STARTP 0x1d06
+#define VPP_VSC_REGION4_ENDP 0x1d07
+#define VPP_VSC_START_PHASE_STEP 0x1d08
+#define VPP_VSC_REGION0_PHASE_SLOPE 0x1d09
+#define VPP_VSC_REGION1_PHASE_SLOPE 0x1d0a
+#define VPP_VSC_REGION3_PHASE_SLOPE 0x1d0b
+#define VPP_VSC_REGION4_PHASE_SLOPE 0x1d0c
+#define VPP_VSC_PHASE_CTRL 0x1d0d
+#define VPP_VSC_INI_PHASE 0x1d0e
+#define VPP_HSC_REGION12_STARTP 0x1d10
+#define VPP_HSC_REGION34_STARTP 0x1d11
+#define VPP_HSC_REGION4_ENDP 0x1d12
+#define VPP_HSC_START_PHASE_STEP 0x1d13
+#define VPP_HSC_REGION0_PHASE_SLOPE 0x1d14
+#define VPP_HSC_REGION1_PHASE_SLOPE 0x1d15
+#define VPP_HSC_REGION3_PHASE_SLOPE 0x1d16
+#define VPP_HSC_REGION4_PHASE_SLOPE 0x1d17
+#define VPP_HSC_PHASE_CTRL 0x1d18
+#define VPP_SC_MISC 0x1d19
+#define VPP_PREBLEND_VD1_H_START_END 0x1d1a
+#define VPP_PREBLEND_VD1_V_START_END 0x1d1b
+#define VPP_POSTBLEND_VD1_H_START_END 0x1d1c
+#define VPP_POSTBLEND_VD1_V_START_END 0x1d1d
+#define VPP_BLEND_VD2_H_START_END 0x1d1e
+#define VPP_BLEND_VD2_V_START_END 0x1d1f
+#define VPP_PREBLEND_H_SIZE 0x1d20
+#define VPP_POSTBLEND_H_SIZE 0x1d21
+#define VPP_HOLD_LINES 0x1d22
+#define VPP_BLEND_ONECOLOR_CTRL 0x1d23
+#define VPP_PREBLEND_CURRENT_XY 0x1d24
+#define VPP_POSTBLEND_CURRENT_XY 0x1d25
+#define VPP_MISC 0x1d26
+#define		VPP_PREBLEND_ENABLE	BIT(6)
+#define		VPP_POSTBLEND_ENABLE	BIT(7)
+#define		VPP_OSD2_ALPHA_PREMULT	BIT(8)
+#define		VPP_OSD1_ALPHA_PREMULT	BIT(9)
+#define		VPP_VD1_POSTBLEND	BIT(10)
+#define		VPP_VD2_POSTBLEND	BIT(11)
+#define		VPP_OSD1_POSTBLEND	BIT(12)
+#define		VPP_OSD2_POSTBLEND	BIT(13)
+#define		VPP_VD1_PREBLEND	BIT(14)
+#define		VPP_VD2_PREBLEND	BIT(15)
+#define		VPP_OSD1_PREBLEND	BIT(16)
+#define		VPP_OSD2_PREBLEND	BIT(17)
+#define VPP_OFIFO_SIZE 0x1d27
+#define VPP_FIFO_STATUS 0x1d28
+#define VPP_SMOKE_CTRL 0x1d29
+#define VPP_SMOKE1_VAL 0x1d2a
+#define VPP_SMOKE2_VAL 0x1d2b
+#define VPP_SMOKE3_VAL 0x1d2c
+#define VPP_SMOKE1_H_START_END 0x1d2d
+#define VPP_SMOKE1_V_START_END 0x1d2e
+#define VPP_SMOKE2_H_START_END 0x1d2f
+#define VPP_SMOKE2_V_START_END 0x1d30
+#define VPP_SMOKE3_H_START_END 0x1d31
+#define VPP_SMOKE3_V_START_END 0x1d32
+#define VPP_SCO_FIFO_CTRL 0x1d33
+#define VPP_HSC_PHASE_CTRL1 0x1d34
+#define VPP_HSC_INI_PAT_CTRL 0x1d35
+#define VPP_VADJ_CTRL 0x1d40
+#define VPP_VADJ1_Y 0x1d41
+#define VPP_VADJ1_MA_MB 0x1d42
+#define VPP_VADJ1_MC_MD 0x1d43
+#define VPP_VADJ2_Y 0x1d44
+#define VPP_VADJ2_MA_MB 0x1d45
+#define VPP_VADJ2_MC_MD 0x1d46
+#define VPP_HSHARP_CTRL 0x1d50
+#define VPP_HSHARP_LUMA_THRESH01 0x1d51
+#define VPP_HSHARP_LUMA_THRESH23 0x1d52
+#define VPP_HSHARP_CHROMA_THRESH01 0x1d53
+#define VPP_HSHARP_CHROMA_THRESH23 0x1d54
+#define VPP_HSHARP_LUMA_GAIN 0x1d55
+#define VPP_HSHARP_CHROMA_GAIN 0x1d56
+#define VPP_MATRIX_PROBE_COLOR 0x1d5c
+#define VPP_MATRIX_HL_COLOR 0x1d5d
+#define VPP_MATRIX_PROBE_POS 0x1d5e
+#define VPP_MATRIX_CTRL 0x1d5f
+#define VPP_MATRIX_COEF00_01 0x1d60
+#define VPP_MATRIX_COEF02_10 0x1d61
+#define VPP_MATRIX_COEF11_12 0x1d62
+#define VPP_MATRIX_COEF20_21 0x1d63
+#define VPP_MATRIX_COEF22 0x1d64
+#define VPP_MATRIX_OFFSET0_1 0x1d65
+#define VPP_MATRIX_OFFSET2 0x1d66
+#define VPP_MATRIX_PRE_OFFSET0_1 0x1d67
+#define VPP_MATRIX_PRE_OFFSET2 0x1d68
+#define VPP_DUMMY_DATA1 0x1d69
+#define VPP_GAINOFF_CTRL0 0x1d6a
+#define VPP_GAINOFF_CTRL1 0x1d6b
+#define VPP_GAINOFF_CTRL2 0x1d6c
+#define VPP_GAINOFF_CTRL3 0x1d6d
+#define VPP_GAINOFF_CTRL4 0x1d6e
+#define VPP_CHROMA_ADDR_PORT 0x1d70
+#define VPP_CHROMA_DATA_PORT 0x1d71
+#define VPP_GCLK_CTRL0 0x1d72
+#define VPP_GCLK_CTRL1 0x1d73
+#define VPP_SC_GCLK_CTRL 0x1d74
+#define VPP_MISC1 0x1d76
+#define VPP_BLACKEXT_CTRL 0x1d80
+#define VPP_DNLP_CTRL_00 0x1d81
+#define VPP_DNLP_CTRL_01 0x1d82
+#define VPP_DNLP_CTRL_02 0x1d83
+#define VPP_DNLP_CTRL_03 0x1d84
+#define VPP_DNLP_CTRL_04 0x1d85
+#define VPP_DNLP_CTRL_05 0x1d86
+#define VPP_DNLP_CTRL_06 0x1d87
+#define VPP_DNLP_CTRL_07 0x1d88
+#define VPP_DNLP_CTRL_08 0x1d89
+#define VPP_DNLP_CTRL_09 0x1d8a
+#define VPP_DNLP_CTRL_10 0x1d8b
+#define VPP_DNLP_CTRL_11 0x1d8c
+#define VPP_DNLP_CTRL_12 0x1d8d
+#define VPP_DNLP_CTRL_13 0x1d8e
+#define VPP_DNLP_CTRL_14 0x1d8f
+#define VPP_DNLP_CTRL_15 0x1d90
+#define VPP_PEAKING_HGAIN 0x1d91
+#define VPP_PEAKING_VGAIN 0x1d92
+#define VPP_PEAKING_NLP_1 0x1d93
+#define VPP_DOLBY_CTRL 0x1d93
+#define VPP_PEAKING_NLP_2 0x1d94
+#define VPP_PEAKING_NLP_3 0x1d95
+#define VPP_PEAKING_NLP_4 0x1d96
+#define VPP_PEAKING_NLP_5 0x1d97
+#define VPP_SHARP_LIMIT 0x1d98
+#define VPP_VLTI_CTRL 0x1d99
+#define VPP_HLTI_CTRL 0x1d9a
+#define VPP_CTI_CTRL 0x1d9b
+#define VPP_BLUE_STRETCH_1 0x1d9c
+#define VPP_BLUE_STRETCH_2 0x1d9d
+#define VPP_BLUE_STRETCH_3 0x1d9e
+#define VPP_CCORING_CTRL 0x1da0
+#define VPP_VE_ENABLE_CTRL 0x1da1
+#define VPP_VE_DEMO_LEFT_TOP_SCREEN_WIDTH 0x1da2
+#define VPP_VE_DEMO_CENTER_BAR 0x1da3
+#define VPP_VE_H_V_SIZE 0x1da4
+#define VPP_VDO_MEAS_CTRL 0x1da8
+#define VPP_VDO_MEAS_VS_COUNT_HI 0x1da9
+#define VPP_VDO_MEAS_VS_COUNT_LO 0x1daa
+#define VPP_INPUT_CTRL 0x1dab
+#define VPP_CTI_CTRL2 0x1dac
+#define VPP_PEAKING_SAT_THD1 0x1dad
+#define VPP_PEAKING_SAT_THD2 0x1dae
+#define VPP_PEAKING_SAT_THD3 0x1daf
+#define VPP_PEAKING_SAT_THD4 0x1db0
+#define VPP_PEAKING_SAT_THD5 0x1db1
+#define VPP_PEAKING_SAT_THD6 0x1db2
+#define VPP_PEAKING_SAT_THD7 0x1db3
+#define VPP_PEAKING_SAT_THD8 0x1db4
+#define VPP_PEAKING_SAT_THD9 0x1db5
+#define VPP_PEAKING_GAIN_ADD1 0x1db6
+#define VPP_PEAKING_GAIN_ADD2 0x1db7
+#define VPP_PEAKING_DNLP 0x1db8
+#define VPP_SHARP_DEMO_WIN_CTRL1 0x1db9
+#define VPP_SHARP_DEMO_WIN_CTRL2 0x1dba
+#define VPP_FRONT_HLTI_CTRL 0x1dbb
+#define VPP_FRONT_CTI_CTRL 0x1dbc
+#define VPP_FRONT_CTI_CTRL2 0x1dbd
+#define VPP_OSD_VSC_PHASE_STEP 0x1dc0
+#define VPP_OSD_VSC_INI_PHASE 0x1dc1
+#define VPP_OSD_VSC_CTRL0 0x1dc2
+#define VPP_OSD_HSC_PHASE_STEP 0x1dc3
+#define VPP_OSD_HSC_INI_PHASE 0x1dc4
+#define VPP_OSD_HSC_CTRL0 0x1dc5
+#define VPP_OSD_HSC_INI_PAT_CTRL 0x1dc6
+#define VPP_OSD_SC_DUMMY_DATA 0x1dc7
+#define VPP_OSD_SC_CTRL0 0x1dc8
+#define VPP_OSD_SCI_WH_M1 0x1dc9
+#define VPP_OSD_SCO_H_START_END 0x1dca
+#define VPP_OSD_SCO_V_START_END 0x1dcb
+#define VPP_OSD_SCALE_COEF_IDX 0x1dcc
+#define VPP_OSD_SCALE_COEF 0x1dcd
+#define VPP_INT_LINE_NUM 0x1dce
+
+/* viu2 */
+#define VIU2_ADDR_START 0x1e00
+#define VIU2_ADDR_END 0x1eff
+#define VIU2_SW_RESET 0x1e01
+#define VIU2_OSD1_CTRL_STAT 0x1e10
+#define VIU2_OSD1_CTRL_STAT2 0x1e2d
+#define VIU2_OSD1_COLOR_ADDR 0x1e11
+#define VIU2_OSD1_COLOR 0x1e12
+#define VIU2_OSD1_TCOLOR_AG0 0x1e17
+#define VIU2_OSD1_TCOLOR_AG1 0x1e18
+#define VIU2_OSD1_TCOLOR_AG2 0x1e19
+#define VIU2_OSD1_TCOLOR_AG3 0x1e1a
+#define VIU2_OSD1_BLK0_CFG_W0 0x1e1b
+#define VIU2_OSD1_BLK1_CFG_W0 0x1e1f
+#define VIU2_OSD1_BLK2_CFG_W0 0x1e23
+#define VIU2_OSD1_BLK3_CFG_W0 0x1e27
+#define VIU2_OSD1_BLK0_CFG_W1 0x1e1c
+#define VIU2_OSD1_BLK1_CFG_W1 0x1e20
+#define VIU2_OSD1_BLK2_CFG_W1 0x1e24
+#define VIU2_OSD1_BLK3_CFG_W1 0x1e28
+#define VIU2_OSD1_BLK0_CFG_W2 0x1e1d
+#define VIU2_OSD1_BLK1_CFG_W2 0x1e21
+#define VIU2_OSD1_BLK2_CFG_W2 0x1e25
+#define VIU2_OSD1_BLK3_CFG_W2 0x1e29
+#define VIU2_OSD1_BLK0_CFG_W3 0x1e1e
+#define VIU2_OSD1_BLK1_CFG_W3 0x1e22
+#define VIU2_OSD1_BLK2_CFG_W3 0x1e26
+#define VIU2_OSD1_BLK3_CFG_W3 0x1e2a
+#define VIU2_OSD1_BLK0_CFG_W4 0x1e13
+#define VIU2_OSD1_BLK1_CFG_W4 0x1e14
+#define VIU2_OSD1_BLK2_CFG_W4 0x1e15
+#define VIU2_OSD1_BLK3_CFG_W4 0x1e16
+#define VIU2_OSD1_FIFO_CTRL_STAT 0x1e2b
+#define VIU2_OSD1_TEST_RDDATA 0x1e2c
+#define VIU2_OSD1_PROT_CTRL 0x1e2e
+#define VIU2_OSD2_CTRL_STAT 0x1e30
+#define VIU2_OSD2_CTRL_STAT2 0x1e4d
+#define VIU2_OSD2_COLOR_ADDR 0x1e31
+#define VIU2_OSD2_COLOR 0x1e32
+#define VIU2_OSD2_HL1_H_START_END 0x1e33
+#define VIU2_OSD2_HL1_V_START_END 0x1e34
+#define VIU2_OSD2_HL2_H_START_END 0x1e35
+#define VIU2_OSD2_HL2_V_START_END 0x1e36
+#define VIU2_OSD2_TCOLOR_AG0 0x1e37
+#define VIU2_OSD2_TCOLOR_AG1 0x1e38
+#define VIU2_OSD2_TCOLOR_AG2 0x1e39
+#define VIU2_OSD2_TCOLOR_AG3 0x1e3a
+#define VIU2_OSD2_BLK0_CFG_W0 0x1e3b
+#define VIU2_OSD2_BLK1_CFG_W0 0x1e3f
+#define VIU2_OSD2_BLK2_CFG_W0 0x1e43
+#define VIU2_OSD2_BLK3_CFG_W0 0x1e47
+#define VIU2_OSD2_BLK0_CFG_W1 0x1e3c
+#define VIU2_OSD2_BLK1_CFG_W1 0x1e40
+#define VIU2_OSD2_BLK2_CFG_W1 0x1e44
+#define VIU2_OSD2_BLK3_CFG_W1 0x1e48
+#define VIU2_OSD2_BLK0_CFG_W2 0x1e3d
+#define VIU2_OSD2_BLK1_CFG_W2 0x1e41
+#define VIU2_OSD2_BLK2_CFG_W2 0x1e45
+#define VIU2_OSD2_BLK3_CFG_W2 0x1e49
+#define VIU2_OSD2_BLK0_CFG_W3 0x1e3e
+#define VIU2_OSD2_BLK1_CFG_W3 0x1e42
+#define VIU2_OSD2_BLK2_CFG_W3 0x1e46
+#define VIU2_OSD2_BLK3_CFG_W3 0x1e4a
+#define VIU2_OSD2_BLK0_CFG_W4 0x1e64
+#define VIU2_OSD2_BLK1_CFG_W4 0x1e65
+#define VIU2_OSD2_BLK2_CFG_W4 0x1e66
+#define VIU2_OSD2_BLK3_CFG_W4 0x1e67
+#define VIU2_OSD2_FIFO_CTRL_STAT 0x1e4b
+#define VIU2_OSD2_TEST_RDDATA 0x1e4c
+#define VIU2_OSD2_PROT_CTRL 0x1e4e
+#define VIU2_VD1_IF0_GEN_REG 0x1e50
+#define VIU2_VD1_IF0_CANVAS0 0x1e51
+#define VIU2_VD1_IF0_CANVAS1 0x1e52
+#define VIU2_VD1_IF0_LUMA_X0 0x1e53
+#define VIU2_VD1_IF0_LUMA_Y0 0x1e54
+#define VIU2_VD1_IF0_CHROMA_X0 0x1e55
+#define VIU2_VD1_IF0_CHROMA_Y0 0x1e56
+#define VIU2_VD1_IF0_LUMA_X1 0x1e57
+#define VIU2_VD1_IF0_LUMA_Y1 0x1e58
+#define VIU2_VD1_IF0_CHROMA_X1 0x1e59
+#define VIU2_VD1_IF0_CHROMA_Y1 0x1e5a
+#define VIU2_VD1_IF0_RPT_LOOP 0x1e5b
+#define VIU2_VD1_IF0_LUMA0_RPT_PAT 0x1e5c
+#define VIU2_VD1_IF0_CHROMA0_RPT_PAT 0x1e5d
+#define VIU2_VD1_IF0_LUMA1_RPT_PAT 0x1e5e
+#define VIU2_VD1_IF0_CHROMA1_RPT_PAT 0x1e5f
+#define VIU2_VD1_IF0_LUMA_PSEL 0x1e60
+#define VIU2_VD1_IF0_CHROMA_PSEL 0x1e61
+#define VIU2_VD1_IF0_DUMMY_PIXEL 0x1e62
+#define VIU2_VD1_IF0_LUMA_FIFO_SIZE 0x1e63
+#define VIU2_VD1_IF0_RANGE_MAP_Y 0x1e6a
+#define VIU2_VD1_IF0_RANGE_MAP_CB 0x1e6b
+#define VIU2_VD1_IF0_RANGE_MAP_CR 0x1e6c
+#define VIU2_VD1_IF0_GEN_REG2 0x1e6d
+#define VIU2_VD1_IF0_PROT_CNTL 0x1e6e
+#define VIU2_VD1_FMT_CTRL 0x1e68
+#define VIU2_VD1_FMT_W 0x1e69
+
+/* encode */
+#define ENCP_VFIFO2VD_CTL 0x1b58
+#define ENCP_VFIFO2VD_PIXEL_START 0x1b59
+#define ENCP_VFIFO2VD_PIXEL_END 0x1b5a
+#define ENCP_VFIFO2VD_LINE_TOP_START 0x1b5b
+#define ENCP_VFIFO2VD_LINE_TOP_END 0x1b5c
+#define ENCP_VFIFO2VD_LINE_BOT_START 0x1b5d
+#define ENCP_VFIFO2VD_LINE_BOT_END 0x1b5e
+#define VENC_SYNC_ROUTE 0x1b60
+#define VENC_VIDEO_EXSRC 0x1b61
+#define VENC_DVI_SETTING 0x1b62
+#define VENC_C656_CTRL 0x1b63
+#define VENC_UPSAMPLE_CTRL0 0x1b64
+#define VENC_UPSAMPLE_CTRL1 0x1b65
+#define VENC_UPSAMPLE_CTRL2 0x1b66
+#define TCON_INVERT_CTL 0x1b67
+#define VENC_VIDEO_PROG_MODE 0x1b68
+#define VENC_ENCI_LINE 0x1b69
+#define VENC_ENCI_PIXEL 0x1b6a
+#define VENC_ENCP_LINE 0x1b6b
+#define VENC_ENCP_PIXEL 0x1b6c
+#define VENC_STATA 0x1b6d
+#define VENC_INTCTRL 0x1b6e
+#define VENC_INTFLAG 0x1b6f
+#define VENC_VIDEO_TST_EN 0x1b70
+#define VENC_VIDEO_TST_MDSEL 0x1b71
+#define VENC_VIDEO_TST_Y 0x1b72
+#define VENC_VIDEO_TST_CB 0x1b73
+#define VENC_VIDEO_TST_CR 0x1b74
+#define VENC_VIDEO_TST_CLRBAR_STRT 0x1b75
+#define VENC_VIDEO_TST_CLRBAR_WIDTH 0x1b76
+#define VENC_VIDEO_TST_VDCNT_STSET 0x1b77
+#define VENC_VDAC_DACSEL0 0x1b78
+#define VENC_VDAC_DACSEL1 0x1b79
+#define VENC_VDAC_DACSEL2 0x1b7a
+#define VENC_VDAC_DACSEL3 0x1b7b
+#define VENC_VDAC_DACSEL4 0x1b7c
+#define VENC_VDAC_DACSEL5 0x1b7d
+#define VENC_VDAC_SETTING 0x1b7e
+#define VENC_VDAC_TST_VAL 0x1b7f
+#define VENC_VDAC_DAC0_GAINCTRL 0x1bf0
+#define VENC_VDAC_DAC0_OFFSET 0x1bf1
+#define VENC_VDAC_DAC1_GAINCTRL 0x1bf2
+#define VENC_VDAC_DAC1_OFFSET 0x1bf3
+#define VENC_VDAC_DAC2_GAINCTRL 0x1bf4
+#define VENC_VDAC_DAC2_OFFSET 0x1bf5
+#define VENC_VDAC_DAC3_GAINCTRL 0x1bf6
+#define VENC_VDAC_DAC3_OFFSET 0x1bf7
+#define VENC_VDAC_DAC4_GAINCTRL 0x1bf8
+#define VENC_VDAC_DAC4_OFFSET 0x1bf9
+#define VENC_VDAC_DAC5_GAINCTRL 0x1bfa
+#define VENC_VDAC_DAC5_OFFSET 0x1bfb
+#define VENC_VDAC_FIFO_CTRL 0x1bfc
+#define ENCL_TCON_INVERT_CTL 0x1bfd
+#define ENCP_VIDEO_EN 0x1b80
+#define ENCP_VIDEO_SYNC_MODE 0x1b81
+#define ENCP_MACV_EN 0x1b82
+#define ENCP_VIDEO_Y_SCL 0x1b83
+#define ENCP_VIDEO_PB_SCL 0x1b84
+#define ENCP_VIDEO_PR_SCL 0x1b85
+#define ENCP_VIDEO_SYNC_SCL 0x1b86
+#define ENCP_VIDEO_MACV_SCL 0x1b87
+#define ENCP_VIDEO_Y_OFFST 0x1b88
+#define ENCP_VIDEO_PB_OFFST 0x1b89
+#define ENCP_VIDEO_PR_OFFST 0x1b8a
+#define ENCP_VIDEO_SYNC_OFFST 0x1b8b
+#define ENCP_VIDEO_MACV_OFFST 0x1b8c
+#define ENCP_VIDEO_MODE 0x1b8d
+#define ENCP_VIDEO_MODE_ADV 0x1b8e
+#define ENCP_DBG_PX_RST 0x1b90
+#define ENCP_DBG_LN_RST 0x1b91
+#define ENCP_DBG_PX_INT 0x1b92
+#define ENCP_DBG_LN_INT 0x1b93
+#define ENCP_VIDEO_YFP1_HTIME 0x1b94
+#define ENCP_VIDEO_YFP2_HTIME 0x1b95
+#define ENCP_VIDEO_YC_DLY 0x1b96
+#define ENCP_VIDEO_MAX_PXCNT 0x1b97
+#define ENCP_VIDEO_HSPULS_BEGIN 0x1b98
+#define ENCP_VIDEO_HSPULS_END 0x1b99
+#define ENCP_VIDEO_HSPULS_SWITCH 0x1b9a
+#define ENCP_VIDEO_VSPULS_BEGIN 0x1b9b
+#define ENCP_VIDEO_VSPULS_END 0x1b9c
+#define ENCP_VIDEO_VSPULS_BLINE 0x1b9d
+#define ENCP_VIDEO_VSPULS_ELINE 0x1b9e
+#define ENCP_VIDEO_EQPULS_BEGIN 0x1b9f
+#define ENCP_VIDEO_EQPULS_END 0x1ba0
+#define ENCP_VIDEO_EQPULS_BLINE 0x1ba1
+#define ENCP_VIDEO_EQPULS_ELINE 0x1ba2
+#define ENCP_VIDEO_HAVON_END 0x1ba3
+#define ENCP_VIDEO_HAVON_BEGIN 0x1ba4
+#define ENCP_VIDEO_VAVON_ELINE 0x1baf
+#define ENCP_VIDEO_VAVON_BLINE 0x1ba6
+#define ENCP_VIDEO_HSO_BEGIN 0x1ba7
+#define ENCP_VIDEO_HSO_END 0x1ba8
+#define ENCP_VIDEO_VSO_BEGIN 0x1ba9
+#define ENCP_VIDEO_VSO_END 0x1baa
+#define ENCP_VIDEO_VSO_BLINE 0x1bab
+#define ENCP_VIDEO_VSO_ELINE 0x1bac
+#define ENCP_VIDEO_SYNC_WAVE_CURVE 0x1bad
+#define ENCP_VIDEO_MAX_LNCNT 0x1bae
+#define ENCP_VIDEO_SY_VAL 0x1bb0
+#define ENCP_VIDEO_SY2_VAL 0x1bb1
+#define ENCP_VIDEO_BLANKY_VAL 0x1bb2
+#define ENCP_VIDEO_BLANKPB_VAL 0x1bb3
+#define ENCP_VIDEO_BLANKPR_VAL 0x1bb4
+#define ENCP_VIDEO_HOFFST 0x1bb5
+#define ENCP_VIDEO_VOFFST 0x1bb6
+#define ENCP_VIDEO_RGB_CTRL 0x1bb7
+#define ENCP_VIDEO_FILT_CTRL 0x1bb8
+#define ENCP_VIDEO_OFLD_VPEQ_OFST 0x1bb9
+#define ENCP_VIDEO_OFLD_VOAV_OFST 0x1bba
+#define ENCP_VIDEO_MATRIX_CB 0x1bbb
+#define ENCP_VIDEO_MATRIX_CR 0x1bbc
+#define ENCP_VIDEO_RGBIN_CTRL 0x1bbd
+#define ENCP_MACV_BLANKY_VAL 0x1bc0
+#define ENCP_MACV_MAXY_VAL 0x1bc1
+#define ENCP_MACV_1ST_PSSYNC_STRT 0x1bc2
+#define ENCP_MACV_PSSYNC_STRT 0x1bc3
+#define ENCP_MACV_AGC_STRT 0x1bc4
+#define ENCP_MACV_AGC_END 0x1bc5
+#define ENCP_MACV_WAVE_END 0x1bc6
+#define ENCP_MACV_STRTLINE 0x1bc7
+#define ENCP_MACV_ENDLINE 0x1bc8
+#define ENCP_MACV_TS_CNT_MAX_L 0x1bc9
+#define ENCP_MACV_TS_CNT_MAX_H 0x1bca
+#define ENCP_MACV_TIME_DOWN 0x1bcb
+#define ENCP_MACV_TIME_LO 0x1bcc
+#define ENCP_MACV_TIME_UP 0x1bcd
+#define ENCP_MACV_TIME_RST 0x1bce
+#define ENCP_VBI_CTRL 0x1bd0
+#define ENCP_VBI_SETTING 0x1bd1
+#define ENCP_VBI_BEGIN 0x1bd2
+#define ENCP_VBI_WIDTH 0x1bd3
+#define ENCP_VBI_HVAL 0x1bd4
+#define ENCP_VBI_DATA0 0x1bd5
+#define ENCP_VBI_DATA1 0x1bd6
+#define C656_HS_ST 0x1be0
+#define C656_HS_ED 0x1be1
+#define C656_VS_LNST_E 0x1be2
+#define C656_VS_LNST_O 0x1be3
+#define C656_VS_LNED_E 0x1be4
+#define C656_VS_LNED_O 0x1be5
+#define C656_FS_LNST 0x1be6
+#define C656_FS_LNED 0x1be7
+#define ENCI_VIDEO_MODE 0x1b00
+#define ENCI_VIDEO_MODE_ADV 0x1b01
+#define ENCI_VIDEO_FSC_ADJ 0x1b02
+#define ENCI_VIDEO_BRIGHT 0x1b03
+#define ENCI_VIDEO_CONT 0x1b04
+#define ENCI_VIDEO_SAT 0x1b05
+#define ENCI_VIDEO_HUE 0x1b06
+#define ENCI_VIDEO_SCH 0x1b07
+#define ENCI_SYNC_MODE 0x1b08
+#define ENCI_SYNC_CTRL 0x1b09
+#define ENCI_SYNC_HSO_BEGIN 0x1b0a
+#define ENCI_SYNC_HSO_END 0x1b0b
+#define ENCI_SYNC_VSO_EVN 0x1b0c
+#define ENCI_SYNC_VSO_ODD 0x1b0d
+#define ENCI_SYNC_VSO_EVNLN 0x1b0e
+#define ENCI_SYNC_VSO_ODDLN 0x1b0f
+#define ENCI_SYNC_HOFFST 0x1b10
+#define ENCI_SYNC_VOFFST 0x1b11
+#define ENCI_SYNC_ADJ 0x1b12
+#define ENCI_RGB_SETTING 0x1b13
+#define ENCI_DE_H_BEGIN 0x1b16
+#define ENCI_DE_H_END 0x1b17
+#define ENCI_DE_V_BEGIN_EVEN 0x1b18
+#define ENCI_DE_V_END_EVEN 0x1b19
+#define ENCI_DE_V_BEGIN_ODD 0x1b1a
+#define ENCI_DE_V_END_ODD 0x1b1b
+#define ENCI_VBI_SETTING 0x1b20
+#define ENCI_VBI_CCDT_EVN 0x1b21
+#define ENCI_VBI_CCDT_ODD 0x1b22
+#define ENCI_VBI_CC525_LN 0x1b23
+#define ENCI_VBI_CC625_LN 0x1b24
+#define ENCI_VBI_WSSDT 0x1b25
+#define ENCI_VBI_WSS_LN 0x1b26
+#define ENCI_VBI_CGMSDT_L 0x1b27
+#define ENCI_VBI_CGMSDT_H 0x1b28
+#define ENCI_VBI_CGMS_LN 0x1b29
+#define ENCI_VBI_TTX_HTIME 0x1b2a
+#define ENCI_VBI_TTX_LN 0x1b2b
+#define ENCI_VBI_TTXDT0 0x1b2c
+#define ENCI_VBI_TTXDT1 0x1b2d
+#define ENCI_VBI_TTXDT2 0x1b2e
+#define ENCI_VBI_TTXDT3 0x1b2f
+#define ENCI_MACV_N0 0x1b30
+#define ENCI_MACV_N1 0x1b31
+#define ENCI_MACV_N2 0x1b32
+#define ENCI_MACV_N3 0x1b33
+#define ENCI_MACV_N4 0x1b34
+#define ENCI_MACV_N5 0x1b35
+#define ENCI_MACV_N6 0x1b36
+#define ENCI_MACV_N7 0x1b37
+#define ENCI_MACV_N8 0x1b38
+#define ENCI_MACV_N9 0x1b39
+#define ENCI_MACV_N10 0x1b3a
+#define ENCI_MACV_N11 0x1b3b
+#define ENCI_MACV_N12 0x1b3c
+#define ENCI_MACV_N13 0x1b3d
+#define ENCI_MACV_N14 0x1b3e
+#define ENCI_MACV_N15 0x1b3f
+#define ENCI_MACV_N16 0x1b40
+#define ENCI_MACV_N17 0x1b41
+#define ENCI_MACV_N18 0x1b42
+#define ENCI_MACV_N19 0x1b43
+#define ENCI_MACV_N20 0x1b44
+#define ENCI_MACV_N21 0x1b45
+#define ENCI_MACV_N22 0x1b46
+#define ENCI_DBG_PX_RST 0x1b48
+#define ENCI_DBG_FLDLN_RST 0x1b49
+#define ENCI_DBG_PX_INT 0x1b4a
+#define ENCI_DBG_FLDLN_INT 0x1b4b
+#define ENCI_DBG_MAXPX 0x1b4c
+#define ENCI_DBG_MAXLN 0x1b4d
+#define ENCI_MACV_MAX_AMP 0x1b50
+#define ENCI_MACV_PULSE_LO 0x1b51
+#define ENCI_MACV_PULSE_HI 0x1b52
+#define ENCI_MACV_BKP_MAX 0x1b53
+#define ENCI_CFILT_CTRL 0x1b54
+#define ENCI_CFILT7 0x1b55
+#define ENCI_YC_DELAY 0x1b56
+#define ENCI_VIDEO_EN 0x1b57
+#define ENCI_DVI_HSO_BEGIN 0x1c00
+#define ENCI_DVI_HSO_END 0x1c01
+#define ENCI_DVI_VSO_BLINE_EVN 0x1c02
+#define ENCI_DVI_VSO_BLINE_ODD 0x1c03
+#define ENCI_DVI_VSO_ELINE_EVN 0x1c04
+#define ENCI_DVI_VSO_ELINE_ODD 0x1c05
+#define ENCI_DVI_VSO_BEGIN_EVN 0x1c06
+#define ENCI_DVI_VSO_BEGIN_ODD 0x1c07
+#define ENCI_DVI_VSO_END_EVN 0x1c08
+#define ENCI_DVI_VSO_END_ODD 0x1c09
+#define ENCI_CFILT_CTRL2 0x1c0a
+#define ENCI_DACSEL_0 0x1c0b
+#define ENCI_DACSEL_1 0x1c0c
+#define ENCP_DACSEL_0 0x1c0d
+#define ENCP_DACSEL_1 0x1c0e
+#define ENCP_MAX_LINE_SWITCH_POINT 0x1c0f
+#define ENCI_TST_EN 0x1c10
+#define ENCI_TST_MDSEL 0x1c11
+#define ENCI_TST_Y 0x1c12
+#define ENCI_TST_CB 0x1c13
+#define ENCI_TST_CR 0x1c14
+#define ENCI_TST_CLRBAR_STRT 0x1c15
+#define ENCI_TST_CLRBAR_WIDTH 0x1c16
+#define ENCI_TST_VDCNT_STSET 0x1c17
+#define ENCI_VFIFO2VD_CTL 0x1c18
+#define ENCI_VFIFO2VD_PIXEL_START 0x1c19
+#define ENCI_VFIFO2VD_PIXEL_END 0x1c1a
+#define ENCI_VFIFO2VD_LINE_TOP_START 0x1c1b
+#define ENCI_VFIFO2VD_LINE_TOP_END 0x1c1c
+#define ENCI_VFIFO2VD_LINE_BOT_START 0x1c1d
+#define ENCI_VFIFO2VD_LINE_BOT_END 0x1c1e
+#define ENCI_VFIFO2VD_CTL2 0x1c1f
+#define ENCT_VFIFO2VD_CTL 0x1c20
+#define ENCT_VFIFO2VD_PIXEL_START 0x1c21
+#define ENCT_VFIFO2VD_PIXEL_END 0x1c22
+#define ENCT_VFIFO2VD_LINE_TOP_START 0x1c23
+#define ENCT_VFIFO2VD_LINE_TOP_END 0x1c24
+#define ENCT_VFIFO2VD_LINE_BOT_START 0x1c25
+#define ENCT_VFIFO2VD_LINE_BOT_END 0x1c26
+#define ENCT_VFIFO2VD_CTL2 0x1c27
+#define ENCT_TST_EN 0x1c28
+#define ENCT_TST_MDSEL 0x1c29
+#define ENCT_TST_Y 0x1c2a
+#define ENCT_TST_CB 0x1c2b
+#define ENCT_TST_CR 0x1c2c
+#define ENCT_TST_CLRBAR_STRT 0x1c2d
+#define ENCT_TST_CLRBAR_WIDTH 0x1c2e
+#define ENCT_TST_VDCNT_STSET 0x1c2f
+#define ENCP_DVI_HSO_BEGIN 0x1c30
+#define ENCP_DVI_HSO_END 0x1c31
+#define ENCP_DVI_VSO_BLINE_EVN 0x1c32
+#define ENCP_DVI_VSO_BLINE_ODD 0x1c33
+#define ENCP_DVI_VSO_ELINE_EVN 0x1c34
+#define ENCP_DVI_VSO_ELINE_ODD 0x1c35
+#define ENCP_DVI_VSO_BEGIN_EVN 0x1c36
+#define ENCP_DVI_VSO_BEGIN_ODD 0x1c37
+#define ENCP_DVI_VSO_END_EVN 0x1c38
+#define ENCP_DVI_VSO_END_ODD 0x1c39
+#define ENCP_DE_H_BEGIN 0x1c3a
+#define ENCP_DE_H_END 0x1c3b
+#define ENCP_DE_V_BEGIN_EVEN 0x1c3c
+#define ENCP_DE_V_END_EVEN 0x1c3d
+#define ENCP_DE_V_BEGIN_ODD 0x1c3e
+#define ENCP_DE_V_END_ODD 0x1c3f
+#define ENCI_SYNC_LINE_LENGTH 0x1c40
+#define ENCI_SYNC_PIXEL_EN 0x1c41
+#define ENCI_SYNC_TO_LINE_EN 0x1c42
+#define ENCI_SYNC_TO_PIXEL 0x1c43
+#define ENCP_SYNC_LINE_LENGTH 0x1c44
+#define ENCP_SYNC_PIXEL_EN 0x1c45
+#define ENCP_SYNC_TO_LINE_EN 0x1c46
+#define ENCP_SYNC_TO_PIXEL 0x1c47
+#define ENCT_SYNC_LINE_LENGTH 0x1c48
+#define ENCT_SYNC_PIXEL_EN 0x1c49
+#define ENCT_SYNC_TO_LINE_EN 0x1c4a
+#define ENCT_SYNC_TO_PIXEL 0x1c4b
+#define ENCL_SYNC_LINE_LENGTH 0x1c4c
+#define ENCL_SYNC_PIXEL_EN 0x1c4d
+#define ENCL_SYNC_TO_LINE_EN 0x1c4e
+#define ENCL_SYNC_TO_PIXEL 0x1c4f
+#define ENCP_VFIFO2VD_CTL2 0x1c50
+#define VENC_DVI_SETTING_MORE 0x1c51
+#define VENC_VDAC_DAC4_FILT_CTRL0 0x1c54
+#define VENC_VDAC_DAC4_FILT_CTRL1 0x1c55
+#define VENC_VDAC_DAC5_FILT_CTRL0 0x1c56
+#define VENC_VDAC_DAC5_FILT_CTRL1 0x1c57
+#define VENC_VDAC_DAC0_FILT_CTRL0 0x1c58
+#define VENC_VDAC_DAC0_FILT_CTRL1 0x1c59
+#define VENC_VDAC_DAC1_FILT_CTRL0 0x1c5a
+#define VENC_VDAC_DAC1_FILT_CTRL1 0x1c5b
+#define VENC_VDAC_DAC2_FILT_CTRL0 0x1c5c
+#define VENC_VDAC_DAC2_FILT_CTRL1 0x1c5d
+#define VENC_VDAC_DAC3_FILT_CTRL0 0x1c5e
+#define VENC_VDAC_DAC3_FILT_CTRL1 0x1c5f
+#define ENCT_VIDEO_EN 0x1c60
+#define ENCT_VIDEO_Y_SCL 0x1c61
+#define ENCT_VIDEO_PB_SCL 0x1c62
+#define ENCT_VIDEO_PR_SCL 0x1c63
+#define ENCT_VIDEO_Y_OFFST 0x1c64
+#define ENCT_VIDEO_PB_OFFST 0x1c65
+#define ENCT_VIDEO_PR_OFFST 0x1c66
+#define ENCT_VIDEO_MODE 0x1c67
+#define ENCT_VIDEO_MODE_ADV 0x1c68
+#define ENCT_DBG_PX_RST 0x1c69
+#define ENCT_DBG_LN_RST 0x1c6a
+#define ENCT_DBG_PX_INT 0x1c6b
+#define ENCT_DBG_LN_INT 0x1c6c
+#define ENCT_VIDEO_YFP1_HTIME 0x1c6d
+#define ENCT_VIDEO_YFP2_HTIME 0x1c6e
+#define ENCT_VIDEO_YC_DLY 0x1c6f
+#define ENCT_VIDEO_MAX_PXCNT 0x1c70
+#define ENCT_VIDEO_HAVON_END 0x1c71
+#define ENCT_VIDEO_HAVON_BEGIN 0x1c72
+#define ENCT_VIDEO_VAVON_ELINE 0x1c73
+#define ENCT_VIDEO_VAVON_BLINE 0x1c74
+#define ENCT_VIDEO_HSO_BEGIN 0x1c75
+#define ENCT_VIDEO_HSO_END 0x1c76
+#define ENCT_VIDEO_VSO_BEGIN 0x1c77
+#define ENCT_VIDEO_VSO_END 0x1c78
+#define ENCT_VIDEO_VSO_BLINE 0x1c79
+#define ENCT_VIDEO_VSO_ELINE 0x1c7a
+#define ENCT_VIDEO_MAX_LNCNT 0x1c7b
+#define ENCT_VIDEO_BLANKY_VAL 0x1c7c
+#define ENCT_VIDEO_BLANKPB_VAL 0x1c7d
+#define ENCT_VIDEO_BLANKPR_VAL 0x1c7e
+#define ENCT_VIDEO_HOFFST 0x1c7f
+#define ENCT_VIDEO_VOFFST 0x1c80
+#define ENCT_VIDEO_RGB_CTRL 0x1c81
+#define ENCT_VIDEO_FILT_CTRL 0x1c82
+#define ENCT_VIDEO_OFLD_VPEQ_OFST 0x1c83
+#define ENCT_VIDEO_OFLD_VOAV_OFST 0x1c84
+#define ENCT_VIDEO_MATRIX_CB 0x1c85
+#define ENCT_VIDEO_MATRIX_CR 0x1c86
+#define ENCT_VIDEO_RGBIN_CTRL 0x1c87
+#define ENCT_MAX_LINE_SWITCH_POINT 0x1c88
+#define ENCT_DACSEL_0 0x1c89
+#define ENCT_DACSEL_1 0x1c8a
+#define ENCL_VFIFO2VD_CTL 0x1c90
+#define ENCL_VFIFO2VD_PIXEL_START 0x1c91
+#define ENCL_VFIFO2VD_PIXEL_END 0x1c92
+#define ENCL_VFIFO2VD_LINE_TOP_START 0x1c93
+#define ENCL_VFIFO2VD_LINE_TOP_END 0x1c94
+#define ENCL_VFIFO2VD_LINE_BOT_START 0x1c95
+#define ENCL_VFIFO2VD_LINE_BOT_END 0x1c96
+#define ENCL_VFIFO2VD_CTL2 0x1c97
+#define ENCL_TST_EN 0x1c98
+#define ENCL_TST_MDSEL 0x1c99
+#define ENCL_TST_Y 0x1c9a
+#define ENCL_TST_CB 0x1c9b
+#define ENCL_TST_CR 0x1c9c
+#define ENCL_TST_CLRBAR_STRT 0x1c9d
+#define ENCL_TST_CLRBAR_WIDTH 0x1c9e
+#define ENCL_TST_VDCNT_STSET 0x1c9f
+#define ENCL_VIDEO_EN 0x1ca0
+#define ENCL_VIDEO_Y_SCL 0x1ca1
+#define ENCL_VIDEO_PB_SCL 0x1ca2
+#define ENCL_VIDEO_PR_SCL 0x1ca3
+#define ENCL_VIDEO_Y_OFFST 0x1ca4
+#define ENCL_VIDEO_PB_OFFST 0x1ca5
+#define ENCL_VIDEO_PR_OFFST 0x1ca6
+#define ENCL_VIDEO_MODE 0x1ca7
+#define ENCL_VIDEO_MODE_ADV 0x1ca8
+#define ENCL_DBG_PX_RST 0x1ca9
+#define ENCL_DBG_LN_RST 0x1caa
+#define ENCL_DBG_PX_INT 0x1cab
+#define ENCL_DBG_LN_INT 0x1cac
+#define ENCL_VIDEO_YFP1_HTIME 0x1cad
+#define ENCL_VIDEO_YFP2_HTIME 0x1cae
+#define ENCL_VIDEO_YC_DLY 0x1caf
+#define ENCL_VIDEO_MAX_PXCNT 0x1cb0
+#define ENCL_VIDEO_HAVON_END 0x1cb1
+#define ENCL_VIDEO_HAVON_BEGIN 0x1cb2
+#define ENCL_VIDEO_VAVON_ELINE 0x1cb3
+#define ENCL_VIDEO_VAVON_BLINE 0x1cb4
+#define ENCL_VIDEO_HSO_BEGIN 0x1cb5
+#define ENCL_VIDEO_HSO_END 0x1cb6
+#define ENCL_VIDEO_VSO_BEGIN 0x1cb7
+#define ENCL_VIDEO_VSO_END 0x1cb8
+#define ENCL_VIDEO_VSO_BLINE 0x1cb9
+#define ENCL_VIDEO_VSO_ELINE 0x1cba
+#define ENCL_VIDEO_MAX_LNCNT 0x1cbb
+#define ENCL_VIDEO_BLANKY_VAL 0x1cbc
+#define ENCL_VIDEO_BLANKPB_VAL 0x1cbd
+#define ENCL_VIDEO_BLANKPR_VAL 0x1cbe
+#define ENCL_VIDEO_HOFFST 0x1cbf
+#define ENCL_VIDEO_VOFFST 0x1cc0
+#define ENCL_VIDEO_RGB_CTRL 0x1cc1
+#define ENCL_VIDEO_FILT_CTRL 0x1cc2
+#define ENCL_VIDEO_OFLD_VPEQ_OFST 0x1cc3
+#define ENCL_VIDEO_OFLD_VOAV_OFST 0x1cc4
+#define ENCL_VIDEO_MATRIX_CB 0x1cc5
+#define ENCL_VIDEO_MATRIX_CR 0x1cc6
+#define ENCL_VIDEO_RGBIN_CTRL 0x1cc7
+#define ENCL_MAX_LINE_SWITCH_POINT 0x1cc8
+#define ENCL_DACSEL_0 0x1cc9
+#define ENCL_DACSEL_1 0x1cca
+#define RDMA_AHB_START_ADDR_MAN 0x1100
+#define RDMA_AHB_END_ADDR_MAN 0x1101
+#define RDMA_AHB_START_ADDR_1 0x1102
+#define RDMA_AHB_END_ADDR_1 0x1103
+#define RDMA_AHB_START_ADDR_2 0x1104
+#define RDMA_AHB_END_ADDR_2 0x1105
+#define RDMA_AHB_START_ADDR_3 0x1106
+#define RDMA_AHB_END_ADDR_3 0x1107
+#define RDMA_AHB_START_ADDR_4 0x1108
+#define RDMA_AHB_END_ADDR_4 0x1109
+#define RDMA_AHB_START_ADDR_5 0x110a
+#define RDMA_AHB_END_ADDR_5 0x110b
+#define RDMA_AHB_START_ADDR_6 0x110c
+#define RDMA_AHB_END_ADDR_6 0x110d
+#define RDMA_AHB_START_ADDR_7 0x110e
+#define RDMA_AHB_END_ADDR_7 0x110f
+#define RDMA_ACCESS_AUTO 0x1110
+#define RDMA_ACCESS_AUTO2 0x1111
+#define RDMA_ACCESS_AUTO3 0x1112
+#define RDMA_ACCESS_MAN 0x1113
+#define RDMA_CTRL 0x1114
+#define RDMA_STATUS 0x1115
+#define RDMA_STATUS2 0x1116
+#define RDMA_STATUS3 0x1117
+#define L_GAMMA_CNTL_PORT 0x1400
+#define L_GAMMA_DATA_PORT 0x1401
+#define L_GAMMA_ADDR_PORT 0x1402
+#define L_GAMMA_VCOM_HSWITCH_ADDR 0x1403
+#define L_RGB_BASE_ADDR 0x1405
+#define L_RGB_COEFF_ADDR 0x1406
+#define L_POL_CNTL_ADDR 0x1407
+#define L_DITH_CNTL_ADDR 0x1408
+#define L_GAMMA_PROBE_CTRL 0x1409
+#define L_GAMMA_PROBE_COLOR_L 0x140a
+#define L_GAMMA_PROBE_COLOR_H 0x140b
+#define L_GAMMA_PROBE_HL_COLOR 0x140c
+#define L_GAMMA_PROBE_POS_X 0x140d
+#define L_GAMMA_PROBE_POS_Y 0x140e
+#define L_STH1_HS_ADDR 0x1410
+#define L_STH1_HE_ADDR 0x1411
+#define L_STH1_VS_ADDR 0x1412
+#define L_STH1_VE_ADDR 0x1413
+#define L_STH2_HS_ADDR 0x1414
+#define L_STH2_HE_ADDR 0x1415
+#define L_STH2_VS_ADDR 0x1416
+#define L_STH2_VE_ADDR 0x1417
+#define L_OEH_HS_ADDR 0x1418
+#define L_OEH_HE_ADDR 0x1419
+#define L_OEH_VS_ADDR 0x141a
+#define L_OEH_VE_ADDR 0x141b
+#define L_VCOM_HSWITCH_ADDR 0x141c
+#define L_VCOM_VS_ADDR 0x141d
+#define L_VCOM_VE_ADDR 0x141e
+#define L_CPV1_HS_ADDR 0x141f
+#define L_CPV1_HE_ADDR 0x1420
+#define L_CPV1_VS_ADDR 0x1421
+#define L_CPV1_VE_ADDR 0x1422
+#define L_CPV2_HS_ADDR 0x1423
+#define L_CPV2_HE_ADDR 0x1424
+#define L_CPV2_VS_ADDR 0x1425
+#define L_CPV2_VE_ADDR 0x1426
+#define L_STV1_HS_ADDR 0x1427
+#define L_STV1_HE_ADDR 0x1428
+#define L_STV1_VS_ADDR 0x1429
+#define L_STV1_VE_ADDR 0x142a
+#define L_STV2_HS_ADDR 0x142b
+#define L_STV2_HE_ADDR 0x142c
+#define L_STV2_VS_ADDR 0x142d
+#define L_STV2_VE_ADDR 0x142e
+#define L_OEV1_HS_ADDR 0x142f
+#define L_OEV1_HE_ADDR 0x1430
+#define L_OEV1_VS_ADDR 0x1431
+#define L_OEV1_VE_ADDR 0x1432
+#define L_OEV2_HS_ADDR 0x1433
+#define L_OEV2_HE_ADDR 0x1434
+#define L_OEV2_VS_ADDR 0x1435
+#define L_OEV2_VE_ADDR 0x1436
+#define L_OEV3_HS_ADDR 0x1437
+#define L_OEV3_HE_ADDR 0x1438
+#define L_OEV3_VS_ADDR 0x1439
+#define L_OEV3_VE_ADDR 0x143a
+#define L_LCD_PWR_ADDR 0x143b
+#define L_LCD_PWM0_LO_ADDR 0x143c
+#define L_LCD_PWM0_HI_ADDR 0x143d
+#define L_LCD_PWM1_LO_ADDR 0x143e
+#define L_LCD_PWM1_HI_ADDR 0x143f
+#define L_INV_CNT_ADDR 0x1440
+#define L_TCON_MISC_SEL_ADDR 0x1441
+#define L_DUAL_PORT_CNTL_ADDR 0x1442
+#define MLVDS_CLK_CTL1_HI 0x1443
+#define MLVDS_CLK_CTL1_LO 0x1444
+#define L_TCON_DOUBLE_CTL 0x1449
+#define L_TCON_PATTERN_HI 0x144a
+#define L_TCON_PATTERN_LO 0x144b
+#define LDIM_BL_ADDR_PORT 0x144e
+#define LDIM_BL_DATA_PORT 0x144f
+#define L_DE_HS_ADDR 0x1451
+#define L_DE_HE_ADDR 0x1452
+#define L_DE_VS_ADDR 0x1453
+#define L_DE_VE_ADDR 0x1454
+#define L_HSYNC_HS_ADDR 0x1455
+#define L_HSYNC_HE_ADDR 0x1456
+#define L_HSYNC_VS_ADDR 0x1457
+#define L_HSYNC_VE_ADDR 0x1458
+#define L_VSYNC_HS_ADDR 0x1459
+#define L_VSYNC_HE_ADDR 0x145a
+#define L_VSYNC_VS_ADDR 0x145b
+#define L_VSYNC_VE_ADDR 0x145c
+#define L_LCD_MCU_CTL 0x145d
+#define DUAL_MLVDS_CTL 0x1460
+#define DUAL_MLVDS_LINE_START 0x1461
+#define DUAL_MLVDS_LINE_END 0x1462
+#define DUAL_MLVDS_PIXEL_W_START_L 0x1463
+#define DUAL_MLVDS_PIXEL_W_END_L 0x1464
+#define DUAL_MLVDS_PIXEL_W_START_R 0x1465
+#define DUAL_MLVDS_PIXEL_W_END_R 0x1466
+#define DUAL_MLVDS_PIXEL_R_START_L 0x1467
+#define DUAL_MLVDS_PIXEL_R_CNT_L 0x1468
+#define DUAL_MLVDS_PIXEL_R_START_R 0x1469
+#define DUAL_MLVDS_PIXEL_R_CNT_R 0x146a
+#define V_INVERSION_PIXEL 0x1470
+#define V_INVERSION_LINE 0x1471
+#define V_INVERSION_CONTROL 0x1472
+#define MLVDS2_CONTROL 0x1474
+#define MLVDS2_CONFIG_HI 0x1475
+#define MLVDS2_CONFIG_LO 0x1476
+#define MLVDS2_DUAL_GATE_WR_START 0x1477
+#define MLVDS2_DUAL_GATE_WR_END 0x1478
+#define MLVDS2_DUAL_GATE_RD_START 0x1479
+#define MLVDS2_DUAL_GATE_RD_END 0x147a
+#define MLVDS2_SECOND_RESET_CTL 0x147b
+#define MLVDS2_DUAL_GATE_CTL_HI 0x147c
+#define MLVDS2_DUAL_GATE_CTL_LO 0x147d
+#define MLVDS2_RESET_CONFIG_HI 0x147e
+#define MLVDS2_RESET_CONFIG_LO 0x147f
+#define GAMMA_CNTL_PORT 0x1480
+#define GAMMA_DATA_PORT 0x1481
+#define GAMMA_ADDR_PORT 0x1482
+#define GAMMA_VCOM_HSWITCH_ADDR 0x1483
+#define RGB_BASE_ADDR 0x1485
+#define RGB_COEFF_ADDR 0x1486
+#define POL_CNTL_ADDR 0x1487
+#define DITH_CNTL_ADDR 0x1488
+#define GAMMA_PROBE_CTRL 0x1489
+#define GAMMA_PROBE_COLOR_L 0x148a
+#define GAMMA_PROBE_COLOR_H 0x148b
+#define GAMMA_PROBE_HL_COLOR 0x148c
+#define GAMMA_PROBE_POS_X 0x148d
+#define GAMMA_PROBE_POS_Y 0x148e
+#define STH1_HS_ADDR 0x1490
+#define STH1_HE_ADDR 0x1491
+#define STH1_VS_ADDR 0x1492
+#define STH1_VE_ADDR 0x1493
+#define STH2_HS_ADDR 0x1494
+#define STH2_HE_ADDR 0x1495
+#define STH2_VS_ADDR 0x1496
+#define STH2_VE_ADDR 0x1497
+#define OEH_HS_ADDR 0x1498
+#define OEH_HE_ADDR 0x1499
+#define OEH_VS_ADDR 0x149a
+#define OEH_VE_ADDR 0x149b
+#define VCOM_HSWITCH_ADDR 0x149c
+#define VCOM_VS_ADDR 0x149d
+#define VCOM_VE_ADDR 0x149e
+#define CPV1_HS_ADDR 0x149f
+#define CPV1_HE_ADDR 0x14a0
+#define CPV1_VS_ADDR 0x14a1
+#define CPV1_VE_ADDR 0x14a2
+#define CPV2_HS_ADDR 0x14a3
+#define CPV2_HE_ADDR 0x14a4
+#define CPV2_VS_ADDR 0x14a5
+#define CPV2_VE_ADDR 0x14a6
+#define STV1_HS_ADDR 0x14a7
+#define STV1_HE_ADDR 0x14a8
+#define STV1_VS_ADDR 0x14a9
+#define STV1_VE_ADDR 0x14aa
+#define STV2_HS_ADDR 0x14ab
+#define STV2_HE_ADDR 0x14ac
+#define STV2_VS_ADDR 0x14ad
+#define STV2_VE_ADDR 0x14ae
+#define OEV1_HS_ADDR 0x14af
+#define OEV1_HE_ADDR 0x14b0
+#define OEV1_VS_ADDR 0x14b1
+#define OEV1_VE_ADDR 0x14b2
+#define OEV2_HS_ADDR 0x14b3
+#define OEV2_HE_ADDR 0x14b4
+#define OEV2_VS_ADDR 0x14b5
+#define OEV2_VE_ADDR 0x14b6
+#define OEV3_HS_ADDR 0x14b7
+#define OEV3_HE_ADDR 0x14b8
+#define OEV3_VS_ADDR 0x14b9
+#define OEV3_VE_ADDR 0x14ba
+#define LCD_PWR_ADDR 0x14bb
+#define LCD_PWM0_LO_ADDR 0x14bc
+#define LCD_PWM0_HI_ADDR 0x14bd
+#define LCD_PWM1_LO_ADDR 0x14be
+#define LCD_PWM1_HI_ADDR 0x14bf
+#define INV_CNT_ADDR 0x14c0
+#define TCON_MISC_SEL_ADDR 0x14c1
+#define DUAL_PORT_CNTL_ADDR 0x14c2
+#define MLVDS_CONTROL 0x14c3
+#define MLVDS_RESET_PATTERN_HI 0x14c4
+#define MLVDS_RESET_PATTERN_LO 0x14c5
+#define MLVDS_RESET_PATTERN_EXT 0x14c6
+#define MLVDS_CONFIG_HI 0x14c7
+#define MLVDS_CONFIG_LO 0x14c8
+#define TCON_DOUBLE_CTL 0x14c9
+#define TCON_PATTERN_HI 0x14ca
+#define TCON_PATTERN_LO 0x14cb
+#define TCON_CONTROL_HI 0x14cc
+#define TCON_CONTROL_LO 0x14cd
+#define LVDS_BLANK_DATA_HI 0x14ce
+#define LVDS_BLANK_DATA_LO 0x14cf
+#define LVDS_PACK_CNTL_ADDR 0x14d0
+#define DE_HS_ADDR 0x14d1
+#define DE_HE_ADDR 0x14d2
+#define DE_VS_ADDR 0x14d3
+#define DE_VE_ADDR 0x14d4
+#define HSYNC_HS_ADDR 0x14d5
+#define HSYNC_HE_ADDR 0x14d6
+#define HSYNC_VS_ADDR 0x14d7
+#define HSYNC_VE_ADDR 0x14d8
+#define VSYNC_HS_ADDR 0x14d9
+#define VSYNC_HE_ADDR 0x14da
+#define VSYNC_VS_ADDR 0x14db
+#define VSYNC_VE_ADDR 0x14dc
+#define LCD_MCU_CTL 0x14dd
+#define LCD_MCU_DATA_0 0x14de
+#define LCD_MCU_DATA_1 0x14df
+#define LVDS_GEN_CNTL 0x14e0
+#define LVDS_PHY_CNTL0 0x14e1
+#define LVDS_PHY_CNTL1 0x14e2
+#define LVDS_PHY_CNTL2 0x14e3
+#define LVDS_PHY_CNTL3 0x14e4
+#define LVDS_PHY_CNTL4 0x14e5
+#define LVDS_PHY_CNTL5 0x14e6
+#define LVDS_SRG_TEST 0x14e8
+#define LVDS_BIST_MUX0 0x14e9
+#define LVDS_BIST_MUX1 0x14ea
+#define LVDS_BIST_FIXED0 0x14eb
+#define LVDS_BIST_FIXED1 0x14ec
+#define LVDS_BIST_CNTL0 0x14ed
+#define LVDS_CLKB_CLKA 0x14ee
+#define LVDS_PHY_CLK_CNTL 0x14ef
+#define LVDS_SER_EN 0x14f0
+#define LVDS_PHY_CNTL6 0x14f1
+#define LVDS_PHY_CNTL7 0x14f2
+#define LVDS_PHY_CNTL8 0x14f3
+#define MLVDS_CLK_CTL0_HI 0x14f4
+#define MLVDS_CLK_CTL0_LO 0x14f5
+#define MLVDS_DUAL_GATE_WR_START 0x14f6
+#define MLVDS_DUAL_GATE_WR_END 0x14f7
+#define MLVDS_DUAL_GATE_RD_START 0x14f8
+#define MLVDS_DUAL_GATE_RD_END 0x14f9
+#define MLVDS_SECOND_RESET_CTL 0x14fa
+#define MLVDS_DUAL_GATE_CTL_HI 0x14fb
+#define MLVDS_DUAL_GATE_CTL_LO 0x14fc
+#define MLVDS_RESET_CONFIG_HI 0x14fd
+#define MLVDS_RESET_CONFIG_LO 0x14fe
+#define VPU_OSD1_MMC_CTRL 0x2701
+#define VPU_OSD2_MMC_CTRL 0x2702
+#define VPU_VD1_MMC_CTRL 0x2703
+#define VPU_VD2_MMC_CTRL 0x2704
+#define VPU_DI_IF1_MMC_CTRL 0x2705
+#define VPU_DI_MEM_MMC_CTRL 0x2706
+#define VPU_DI_INP_MMC_CTRL 0x2707
+#define VPU_DI_MTNRD_MMC_CTRL 0x2708
+#define VPU_DI_CHAN2_MMC_CTRL 0x2709
+#define VPU_DI_MTNWR_MMC_CTRL 0x270a
+#define VPU_DI_NRWR_MMC_CTRL 0x270b
+#define VPU_DI_DIWR_MMC_CTRL 0x270c
+#define VPU_VDIN0_MMC_CTRL 0x270d
+#define VPU_VDIN1_MMC_CTRL 0x270e
+#define VPU_BT656_MMC_CTRL 0x270f
+#define VPU_TVD3D_MMC_CTRL 0x2710
+#define VPU_TVDVBI_MMC_CTRL 0x2711
+#define VPU_TVDVBI_VSLATCH_ADDR 0x2712
+#define VPU_TVDVBI_WRRSP_ADDR 0x2713
+#define VPU_VDIN_PRE_ARB_CTRL 0x2714
+#define VPU_VDISP_PRE_ARB_CTRL 0x2715
+#define VPU_VPUARB2_PRE_ARB_CTRL 0x2716
+#define VPU_OSD3_MMC_CTRL 0x2717
+#define VPU_OSD4_MMC_CTRL 0x2718
+#define VPU_VD3_MMC_CTRL 0x2719
+#define VPU_VIU_VENC_MUX_CTRL 0x271a
+#define		VIU1_SEL_VENC_MASK	0x3
+#define		VIU1_SEL_VENC_ENCL	0
+#define		VIU1_SEL_VENC_ENCI	1
+#define		VIU1_SEL_VENC_ENCP	2
+#define		VIU1_SEL_VENC_ENCT	3
+#define		VIU2_SEL_VENC_MASK	0xc
+#define		VIU2_SEL_VENC_ENCL	0
+#define		VIU2_SEL_VENC_ENCI	(1 << 2)
+#define		VIU2_SEL_VENC_ENCP	(2 << 2)
+#define		VIU2_SEL_VENC_ENCT	(3 << 2)
+#define VPU_HDMI_SETTING 0x271b
+#define ENCI_INFO_READ 0x271c
+#define ENCP_INFO_READ 0x271d
+#define ENCT_INFO_READ 0x271e
+#define ENCL_INFO_READ 0x271f
+#define VPU_SW_RESET 0x2720
+#define VPU_D2D3_MMC_CTRL 0x2721
+#define VPU_CONT_MMC_CTRL 0x2722
+#define VPU_CLK_GATE 0x2723
+#define VPU_RDMA_MMC_CTRL 0x2724
+#define VPU_MEM_PD_REG0 0x2725
+#define VPU_MEM_PD_REG1 0x2726
+#define VPU_HDMI_DATA_OVR 0x2727
+#define VPU_PROT1_MMC_CTRL 0x2728
+#define VPU_PROT2_MMC_CTRL 0x2729
+#define VPU_PROT3_MMC_CTRL 0x272a
+#define VPU_ARB4_V1_MMC_CTRL 0x272b
+#define VPU_ARB4_V2_MMC_CTRL 0x272c
+#define VPU_VPU_PWM_V0 0x2730
+#define VPU_VPU_PWM_V1 0x2731
+#define VPU_VPU_PWM_V2 0x2732
+#define VPU_VPU_PWM_V3 0x2733
+#define VPU_VPU_PWM_H0 0x2734
+#define VPU_VPU_PWM_H1 0x2735
+#define VPU_VPU_PWM_H2 0x2736
+#define VPU_VPU_PWM_H3 0x2737
+#define VPU_MISC_CTRL 0x2740
+#define VPU_ISP_GCLK_CTRL0 0x2741
+#define VPU_ISP_GCLK_CTRL1 0x2742
+#define VPU_VDIN_ASYNC_HOLD_CTRL 0x2743
+#define VPU_VDISP_ASYNC_HOLD_CTRL 0x2744
+#define VPU_VPUARB2_ASYNC_HOLD_CTRL 0x2745
+
+#define VPU_PROT1_CLK_GATE 0x2750
+#define VPU_PROT1_GEN_CNTL 0x2751
+#define VPU_PROT1_X_START_END 0x2752
+#define VPU_PROT1_Y_START_END 0x2753
+#define VPU_PROT1_Y_LEN_STEP 0x2754
+#define VPU_PROT1_RPT_LOOP 0x2755
+#define VPU_PROT1_RPT_PAT 0x2756
+#define VPU_PROT1_DDR 0x2757
+#define VPU_PROT1_RBUF_ROOM 0x2758
+#define VPU_PROT1_STAT_0 0x2759
+#define VPU_PROT1_STAT_1 0x275a
+#define VPU_PROT1_STAT_2 0x275b
+#define VPU_PROT1_REQ_ONOFF 0x275c
+#define VPU_PROT2_CLK_GATE 0x2760
+#define VPU_PROT2_GEN_CNTL 0x2761
+#define VPU_PROT2_X_START_END 0x2762
+#define VPU_PROT2_Y_START_END 0x2763
+#define VPU_PROT2_Y_LEN_STEP 0x2764
+#define VPU_PROT2_RPT_LOOP 0x2765
+#define VPU_PROT2_RPT_PAT 0x2766
+#define VPU_PROT2_DDR 0x2767
+#define VPU_PROT2_RBUF_ROOM 0x2768
+#define VPU_PROT2_STAT_0 0x2769
+#define VPU_PROT2_STAT_1 0x276a
+#define VPU_PROT2_STAT_2 0x276b
+#define VPU_PROT2_REQ_ONOFF 0x276c
+#define VPU_PROT3_CLK_GATE 0x2770
+#define VPU_PROT3_GEN_CNTL 0x2771
+#define VPU_PROT3_X_START_END 0x2772
+#define VPU_PROT3_Y_START_END 0x2773
+#define VPU_PROT3_Y_LEN_STEP 0x2774
+#define VPU_PROT3_RPT_LOOP 0x2775
+#define VPU_PROT3_RPT_PAT 0x2776
+#define VPU_PROT3_DDR 0x2777
+#define VPU_PROT3_RBUF_ROOM 0x2778
+#define VPU_PROT3_STAT_0 0x2779
+#define VPU_PROT3_STAT_1 0x277a
+#define VPU_PROT3_STAT_2 0x277b
+#define VPU_PROT3_REQ_ONOFF 0x277c
+
+/* osd super scale */
+#define OSDSR_HV_SIZEIN 0x3130
+#define OSDSR_CTRL_MODE 0x3131
+#define OSDSR_ABIC_HCOEF 0x3132
+#define OSDSR_YBIC_HCOEF 0x3133
+#define OSDSR_CBIC_HCOEF 0x3134
+#define OSDSR_ABIC_VCOEF 0x3135
+#define OSDSR_YBIC_VCOEF 0x3136
+#define OSDSR_CBIC_VCOEF 0x3137
+#define OSDSR_VAR_PARA 0x3138
+#define OSDSR_CONST_PARA 0x3139
+#define OSDSR_RKE_EXTWIN 0x313a
+#define OSDSR_UK_GRAD2DDIAG_TH_RATE 0x313b
+#define OSDSR_UK_GRAD2DDIAG_LIMIT 0x313c
+#define OSDSR_UK_GRAD2DADJA_TH_RATE 0x313d
+#define OSDSR_UK_GRAD2DADJA_LIMIT 0x313e
+#define OSDSR_UK_BST_GAIN 0x313f
+#define OSDSR_HVBLEND_TH 0x3140
+#define OSDSR_DEMO_WIND_TB 0x3141
+#define OSDSR_DEMO_WIND_LR 0x3142
+#define OSDSR_INT_BLANK_NUM 0x3143
+#define OSDSR_FRM_END_STAT 0x3144
+#define OSDSR_ABIC_HCOEF0 0x3145
+#define OSDSR_YBIC_HCOEF0 0x3146
+#define OSDSR_CBIC_HCOEF0 0x3147
+#define OSDSR_ABIC_VCOEF0 0x3148
+#define OSDSR_YBIC_VCOEF0 0x3149
+#define OSDSR_CBIC_VCOEF0 0x314a
+
+#endif /* __MESON_REGISTERS_H */

+ 167 - 0
drivers/gpu/drm/meson/meson_vclk.c

@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include "meson_drv.h"
+#include "meson_vclk.h"
+
+/*
+ * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL.
+ * We handle the following encodings :
+ * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks
+ *
+ * What is missing :
+ * - HDMI Pixel Clocks generation
+ */
+
+/* HHI Registers */
+#define HHI_VID_PLL_CLK_DIV	0x1a0 /* 0x68 offset in data sheet */
+#define VID_PLL_EN		BIT(19)
+#define VID_PLL_BYPASS		BIT(18)
+#define VID_PLL_PRESET		BIT(15)
+#define HHI_VIID_CLK_DIV	0x128 /* 0x4a offset in data sheet */
+#define VCLK2_DIV_MASK		0xff
+#define VCLK2_DIV_EN		BIT(16)
+#define VCLK2_DIV_RESET		BIT(17)
+#define CTS_VDAC_SEL_MASK	(0xf << 28)
+#define CTS_VDAC_SEL_SHIFT	28
+#define HHI_VIID_CLK_CNTL	0x12c /* 0x4b offset in data sheet */
+#define VCLK2_EN		BIT(19)
+#define VCLK2_SEL_MASK		(0x7 << 16)
+#define VCLK2_SEL_SHIFT		16
+#define VCLK2_SOFT_RESET	BIT(15)
+#define VCLK2_DIV1_EN		BIT(0)
+#define HHI_VID_CLK_DIV		0x164 /* 0x59 offset in data sheet */
+#define CTS_ENCI_SEL_MASK	(0xf << 28)
+#define CTS_ENCI_SEL_SHIFT	28
+#define HHI_VID_CLK_CNTL2	0x194 /* 0x65 offset in data sheet */
+#define CTS_ENCI_EN		BIT(0)
+#define CTS_VDAC_EN		BIT(4)
+
+#define HHI_VDAC_CNTL0		0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1		0x2F8 /* 0xbe offset in data sheet */
+
+#define HHI_HDMI_PLL_CNTL	0x320 /* 0xc8 offset in data sheet */
+#define HHI_HDMI_PLL_CNTL2	0x324 /* 0xc9 offset in data sheet */
+#define HHI_HDMI_PLL_CNTL3	0x328 /* 0xca offset in data sheet */
+#define HHI_HDMI_PLL_CNTL4	0x32C /* 0xcb offset in data sheet */
+#define HHI_HDMI_PLL_CNTL5	0x330 /* 0xcc offset in data sheet */
+#define HHI_HDMI_PLL_CNTL6	0x334 /* 0xcd offset in data sheet */
+
+#define HDMI_PLL_RESET		BIT(28)
+#define HDMI_PLL_LOCK		BIT(31)
+
+/*
+ * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC
+ *
+ * TOFIX: Refactor into table to also handle HDMI frequency and paths
+ */
+static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
+{
+	unsigned int val;
+
+	/* Setup PLL to output 1.485GHz */
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d);
+	} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+		   meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0xa6212844);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c4d000c);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+		regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+
+		/* Reset PLL */
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+					HDMI_PLL_RESET, HDMI_PLL_RESET);
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+					HDMI_PLL_RESET, 0);
+	}
+
+	/* Poll for lock bit */
+	regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
+				 (val & HDMI_PLL_LOCK), 10, 0);
+
+	/* Disable VCLK2 */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
+
+	/* Disable vid_pll output clock */
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
+	/* Enable vid_pll bypass to HDMI pll */
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				VID_PLL_BYPASS, VID_PLL_BYPASS);
+	/* Enable the vid_pll output clock */
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				VID_PLL_EN, VID_PLL_EN);
+
+	/* Setup the VCLK2 divider value to achieve 27MHz */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
+				VCLK2_DIV_MASK, (55 - 1));
+
+	/* select vid_pll for vclk2 */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+				VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
+	/* enable vclk2 gate */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
+
+	/* select vclk_div1 for enci */
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCI_SEL_MASK, (8 << CTS_ENCI_SEL_SHIFT));
+	/* select vclk_div1 for vdac */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
+				CTS_VDAC_SEL_MASK, (8 << CTS_VDAC_SEL_SHIFT));
+
+	/* release vclk2_div_reset and enable vclk2_div */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
+				VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN);
+
+	/* enable vclk2_div1 gate */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+				VCLK2_DIV1_EN, VCLK2_DIV1_EN);
+
+	/* reset vclk2 */
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+				VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
+	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+				VCLK2_SOFT_RESET, 0);
+
+	/* enable enci_clk */
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+				CTS_ENCI_EN, CTS_ENCI_EN);
+	/* enable vdac_clk */
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+				CTS_VDAC_EN, CTS_VDAC_EN);
+}
+
+void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+		      unsigned int freq)
+{
+	if (target == MESON_VCLK_TARGET_CVBS && freq == MESON_VCLK_CVBS)
+		meson_venci_cvbs_clock_config(priv);
+}

+ 34 - 0
drivers/gpu/drm/meson/meson_vclk.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Video Clock */
+
+#ifndef __MESON_VCLK_H
+#define __MESON_VCLK_H
+
+enum {
+	MESON_VCLK_TARGET_CVBS = 0,
+};
+
+/* 27MHz is the CVBS Pixel Clock */
+#define MESON_VCLK_CVBS	27000
+
+void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+		      unsigned int freq);
+
+#endif /* __MESON_VCLK_H */

+ 254 - 0
drivers/gpu/drm/meson/meson_venc.c

@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include "meson_drv.h"
+#include "meson_venc.h"
+#include "meson_vpp.h"
+#include "meson_vclk.h"
+#include "meson_registers.h"
+
+/*
+ * VENC Handle the pixels encoding to the output formats.
+ * We handle the following encodings :
+ * - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter
+ *
+ * What is missing :
+ * - TMDS/HDMI Encoding via ENCI_DIV and ENCP
+ * - Setup of more clock rates for HDMI modes
+ * - LCD Panel encoding via ENCL
+ * - TV Panel encoding via ENCT
+ */
+
+struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
+	.mode_tag = MESON_VENC_MODE_CVBS_PAL,
+	.hso_begin = 3,
+	.hso_end = 129,
+	.vso_even = 3,
+	.vso_odd = 260,
+	.macv_max_amp = 7,
+	.video_prog_mode = 0xff,
+	.video_mode = 0x13,
+	.sch_adjust = 0x28,
+	.yc_delay = 0x343,
+	.pixel_start = 251,
+	.pixel_end = 1691,
+	.top_field_line_start = 22,
+	.top_field_line_end = 310,
+	.bottom_field_line_start = 23,
+	.bottom_field_line_end = 311,
+	.video_saturation = 9,
+	.video_contrast = 0,
+	.video_brightness = 0,
+	.video_hue = 0,
+	.analog_sync_adj = 0x8080,
+};
+
+struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc = {
+	.mode_tag = MESON_VENC_MODE_CVBS_NTSC,
+	.hso_begin = 5,
+	.hso_end = 129,
+	.vso_even = 3,
+	.vso_odd = 260,
+	.macv_max_amp = 0xb,
+	.video_prog_mode = 0xf0,
+	.video_mode = 0x8,
+	.sch_adjust = 0x20,
+	.yc_delay = 0x333,
+	.pixel_start = 227,
+	.pixel_end = 1667,
+	.top_field_line_start = 18,
+	.top_field_line_end = 258,
+	.bottom_field_line_start = 19,
+	.bottom_field_line_end = 259,
+	.video_saturation = 18,
+	.video_contrast = 3,
+	.video_brightness = 0,
+	.video_hue = 0,
+	.analog_sync_adj = 0x9c00,
+};
+
+void meson_venci_cvbs_mode_set(struct meson_drm *priv,
+			       struct meson_cvbs_enci_mode *mode)
+{
+	if (mode->mode_tag == priv->venc.current_mode)
+		return;
+
+	/* CVBS Filter settings */
+	writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL));
+	writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2));
+
+	/* Digital Video Select : Interlace, clk27 clk, external */
+	writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING));
+
+	/* Reset Video Mode */
+	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE));
+	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+	/* Horizontal sync signal output */
+	writel_relaxed(mode->hso_begin,
+			priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN));
+	writel_relaxed(mode->hso_end,
+			priv->io_base + _REG(ENCI_SYNC_HSO_END));
+
+	/* Vertical Sync lines */
+	writel_relaxed(mode->vso_even,
+			priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN));
+	writel_relaxed(mode->vso_odd,
+			priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN));
+
+	/* Macrovision max amplitude change */
+	writel_relaxed(0x8100 + mode->macv_max_amp,
+			priv->io_base + _REG(ENCI_MACV_MAX_AMP));
+
+	/* Video mode */
+	writel_relaxed(mode->video_prog_mode,
+			priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
+	writel_relaxed(mode->video_mode,
+			priv->io_base + _REG(ENCI_VIDEO_MODE));
+
+	/* Advanced Video Mode :
+	 * Demux shifting 0x2
+	 * Blank line end at line17/22
+	 * High bandwidth Luma Filter
+	 * Low bandwidth Chroma Filter
+	 * Bypass luma low pass filter
+	 * No macrovision on CSYNC
+	 */
+	writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+	writel(mode->sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH));
+
+	/* Sync mode : MASTER Master mode, free run, send HSO/VSO out */
+	writel_relaxed(0x07, priv->io_base + _REG(ENCI_SYNC_MODE));
+
+	/* 0x3 Y, C, and Component Y delay */
+	writel_relaxed(mode->yc_delay, priv->io_base + _REG(ENCI_YC_DELAY));
+
+	/* Timings */
+	writel_relaxed(mode->pixel_start,
+			priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START));
+	writel_relaxed(mode->pixel_end,
+			priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END));
+
+	writel_relaxed(mode->top_field_line_start,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START));
+	writel_relaxed(mode->top_field_line_end,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END));
+
+	writel_relaxed(mode->bottom_field_line_start,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START));
+	writel_relaxed(mode->bottom_field_line_end,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END));
+
+	/* Internal Venc, Internal VIU Sync, Internal Vencoder */
+	writel_relaxed(0, priv->io_base + _REG(VENC_SYNC_ROUTE));
+
+	/* UNreset Interlaced TV Encoder */
+	writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST));
+
+	/* Enable Vfifo2vd, Y_Cb_Y_Cr select */
+	writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL));
+
+	/* Power UP Dacs */
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_SETTING));
+
+	/* Video Upsampling */
+	writel_relaxed(0x0061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL0));
+	writel_relaxed(0x4061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL1));
+	writel_relaxed(0x5061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL2));
+
+	/* Select Interlace Y DACs */
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL0));
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL1));
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL2));
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL3));
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL4));
+	writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL5));
+
+	/* Select ENCI for VIU */
+	meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI);
+
+	/* Enable ENCI FIFO */
+	writel_relaxed(0x2000, priv->io_base + _REG(VENC_VDAC_FIFO_CTRL));
+
+	/* Select ENCI DACs 0, 1, 4, and 5 */
+	writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_0));
+	writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_1));
+
+	/* Interlace video enable */
+	writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
+
+	/* Configure Video Saturation / Contrast / Brightness / Hue */
+	writel_relaxed(mode->video_saturation,
+			priv->io_base + _REG(ENCI_VIDEO_SAT));
+	writel_relaxed(mode->video_contrast,
+			priv->io_base + _REG(ENCI_VIDEO_CONT));
+	writel_relaxed(mode->video_brightness,
+			priv->io_base + _REG(ENCI_VIDEO_BRIGHT));
+	writel_relaxed(mode->video_hue,
+			priv->io_base + _REG(ENCI_VIDEO_HUE));
+
+	/* Enable DAC0 Filter */
+	writel_relaxed(0x1, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0));
+	writel_relaxed(0xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1));
+
+	/* 0 in Macrovision register 0 */
+	writel_relaxed(0, priv->io_base + _REG(ENCI_MACV_N0));
+
+	/* Analog Synchronization and color burst value adjust */
+	writel_relaxed(mode->analog_sync_adj,
+			priv->io_base + _REG(ENCI_SYNC_ADJ));
+
+	/* Setup 27MHz vclk2 for ENCI and VDAC */
+	meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS);
+
+	priv->venc.current_mode = mode->mode_tag;
+}
+
+/* Returns the current ENCI field polarity */
+unsigned int meson_venci_get_field(struct meson_drm *priv)
+{
+	return readl_relaxed(priv->io_base + _REG(ENCI_INFO_READ)) & BIT(29);
+}
+
+void meson_venc_enable_vsync(struct meson_drm *priv)
+{
+	writel_relaxed(2, priv->io_base + _REG(VENC_INTCTRL));
+}
+
+void meson_venc_disable_vsync(struct meson_drm *priv)
+{
+	writel_relaxed(0, priv->io_base + _REG(VENC_INTCTRL));
+}
+
+void meson_venc_init(struct meson_drm *priv)
+{
+	/* Disable all encoders */
+	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
+	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
+	writel_relaxed(0, priv->io_base + _REG(ENCL_VIDEO_EN));
+
+	/* Disable VSync IRQ */
+	meson_venc_disable_vsync(priv);
+
+	priv->venc.current_mode = MESON_VENC_MODE_NONE;
+}

+ 72 - 0
drivers/gpu/drm/meson/meson_venc.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Video Encoders
+ * - ENCI : Interlace Video Encoder
+ * - ENCI_DVI : Interlace Video Encoder for DVI/HDMI
+ * - ENCP : Progressive Video Encoder
+ */
+
+#ifndef __MESON_VENC_H
+#define __MESON_VENC_H
+
+enum {
+	MESON_VENC_MODE_NONE = 0,
+	MESON_VENC_MODE_CVBS_PAL,
+	MESON_VENC_MODE_CVBS_NTSC,
+};
+
+struct meson_cvbs_enci_mode {
+	unsigned int mode_tag;
+	unsigned int hso_begin; /* HSO begin position */
+	unsigned int hso_end; /* HSO end position */
+	unsigned int vso_even; /* VSO even line */
+	unsigned int vso_odd; /* VSO odd line */
+	unsigned int macv_max_amp; /* Macrovision max amplitude */
+	unsigned int video_prog_mode;
+	unsigned int video_mode;
+	unsigned int sch_adjust;
+	unsigned int yc_delay;
+	unsigned int pixel_start;
+	unsigned int pixel_end;
+	unsigned int top_field_line_start;
+	unsigned int top_field_line_end;
+	unsigned int bottom_field_line_start;
+	unsigned int bottom_field_line_end;
+	unsigned int video_saturation;
+	unsigned int video_contrast;
+	unsigned int video_brightness;
+	unsigned int video_hue;
+	unsigned int analog_sync_adj;
+};
+
+/* CVBS Timings and Parameters */
+extern struct meson_cvbs_enci_mode meson_cvbs_enci_pal;
+extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
+
+void meson_venci_cvbs_mode_set(struct meson_drm *priv,
+			       struct meson_cvbs_enci_mode *mode);
+unsigned int meson_venci_get_field(struct meson_drm *priv);
+
+void meson_venc_enable_vsync(struct meson_drm *priv);
+void meson_venc_disable_vsync(struct meson_drm *priv);
+
+void meson_venc_init(struct meson_drm *priv);
+
+#endif /* __MESON_VENC_H */

+ 293 - 0
drivers/gpu/drm/meson/meson_venc_cvbs.c

@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "meson_venc_cvbs.h"
+#include "meson_venc.h"
+#include "meson_registers.h"
+
+/* HHI VDAC Registers */
+#define HHI_VDAC_CNTL0		0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1		0x2F8 /* 0xbe offset in data sheet */
+
+struct meson_venc_cvbs {
+	struct drm_encoder	encoder;
+	struct drm_connector	connector;
+	struct meson_drm	*priv;
+};
+#define encoder_to_meson_venc_cvbs(x) \
+	container_of(x, struct meson_venc_cvbs, encoder)
+
+#define connector_to_meson_venc_cvbs(x) \
+	container_of(x, struct meson_venc_cvbs, connector)
+
+/* Supported Modes */
+
+struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT] = {
+	{ /* PAL */
+		.enci = &meson_cvbs_enci_pal,
+		.mode = {
+			DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
+				 720, 732, 795, 864, 0, 576, 580, 586, 625, 0,
+				 DRM_MODE_FLAG_INTERLACE),
+			.vrefresh = 50,
+			.picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
+		},
+	},
+	{ /* NTSC */
+		.enci = &meson_cvbs_enci_ntsc,
+		.mode = {
+			DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
+				720, 739, 801, 858, 0, 480, 488, 494, 525, 0,
+				DRM_MODE_FLAG_INTERLACE),
+			.vrefresh = 60,
+			.picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
+		},
+	},
+};
+
+/* Connector */
+
+static void meson_cvbs_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+meson_cvbs_connector_detect(struct drm_connector *connector, bool force)
+{
+	/* FIXME: Add load-detect or jack-detect if possible */
+	return connector_status_connected;
+}
+
+static int meson_cvbs_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_display_mode *mode;
+	int i;
+
+	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
+		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
+
+		mode = drm_mode_duplicate(dev, &meson_mode->mode);
+		if (!mode) {
+			DRM_ERROR("Failed to create a new display mode\n");
+			return 0;
+		}
+
+		drm_mode_probed_add(connector, mode);
+	}
+
+	return i;
+}
+
+static int meson_cvbs_connector_mode_valid(struct drm_connector *connector,
+					   struct drm_display_mode *mode)
+{
+	/* Validate the modes added in get_modes */
+	return MODE_OK;
+}
+
+static const struct drm_connector_funcs meson_cvbs_connector_funcs = {
+	.dpms			= drm_atomic_helper_connector_dpms,
+	.detect			= meson_cvbs_connector_detect,
+	.fill_modes		= drm_helper_probe_single_connector_modes,
+	.destroy		= meson_cvbs_connector_destroy,
+	.reset			= drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
+};
+
+static const
+struct drm_connector_helper_funcs meson_cvbs_connector_helper_funcs = {
+	.get_modes	= meson_cvbs_connector_get_modes,
+	.mode_valid	= meson_cvbs_connector_mode_valid,
+};
+
+/* Encoder */
+
+static void meson_venc_cvbs_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs meson_venc_cvbs_encoder_funcs = {
+	.destroy        = meson_venc_cvbs_encoder_destroy,
+};
+
+static int meson_venc_cvbs_encoder_atomic_check(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	int i;
+
+	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
+		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
+
+		if (drm_mode_equal(&crtc_state->mode, &meson_mode->mode))
+			return 0;
+	}
+
+	return -EINVAL;
+}
+
+static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder)
+{
+	struct meson_venc_cvbs *meson_venc_cvbs =
+					encoder_to_meson_venc_cvbs(encoder);
+	struct meson_drm *priv = meson_venc_cvbs->priv;
+
+	/* Disable CVBS VDAC */
+	regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
+	regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
+}
+
+static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder)
+{
+	struct meson_venc_cvbs *meson_venc_cvbs =
+					encoder_to_meson_venc_cvbs(encoder);
+	struct meson_drm *priv = meson_venc_cvbs->priv;
+
+	/* VDAC0 source is not from ATV */
+	writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0));
+
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
+		regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
+	else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+		 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+		regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
+
+	regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
+}
+
+static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted_mode)
+{
+	struct meson_venc_cvbs *meson_venc_cvbs =
+					encoder_to_meson_venc_cvbs(encoder);
+	int i;
+
+	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
+		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
+
+		if (drm_mode_equal(mode, &meson_mode->mode)) {
+			meson_venci_cvbs_mode_set(meson_venc_cvbs->priv,
+						  meson_mode->enci);
+			break;
+		}
+	}
+}
+
+static const struct drm_encoder_helper_funcs
+				meson_venc_cvbs_encoder_helper_funcs = {
+	.atomic_check	= meson_venc_cvbs_encoder_atomic_check,
+	.disable	= meson_venc_cvbs_encoder_disable,
+	.enable		= meson_venc_cvbs_encoder_enable,
+	.mode_set	= meson_venc_cvbs_encoder_mode_set,
+};
+
+static bool meson_venc_cvbs_connector_is_available(struct meson_drm *priv)
+{
+	struct device_node *ep, *remote;
+
+	/* CVBS VDAC output is on the first port, first endpoint */
+	ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0);
+	if (!ep)
+		return false;
+
+
+	/* If the endpoint node exists, consider it enabled */
+	remote = of_graph_get_remote_port(ep);
+	if (remote) {
+		of_node_put(ep);
+		return true;
+	}
+
+	of_node_put(ep);
+	of_node_put(remote);
+
+	return false;
+}
+
+int meson_venc_cvbs_create(struct meson_drm *priv)
+{
+	struct drm_device *drm = priv->drm;
+	struct meson_venc_cvbs *meson_venc_cvbs;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	int ret;
+
+	if (!meson_venc_cvbs_connector_is_available(priv)) {
+		dev_info(drm->dev, "CVBS Output connector not available\n");
+		return -ENODEV;
+	}
+
+	meson_venc_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_venc_cvbs),
+				       GFP_KERNEL);
+	if (!meson_venc_cvbs)
+		return -ENOMEM;
+
+	meson_venc_cvbs->priv = priv;
+	encoder = &meson_venc_cvbs->encoder;
+	connector = &meson_venc_cvbs->connector;
+
+	/* Connector */
+
+	drm_connector_helper_add(connector,
+				 &meson_cvbs_connector_helper_funcs);
+
+	ret = drm_connector_init(drm, connector, &meson_cvbs_connector_funcs,
+				 DRM_MODE_CONNECTOR_Composite);
+	if (ret) {
+		dev_err(priv->dev, "Failed to init CVBS connector\n");
+		return ret;
+	}
+
+	connector->interlace_allowed = 1;
+
+	/* Encoder */
+
+	drm_encoder_helper_add(encoder, &meson_venc_cvbs_encoder_helper_funcs);
+
+	ret = drm_encoder_init(drm, encoder, &meson_venc_cvbs_encoder_funcs,
+			       DRM_MODE_ENCODER_TVDAC, "meson_venc_cvbs");
+	if (ret) {
+		dev_err(priv->dev, "Failed to init CVBS encoder\n");
+		return ret;
+	}
+
+	encoder->possible_crtcs = BIT(0);
+
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}

+ 41 - 0
drivers/gpu/drm/meson/meson_venc_cvbs.h

@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#ifndef __MESON_VENC_CVBS_H
+#define __MESON_VENC_CVBS_H
+
+#include "meson_drv.h"
+#include "meson_venc.h"
+
+struct meson_cvbs_mode {
+	struct meson_cvbs_enci_mode *enci;
+	struct drm_display_mode mode;
+};
+
+#define MESON_CVBS_MODES_COUNT	2
+
+/* Modes supported by the CVBS output */
+extern struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT];
+
+int meson_venc_cvbs_create(struct meson_drm *priv);
+
+#endif /* __MESON_VENC_CVBS_H */

+ 331 - 0
drivers/gpu/drm/meson/meson_viu.c

@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include "meson_drv.h"
+#include "meson_viu.h"
+#include "meson_vpp.h"
+#include "meson_venc.h"
+#include "meson_canvas.h"
+#include "meson_registers.h"
+
+/*
+ * VIU Handles the Pixel scanout and the basic Colorspace conversions
+ * We handle the following features :
+ * - OSD1 RGB565/RGB888/xRGB8888 scanout
+ * - RGB conversion to x/cb/cr
+ * - Progressive or Interlace buffer scanout
+ * - OSD1 Commit on Vsync
+ * - HDR OSD matrix for GXL/GXM
+ *
+ * What is missing :
+ * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
+ * - YUV4:2:2 Y0CbY1Cr scanout
+ * - Conversion to YUV 4:4:4 from 4:2:2 input
+ * - Colorkey Alpha matching
+ * - Big endian scanout
+ * - X/Y reverse scanout
+ * - Global alpha setup
+ * - OSD2 support, would need interlace switching on vsync
+ * - OSD1 full scaling to support TV overscan
+ */
+
+/* OSD csc defines */
+
+enum viu_matrix_sel_e {
+	VIU_MATRIX_OSD_EOTF = 0,
+	VIU_MATRIX_OSD,
+};
+
+enum viu_lut_sel_e {
+	VIU_LUT_OSD_EOTF = 0,
+	VIU_LUT_OSD_OETF,
+};
+
+#define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
+#define MATRIX_5X3_COEF_SIZE 24
+
+#define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
+#define EOTF_COEFF_SIZE 10
+#define EOTF_COEFF_RIGHTSHIFT 1
+
+static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
+	0, 0, 0, /* pre offset */
+	COEFF_NORM(0.181873),	COEFF_NORM(0.611831),	COEFF_NORM(0.061765),
+	COEFF_NORM(-0.100251),	COEFF_NORM(-0.337249),	COEFF_NORM(0.437500),
+	COEFF_NORM(0.437500),	COEFF_NORM(-0.397384),	COEFF_NORM(-0.040116),
+	0, 0, 0, /* 10'/11'/12' */
+	0, 0, 0, /* 20'/21'/22' */
+	64, 512, 512, /* offset */
+	0, 0, 0 /* mode, right_shift, clip_en */
+};
+
+/*  eotf matrix: bypass */
+static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
+	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),
+	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),
+	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),
+	EOTF_COEFF_RIGHTSHIFT /* right shift */
+};
+
+void meson_viu_set_osd_matrix(struct meson_drm *priv,
+			      enum viu_matrix_sel_e m_select,
+			      int *m, bool csc_on)
+{
+	if (m_select == VIU_MATRIX_OSD) {
+		/* osd matrix, VIU_MATRIX_0 */
+		writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
+			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
+		writel(m[2] & 0xfff,
+			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
+		writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
+			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
+		writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
+			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
+		writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
+			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
+		writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
+			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
+
+		if (m[21]) {
+			writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
+				priv->io_base +
+					_REG(VIU_OSD1_MATRIX_COEF22_30));
+			writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
+				priv->io_base +
+					_REG(VIU_OSD1_MATRIX_COEF31_32));
+			writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
+				priv->io_base +
+					_REG(VIU_OSD1_MATRIX_COEF40_41));
+			writel(m[17] & 0x1fff, priv->io_base +
+				_REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
+		} else
+			writel((m[11] & 0x1fff) << 16, priv->io_base +
+				_REG(VIU_OSD1_MATRIX_COEF22_30));
+
+		writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
+			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
+		writel(m[20] & 0xfff,
+			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
+
+		writel_bits_relaxed(3 << 30, m[21] << 30,
+			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
+		writel_bits_relaxed(7 << 16, m[22] << 16,
+			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
+
+		/* 23 reserved for clipping control */
+		writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
+			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
+		writel_bits_relaxed(BIT(1), 0,
+			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
+	} else if (m_select == VIU_MATRIX_OSD_EOTF) {
+		int i;
+
+		/* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
+		for (i = 0; i < 5; i++)
+			writel(((m[i * 2] & 0x1fff) << 16) |
+				(m[i * 2 + 1] & 0x1fff), priv->io_base +
+				_REG(VIU_OSD1_EOTF_CTL + i + 1));
+
+		writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0,
+			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
+		writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0,
+			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
+	}
+}
+
+#define OSD_EOTF_LUT_SIZE 33
+#define OSD_OETF_LUT_SIZE 41
+
+void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel,
+			   unsigned int *r_map, unsigned int *g_map,
+			   unsigned int *b_map,
+			   bool csc_on)
+{
+	unsigned int addr_port;
+	unsigned int data_port;
+	unsigned int ctrl_port;
+	int i;
+
+	if (lut_sel == VIU_LUT_OSD_EOTF) {
+		addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
+		data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
+		ctrl_port = VIU_OSD1_EOTF_CTL;
+	} else if (lut_sel == VIU_LUT_OSD_OETF) {
+		addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
+		data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
+		ctrl_port = VIU_OSD1_OETF_CTL;
+	} else
+		return;
+
+	if (lut_sel == VIU_LUT_OSD_OETF) {
+		writel(0, priv->io_base + _REG(addr_port));
+
+		for (i = 0; i < 20; i++)
+			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
+				priv->io_base + _REG(data_port));
+
+		writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
+			priv->io_base + _REG(data_port));
+
+		for (i = 0; i < 20; i++)
+			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
+				priv->io_base + _REG(data_port));
+
+		for (i = 0; i < 20; i++)
+			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
+				priv->io_base + _REG(data_port));
+
+		writel(b_map[OSD_OETF_LUT_SIZE - 1],
+			priv->io_base + _REG(data_port));
+
+		if (csc_on)
+			writel_bits_relaxed(0x7 << 29, 7 << 29,
+					    priv->io_base + _REG(ctrl_port));
+		else
+			writel_bits_relaxed(0x7 << 29, 0,
+					    priv->io_base + _REG(ctrl_port));
+	} else if (lut_sel == VIU_LUT_OSD_EOTF) {
+		writel(0, priv->io_base + _REG(addr_port));
+
+		for (i = 0; i < 20; i++)
+			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
+				priv->io_base + _REG(data_port));
+
+		writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
+			priv->io_base + _REG(data_port));
+
+		for (i = 0; i < 20; i++)
+			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
+				priv->io_base + _REG(data_port));
+
+		for (i = 0; i < 20; i++)
+			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
+				priv->io_base + _REG(data_port));
+
+		writel(b_map[OSD_EOTF_LUT_SIZE - 1],
+			priv->io_base + _REG(data_port));
+
+		if (csc_on)
+			writel_bits_relaxed(7 << 27, 7 << 27,
+					    priv->io_base + _REG(ctrl_port));
+		else
+			writel_bits_relaxed(7 << 27, 0,
+					    priv->io_base + _REG(ctrl_port));
+
+		writel_bits_relaxed(BIT(31), BIT(31),
+				    priv->io_base + _REG(ctrl_port));
+	}
+}
+
+/* eotf lut: linear */
+static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
+	0x0000,	0x0200,	0x0400, 0x0600,
+	0x0800, 0x0a00, 0x0c00, 0x0e00,
+	0x1000, 0x1200, 0x1400, 0x1600,
+	0x1800, 0x1a00, 0x1c00, 0x1e00,
+	0x2000, 0x2200, 0x2400, 0x2600,
+	0x2800, 0x2a00, 0x2c00, 0x2e00,
+	0x3000, 0x3200, 0x3400, 0x3600,
+	0x3800, 0x3a00, 0x3c00, 0x3e00,
+	0x4000
+};
+
+/* osd oetf lut: linear */
+static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
+	0, 0, 0, 0,
+	0, 32, 64, 96,
+	128, 160, 196, 224,
+	256, 288, 320, 352,
+	384, 416, 448, 480,
+	512, 544, 576, 608,
+	640, 672, 704, 736,
+	768, 800, 832, 864,
+	896, 928, 960, 992,
+	1023, 1023, 1023, 1023,
+	1023
+};
+
+static void meson_viu_load_matrix(struct meson_drm *priv)
+{
+	/* eotf lut bypass */
+	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
+			      eotf_33_linear_mapping, /* R */
+			      eotf_33_linear_mapping, /* G */
+			      eotf_33_linear_mapping, /* B */
+			      false);
+
+	/* eotf matrix bypass */
+	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
+				 eotf_bypass_coeff,
+				 false);
+
+	/* oetf lut bypass */
+	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
+			      oetf_41_linear_mapping, /* R */
+			      oetf_41_linear_mapping, /* G */
+			      oetf_41_linear_mapping, /* B */
+			      false);
+
+	/* osd matrix RGB709 to YUV709 limit */
+	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
+				 RGB709_to_YUV709l_coeff,
+				 true);
+}
+
+void meson_viu_init(struct meson_drm *priv)
+{
+	uint32_t reg;
+
+	/* Disable OSDs */
+	writel_bits_relaxed(BIT(0) | BIT(21), 0,
+			priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
+	writel_bits_relaxed(BIT(0) | BIT(21), 0,
+			priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
+
+	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+	    meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+		meson_viu_load_matrix(priv);
+
+	/* Initialize OSD1 fifo control register */
+	reg = BIT(0) |	/* Urgent DDR request priority */
+	      (4 << 5) | /* hold_fifo_lines */
+	      (3 << 10) | /* burst length 64 */
+	      (32 << 12) | /* fifo_depth_val: 32*8=256 */
+	      (2 << 22) | /* 4 words in 1 burst */
+	      (2 << 24);
+	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
+	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
+
+	/* Set OSD alpha replace value */
+	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
+			    0xff << OSD_REPLACE_SHIFT,
+			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
+	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
+			    0xff << OSD_REPLACE_SHIFT,
+			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
+
+	priv->viu.osd1_enabled = false;
+	priv->viu.osd1_commit = false;
+	priv->viu.osd1_interlace = false;
+}

+ 64 - 0
drivers/gpu/drm/meson/meson_viu.h

@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Video Input Unit */
+
+#ifndef __MESON_VIU_H
+#define __MESON_VIU_H
+
+/* OSDx_BLKx_CFG */
+#define OSD_CANVAS_SEL		16
+
+#define OSD_ENDIANNESS_LE	BIT(15)
+#define OSD_ENDIANNESS_BE	(0)
+
+#define OSD_BLK_MODE_422	(0x03 << 8)
+#define OSD_BLK_MODE_16		(0x04 << 8)
+#define OSD_BLK_MODE_32		(0x05 << 8)
+#define OSD_BLK_MODE_24		(0x07 << 8)
+
+#define OSD_OUTPUT_COLOR_RGB	BIT(7)
+#define OSD_OUTPUT_COLOR_YUV	(0)
+
+#define OSD_COLOR_MATRIX_32_RGBA	(0x00 << 2)
+#define OSD_COLOR_MATRIX_32_ARGB	(0x01 << 2)
+#define OSD_COLOR_MATRIX_32_ABGR	(0x02 << 2)
+#define OSD_COLOR_MATRIX_32_BGRA	(0x03 << 2)
+
+#define OSD_COLOR_MATRIX_24_RGB		(0x00 << 2)
+
+#define OSD_COLOR_MATRIX_16_RGB655	(0x00 << 2)
+#define OSD_COLOR_MATRIX_16_RGB565	(0x04 << 2)
+
+#define OSD_INTERLACE_ENABLED	BIT(1)
+#define OSD_INTERLACE_ODD	BIT(0)
+#define OSD_INTERLACE_EVEN	(0)
+
+/* OSDx_CTRL_STAT */
+#define OSD_ENABLE		BIT(21)
+#define OSD_BLK0_ENABLE		BIT(0)
+
+#define OSD_GLOBAL_ALPHA_SHIFT	12
+
+/* OSDx_CTRL_STAT2 */
+#define OSD_REPLACE_EN		BIT(14)
+#define OSD_REPLACE_SHIFT	6
+
+void meson_viu_init(struct meson_drm *priv);
+
+#endif /* __MESON_VIU_H */

+ 162 - 0
drivers/gpu/drm/meson/meson_vpp.c

@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include "meson_drv.h"
+#include "meson_vpp.h"
+#include "meson_registers.h"
+
+/*
+ * VPP Handles all the Post Processing after the Scanout from the VIU
+ * We handle the following post processings :
+ * - Postblend : Blends the OSD1 only
+ *	We exclude OSD2, VS1, VS1 and Preblend output
+ * - Vertical OSD Scaler for OSD1 only, we disable vertical scaler and
+ *	use it only for interlace scanout
+ * - Intermediate FIFO with default Amlogic values
+ *
+ * What is missing :
+ * - Preblend for video overlay pre-scaling
+ * - OSD2 support for cursor framebuffer
+ * - Video pre-scaling before postblend
+ * - Full Vertical/Horizontal OSD scaling to support TV overscan
+ * - HDR conversion
+ */
+
+void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux)
+{
+	writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL));
+}
+
+/*
+ * When the output is interlaced, the OSD must switch between
+ * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
+ * at each vsync.
+ * But the vertical scaler can provide such funtionnality if
+ * is configured for 2:1 scaling with interlace options enabled.
+ */
+void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv,
+					    struct drm_rect *input)
+{
+	writel_relaxed(BIT(3) /* Enable scaler */ |
+		       BIT(2), /* Select OSD1 */
+			priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+
+	writel_relaxed(((drm_rect_width(input) - 1) << 16) |
+		       (drm_rect_height(input) - 1),
+			priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
+	/* 2:1 scaling */
+	writel_relaxed(((input->x1) << 16) | (input->x2),
+			priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
+	writel_relaxed(((input->y1 >> 1) << 16) | (input->y2 >> 1),
+			priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
+
+	/* 2:1 scaling values */
+	writel_relaxed(BIT(16), priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
+	writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
+
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+
+	writel_relaxed((4 << 0) /* osd_vsc_bank_length */ |
+		       (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ |
+		       (1 << 8) /* osd_vsc_top_rpt_p0_num0 */ |
+		       (6 << 11) /* osd_vsc_bot_ini_rcv_num0 */ |
+		       (2 << 16) /* osd_vsc_bot_rpt_p0_num0 */ |
+		       BIT(23)	/* osd_prog_interlace */ |
+		       BIT(24), /* Enable vertical scaler */
+			priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+}
+
+void meson_vpp_disable_interlace_vscaler_osd1(struct meson_drm *priv)
+{
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+}
+
+static unsigned int vpp_filter_coefs_4point_bspline[] = {
+	0x15561500, 0x14561600, 0x13561700, 0x12561800,
+	0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
+	0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
+	0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
+	0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
+	0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
+	0x05473301, 0x05463401, 0x04453601, 0x04433702,
+	0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
+	0x033d3d03
+};
+
+static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv,
+						 const unsigned int *coefs,
+						 bool is_horizontal)
+{
+	int i;
+
+	writel_relaxed(is_horizontal ? BIT(8) : 0,
+			priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX));
+	for (i = 0; i < 33; i++)
+		writel_relaxed(coefs[i],
+				priv->io_base + _REG(VPP_OSD_SCALE_COEF));
+}
+
+void meson_vpp_init(struct meson_drm *priv)
+{
+	/* set dummy data default YUV black */
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+		writel_relaxed(0x108080, priv->io_base + _REG(VPP_DUMMY_DATA1));
+	else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu")) {
+		writel_bits_relaxed(0xff << 16, 0xff << 16,
+				    priv->io_base + _REG(VIU_MISC_CTRL1));
+		writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL));
+		writel_relaxed(0x1020080,
+				priv->io_base + _REG(VPP_DUMMY_DATA1));
+	}
+
+	/* Initialize vpu fifo control registers */
+	writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) |
+			0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE));
+	writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES));
+
+	/* Turn off preblend */
+	writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0,
+			    priv->io_base + _REG(VPP_MISC));
+
+	/* Turn off POSTBLEND */
+	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
+			    priv->io_base + _REG(VPP_MISC));
+
+	/* Force all planes off */
+	writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND |
+			    VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND, 0,
+			    priv->io_base + _REG(VPP_MISC));
+
+	/* Disable Scalers */
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+	writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+
+	/* Write in the proper filter coefficients. */
+	meson_vpp_write_scaling_filter_coefs(priv,
+				vpp_filter_coefs_4point_bspline, false);
+	meson_vpp_write_scaling_filter_coefs(priv,
+				vpp_filter_coefs_4point_bspline, true);
+}

+ 35 - 0
drivers/gpu/drm/meson/meson_vpp.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Video Post Process */
+
+#ifndef __MESON_VPP_H
+#define __MESON_VPP_H
+
+/* Mux VIU/VPP to ENCI */
+#define MESON_VIU_VPP_MUX_ENCI	0x5
+
+void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux);
+
+void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv,
+					    struct drm_rect *input);
+void meson_vpp_disable_interlace_vscaler_osd1(struct meson_drm *priv);
+
+void meson_vpp_init(struct meson_drm *priv);
+
+#endif /* __MESON_VPP_H */

+ 19 - 0
drivers/gpu/drm/mxsfb/Kconfig

@@ -0,0 +1,19 @@
+config DRM_MXS
+	bool
+	help
+	  Choose this option to select drivers for MXS FB devices
+
+config DRM_MXSFB
+	tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller"
+	depends on DRM && OF
+	depends on COMMON_CLK
+	select DRM_MXS
+	select DRM_KMS_HELPER
+	select DRM_KMS_FB_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	help
+	  Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB
+	  LCD controller.
+
+	  If M is selected the module will be called mxsfb.

+ 2 - 0
drivers/gpu/drm/mxsfb/Makefile

@@ -0,0 +1,2 @@
+mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o
+obj-$(CONFIG_DRM_MXSFB)	+= mxsfb.o

+ 241 - 0
drivers/gpu/drm/mxsfb/mxsfb_crtc.c

@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of_graph.h>
+#include <linux/platform_data/simplefb.h>
+#include <video/videomode.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
+{
+	return (val & mxsfb->devdata->hs_wdth_mask) <<
+		mxsfb->devdata->hs_wdth_shift;
+}
+
+/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
+static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
+{
+	struct drm_crtc *crtc = &mxsfb->pipe.crtc;
+	struct drm_device *drm = crtc->dev;
+	const u32 format = crtc->primary->state->fb->pixel_format;
+	u32 ctrl, ctrl1;
+
+	ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
+
+	/*
+	 * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
+	 * match the selected mode here. This differs from the original
+	 * MXSFB driver, which had the option to configure the bus width
+	 * to arbitrary value. This limitation should not pose an issue.
+	 */
+
+	/* CTRL1 contains IRQ config and status bits, preserve those. */
+	ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
+	ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+
+	switch (format) {
+	case DRM_FORMAT_RGB565:
+		dev_dbg(drm->dev, "Setting up RGB565 mode\n");
+		ctrl |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
+		ctrl |= CTRL_SET_WORD_LENGTH(0);
+		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+		break;
+	case DRM_FORMAT_XRGB8888:
+		dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
+		ctrl |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
+		ctrl |= CTRL_SET_WORD_LENGTH(3);
+		/* Do not use packed pixels = one pixel per word instead. */
+		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+		break;
+	default:
+		dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
+		return -EINVAL;
+	}
+
+	writel(ctrl1, mxsfb->base + LCDC_CTRL1);
+	writel(ctrl, mxsfb->base + LCDC_CTRL);
+
+	return 0;
+}
+
+static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
+{
+	u32 reg;
+
+	if (mxsfb->clk_disp_axi)
+		clk_prepare_enable(mxsfb->clk_disp_axi);
+	clk_prepare_enable(mxsfb->clk);
+	mxsfb_enable_axi_clk(mxsfb);
+
+	/* If it was disabled, re-enable the mode again */
+	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
+
+	/* Enable the SYNC signals first, then the DMA engine */
+	reg = readl(mxsfb->base + LCDC_VDCTRL4);
+	reg |= VDCTRL4_SYNC_SIGNALS_ON;
+	writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
+}
+
+static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
+{
+	u32 reg;
+
+	/*
+	 * Even if we disable the controller here, it will still continue
+	 * until its FIFOs are running out of data
+	 */
+	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+	readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
+			   0, 1000);
+
+	reg = readl(mxsfb->base + LCDC_VDCTRL4);
+	reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+	writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+	mxsfb_disable_axi_clk(mxsfb);
+
+	clk_disable_unprepare(mxsfb->clk);
+	if (mxsfb->clk_disp_axi)
+		clk_disable_unprepare(mxsfb->clk_disp_axi);
+}
+
+static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
+{
+	struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
+	const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
+	u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
+	int err;
+
+	/*
+	 * It seems, you can't re-program the controller if it is still
+	 * running. This may lead to shifted pictures (FIFO issue?), so
+	 * first stop the controller and drain its FIFOs.
+	 */
+	mxsfb_enable_axi_clk(mxsfb);
+
+	/* Clear the FIFOs */
+	writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+	err = mxsfb_set_pixel_fmt(mxsfb);
+	if (err)
+		return;
+
+	clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
+
+	writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
+	       TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
+	       mxsfb->base + mxsfb->devdata->transfer_count);
+
+	vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
+
+	vdctrl0 = VDCTRL0_ENABLE_PRESENT |	/* Always in DOTCLOCK mode */
+		  VDCTRL0_VSYNC_PERIOD_UNIT |
+		  VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+		  VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
+	if (m->flags & DRM_MODE_FLAG_PHSYNC)
+		vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+	if (m->flags & DRM_MODE_FLAG_PVSYNC)
+		vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+	if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
+		vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+	if (bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
+		vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+	writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
+
+	/* Frame length in lines. */
+	writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
+
+	/* Line length in units of clocks or pixels. */
+	hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
+	writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
+	       VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
+	       mxsfb->base + LCDC_VDCTRL2);
+
+	writel(SET_HOR_WAIT_CNT(m->crtc_hblank_end - m->crtc_hsync_end) |
+	       SET_VERT_WAIT_CNT(m->crtc_vblank_end - m->crtc_vsync_end),
+	       mxsfb->base + LCDC_VDCTRL3);
+
+	writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
+	       mxsfb->base + LCDC_VDCTRL4);
+
+	mxsfb_disable_axi_clk(mxsfb);
+}
+
+void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
+{
+	mxsfb_crtc_mode_set_nofb(mxsfb);
+	mxsfb_enable_controller(mxsfb);
+}
+
+void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
+{
+	mxsfb_disable_controller(mxsfb);
+}
+
+void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
+			       struct drm_plane_state *state)
+{
+	struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
+	struct drm_crtc *crtc = &pipe->crtc;
+	struct drm_framebuffer *fb = pipe->plane.state->fb;
+	struct drm_pending_vblank_event *event;
+	struct drm_gem_cma_object *gem;
+
+	if (!crtc)
+		return;
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	event = crtc->state->event;
+	if (event) {
+		crtc->state->event = NULL;
+
+		if (drm_crtc_vblank_get(crtc) == 0) {
+			drm_crtc_arm_vblank_event(crtc, event);
+		} else {
+			drm_crtc_send_vblank_event(crtc, event);
+		}
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+
+	if (!fb)
+		return;
+
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	mxsfb_enable_axi_clk(mxsfb);
+	writel(gem->paddr, mxsfb->base + mxsfb->devdata->next_buf);
+	mxsfb_disable_axi_clk(mxsfb);
+}

+ 444 - 0
drivers/gpu/drm/mxsfb/mxsfb_drv.c

@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/list.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_runtime.h>
+#include <linux/reservation.h>
+
+#include <drm/drmP.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_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+enum mxsfb_devtype {
+	MXSFB_V3,
+	MXSFB_V4,
+};
+
+static const struct mxsfb_devdata mxsfb_devdata[] = {
+	[MXSFB_V3] = {
+		.transfer_count	= LCDC_V3_TRANSFER_COUNT,
+		.cur_buf	= LCDC_V3_CUR_BUF,
+		.next_buf	= LCDC_V3_NEXT_BUF,
+		.debug0		= LCDC_V3_DEBUG0,
+		.hs_wdth_mask	= 0xff,
+		.hs_wdth_shift	= 24,
+		.ipversion	= 3,
+	},
+	[MXSFB_V4] = {
+		.transfer_count	= LCDC_V4_TRANSFER_COUNT,
+		.cur_buf	= LCDC_V4_CUR_BUF,
+		.next_buf	= LCDC_V4_NEXT_BUF,
+		.debug0		= LCDC_V4_DEBUG0,
+		.hs_wdth_mask	= 0x3fff,
+		.hs_wdth_shift	= 18,
+		.ipversion	= 4,
+	},
+};
+
+static const uint32_t mxsfb_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGB565
+};
+
+static struct mxsfb_drm_private *
+drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
+{
+	return container_of(pipe, struct mxsfb_drm_private, pipe);
+}
+
+void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
+{
+	if (mxsfb->clk_axi)
+		clk_prepare_enable(mxsfb->clk_axi);
+}
+
+void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb)
+{
+	if (mxsfb->clk_axi)
+		clk_disable_unprepare(mxsfb->clk_axi);
+}
+
+static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
+	.fb_create		= drm_fb_cma_create,
+	.atomic_check		= drm_atomic_helper_check,
+	.atomic_commit		= drm_atomic_helper_commit,
+};
+
+static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
+			      struct drm_crtc_state *crtc_state)
+{
+	struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+
+	mxsfb_crtc_enable(mxsfb);
+}
+
+static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+	struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+
+	mxsfb_crtc_disable(mxsfb);
+}
+
+static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
+			      struct drm_plane_state *plane_state)
+{
+	struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+
+	mxsfb_plane_atomic_update(mxsfb, plane_state);
+}
+
+static int mxsfb_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
+				 struct drm_plane_state *plane_state)
+{
+	return drm_fb_cma_prepare_fb(&pipe->plane, plane_state);
+}
+
+struct drm_simple_display_pipe_funcs mxsfb_funcs = {
+	.enable		= mxsfb_pipe_enable,
+	.disable	= mxsfb_pipe_disable,
+	.update		= mxsfb_pipe_update,
+	.prepare_fb	= mxsfb_pipe_prepare_fb,
+};
+
+static int mxsfb_load(struct drm_device *drm, unsigned long flags)
+{
+	struct platform_device *pdev = to_platform_device(drm->dev);
+	struct mxsfb_drm_private *mxsfb;
+	struct resource *res;
+	int ret;
+
+	mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL);
+	if (!mxsfb)
+		return -ENOMEM;
+
+	drm->dev_private = mxsfb;
+	mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mxsfb->base = devm_ioremap_resource(drm->dev, res);
+	if (IS_ERR(mxsfb->base))
+		return PTR_ERR(mxsfb->base);
+
+	mxsfb->clk = devm_clk_get(drm->dev, NULL);
+	if (IS_ERR(mxsfb->clk))
+		return PTR_ERR(mxsfb->clk);
+
+	mxsfb->clk_axi = devm_clk_get(drm->dev, "axi");
+	if (IS_ERR(mxsfb->clk_axi))
+		mxsfb->clk_axi = NULL;
+
+	mxsfb->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
+	if (IS_ERR(mxsfb->clk_disp_axi))
+		mxsfb->clk_disp_axi = NULL;
+
+	ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(drm->dev);
+
+	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+	if (ret < 0) {
+		dev_err(drm->dev, "Failed to initialise vblank\n");
+		goto err_vblank;
+	}
+
+	/* Modeset init */
+	drm_mode_config_init(drm);
+
+	ret = mxsfb_create_output(drm);
+	if (ret < 0) {
+		dev_err(drm->dev, "Failed to create outputs\n");
+		goto err_vblank;
+	}
+
+	ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
+			mxsfb_formats, ARRAY_SIZE(mxsfb_formats),
+			&mxsfb->connector);
+	if (ret < 0) {
+		dev_err(drm->dev, "Cannot setup simple display pipe\n");
+		goto err_vblank;
+	}
+
+	ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
+	if (ret) {
+		dev_err(drm->dev, "Cannot connect panel\n");
+		goto err_vblank;
+	}
+
+	drm->mode_config.min_width	= MXSFB_MIN_XRES;
+	drm->mode_config.min_height	= MXSFB_MIN_YRES;
+	drm->mode_config.max_width	= MXSFB_MAX_XRES;
+	drm->mode_config.max_height	= MXSFB_MAX_YRES;
+	drm->mode_config.funcs		= &mxsfb_mode_config_funcs;
+
+	drm_mode_config_reset(drm);
+
+	pm_runtime_get_sync(drm->dev);
+	ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
+	pm_runtime_put_sync(drm->dev);
+
+	if (ret < 0) {
+		dev_err(drm->dev, "Failed to install IRQ handler\n");
+		goto err_irq;
+	}
+
+	drm_kms_helper_poll_init(drm);
+
+	mxsfb->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
+					  drm->mode_config.num_connector);
+	if (IS_ERR(mxsfb->fbdev)) {
+		mxsfb->fbdev = NULL;
+		dev_err(drm->dev, "Failed to init FB CMA area\n");
+		goto err_cma;
+	}
+
+	platform_set_drvdata(pdev, drm);
+
+	drm_helper_hpd_irq_event(drm);
+
+	return 0;
+
+err_cma:
+	drm_irq_uninstall(drm);
+err_irq:
+	drm_panel_detach(mxsfb->panel);
+err_vblank:
+	pm_runtime_disable(drm->dev);
+
+	return ret;
+}
+
+static void mxsfb_unload(struct drm_device *drm)
+{
+	struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+	if (mxsfb->fbdev)
+		drm_fbdev_cma_fini(mxsfb->fbdev);
+
+	drm_kms_helper_poll_fini(drm);
+	drm_mode_config_cleanup(drm);
+	drm_vblank_cleanup(drm);
+
+	pm_runtime_get_sync(drm->dev);
+	drm_irq_uninstall(drm);
+	pm_runtime_put_sync(drm->dev);
+
+	drm->dev_private = NULL;
+
+	pm_runtime_disable(drm->dev);
+}
+
+static void mxsfb_lastclose(struct drm_device *drm)
+{
+	struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+	drm_fbdev_cma_restore_mode(mxsfb->fbdev);
+}
+
+static int mxsfb_enable_vblank(struct drm_device *drm, unsigned int crtc)
+{
+	struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+	/* Clear and enable VBLANK IRQ */
+	mxsfb_enable_axi_clk(mxsfb);
+	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
+	mxsfb_disable_axi_clk(mxsfb);
+
+	return 0;
+}
+
+static void mxsfb_disable_vblank(struct drm_device *drm, unsigned int crtc)
+{
+	struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+	/* Disable and clear VBLANK IRQ */
+	mxsfb_enable_axi_clk(mxsfb);
+	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+	mxsfb_disable_axi_clk(mxsfb);
+}
+
+static void mxsfb_irq_preinstall(struct drm_device *drm)
+{
+	mxsfb_disable_vblank(drm, 0);
+}
+
+static irqreturn_t mxsfb_irq_handler(int irq, void *data)
+{
+	struct drm_device *drm = data;
+	struct mxsfb_drm_private *mxsfb = drm->dev_private;
+	u32 reg;
+
+	mxsfb_enable_axi_clk(mxsfb);
+
+	reg = readl(mxsfb->base + LCDC_CTRL1);
+
+	if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
+		drm_crtc_handle_vblank(&mxsfb->pipe.crtc);
+
+	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+
+	mxsfb_disable_axi_clk(mxsfb);
+
+	return IRQ_HANDLED;
+}
+
+static const struct file_operations fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= noop_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct drm_driver mxsfb_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
+				  DRIVER_PRIME | DRIVER_ATOMIC |
+				  DRIVER_HAVE_IRQ,
+	.lastclose		= mxsfb_lastclose,
+	.irq_handler		= mxsfb_irq_handler,
+	.irq_preinstall		= mxsfb_irq_preinstall,
+	.irq_uninstall		= mxsfb_irq_preinstall,
+	.get_vblank_counter	= drm_vblank_no_hw_counter,
+	.enable_vblank		= mxsfb_enable_vblank,
+	.disable_vblank		= mxsfb_disable_vblank,
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= drm_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_export	= drm_gem_prime_export,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+	.fops	= &fops,
+	.name	= "mxsfb-drm",
+	.desc	= "MXSFB Controller DRM",
+	.date	= "20160824",
+	.major	= 1,
+	.minor	= 0,
+};
+
+static const struct platform_device_id mxsfb_devtype[] = {
+	{ .name = "imx23-fb", .driver_data = MXSFB_V3, },
+	{ .name = "imx28-fb", .driver_data = MXSFB_V4, },
+	{ .name = "imx6sx-fb", .driver_data = MXSFB_V4, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
+
+static const struct of_device_id mxsfb_dt_ids[] = {
+	{ .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
+	{ .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
+	{ .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
+
+static int mxsfb_probe(struct platform_device *pdev)
+{
+	struct drm_device *drm;
+	const struct of_device_id *of_id =
+			of_match_device(mxsfb_dt_ids, &pdev->dev);
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	if (of_id)
+		pdev->id_entry = of_id->data;
+
+	drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev);
+	if (!drm)
+		return -ENOMEM;
+
+	ret = mxsfb_load(drm, 0);
+	if (ret)
+		goto err_free;
+
+	ret = drm_dev_register(drm, 0);
+	if (ret)
+		goto err_unload;
+
+	return 0;
+
+err_unload:
+	mxsfb_unload(drm);
+err_free:
+	drm_dev_unref(drm);
+
+	return ret;
+}
+
+static int mxsfb_remove(struct platform_device *pdev)
+{
+	struct drm_device *drm = platform_get_drvdata(pdev);
+
+	drm_dev_unregister(drm);
+	mxsfb_unload(drm);
+	drm_dev_unref(drm);
+
+	return 0;
+}
+
+static struct platform_driver mxsfb_platform_driver = {
+	.probe		= mxsfb_probe,
+	.remove		= mxsfb_remove,
+	.id_table	= mxsfb_devtype,
+	.driver	= {
+		.name		= "mxsfb",
+		.of_match_table	= mxsfb_dt_ids,
+	},
+};
+
+module_platform_driver(mxsfb_platform_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale MXS DRM/KMS driver");
+MODULE_LICENSE("GPL");

+ 54 - 0
drivers/gpu/drm/mxsfb/mxsfb_drv.h

@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * i.MX23/i.MX28/i.MX6SX MXSFB LCD controller driver.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MXSFB_DRV_H__
+#define __MXSFB_DRV_H__
+
+struct mxsfb_devdata {
+	unsigned int	 transfer_count;
+	unsigned int	 cur_buf;
+	unsigned int	 next_buf;
+	unsigned int	 debug0;
+	unsigned int	 hs_wdth_mask;
+	unsigned int	 hs_wdth_shift;
+	unsigned int	 ipversion;
+};
+
+struct mxsfb_drm_private {
+	const struct mxsfb_devdata	*devdata;
+
+	void __iomem			*base;	/* registers */
+	struct clk			*clk;
+	struct clk			*clk_axi;
+	struct clk			*clk_disp_axi;
+
+	struct drm_simple_display_pipe	pipe;
+	struct drm_connector		connector;
+	struct drm_panel		*panel;
+	struct drm_fbdev_cma		*fbdev;
+};
+
+int mxsfb_setup_crtc(struct drm_device *dev);
+int mxsfb_create_output(struct drm_device *dev);
+
+void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb);
+void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb);
+
+void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
+void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
+void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
+			       struct drm_plane_state *state);
+
+#endif /* __MXSFB_DRV_H__ */

+ 131 - 0
drivers/gpu/drm/mxsfb/mxsfb_out.c

@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_graph.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_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/drmP.h>
+
+#include "mxsfb_drv.h"
+
+static struct mxsfb_drm_private *
+drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
+{
+	return container_of(connector, struct mxsfb_drm_private, connector);
+}
+
+static int mxsfb_panel_get_modes(struct drm_connector *connector)
+{
+	struct mxsfb_drm_private *mxsfb =
+			drm_connector_to_mxsfb_drm_private(connector);
+
+	if (mxsfb->panel)
+		return mxsfb->panel->funcs->get_modes(mxsfb->panel);
+
+	return 0;
+}
+
+static const struct
+drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = {
+	.get_modes = mxsfb_panel_get_modes,
+};
+
+static enum drm_connector_status
+mxsfb_panel_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct mxsfb_drm_private *mxsfb =
+			drm_connector_to_mxsfb_drm_private(connector);
+
+	if (mxsfb->panel)
+		return connector_status_connected;
+
+	return connector_status_disconnected;
+}
+
+static void mxsfb_panel_connector_destroy(struct drm_connector *connector)
+{
+	struct mxsfb_drm_private *mxsfb =
+			drm_connector_to_mxsfb_drm_private(connector);
+
+	if (mxsfb->panel)
+		drm_panel_detach(mxsfb->panel);
+
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
+	.dpms			= drm_atomic_helper_connector_dpms,
+	.detect			= mxsfb_panel_connector_detect,
+	.fill_modes		= drm_helper_probe_single_connector_modes,
+	.destroy		= mxsfb_panel_connector_destroy,
+	.reset			= drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
+};
+
+static int mxsfb_attach_endpoint(struct drm_device *drm,
+				 const struct of_endpoint *ep)
+{
+	struct mxsfb_drm_private *mxsfb = drm->dev_private;
+	struct device_node *np;
+	struct drm_panel *panel;
+	int ret = -EPROBE_DEFER;
+
+	np = of_graph_get_remote_port_parent(ep->local_node);
+	panel = of_drm_find_panel(np);
+	of_node_put(np);
+
+	if (!panel)
+		return -EPROBE_DEFER;
+
+	mxsfb->connector.dpms = DRM_MODE_DPMS_OFF;
+	mxsfb->connector.polled = 0;
+	drm_connector_helper_add(&mxsfb->connector,
+			&mxsfb_panel_connector_helper_funcs);
+	ret = drm_connector_init(drm, &mxsfb->connector,
+				 &mxsfb_panel_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (!ret)
+		mxsfb->panel = panel;
+
+	return ret;
+}
+
+int mxsfb_create_output(struct drm_device *drm)
+{
+	struct device_node *ep_np = NULL;
+	struct of_endpoint ep;
+	int ret;
+
+	for_each_endpoint_of_node(drm->dev->of_node, ep_np) {
+		ret = of_graph_parse_endpoint(ep_np, &ep);
+		if (!ret)
+			ret = mxsfb_attach_endpoint(drm, &ep);
+
+		if (ret) {
+			of_node_put(ep_np);
+			return ret;
+		}
+	}
+
+	return 0;
+}

+ 114 - 0
drivers/gpu/drm/mxsfb/mxsfb_regs.h

@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * i.MX23/i.MX28/i.MX6SX MXSFB LCD controller driver.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MXSFB_REGS_H__
+#define __MXSFB_REGS_H__
+
+#define REG_SET	4
+#define REG_CLR	8
+
+#define LCDC_CTRL			0x00
+#define LCDC_CTRL1			0x10
+#define LCDC_V3_TRANSFER_COUNT		0x20
+#define LCDC_V4_TRANSFER_COUNT		0x30
+#define LCDC_V4_CUR_BUF			0x40
+#define LCDC_V4_NEXT_BUF		0x50
+#define LCDC_V3_CUR_BUF			0x30
+#define LCDC_V3_NEXT_BUF		0x40
+#define LCDC_VDCTRL0			0x70
+#define LCDC_VDCTRL1			0x80
+#define LCDC_VDCTRL2			0x90
+#define LCDC_VDCTRL3			0xa0
+#define LCDC_VDCTRL4			0xb0
+#define LCDC_V4_DEBUG0			0x1d0
+#define LCDC_V3_DEBUG0			0x1f0
+
+#define CTRL_SFTRST			(1 << 31)
+#define CTRL_CLKGATE			(1 << 30)
+#define CTRL_BYPASS_COUNT		(1 << 19)
+#define CTRL_VSYNC_MODE			(1 << 18)
+#define CTRL_DOTCLK_MODE		(1 << 17)
+#define CTRL_DATA_SELECT		(1 << 16)
+#define CTRL_SET_BUS_WIDTH(x)		(((x) & 0x3) << 10)
+#define CTRL_GET_BUS_WIDTH(x)		(((x) >> 10) & 0x3)
+#define CTRL_SET_WORD_LENGTH(x)		(((x) & 0x3) << 8)
+#define CTRL_GET_WORD_LENGTH(x)		(((x) >> 8) & 0x3)
+#define CTRL_MASTER			(1 << 5)
+#define CTRL_DF16			(1 << 3)
+#define CTRL_DF18			(1 << 2)
+#define CTRL_DF24			(1 << 1)
+#define CTRL_RUN			(1 << 0)
+
+#define CTRL1_FIFO_CLEAR		(1 << 21)
+#define CTRL1_SET_BYTE_PACKAGING(x)	(((x) & 0xf) << 16)
+#define CTRL1_GET_BYTE_PACKAGING(x)	(((x) >> 16) & 0xf)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN	(1 << 13)
+#define CTRL1_CUR_FRAME_DONE_IRQ	(1 << 9)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x)	(((x) & 0xffff) << 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x)	(((x) >> 16) & 0xffff)
+#define TRANSFER_COUNT_SET_HCOUNT(x)	((x) & 0xffff)
+#define TRANSFER_COUNT_GET_HCOUNT(x)	((x) & 0xffff)
+
+#define VDCTRL0_ENABLE_PRESENT		(1 << 28)
+#define VDCTRL0_VSYNC_ACT_HIGH		(1 << 27)
+#define VDCTRL0_HSYNC_ACT_HIGH		(1 << 26)
+#define VDCTRL0_DOTCLK_ACT_FALLING	(1 << 25)
+#define VDCTRL0_ENABLE_ACT_HIGH		(1 << 24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT	(1 << 21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	(1 << 20)
+#define VDCTRL0_HALF_LINE		(1 << 19)
+#define VDCTRL0_HALF_LINE_MODE		(1 << 18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define VDCTRL2_SET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
+#define VDCTRL2_GET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS	(1 << 29)
+#define VDCTRL3_VSYNC_ONLY		(1 << 28)
+#define SET_HOR_WAIT_CNT(x)		(((x) & 0xfff) << 16)
+#define GET_HOR_WAIT_CNT(x)		(((x) >> 16) & 0xfff)
+#define SET_VERT_WAIT_CNT(x)		((x) & 0xffff)
+#define GET_VERT_WAIT_CNT(x)		((x) & 0xffff)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x)	(((x) & 0x7) << 29) /* v4 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x)	(((x) >> 29) & 0x7) /* v4 only */
+#define VDCTRL4_SYNC_SIGNALS_ON		(1 << 18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x)	((x) & 0x3ffff)
+
+#define DEBUG0_HSYNC			(1 < 26)
+#define DEBUG0_VSYNC			(1 < 25)
+
+#define MXSFB_MIN_XRES			120
+#define MXSFB_MIN_YRES			120
+#define MXSFB_MAX_XRES			0xffff
+#define MXSFB_MAX_YRES			0xffff
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+#define STMLCDIF_8BIT  1 /* pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
+
+#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT	(1 << 6)
+#define MXSFB_SYNC_DOTCLK_FALLING_ACT	(1 << 7) /* negative edge sampling */
+
+#endif /* __MXSFB_REGS_H__ */

+ 76 - 4
drivers/gpu/drm/nouveau/nouveau_backlight.c

@@ -30,12 +30,37 @@
  * Register locations derived from NVClock by Roderick Colenbrander
  * Register locations derived from NVClock by Roderick Colenbrander
  */
  */
 
 
+#include <linux/apple-gmux.h>
 #include <linux/backlight.h>
 #include <linux/backlight.h>
+#include <linux/idr.h>
 
 
 #include "nouveau_drv.h"
 #include "nouveau_drv.h"
 #include "nouveau_reg.h"
 #include "nouveau_reg.h"
 #include "nouveau_encoder.h"
 #include "nouveau_encoder.h"
 
 
+static struct ida bl_ida;
+#define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0'
+
+struct backlight_connector {
+	struct list_head head;
+	int id;
+};
+
+static bool
+nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE], struct backlight_connector
+		*connector)
+{
+	const int nb = ida_simple_get(&bl_ida, 0, 0, GFP_KERNEL);
+	if (nb < 0 || nb >= 100)
+		return false;
+	if (nb > 0)
+		snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb);
+	else
+		snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight");
+	connector->id = nb;
+	return true;
+}
+
 static int
 static int
 nv40_get_intensity(struct backlight_device *bd)
 nv40_get_intensity(struct backlight_device *bd)
 {
 {
@@ -74,6 +99,8 @@ nv40_backlight_init(struct drm_connector *connector)
 	struct nvif_object *device = &drm->device.object;
 	struct nvif_object *device = &drm->device.object;
 	struct backlight_properties props;
 	struct backlight_properties props;
 	struct backlight_device *bd;
 	struct backlight_device *bd;
+	struct backlight_connector bl_connector;
+	char backlight_name[BL_NAME_SIZE];
 
 
 	if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
 	if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
 		return 0;
 		return 0;
@@ -81,10 +108,19 @@ nv40_backlight_init(struct drm_connector *connector)
 	memset(&props, 0, sizeof(struct backlight_properties));
 	memset(&props, 0, sizeof(struct backlight_properties));
 	props.type = BACKLIGHT_RAW;
 	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 31;
 	props.max_brightness = 31;
-	bd = backlight_device_register("nv_backlight", connector->kdev, drm,
+	if (!nouveau_get_backlight_name(backlight_name, &bl_connector)) {
+		NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n");
+		return 0;
+	}
+	bd = backlight_device_register(backlight_name , connector->kdev, drm,
 				       &nv40_bl_ops, &props);
 				       &nv40_bl_ops, &props);
-	if (IS_ERR(bd))
+
+	if (IS_ERR(bd)) {
+		if (bl_connector.id > 0)
+			ida_simple_remove(&bl_ida, bl_connector.id);
 		return PTR_ERR(bd);
 		return PTR_ERR(bd);
+	}
+	list_add(&bl_connector.head, &drm->bl_connectors);
 	drm->backlight = bd;
 	drm->backlight = bd;
 	bd->props.brightness = nv40_get_intensity(bd);
 	bd->props.brightness = nv40_get_intensity(bd);
 	backlight_update_status(bd);
 	backlight_update_status(bd);
@@ -182,6 +218,8 @@ nv50_backlight_init(struct drm_connector *connector)
 	struct backlight_properties props;
 	struct backlight_properties props;
 	struct backlight_device *bd;
 	struct backlight_device *bd;
 	const struct backlight_ops *ops;
 	const struct backlight_ops *ops;
+	struct backlight_connector bl_connector;
+	char backlight_name[BL_NAME_SIZE];
 
 
 	nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
 	nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
 	if (!nv_encoder) {
 	if (!nv_encoder) {
@@ -203,11 +241,20 @@ nv50_backlight_init(struct drm_connector *connector)
 	memset(&props, 0, sizeof(struct backlight_properties));
 	memset(&props, 0, sizeof(struct backlight_properties));
 	props.type = BACKLIGHT_RAW;
 	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 100;
 	props.max_brightness = 100;
-	bd = backlight_device_register("nv_backlight", connector->kdev,
+	if (!nouveau_get_backlight_name(backlight_name, &bl_connector)) {
+		NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n");
+		return 0;
+	}
+	bd = backlight_device_register(backlight_name , connector->kdev,
 				       nv_encoder, ops, &props);
 				       nv_encoder, ops, &props);
-	if (IS_ERR(bd))
+
+	if (IS_ERR(bd)) {
+		if (bl_connector.id > 0)
+			ida_simple_remove(&bl_ida, bl_connector.id);
 		return PTR_ERR(bd);
 		return PTR_ERR(bd);
+	}
 
 
+	list_add(&bl_connector.head, &drm->bl_connectors);
 	drm->backlight = bd;
 	drm->backlight = bd;
 	bd->props.brightness = bd->ops->get_brightness(bd);
 	bd->props.brightness = bd->ops->get_brightness(bd);
 	backlight_update_status(bd);
 	backlight_update_status(bd);
@@ -221,6 +268,13 @@ nouveau_backlight_init(struct drm_device *dev)
 	struct nvif_device *device = &drm->device;
 	struct nvif_device *device = &drm->device;
 	struct drm_connector *connector;
 	struct drm_connector *connector;
 
 
+	if (apple_gmux_present()) {
+		NV_INFO(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n");
+		return 0;
+	}
+
+	INIT_LIST_HEAD(&drm->bl_connectors);
+
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
 		if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
 		    connector->connector_type != DRM_MODE_CONNECTOR_eDP)
 		    connector->connector_type != DRM_MODE_CONNECTOR_eDP)
@@ -247,9 +301,27 @@ void
 nouveau_backlight_exit(struct drm_device *dev)
 nouveau_backlight_exit(struct drm_device *dev)
 {
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct backlight_connector *connector;
+
+	list_for_each_entry(connector, &drm->bl_connectors, head) {
+		if (connector->id >= 0)
+			ida_simple_remove(&bl_ida, connector->id);
+	}
 
 
 	if (drm->backlight) {
 	if (drm->backlight) {
 		backlight_device_unregister(drm->backlight);
 		backlight_device_unregister(drm->backlight);
 		drm->backlight = NULL;
 		drm->backlight = NULL;
 	}
 	}
 }
 }
+
+void
+nouveau_backlight_ctor(void)
+{
+	ida_init(&bl_ida);
+}
+
+void
+nouveau_backlight_dtor(void)
+{
+	ida_destroy(&bl_ida);
+}

+ 1 - 0
drivers/gpu/drm/nouveau/nouveau_bo.c

@@ -1209,6 +1209,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
 			       nvbo->page_shift != vma->vm->mmu->lpg_shift)) {
 			       nvbo->page_shift != vma->vm->mmu->lpg_shift)) {
 			nvkm_vm_map(vma, new_mem->mm_node);
 			nvkm_vm_map(vma, new_mem->mm_node);
 		} else {
 		} else {
+			WARN_ON(ttm_bo_wait(bo, false, false));
 			nvkm_vm_unmap(vma);
 			nvkm_vm_unmap(vma);
 		}
 		}
 	}
 	}

+ 10 - 0
drivers/gpu/drm/nouveau/nouveau_display.h

@@ -91,6 +91,8 @@ int nouveau_crtc_set_config(struct drm_mode_set *set);
 #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
 #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
 extern int nouveau_backlight_init(struct drm_device *);
 extern int nouveau_backlight_init(struct drm_device *);
 extern void nouveau_backlight_exit(struct drm_device *);
 extern void nouveau_backlight_exit(struct drm_device *);
+extern void nouveau_backlight_ctor(void);
+extern void nouveau_backlight_dtor(void);
 #else
 #else
 static inline int
 static inline int
 nouveau_backlight_init(struct drm_device *dev)
 nouveau_backlight_init(struct drm_device *dev)
@@ -101,6 +103,14 @@ nouveau_backlight_init(struct drm_device *dev)
 static inline void
 static inline void
 nouveau_backlight_exit(struct drm_device *dev) {
 nouveau_backlight_exit(struct drm_device *dev) {
 }
 }
+
+static inline void
+nouveau_backlight_ctor(void) {
+}
+
+static inline void
+nouveau_backlight_dtor(void) {
+}
 #endif
 #endif
 
 
 struct drm_framebuffer *
 struct drm_framebuffer *

+ 2 - 0
drivers/gpu/drm/nouveau/nouveau_drm.c

@@ -1122,6 +1122,7 @@ nouveau_drm_init(void)
 #endif
 #endif
 
 
 	nouveau_register_dsm_handler();
 	nouveau_register_dsm_handler();
+	nouveau_backlight_ctor();
 	return drm_pci_init(&driver_pci, &nouveau_drm_pci_driver);
 	return drm_pci_init(&driver_pci, &nouveau_drm_pci_driver);
 }
 }
 
 
@@ -1132,6 +1133,7 @@ nouveau_drm_exit(void)
 		return;
 		return;
 
 
 	drm_pci_exit(&driver_pci, &nouveau_drm_pci_driver);
 	drm_pci_exit(&driver_pci, &nouveau_drm_pci_driver);
+	nouveau_backlight_dtor();
 	nouveau_unregister_dsm_handler();
 	nouveau_unregister_dsm_handler();
 
 
 #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
 #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER

+ 1 - 0
drivers/gpu/drm/nouveau/nouveau_drv.h

@@ -163,6 +163,7 @@ struct nouveau_drm {
 	struct nvbios vbios;
 	struct nvbios vbios;
 	struct nouveau_display *display;
 	struct nouveau_display *display;
 	struct backlight_device *backlight;
 	struct backlight_device *backlight;
+	struct list_head bl_connectors;
 	struct work_struct hpd_work;
 	struct work_struct hpd_work;
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_ACPI
 	struct notifier_block acpi_nb;
 	struct notifier_block acpi_nb;

+ 5 - 0
drivers/gpu/drm/nouveau/nv50_display.c

@@ -1726,6 +1726,11 @@ nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 			evo_data(push, asyh->core.handle);
 			evo_data(push, asyh->core.handle);
 			evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
 			evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
 			evo_data(push, (asyh->core.y << 16) | asyh->core.x);
 			evo_data(push, (asyh->core.y << 16) | asyh->core.x);
+			/* EVO will complain with INVALID_STATE if we have an
+			 * active cursor and (re)specify HeadSetContextDmaIso
+			 * without also updating HeadSetOffsetCursor.
+			 */
+			asyh->set.curs = asyh->curs.visible;
 		} else
 		} else
 		if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
 		if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
 			evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
 			evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);

部分文件因为文件数量过多而无法显示