Merge tag 'drm-misc-next-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc...
authorDave Airlie <airlied@redhat.com>
Fri, 23 Feb 2018 01:12:52 +0000 (11:12 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 23 Feb 2018 01:12:52 +0000 (11:12 +1000)
drm-misc-next for 4.17:

Cross-subsystem Changes:
- Backlight helpers to enable/disable and find devices in dt (Meghana)

Core Changes:
- Documentation improvements (Chris/Daniel/Jani)
- simple_kms_helper: Add mode_valid() support (Linus)
- mm: Fix bug in interval_tree causing nodes to be out-of-order (Chris)

Driver Changes:
- tinydrm/panel: Use the new backlight helpers (Meghana)
- rockchip: Support gem_prime_import_sg_table + some fixes (Various)
- sun4i: Add A83T HDMI support using dw-hdmi (Jernej)

Cc: Meghana Madhyastha <meghana.madhyastha@gmail.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Jernej Skrabec <jernej.skrabec@siol.net>
* tag 'drm-misc-next-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc: (41 commits)
  drm/omapdrm: Use of_find_backlight helper
  drm/panel: Use of_find_backlight helper
  drm/omapdrm: Use backlight_enable/disable helpers
  drm/panel: Use backlight_enable/disable helpers
  drm/tinydrm: Call devres version of of_find_backlight
  drm/tinydrm: Replace tinydrm_of_find_backlight with of_find_backlight
  drm/tinydrm: Convert tinydrm_enable/disable_backlight to backlight_enable/disable
  drm: add documentation for tv connector state margins
  drm/doc: Use new substruct support
  drm/doc: Polish for drm_mode_parse_command_line_for_connector
  drm/docs: Document "scaling mode" property better
  drm/docs: Align layout of optional plane blending properties
  drm/docs: Discourage adding more to kms-properties.csv
  drm: simple_kms_helper: Add mode_valid() callback support
  drm/todo: Add idr_init_base todo
  drm: Use idr_init_base(1) when using id==0 for invalid
  drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem
  drm: NULL pointer dereference [null-pointer-deref] (CWE 476) problem
  dma-buf/sw_sync: Fix kerneldoc warnings
  drm: Fix kerneldoc warnings for drm_lease
  ...

53 files changed:
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
Documentation/gpu/drm-kms.rst
Documentation/gpu/kms-properties.csv
Documentation/gpu/todo.rst
drivers/dma-buf/sw_sync.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/gpu/drm/drm_blend.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_lease.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_simple_kms_helper.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/imx/dw_hdmi-imx.c
drivers/gpu/drm/meson/meson_dw_hdmi.c
drivers/gpu/drm/omapdrm/displays/panel-dpi.c
drivers/gpu/drm/panel/panel-innolux-p079zca.c
drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
drivers/gpu/drm/rockchip/dw-mipi-dsi.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/inno_hdmi.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/sun4i/Kconfig
drivers/gpu/drm/sun4i/Makefile
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c [new file with mode: 0644]
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h [new file with mode: 0644]
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c [new file with mode: 0644]
drivers/gpu/drm/sun4i/sun8i_mixer.c
drivers/gpu/drm/tinydrm/Kconfig
drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
drivers/gpu/drm/tinydrm/mi0283qt.c
drivers/gpu/drm/tinydrm/mipi-dbi.c
drivers/gpu/drm/tinydrm/st7735r.c
drivers/video/backlight/backlight.c
include/drm/bridge/dw_hdmi.h
include/drm/drm_connector.h
include/drm/drm_dp_helper.h
include/drm/drm_simple_kms_helper.h
include/drm/drm_vblank.h
include/drm/tinydrm/tinydrm-helpers.h
include/linux/backlight.h

diff --git a/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
new file mode 100644 (file)
index 0000000..8df7d2e
--- /dev/null
@@ -0,0 +1,74 @@
+Rockchip RK3399 specific extensions to the cdn Display Port
+================================
+
+Required properties:
+- compatible: must be "rockchip,rk3399-cdn-dp"
+
+- reg: physical base address of the controller and length
+
+- clocks: from common clock binding: handle to dp clock.
+
+- clock-names: from common clock binding:
+              Required elements: "core-clk" "pclk" "spdif" "grf"
+
+- resets : a list of phandle + reset specifier pairs
+- reset-names : string of reset names
+               Required elements: "apb", "core", "dptx", "spdif"
+- power-domains : power-domain property defined with a phandle
+                 to respective power domain.
+- assigned-clocks: main clock, should be <&cru SCLK_DP_CORE>
+- assigned-clock-rates : the DP core clk frequency, shall be: 100000000
+
+- rockchip,grf: this soc should set GRF regs, so need get grf here.
+
+- ports: contain a port nodes with endpoint definitions as defined in
+        Documentation/devicetree/bindings/media/video-interfaces.txt.
+        contained 2 endpoints, connecting to the output of vop.
+
+- phys: from general PHY binding: the phandle for the PHY device.
+
+- extcon: extcon specifier for the Power Delivery
+
+- #sound-dai-cells = it must be 1 if your system is using 2 DAIs: I2S, SPDIF
+
+-------------------------------------------------------------------------------
+
+Example:
+       cdn_dp: dp@fec00000 {
+               compatible = "rockchip,rk3399-cdn-dp";
+               reg = <0x0 0xfec00000 0x0 0x100000>;
+               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
+                        <&cru SCLK_SPDIF_REC_DPTX>, <&cru PCLK_VIO_GRF>;
+               clock-names = "core-clk", "pclk", "spdif", "grf";
+               assigned-clocks = <&cru SCLK_DP_CORE>;
+               assigned-clock-rates = <100000000>;
+               power-domains = <&power RK3399_PD_HDCP>;
+               phys = <&tcphy0_dp>, <&tcphy1_dp>;
+               resets = <&cru SRST_DPTX_SPDIF_REC>;
+               reset-names = "spdif";
+               extcon = <&fusb0>, <&fusb1>;
+               rockchip,grf = <&grf>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #sound-dai-cells = <1>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       dp_in: port {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               dp_in_vopb: endpoint@0 {
+                                       reg = <0>;
+                                       remote-endpoint = <&vopb_out_dp>;
+                               };
+
+                               dp_in_vopl: endpoint@1 {
+                                       reg = <1>;
+                                       remote-endpoint = <&vopl_out_dp>;
+                               };
+                       };
+               };
+       };
index cd626ee1147a2c92da8592dbd6a48728b54181e0..b995bfee734aeb7976b5ff2bae916cd8c39971be 100644 (file)
@@ -64,6 +64,52 @@ Required properties:
     first port should be the input endpoint. The second should be the
     output, usually to an HDMI connector.
 
+DWC HDMI TX Encoder
+-------------------
+
+The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with Allwinner's own PHY IP. It supports audio and video outputs and CEC.
+
+These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
+Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
+following device-specific properties.
+
+Required properties:
+
+  - compatible: value must be one of:
+    * "allwinner,sun8i-a83t-dw-hdmi"
+  - reg: base address and size of memory-mapped region
+  - reg-io-width: See dw_hdmi.txt. Shall be 1.
+  - interrupts: HDMI interrupt number
+  - clocks: phandles to the clocks feeding the HDMI encoder
+    * iahb: the HDMI bus clock
+    * isfr: the HDMI register clock
+    * tmds: TMDS clock
+  - clock-names: the clock names mentioned above
+  - resets: phandle to the reset controller
+  - reset-names: must be "ctrl"
+  - phys: phandle to the DWC HDMI PHY
+  - phy-names: must be "phy"
+
+  - ports: A ports node with endpoint definitions as defined in
+    Documentation/devicetree/bindings/media/video-interfaces.txt. The
+    first port should be the input endpoint. The second should be the
+    output, usually to an HDMI connector.
+
+DWC HDMI PHY
+------------
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun8i-a83t-hdmi-phy
+  - reg: base address and size of memory-mapped region
+  - clocks: phandles to the clocks feeding the HDMI PHY
+    * bus: the HDMI PHY interface clock
+    * mod: the HDMI PHY module clock
+  - clock-names: the clock names mentioned above
+  - resets: phandle to the reset controller driving the PHY
+  - reset-names: must be "phy"
+
 TV Encoder
 ----------
 
@@ -94,24 +140,26 @@ Required properties:
    * allwinner,sun7i-a20-tcon
    * allwinner,sun8i-a33-tcon
    * allwinner,sun8i-a83t-tcon-lcd
+   * allwinner,sun8i-a83t-tcon-tv
    * allwinner,sun8i-v3s-tcon
  - reg: base address and size of memory-mapped region
  - interrupts: interrupt associated to this IP
- - clocks: phandles to the clocks feeding the TCON. Three are needed:
+ - clocks: phandles to the clocks feeding the TCON.
    - 'ahb': the interface clocks
-   - 'tcon-ch0': The clock driving the TCON channel 0
+   - 'tcon-ch0': The clock driving the TCON channel 0, except for A83T TV TCON
  - resets: phandles to the reset controllers driving the encoder
    - "lcd": the reset line for the TCON channel 0
 
  - clock-names: the clock names mentioned above
  - reset-names: the reset names mentioned above
- - clock-output-names: Name of the pixel clock created
+ - clock-output-names: Name of the pixel clock created, if TCON supports
+   channel 0.
 
 - ports: A ports node with endpoint definitions as defined in
   Documentation/devicetree/bindings/media/video-interfaces.txt. The
   first port should be the input endpoint, the second one the output
 
-  The output may have multiple endpoints. The TCON has two channels,
+  The output may have multiple endpoints. TCON can have 1 or 2 channels,
   usually with the first channel being used for the panels interfaces
   (RGB, LVDS, etc.), and the second being used for the outputs that
   require another controller (TV Encoder, HDMI, etc.). The endpoints
@@ -122,8 +170,8 @@ Required properties:
 On SoCs other than the A33 and V3s, there is one more clock required:
    - 'tcon-ch1': The clock driving the TCON channel 1
 
-On SoCs that support LVDS (all SoCs but the A13, H3, H5 and V3s), you
-need one more reset line:
+When TCON support LVDS (all TCONs except TV TCON on A83T and those found
+in A13, H3, H5 and V3s SoCs), you need one more reset line:
    - 'lvds': The reset line driving the LVDS logic
 
 And on the A23, A31, A31s and A33, you need one more clock line:
@@ -226,6 +274,7 @@ supported.
 Required properties:
   - compatible: value must be one of:
     * allwinner,sun8i-a83t-de2-mixer-0
+    * allwinner,sun8i-a83t-de2-mixer-1
     * allwinner,sun8i-v3s-de2-mixer
   - reg: base address and size of the memory-mapped region.
   - clocks: phandles to the clocks feeding the mixer
index 2dcf5b42015debbe9c047c61f2a0c35df7d02d65..56a3780e39b8ec86e1adecf5811ad3305aa53ce9 100644 (file)
@@ -547,8 +547,9 @@ Explicit Fencing Properties
 Existing KMS Properties
 -----------------------
 
-The following table gives description of drm properties exposed by
-various modules/drivers.
+The following table gives description of drm properties exposed by various
+modules/drivers. Because this table is very unwieldy, do not add any new
+properties here. Instead document them in a section above.
 
 .. csv-table::
    :header-rows: 1
index 927b65e14219d57c01a1993670a9572ddb7f5570..6b28b014cb7dc74df402d8cef45e4317cd5ff601 100644 (file)
@@ -1,5 +1,4 @@
 Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions
-,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon."
 ,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD
 ,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD
 ,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD
index 1e593370f64f061b550e273da46e1cd96645f244..1a0a413eecedbf92437aa323d8070e40a7c8bc03 100644 (file)
@@ -212,6 +212,16 @@ probably use drm_fb_helper_fbdev_teardown().
 
 Contact: Maintainer of the driver you plan to convert
 
+idr_init_base()
+---------------
+
+DRM core&drivers uses a lot of idr (integer lookup directories) for mapping
+userspace IDs to internal objects, and in most places ID=0 means NULL and hence
+is never used. Switching to idr_init_base() for these would make the idr more
+efficient.
+
+Contact: Daniel Vetter
+
 Core refactorings
 =================
 
index 7779bdbd18d132516facdecf161721235ec62736..3d78ca89a605396af847367d8f6aafc4a3b36456 100644 (file)
@@ -235,10 +235,10 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
 
 /**
  * sync_pt_create() - creates a sync pt
- * @parent:    fence's parent sync_timeline
- * @inc:       value of the fence
+ * @obj:       parent sync_timeline
+ * @value:     value of the fence
  *
- * Creates a new sync_pt as a child of @parent.  @size bytes will be
+ * Creates a new sync_pt (fence) as a child of @parent.  @size bytes will be
  * allocated allowing for implementation specific data to be kept after
  * the generic sync_timeline struct. Returns the sync_pt object or
  * NULL in case of error.
index 704e879711e4f74a7b275a76019c283a1140df42..b1d5aee46316deb252b0f492e6bada9acf9182fd 100644 (file)
@@ -194,7 +194,7 @@ static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev,
        return tt;
 }
 
-struct ttm_bo_driver bochs_bo_driver = {
+static struct ttm_bo_driver bochs_bo_driver = {
        .ttm_tt_create = bochs_ttm_tt_create,
        .ttm_tt_populate = ttm_pool_populate,
        .ttm_tt_unpopulate = ttm_pool_unpopulate,
index a38db40ce990de2c572fd0b0c2aca42d8273611c..f9802399cc0de27dae4131a20ceab434b370114f 100644 (file)
@@ -1037,19 +1037,21 @@ static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
                         HDMI_PHY_CONF0_SVSRET_MASK);
 }
 
-static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
+void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
 {
        hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
                         HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
                         HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
 }
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_pddq);
 
-static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
+void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
 {
        hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
                         HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
                         HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
 }
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_txpwron);
 
 static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
 {
@@ -1065,6 +1067,22 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
                         HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
+void dw_hdmi_phy_reset(struct dw_hdmi *hdmi)
+{
+       /* PHY reset. The reset signal is active high on Gen2 PHYs. */
+       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+       hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+
+void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
+{
+       hdmi_phy_test_clear(hdmi, 1);
+       hdmi_writeb(hdmi, address, HDMI_PHY_I2CM_SLAVE_ADDR);
+       hdmi_phy_test_clear(hdmi, 0);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_set_addr);
+
 static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
 {
        const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
@@ -1203,16 +1221,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
        if (phy->has_svsret)
                dw_hdmi_phy_enable_svsret(hdmi, 1);
 
-       /* PHY reset. The reset signal is active high on Gen2 PHYs. */
-       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
-       hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+       dw_hdmi_phy_reset(hdmi);
 
        hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
 
-       hdmi_phy_test_clear(hdmi, 1);
-       hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
-                   HDMI_PHY_I2CM_SLAVE_ADDR);
-       hdmi_phy_test_clear(hdmi, 0);
+       dw_hdmi_phy_i2c_set_addr(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2);
 
        /* Write to the PHY as configured by the platform */
        if (pdata->configure_phy)
@@ -1251,15 +1264,16 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
        dw_hdmi_phy_power_off(hdmi);
 }
 
-static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
-                                                     void *data)
+enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
+                                              void *data)
 {
        return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
                connector_status_connected : connector_status_disconnected;
 }
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_read_hpd);
 
-static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
-                                  bool force, bool disabled, bool rxsense)
+void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
+                           bool force, bool disabled, bool rxsense)
 {
        u8 old_mask = hdmi->phy_mask;
 
@@ -1271,8 +1285,9 @@ static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
        if (old_mask != hdmi->phy_mask)
                hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
 }
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_update_hpd);
 
-static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
+void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
 {
        /*
         * Configure the PHY RX SENSE and HPD interrupts polarities and clear
@@ -1291,6 +1306,7 @@ static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
        hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
                    HDMI_IH_MUTE_PHY_STAT0);
 }
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_setup_hpd);
 
 static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
        .init = dw_hdmi_phy_init,
@@ -1634,9 +1650,10 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
         * then write one of the FC registers several times.
         *
         * The number of iterations matters and depends on the HDMI TX revision
-        * (and possibly on the platform). So far only i.MX6Q (v1.30a) and
-        * i.MX6DL (v1.31a) have been identified as needing the workaround, with
-        * 4 and 1 iterations respectively.
+        * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
+        * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
+        * as needing the workaround, with 4 iterations for v1.30a and 1
+        * iteration for others.
         */
 
        switch (hdmi->version) {
@@ -1644,6 +1661,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
                count = 4;
                break;
        case 0x131a:
+       case 0x132a:
                count = 1;
                break;
        default:
@@ -2525,8 +2543,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
        if (hdmi->i2c)
                dw_hdmi_i2c_init(hdmi);
 
-       platform_set_drvdata(pdev, hdmi);
-
        return hdmi;
 
 err_iahb:
@@ -2576,25 +2592,23 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 /* -----------------------------------------------------------------------------
  * Probe/remove API, used from platforms based on the DRM bridge API.
  */
-int dw_hdmi_probe(struct platform_device *pdev,
-                 const struct dw_hdmi_plat_data *plat_data)
+struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
+                             const struct dw_hdmi_plat_data *plat_data)
 {
        struct dw_hdmi *hdmi;
 
        hdmi = __dw_hdmi_probe(pdev, plat_data);
        if (IS_ERR(hdmi))
-               return PTR_ERR(hdmi);
+               return hdmi;
 
        drm_bridge_add(&hdmi->bridge);
 
-       return 0;
+       return hdmi;
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_probe);
 
-void dw_hdmi_remove(struct platform_device *pdev)
+void dw_hdmi_remove(struct dw_hdmi *hdmi)
 {
-       struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
-
        drm_bridge_remove(&hdmi->bridge);
 
        __dw_hdmi_remove(hdmi);
@@ -2604,31 +2618,30 @@ EXPORT_SYMBOL_GPL(dw_hdmi_remove);
 /* -----------------------------------------------------------------------------
  * Bind/unbind API, used from platforms based on the component framework.
  */
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-                const struct dw_hdmi_plat_data *plat_data)
+struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
+                            struct drm_encoder *encoder,
+                            const struct dw_hdmi_plat_data *plat_data)
 {
        struct dw_hdmi *hdmi;
        int ret;
 
        hdmi = __dw_hdmi_probe(pdev, plat_data);
        if (IS_ERR(hdmi))
-               return PTR_ERR(hdmi);
+               return hdmi;
 
        ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
        if (ret) {
-               dw_hdmi_remove(pdev);
+               dw_hdmi_remove(hdmi);
                DRM_ERROR("Failed to initialize bridge with drm\n");
-               return ret;
+               return ERR_PTR(ret);
        }
 
-       return 0;
+       return hdmi;
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_bind);
 
-void dw_hdmi_unbind(struct device *dev)
+void dw_hdmi_unbind(struct dw_hdmi *hdmi)
 {
-       struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
        __dw_hdmi_remove(hdmi);
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
index 4c62dff14893646f7e818d1fb87947da52a3ccef..5a81e1b4c076894804085dee2feb9c39629aadc8 100644 (file)
  * On top of this basic transformation additional properties can be exposed by
  * the driver:
  *
- * - Rotation is set up with drm_plane_create_rotation_property(). It adds a
- *   rotation and reflection step between the source and destination rectangles.
- *   Without this property the rectangle is only scaled, but not rotated or
- *   reflected.
+ * rotation:
+ *     Rotation is set up with drm_plane_create_rotation_property(). It adds a
+ *     rotation and reflection step between the source and destination rectangles.
+ *     Without this property the rectangle is only scaled, but not rotated or
+ *     reflected.
  *
- * - Z position is set up with drm_plane_create_zpos_immutable_property() and
- *   drm_plane_create_zpos_property(). It controls the visibility of overlapping
- *   planes. Without this property the primary plane is always below the cursor
- *   plane, and ordering between all other planes is undefined.
+ * zpos:
+ *     Z position is set up with drm_plane_create_zpos_immutable_property() and
+ *     drm_plane_create_zpos_property(). It controls the visibility of overlapping
+ *     planes. Without this property the primary plane is always below the cursor
+ *     plane, and ordering between all other planes is undefined.
  *
  * Note that all the property extensions described here apply either to the
  * plane or the CRTC (e.g. for the background color, which currently is not
index 16b9c3810af22c9920bfea381618cb04fe9d2227..b3cde897cd802ed841f6ac9cdc30c7e9354a66ac 100644 (file)
@@ -849,13 +849,13 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
  *
  *     The value of this property can be one of the following:
  *
- *     DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0
+ *     DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0
  *             The link is not protected, content is transmitted in the clear.
- *     DRM_MODE_CONTENT_PROTECTION_DESIRED = 1
+ *     DRM_MODE_CONTENT_PROTECTION_DESIRED = 1
  *             Userspace has requested content protection, but the link is not
  *             currently protected. When in this state, kernel should enable
  *             Content Protection as soon as possible.
- *     DRM_MODE_CONTENT_PROTECTION_ENABLED = 2
+ *     DRM_MODE_CONTENT_PROTECTION_ENABLED = 2
  *             Userspace has requested content protection, and the link is
  *             protected. Only the driver can set the property to this value.
  *             If userspace attempts to set to ENABLED, kernel will return
@@ -889,7 +889,31 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
  *     INPUT_PROP_DIRECT) will still map 1:1 to the actual LCD panel
  *     coordinates, so if userspace rotates the picture to adjust for
  *     the orientation it must also apply the same transformation to the
- *     touchscreen input coordinates.
+ *     touchscreen input coordinates. This property is initialized by calling
+ *     drm_connector_init_panel_orientation_property().
+ *
+ * scaling mode:
+ *     This property defines how a non-native mode is upscaled to the native
+ *     mode of an LCD panel:
+ *
+ *     None:
+ *             No upscaling happens, scaling is left to the panel. Not all
+ *             drivers expose this mode.
+ *     Full:
+ *             The output is upscaled to the full resolution of the panel,
+ *             ignoring the aspect ratio.
+ *     Center:
+ *             No upscaling happens, the output is centered within the native
+ *             resolution the panel.
+ *     Full aspect:
+ *             The output is upscaled to maximize either the width or height
+ *             while retaining the aspect ratio.
+ *
+ *     This property should be set up by calling
+ *     drm_connector_attach_scaling_mode_property(). Note that drivers
+ *     can also expose this property to external outputs, in which case they
+ *     must support "None", which should be the default (since external screens
+ *     have a built-in scaler).
  */
 
 int drm_connector_create_standard_properties(struct drm_device *dev)
index 36df7df5fe1a0c1dc62df682fdccb282e9c42140..6fac4129e6a258de19654548512b446ca1058f3f 100644 (file)
@@ -1082,10 +1082,12 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port)
                lct = drm_dp_calculate_rad(port, rad);
 
                port->mstb = drm_dp_add_mst_branch_device(lct, rad);
-               port->mstb->mgr = port->mgr;
-               port->mstb->port_parent = port;
+               if (port->mstb) {
+                       port->mstb->mgr = port->mgr;
+                       port->mstb->port_parent = port;
 
-               send_link = true;
+                       send_link = true;
+               }
                break;
        }
        return send_link;
index b1cb2627548f6a93d58a05254f811bfb6a1930b8..a797bbf1cab83bd57ea7b201349aabb506031015 100644 (file)
@@ -2083,6 +2083,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
        if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) {
                mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0,
                                    false);
+               if (!mode)
+                       return NULL;
                mode->hdisplay = 1366;
                mode->hsync_start = mode->hsync_start - 1;
                mode->hsync_end = mode->hsync_end - 1;
index 01f8d9481211fc1982000998f9e9e7bd87c5d92a..4975ba9a7bc897ba844bba610550af507b943c7b 100644 (file)
@@ -98,7 +98,7 @@ drm_gem_init(struct drm_device *dev)
        struct drm_vma_offset_manager *vma_offset_manager;
 
        mutex_init(&dev->object_name_lock);
-       idr_init(&dev->object_name_idr);
+       idr_init_base(&dev->object_name_idr, 1);
 
        vma_offset_manager = kzalloc(sizeof(*vma_offset_manager), GFP_KERNEL);
        if (!vma_offset_manager) {
@@ -776,7 +776,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
 void
 drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
 {
-       idr_init(&file_private->object_idr);
+       idr_init_base(&file_private->object_idr, 1);
        spin_lock_init(&file_private->table_lock);
 }
 
index 1402c0e71b03d18866139056b12f0d5fd84b6afb..d345563fdff3133f3a156e9387cea90655600bb9 100644 (file)
@@ -44,7 +44,7 @@ EXPORT_SYMBOL(drm_lease_owner);
 /**
  * _drm_find_lessee - find lessee by id (idr_mutex held)
  * @master: drm_master of lessor
- * @id: lessee_id
+ * @lessee_id: id
  *
  * RETURN:
  *
@@ -101,7 +101,7 @@ static bool _drm_has_leased(struct drm_master *master, int id)
 
 /**
  * _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
- * @master: the drm_master
+ * @file_priv: the master drm_file
  * @id: the object id
  *
  * Checks if the specified master holds a lease on the object. Return
@@ -121,7 +121,7 @@ EXPORT_SYMBOL(_drm_lease_held);
 
 /**
  * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
- * @master: the drm_master
+ * @file_priv: the master drm_file
  * @id: the object id
  *
  * Checks if the specified master holds a lease on the object. Return
@@ -149,7 +149,7 @@ EXPORT_SYMBOL(drm_lease_held);
 /**
  * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
  * @file_priv: requestor file
- * @crtcs: bitmask of crtcs to check
+ * @crtcs_in: bitmask of crtcs to check
  *
  * Reconstructs a crtc mask based on the crtcs which are visible
  * through the specified file.
@@ -305,7 +305,7 @@ void drm_lease_destroy(struct drm_master *master)
 
 /**
  * _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
- * @master: the master losing its lease
+ * @top: the master losing its lease
  */
 static void _drm_lease_revoke(struct drm_master *top)
 {
@@ -482,7 +482,7 @@ out_free_objects:
  * drm_mode_create_lease_ioctl - create a new lease
  * @dev: the drm device
  * @data: pointer to struct drm_mode_create_lease
- * @file_priv: the file being manipulated
+ * @lessor_priv: the file being manipulated
  *
  * The master associated with the specified file will have a lease
  * created containing the objects specified in the ioctl structure.
@@ -662,7 +662,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
  * drm_mode_get_lease_ioctl - list leased objects
  * @dev: the drm device
  * @data: pointer to struct drm_mode_get_lease
- * @file_priv: the file being manipulated
+ * @lessee_priv: the file being manipulated
  *
  * Return the list of leased objects for the specified lessee
  */
@@ -722,7 +722,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
  * drm_mode_revoke_lease_ioctl - revoke lease
  * @dev: the drm device
  * @data: pointer to struct drm_mode_revoke_lease
- * @file_priv: the file being manipulated
+ * @lessor_priv: the file being manipulated
  *
  * This removes all of the objects from the lease without
  * actually getting rid of the lease itself; that way all
index c397b523c9454b62ac54a30eb1cc3ce8a6c7517b..5a8033fda4e321a638a658a02cd98dc590ebca36 100644 (file)
@@ -1346,9 +1346,9 @@ EXPORT_SYMBOL(drm_mode_connector_list_update);
  * modeline in fb_mode_option will be parsed instead.
  *
  * This uses the same parameters as the fb modedb.c, except for an extra
- * force-enable, force-enable-digital and force-disable bit at the end:
+ * force-enable, force-enable-digital and force-disable bit at the end::
  *
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
  *
  * The intermediate drm_cmdline_mode structure is required to store additional
  * options from the command line modline like the force-enable/disable flag.
index 9d3f6b70812cd100c8783cf58a8abe09d68c77ba..6c327fdbaaee546729d8f05685278ec188350990 100644 (file)
@@ -34,6 +34,20 @@ static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
        .destroy = drm_encoder_cleanup,
 };
 
+static enum drm_mode_status
+drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
+                              const struct drm_display_mode *mode)
+{
+       struct drm_simple_display_pipe *pipe;
+
+       pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
+       if (!pipe->funcs || !pipe->funcs->mode_valid)
+               /* Anything goes */
+               return MODE_OK;
+
+       return pipe->funcs->mode_valid(crtc, mode);
+}
+
 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
                                     struct drm_crtc_state *state)
 {
@@ -72,6 +86,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
+       .mode_valid = drm_simple_kms_crtc_mode_valid,
        .atomic_check = drm_simple_kms_crtc_check,
        .atomic_enable = drm_simple_kms_crtc_enable,
        .atomic_disable = drm_simple_kms_crtc_disable,
index 0b7b0d1ad2d595a2efacde1cdd4472b401a73278..d4f4ce4845296aca38936902f2dc4698c2720902 100644 (file)
@@ -546,7 +546,7 @@ err_put_fd:
 void
 drm_syncobj_open(struct drm_file *file_private)
 {
-       idr_init(&file_private->syncobj_idr);
+       idr_init_base(&file_private->syncobj_idr, 1);
        spin_lock_init(&file_private->syncobj_table_lock);
 }
 
index b62763aa87069fb3eccb9787dfe73f6ae33a45e2..fe6becdcc29edc8dc4fd105c932375a53c5e5865 100644 (file)
@@ -25,6 +25,7 @@
 struct imx_hdmi {
        struct device *dev;
        struct drm_encoder encoder;
+       struct dw_hdmi *hdmi;
        struct regmap *regmap;
 };
 
@@ -239,14 +240,18 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
        drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS, NULL);
 
-       ret = dw_hdmi_bind(pdev, encoder, plat_data);
+       platform_set_drvdata(pdev, hdmi);
+
+       hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
 
        /*
         * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
         * which would have called the encoder cleanup.  Do it manually.
         */
-       if (ret)
+       if (IS_ERR(hdmi->hdmi)) {
+               ret = PTR_ERR(hdmi->hdmi);
                drm_encoder_cleanup(encoder);
+       }
 
        return ret;
 }
@@ -254,7 +259,9 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
 static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
                               void *data)
 {
-       return dw_hdmi_unbind(dev);
+       struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+
+       dw_hdmi_unbind(hdmi->hdmi);
 }
 
 static const struct component_ops dw_hdmi_imx_ops = {
index 17de3afd98f6a6a3cae133944024c0ad2c41aa6c..d49af17310c99229a6af937f4f5adc3b5eccf212 100644 (file)
@@ -140,6 +140,7 @@ struct meson_dw_hdmi {
        struct clk *venci_clk;
        struct regulator *hdmi_supply;
        u32 irq_stat;
+       struct dw_hdmi *hdmi;
 };
 #define encoder_to_meson_dw_hdmi(x) \
        container_of(x, struct meson_dw_hdmi, encoder)
@@ -302,7 +303,7 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
        }
 }
 
-static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
+static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
 {
        struct meson_drm *priv = dw_hdmi->priv;
 
@@ -409,9 +410,9 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
        msleep(100);
 
        /* Reset PHY 3 times in a row */
-       dw_hdmi_phy_reset(dw_hdmi);
-       dw_hdmi_phy_reset(dw_hdmi);
-       dw_hdmi_phy_reset(dw_hdmi);
+       meson_dw_hdmi_phy_reset(dw_hdmi);
+       meson_dw_hdmi_phy_reset(dw_hdmi);
+       meson_dw_hdmi_phy_reset(dw_hdmi);
 
        /* Temporary Disable VENC video stream */
        if (priv->venc.hdmi_use_enci)
@@ -878,9 +879,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
        dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
        dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
 
-       ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
-       if (ret)
-               return ret;
+       platform_set_drvdata(pdev, meson_dw_hdmi);
+
+       meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
+                                          &meson_dw_hdmi->dw_plat_data);
+       if (IS_ERR(meson_dw_hdmi->hdmi))
+               return PTR_ERR(meson_dw_hdmi->hdmi);
 
        DRM_DEBUG_DRIVER("HDMI controller initialized\n");
 
@@ -890,7 +894,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
                                   void *data)
 {
-       dw_hdmi_unbind(dev);
+       struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
+
+       dw_hdmi_unbind(meson_dw_hdmi->hdmi);
 }
 
 static const struct component_ops meson_dw_hdmi_ops = {
index efff6dbbb86fe70494beaef60f19f15b8af8e3b0..48a03f55610aeb58b115590dd76057d98367f585 100644 (file)
@@ -87,11 +87,7 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
        }
 
        gpiod_set_value_cansleep(ddata->enable_gpio, 1);
-
-       if (ddata->backlight) {
-               ddata->backlight->props.power = FB_BLANK_UNBLANK;
-               backlight_update_status(ddata->backlight);
-       }
+       backlight_enable(ddata->backlight);
 
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
@@ -106,10 +102,7 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
        if (!omapdss_device_is_enabled(dssdev))
                return;
 
-       if (ddata->backlight) {
-               ddata->backlight->props.power = FB_BLANK_POWERDOWN;
-               backlight_update_status(ddata->backlight);
-       }
+       backlight_disable(ddata->backlight);
 
        gpiod_set_value_cansleep(ddata->enable_gpio, 0);
        regulator_disable(ddata->vcc_supply);
@@ -164,7 +157,6 @@ static int panel_dpi_probe_of(struct platform_device *pdev)
 {
        struct panel_drv_data *ddata = platform_get_drvdata(pdev);
        struct device_node *node = pdev->dev.of_node;
-       struct device_node *bl_node;
        struct omap_dss_device *in;
        int r;
        struct display_timing timing;
@@ -190,19 +182,15 @@ static int panel_dpi_probe_of(struct platform_device *pdev)
        if (IS_ERR(ddata->vcc_supply))
                return PTR_ERR(ddata->vcc_supply);
 
-       bl_node = of_parse_phandle(node, "backlight", 0);
-       if (bl_node) {
-               ddata->backlight = of_find_backlight_by_node(bl_node);
-               of_node_put(bl_node);
+       ddata->backlight = devm_of_find_backlight(&pdev->dev);
 
-               if (!ddata->backlight)
-                       return -EPROBE_DEFER;
-       }
+       if (IS_ERR(ddata->backlight))
+               return PTR_ERR(ddata->backlight);
 
        r = of_get_display_timing(node, "panel-timing", &timing);
        if (r) {
                dev_err(&pdev->dev, "failed to get video timing\n");
-               goto error_free_backlight;
+               return r;
        }
 
        videomode_from_timing(&timing, &ddata->vm);
@@ -210,19 +198,12 @@ static int panel_dpi_probe_of(struct platform_device *pdev)
        in = omapdss_of_find_source_for_first_ep(node);
        if (IS_ERR(in)) {
                dev_err(&pdev->dev, "failed to find video source\n");
-               r = PTR_ERR(in);
-               goto error_free_backlight;
+               return PTR_ERR(in);
        }
 
        ddata->in = in;
 
        return 0;
-
-error_free_backlight:
-       if (ddata->backlight)
-               put_device(&ddata->backlight->dev);
-
-       return r;
 }
 
 static int panel_dpi_probe(struct platform_device *pdev)
@@ -277,9 +258,6 @@ static int __exit panel_dpi_remove(struct platform_device *pdev)
 
        omap_dss_put_device(in);
 
-       if (ddata->backlight)
-               put_device(&ddata->backlight->dev);
-
        return 0;
 }
 
index 6ba93449fcfbd5c74a25949880e5bc82d80ff10a..57df39b5c5899cd3caaffb51d8dbf5d7b2a2eea2 100644 (file)
@@ -45,8 +45,7 @@ static int innolux_panel_disable(struct drm_panel *panel)
        if (!innolux->enabled)
                return 0;
 
-       innolux->backlight->props.power = FB_BLANK_POWERDOWN;
-       backlight_update_status(innolux->backlight);
+       backlight_disable(innolux->backlight);
 
        err = mipi_dsi_dcs_set_display_off(innolux->link);
        if (err < 0)
@@ -151,8 +150,7 @@ static int innolux_panel_enable(struct drm_panel *panel)
        if (innolux->enabled)
                return 0;
 
-       innolux->backlight->props.power = FB_BLANK_UNBLANK;
-       ret = backlight_update_status(innolux->backlight);
+       ret = backlight_enable(innolux->backlight);
        if (ret) {
                DRM_DEV_ERROR(panel->drm->dev,
                              "Failed to enable backlight %d\n", ret);
@@ -217,7 +215,6 @@ MODULE_DEVICE_TABLE(of, innolux_of_match);
 static int innolux_panel_add(struct innolux_panel *innolux)
 {
        struct device *dev = &innolux->link->dev;
-       struct device_node *np;
        int err;
 
        innolux->supply = devm_regulator_get(dev, "power");
@@ -232,37 +229,22 @@ static int innolux_panel_add(struct innolux_panel *innolux)
                innolux->enable_gpio = NULL;
        }
 
-       np = of_parse_phandle(dev->of_node, "backlight", 0);
-       if (np) {
-               innolux->backlight = of_find_backlight_by_node(np);
-               of_node_put(np);
+       innolux->backlight = devm_of_find_backlight(dev);
 
-               if (!innolux->backlight)
-                       return -EPROBE_DEFER;
-       }
+       if (IS_ERR(innolux->backlight))
+               return PTR_ERR(innolux->backlight);
 
        drm_panel_init(&innolux->base);
        innolux->base.funcs = &innolux_panel_funcs;
        innolux->base.dev = &innolux->link->dev;
 
-       err = drm_panel_add(&innolux->base);
-       if (err < 0)
-               goto put_backlight;
-
-       return 0;
-
-put_backlight:
-       put_device(&innolux->backlight->dev);
-
-       return err;
+       return drm_panel_add(&innolux->base);
 }
 
 static void innolux_panel_del(struct innolux_panel *innolux)
 {
        if (innolux->base.dev)
                drm_panel_remove(&innolux->base);
-
-       put_device(&innolux->backlight->dev);
 }
 
 static int innolux_panel_probe(struct mipi_dsi_device *dsi)
index 5b2340ef74ed0cf069ef46aa9c973542bfbb3755..0a94ab79a6c0f768227a3c273751913ef5bc512e 100644 (file)
@@ -192,8 +192,7 @@ static int jdi_panel_disable(struct drm_panel *panel)
        if (!jdi->enabled)
                return 0;
 
-       jdi->backlight->props.power = FB_BLANK_POWERDOWN;
-       backlight_update_status(jdi->backlight);
+       backlight_disable(jdi->backlight);
 
        jdi->enabled = false;
 
@@ -289,8 +288,7 @@ static int jdi_panel_enable(struct drm_panel *panel)
        if (jdi->enabled)
                return 0;
 
-       jdi->backlight->props.power = FB_BLANK_UNBLANK;
-       backlight_update_status(jdi->backlight);
+       backlight_enable(jdi->backlight);
 
        jdi->enabled = true;
 
index 3cce3ca19601ed5999c045df23fc47ff40462c28..6bf8730f1a2115068e82b5fdc6c4694d9acdb9fb 100644 (file)
@@ -96,10 +96,7 @@ static int sharp_panel_disable(struct drm_panel *panel)
        if (!sharp->enabled)
                return 0;
 
-       if (sharp->backlight) {
-               sharp->backlight->props.power = FB_BLANK_POWERDOWN;
-               backlight_update_status(sharp->backlight);
-       }
+       backlight_disable(sharp->backlight);
 
        sharp->enabled = false;
 
@@ -263,10 +260,7 @@ static int sharp_panel_enable(struct drm_panel *panel)
        if (sharp->enabled)
                return 0;
 
-       if (sharp->backlight) {
-               sharp->backlight->props.power = FB_BLANK_UNBLANK;
-               backlight_update_status(sharp->backlight);
-       }
+       backlight_enable(sharp->backlight);
 
        sharp->enabled = true;
 
@@ -324,8 +318,7 @@ MODULE_DEVICE_TABLE(of, sharp_of_match);
 
 static int sharp_panel_add(struct sharp_panel *sharp)
 {
-       struct device_node *np;
-       int err;
+       struct device *dev = &sharp->link1->dev;
 
        sharp->mode = &default_mode;
 
@@ -333,30 +326,16 @@ static int sharp_panel_add(struct sharp_panel *sharp)
        if (IS_ERR(sharp->supply))
                return PTR_ERR(sharp->supply);
 
-       np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0);
-       if (np) {
-               sharp->backlight = of_find_backlight_by_node(np);
-               of_node_put(np);
+       sharp->backlight = devm_of_find_backlight(dev);
 
-               if (!sharp->backlight)
-                       return -EPROBE_DEFER;
-       }
+       if (IS_ERR(sharp->backlight))
+               return PTR_ERR(sharp->backlight);
 
        drm_panel_init(&sharp->base);
        sharp->base.funcs = &sharp_panel_funcs;
        sharp->base.dev = &sharp->link1->dev;
 
-       err = drm_panel_add(&sharp->base);
-       if (err < 0)
-               goto put_backlight;
-
-       return 0;
-
-put_backlight:
-       if (sharp->backlight)
-               put_device(&sharp->backlight->dev);
-
-       return err;
+       return drm_panel_add(&sharp->base);
 }
 
 static void sharp_panel_del(struct sharp_panel *sharp)
@@ -364,9 +343,6 @@ static void sharp_panel_del(struct sharp_panel *sharp)
        if (sharp->base.dev)
                drm_panel_remove(&sharp->base);
 
-       if (sharp->backlight)
-               put_device(&sharp->backlight->dev);
-
        if (sharp->link2)
                put_device(&sharp->link2->dev);
 }
index 3aeb0bda4947fd7c11d6d363a17d85fdfcfce8f2..494aa9b1628a7275210e9a657522287a76c0e385 100644 (file)
@@ -117,10 +117,7 @@ static int sharp_nt_panel_disable(struct drm_panel *panel)
        if (!sharp_nt->enabled)
                return 0;
 
-       if (sharp_nt->backlight) {
-               sharp_nt->backlight->props.power = FB_BLANK_POWERDOWN;
-               backlight_update_status(sharp_nt->backlight);
-       }
+       backlight_disable(sharp_nt->backlight);
 
        sharp_nt->enabled = false;
 
@@ -203,10 +200,7 @@ static int sharp_nt_panel_enable(struct drm_panel *panel)
        if (sharp_nt->enabled)
                return 0;
 
-       if (sharp_nt->backlight) {
-               sharp_nt->backlight->props.power = FB_BLANK_UNBLANK;
-               backlight_update_status(sharp_nt->backlight);
-       }
+       backlight_enable(sharp_nt->backlight);
 
        sharp_nt->enabled = true;
 
@@ -259,8 +253,6 @@ static const struct drm_panel_funcs sharp_nt_panel_funcs = {
 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
 {
        struct device *dev = &sharp_nt->dsi->dev;
-       struct device_node *np;
-       int ret;
 
        sharp_nt->mode = &default_mode;
 
@@ -277,39 +269,22 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
                gpiod_set_value(sharp_nt->reset_gpio, 0);
        }
 
-       np = of_parse_phandle(dev->of_node, "backlight", 0);
-       if (np) {
-               sharp_nt->backlight = of_find_backlight_by_node(np);
-               of_node_put(np);
+       sharp_nt->backlight = devm_of_find_backlight(dev);
 
-               if (!sharp_nt->backlight)
-                       return -EPROBE_DEFER;
-       }
+       if (IS_ERR(sharp_nt->backlight))
+               return PTR_ERR(sharp_nt->backlight);
 
        drm_panel_init(&sharp_nt->base);
        sharp_nt->base.funcs = &sharp_nt_panel_funcs;
        sharp_nt->base.dev = &sharp_nt->dsi->dev;
 
-       ret = drm_panel_add(&sharp_nt->base);
-       if (ret < 0)
-               goto put_backlight;
-
-       return 0;
-
-put_backlight:
-       if (sharp_nt->backlight)
-               put_device(&sharp_nt->backlight->dev);
-
-       return ret;
+       return drm_panel_add(&sharp_nt->base);
 }
 
 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
 {
        if (sharp_nt->base.dev)
                drm_panel_remove(&sharp_nt->base);
-
-       if (sharp_nt->backlight)
-               put_device(&sharp_nt->backlight->dev);
 }
 
 static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
index dc85b53d58ef2e8fb640e90afdac701e6397a1af..76210ae25094d4ba9b62d7dacbc12f03254d79ae 100644 (file)
@@ -68,12 +68,22 @@ static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = {
 
 static int rcar_dw_hdmi_probe(struct platform_device *pdev)
 {
-       return dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
+       struct dw_hdmi *hdmi;
+
+       hdmi = dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
+       if (IS_ERR(hdmi))
+               return PTR_ERR(hdmi);
+
+       platform_set_drvdata(pdev, hdmi);
+
+       return 0;
 }
 
 static int rcar_dw_hdmi_remove(struct platform_device *pdev)
 {
-       dw_hdmi_remove(pdev);
+       struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+
+       dw_hdmi_remove(hdmi);
 
        return 0;
 }
index b1fe0639227e4bc499fb581ca494217f084a7c6f..591953cbdd18686b3a3e14d7a861edac336fd6fe 100644 (file)
@@ -1202,9 +1202,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
                return ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        dsi->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(dsi->base))
                return PTR_ERR(dsi->base);
index 1eb02a82fd9188533bfd1debce378071b9eab540..3574b0ae2ad1923e39911ac32acabdbd9b3f7613 100644 (file)
@@ -48,6 +48,7 @@ struct rockchip_hdmi {
        const struct rockchip_hdmi_chip_data *chip_data;
        struct clk *vpll_clk;
        struct clk *grf_clk;
+       struct dw_hdmi *hdmi;
 };
 
 #define to_rockchip_hdmi(x)    container_of(x, struct rockchip_hdmi, x)
@@ -377,14 +378,18 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
        drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS, NULL);
 
-       ret = dw_hdmi_bind(pdev, encoder, plat_data);
+       platform_set_drvdata(pdev, hdmi);
+
+       hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
 
        /*
         * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
         * which would have called the encoder cleanup.  Do it manually.
         */
-       if (ret)
+       if (IS_ERR(hdmi->hdmi)) {
+               ret = PTR_ERR(hdmi->hdmi);
                drm_encoder_cleanup(encoder);
+       }
 
        return ret;
 }
@@ -392,7 +397,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
                                    void *data)
 {
-       return dw_hdmi_unbind(dev);
+       struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
+
+       dw_hdmi_unbind(hdmi->hdmi);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
index fab30927a8894862ccab9ebca92be72945220612..f6ad48766d49815084130a4ee7ebf41d250f42a3 100644 (file)
@@ -831,9 +831,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
        hdmi->drm_dev = drm;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -ENXIO;
-
        hdmi->regs = devm_ioremap_resource(dev, iores);
        if (IS_ERR(hdmi->regs))
                return PTR_ERR(hdmi->regs);
index d85431400a0dbdfeaf8312a490439ba8ac8b1e3f..88084ca15115215b3d62cda154c8f7797f7aa0f2 100644 (file)
@@ -230,6 +230,7 @@ static struct drm_driver rockchip_drm_driver = {
        .gem_prime_import       = drm_gem_prime_import,
        .gem_prime_export       = drm_gem_prime_export,
        .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table,
+       .gem_prime_import_sg_table      = rockchip_gem_prime_import_sg_table,
        .gem_prime_vmap         = rockchip_gem_prime_vmap,
        .gem_prime_vunmap       = rockchip_gem_prime_vunmap,
        .gem_prime_mmap         = rockchip_gem_mmap_buf,
index 1d9655576b6efe4ed5af5709265441fb5115607a..074db7a92809532a07333d320e67c31206aeab4e 100644 (file)
@@ -16,6 +16,8 @@
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 #include <drm/drm_vma_manager.h>
+
+#include <linux/dma-buf.h>
 #include <linux/iommu.h>
 
 #include "rockchip_drm_drv.h"
@@ -262,7 +264,6 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
         * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
         */
        vma->vm_flags &= ~VM_PFNMAP;
-       vma->vm_pgoff = 0;
 
        if (rk_obj->pages)
                ret = rockchip_drm_gem_object_mmap_iommu(obj, vma);
@@ -297,6 +298,12 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        if (ret)
                return ret;
 
+       /*
+        * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the
+        * whole buffer from the start.
+        */
+       vma->vm_pgoff = 0;
+
        obj = vma->vm_private_data;
 
        return rockchip_drm_gem_object_mmap(obj, vma);
@@ -309,12 +316,10 @@ static void rockchip_gem_release_object(struct rockchip_gem_object *rk_obj)
 }
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
-                                  bool alloc_kmap)
+       rockchip_gem_alloc_object(struct drm_device *drm, unsigned int size)
 {
        struct rockchip_gem_object *rk_obj;
        struct drm_gem_object *obj;
-       int ret;
 
        size = round_up(size, PAGE_SIZE);
 
@@ -326,6 +331,20 @@ struct rockchip_gem_object *
 
        drm_gem_object_init(drm, obj, size);
 
+       return rk_obj;
+}
+
+struct rockchip_gem_object *
+rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                          bool alloc_kmap)
+{
+       struct rockchip_gem_object *rk_obj;
+       int ret;
+
+       rk_obj = rockchip_gem_alloc_object(drm, size);
+       if (IS_ERR(rk_obj))
+               return rk_obj;
+
        ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
        if (ret)
                goto err_free_rk_obj;
@@ -343,11 +362,21 @@ err_free_rk_obj:
  */
 void rockchip_gem_free_object(struct drm_gem_object *obj)
 {
-       struct rockchip_gem_object *rk_obj;
-
-       rk_obj = to_rockchip_obj(obj);
+       struct drm_device *drm = obj->dev;
+       struct rockchip_drm_private *private = drm->dev_private;
+       struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 
-       rockchip_gem_free_buf(rk_obj);
+       if (obj->import_attach) {
+               if (private->domain) {
+                       rockchip_gem_iommu_unmap(rk_obj);
+               } else {
+                       dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
+                                    rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
+               }
+               drm_prime_gem_destroy(obj, rk_obj->sgt);
+       } else {
+               rockchip_gem_free_buf(rk_obj);
+       }
 
        rockchip_gem_release_object(rk_obj);
 }
@@ -451,6 +480,86 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
        return sgt;
 }
 
+static unsigned long rockchip_sg_get_contiguous_size(struct sg_table *sgt,
+                                                    int count)
+{
+       struct scatterlist *s;
+       dma_addr_t expected = sg_dma_address(sgt->sgl);
+       unsigned int i;
+       unsigned long size = 0;
+
+       for_each_sg(sgt->sgl, s, count, i) {
+               if (sg_dma_address(s) != expected)
+                       break;
+               expected = sg_dma_address(s) + sg_dma_len(s);
+               size += sg_dma_len(s);
+       }
+       return size;
+}
+
+static int
+rockchip_gem_iommu_map_sg(struct drm_device *drm,
+                         struct dma_buf_attachment *attach,
+                         struct sg_table *sg,
+                         struct rockchip_gem_object *rk_obj)
+{
+       rk_obj->sgt = sg;
+       return rockchip_gem_iommu_map(rk_obj);
+}
+
+static int
+rockchip_gem_dma_map_sg(struct drm_device *drm,
+                       struct dma_buf_attachment *attach,
+                       struct sg_table *sg,
+                       struct rockchip_gem_object *rk_obj)
+{
+       int count = dma_map_sg(drm->dev, sg->sgl, sg->nents,
+                              DMA_BIDIRECTIONAL);
+       if (!count)
+               return -EINVAL;
+
+       if (rockchip_sg_get_contiguous_size(sg, count) < attach->dmabuf->size) {
+               DRM_ERROR("failed to map sg_table to contiguous linear address.\n");
+               dma_unmap_sg(drm->dev, sg->sgl, sg->nents,
+                            DMA_BIDIRECTIONAL);
+               return -EINVAL;
+       }
+
+       rk_obj->dma_addr = sg_dma_address(sg->sgl);
+       rk_obj->sgt = sg;
+       return 0;
+}
+
+struct drm_gem_object *
+rockchip_gem_prime_import_sg_table(struct drm_device *drm,
+                                  struct dma_buf_attachment *attach,
+                                  struct sg_table *sg)
+{
+       struct rockchip_drm_private *private = drm->dev_private;
+       struct rockchip_gem_object *rk_obj;
+       int ret;
+
+       rk_obj = rockchip_gem_alloc_object(drm, attach->dmabuf->size);
+       if (IS_ERR(rk_obj))
+               return ERR_CAST(rk_obj);
+
+       if (private->domain)
+               ret = rockchip_gem_iommu_map_sg(drm, attach, sg, rk_obj);
+       else
+               ret = rockchip_gem_dma_map_sg(drm, attach, sg, rk_obj);
+
+       if (ret < 0) {
+               DRM_ERROR("failed to import sg table: %d\n", ret);
+               goto err_free_rk_obj;
+       }
+
+       return &rk_obj->base;
+
+err_free_rk_obj:
+       rockchip_gem_release_object(rk_obj);
+       return ERR_PTR(ret);
+}
+
 void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 {
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
index f237375582fb668053e2082d8a7311a2e2346aa1..d41fa65219d2323ec0484bb142c9cdc1a3991692 100644 (file)
@@ -36,8 +36,9 @@ struct rockchip_gem_object {
 
 struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj);
 struct drm_gem_object *
-rockchip_gem_prime_import_sg_table(struct drm_device *dev, size_t size,
-                                  struct sg_table *sgt);
+rockchip_gem_prime_import_sg_table(struct drm_device *dev,
+                                  struct dma_buf_attachment *attach,
+                                  struct sg_table *sg);
 void *rockchip_gem_prime_vmap(struct drm_gem_object *obj);
 void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 
index 7715853ef90ad77e7bd98d8838eec64f94a24a3f..66736227c96e4449555d508788ee4a09eb54e018 100644 (file)
@@ -95,9 +95,6 @@ struct vop {
        struct drm_device *drm_dev;
        bool is_enabled;
 
-       /* mutex vsync_ work */
-       struct mutex vsync_mutex;
-       bool vsync_work_pending;
        struct completion dsp_hold_completion;
 
        /* protected by dev->event_lock */
@@ -1555,8 +1552,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
        spin_lock_init(&vop->reg_lock);
        spin_lock_init(&vop->irq_lock);
 
-       mutex_init(&vop->vsync_mutex);
-
        ret = devm_request_irq(dev, vop->irq, vop_isr,
                               IRQF_SHARED, dev_name(dev), vop);
        if (ret)
index 882d85db90539ae1b00e194a0cae43bf8fb4918d..7327da3bc94fc3990743995d9fd13c5efa34d03d 100644 (file)
@@ -40,6 +40,15 @@ config DRM_SUN4I_BACKEND
          do some alpha blending and feed graphics to TCON. If M is
          selected the module will be called sun4i-backend.
 
+config DRM_SUN8I_DW_HDMI
+       tristate "Support for Allwinner version of DesignWare HDMI"
+       depends on DRM_SUN4I
+       select DRM_DW_HDMI
+       help
+         Choose this option if you have an Allwinner SoC with the
+         DesignWare HDMI controller with custom HDMI PHY. If M is
+         selected the module will be called sun8i_dw_hdmi.
+
 config DRM_SUN8I_MIXER
        tristate "Support for Allwinner Display Engine 2.0 Mixer"
        default MACH_SUN8I
index 582607c0c48817a98538c85100282d611d7fca9a..1610e748119b6ff3f253f7edf78525e2d0b616fe 100644 (file)
@@ -10,6 +10,9 @@ sun4i-drm-hdmi-y              += sun4i_hdmi_enc.o
 sun4i-drm-hdmi-y               += sun4i_hdmi_i2c.o
 sun4i-drm-hdmi-y               += sun4i_hdmi_tmds_clk.o
 
+sun8i-drm-hdmi-y               += sun8i_dw_hdmi.o
+sun8i-drm-hdmi-y               += sun8i_hdmi_phy.o
+
 sun8i-mixer-y                  += sun8i_mixer.o sun8i_ui_layer.o \
                                   sun8i_vi_layer.o sun8i_ui_scaler.o \
                                   sun8i_vi_scaler.o sun8i_csc.o
@@ -27,4 +30,5 @@ obj-$(CONFIG_DRM_SUN4I)               += sun6i_drc.o
 
 obj-$(CONFIG_DRM_SUN4I_BACKEND)        += sun4i-backend.o sun4i-frontend.o
 obj-$(CONFIG_DRM_SUN4I_HDMI)   += sun4i-drm-hdmi.o
+obj-$(CONFIG_DRM_SUN8I_DW_HDMI)        += sun8i-drm-hdmi.o
 obj-$(CONFIG_DRM_SUN8I_MIXER)  += sun8i-mixer.o
index 4b7340ee629091515db27957f8d215c0b996179b..0d6c5ed44795c411574910153d45c7829d1d56e9 100644 (file)
@@ -84,6 +84,7 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
 
        switch (channel) {
        case 0:
+               WARN_ON(!tcon->quirks->has_channel_0);
                regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
                                   SUN4I_TCON0_CTL_TCON_ENABLE,
                                   enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
@@ -276,6 +277,8 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
        u8 clk_delay;
        u32 reg, val = 0;
 
+       WARN_ON(!tcon->quirks->has_channel_0);
+
        tcon->dclk_min_div = 7;
        tcon->dclk_max_div = 7;
        sun4i_tcon0_mode_set_common(tcon, mode);
@@ -344,6 +347,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
        u8 clk_delay;
        u32 val = 0;
 
+       WARN_ON(!tcon->quirks->has_channel_0);
+
        tcon->dclk_min_div = 6;
        tcon->dclk_max_div = 127;
        sun4i_tcon0_mode_set_common(tcon, mode);
@@ -389,10 +394,10 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
                     SUN4I_TCON0_BASIC3_H_SYNC(hsync));
 
        /* Setup the polarity of the various signals */
-       if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
                val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
 
-       if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
                val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
 
        regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
@@ -574,10 +579,12 @@ static int sun4i_tcon_init_clocks(struct device *dev,
        }
        clk_prepare_enable(tcon->clk);
 
-       tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
-       if (IS_ERR(tcon->sclk0)) {
-               dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
-               return PTR_ERR(tcon->sclk0);
+       if (tcon->quirks->has_channel_0) {
+               tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
+               if (IS_ERR(tcon->sclk0)) {
+                       dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
+                       return PTR_ERR(tcon->sclk0);
+               }
        }
 
        if (tcon->quirks->has_channel_1) {
@@ -934,10 +941,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
                goto err_free_clocks;
        }
 
-       ret = sun4i_dclk_create(dev, tcon);
-       if (ret) {
-               dev_err(dev, "Couldn't create our TCON dot clock\n");
-               goto err_free_clocks;
+       if (tcon->quirks->has_channel_0) {
+               ret = sun4i_dclk_create(dev, tcon);
+               if (ret) {
+                       dev_err(dev, "Couldn't create our TCON dot clock\n");
+                       goto err_free_clocks;
+               }
        }
 
        ret = sun4i_tcon_init_irq(dev, tcon);
@@ -995,7 +1004,8 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
        return 0;
 
 err_free_dotclock:
-       sun4i_dclk_free(tcon);
+       if (tcon->quirks->has_channel_0)
+               sun4i_dclk_free(tcon);
 err_free_clocks:
        sun4i_tcon_free_clocks(tcon);
 err_assert_reset:
@@ -1009,7 +1019,8 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
        struct sun4i_tcon *tcon = dev_get_drvdata(dev);
 
        list_del(&tcon->list);
-       sun4i_dclk_free(tcon);
+       if (tcon->quirks->has_channel_0)
+               sun4i_dclk_free(tcon);
        sun4i_tcon_free_clocks(tcon);
 }
 
@@ -1106,16 +1117,19 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
 }
 
 static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
+       .has_channel_0          = true,
        .has_channel_1          = true,
        .set_mux                = sun4i_a10_tcon_set_mux,
 };
 
 static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
+       .has_channel_0          = true,
        .has_channel_1          = true,
        .set_mux                = sun5i_a13_tcon_set_mux,
 };
 
 static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
+       .has_channel_0          = true,
        .has_channel_1          = true,
        .has_lvds_alt           = true,
        .needs_de_be_mux        = true,
@@ -1123,26 +1137,33 @@ static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
 };
 
 static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
+       .has_channel_0          = true,
        .has_channel_1          = true,
        .needs_de_be_mux        = true,
 };
 
 static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
+       .has_channel_0          = true,
        .has_channel_1          = true,
        /* Same display pipeline structure as A10 */
        .set_mux                = sun4i_a10_tcon_set_mux,
 };
 
 static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
+       .has_channel_0          = true,
        .has_lvds_alt           = true,
 };
 
 static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
-       /* nothing is supported */
+       .has_channel_0          = true,
+};
+
+static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
+       .has_channel_1          = true,
 };
 
 static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
-       /* nothing is supported */
+       .has_channel_0          = true,
 };
 
 /* sun4i_drv uses this list to check if a device node is a TCON */
@@ -1154,6 +1175,7 @@ const struct of_device_id sun4i_tcon_of_table[] = {
        { .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
        { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
        { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
+       { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
        { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
        { }
 };
index b761c7b823c560536b0f44a3c6eab6337d3e32d7..78d55e7cd2b3d286b6d16c19a94c28e55a50c91c 100644 (file)
 struct sun4i_tcon;
 
 struct sun4i_tcon_quirks {
+       bool    has_channel_0;  /* a83t does not have channel 0 on second TCON */
        bool    has_channel_1;  /* a33 does not have channel 1 */
        bool    has_lvds_alt;   /* Does the LVDS clock have a parent other than the TCON clock? */
        bool    needs_de_be_mux; /* sun6i needs mux to select backend */
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
new file mode 100644 (file)
index 0000000..9f40a44
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "sun8i_dw_hdmi.h"
+
+static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+                                          struct drm_display_mode *mode,
+                                          struct drm_display_mode *adj_mode)
+{
+       struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
+
+       clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
+}
+
+static const struct drm_encoder_helper_funcs
+sun8i_dw_hdmi_encoder_helper_funcs = {
+       .mode_set = sun8i_dw_hdmi_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+static enum drm_mode_status
+sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
+                        const struct drm_display_mode *mode)
+{
+       if (mode->clock > 297000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
+                             void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct dw_hdmi_plat_data *plat_data;
+       struct drm_device *drm = data;
+       struct device_node *phy_node;
+       struct drm_encoder *encoder;
+       struct sun8i_dw_hdmi *hdmi;
+       int ret;
+
+       if (!pdev->dev.of_node)
+               return -ENODEV;
+
+       hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+       if (!hdmi)
+               return -ENOMEM;
+
+       plat_data = &hdmi->plat_data;
+       hdmi->dev = &pdev->dev;
+       encoder = &hdmi->encoder;
+
+       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+       /*
+        * If we failed to find the CRTC(s) which this encoder is
+        * supposed to be connected to, it's because the CRTC has
+        * not been registered yet.  Defer probing, and hope that
+        * the required CRTC is added later.
+        */
+       if (encoder->possible_crtcs == 0)
+               return -EPROBE_DEFER;
+
+       hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl");
+       if (IS_ERR(hdmi->rst_ctrl)) {
+               dev_err(dev, "Could not get ctrl reset control\n");
+               return PTR_ERR(hdmi->rst_ctrl);
+       }
+
+       hdmi->clk_tmds = devm_clk_get(dev, "tmds");
+       if (IS_ERR(hdmi->clk_tmds)) {
+               dev_err(dev, "Couldn't get the tmds clock\n");
+               return PTR_ERR(hdmi->clk_tmds);
+       }
+
+       ret = reset_control_deassert(hdmi->rst_ctrl);
+       if (ret) {
+               dev_err(dev, "Could not deassert ctrl reset control\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(hdmi->clk_tmds);
+       if (ret) {
+               dev_err(dev, "Could not enable tmds clock\n");
+               goto err_assert_ctrl_reset;
+       }
+
+       phy_node = of_parse_phandle(dev->of_node, "phys", 0);
+       if (!phy_node) {
+               dev_err(dev, "Can't found PHY phandle\n");
+               goto err_disable_clk_tmds;
+       }
+
+       ret = sun8i_hdmi_phy_probe(hdmi, phy_node);
+       of_node_put(phy_node);
+       if (ret) {
+               dev_err(dev, "Couldn't get the HDMI PHY\n");
+               goto err_disable_clk_tmds;
+       }
+
+       drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
+       drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS, NULL);
+
+       sun8i_hdmi_phy_init(hdmi->phy);
+
+       plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid;
+       plat_data->phy_ops = sun8i_hdmi_phy_get_ops();
+       plat_data->phy_name = "sun8i_dw_hdmi_phy";
+       plat_data->phy_data = hdmi->phy;
+
+       platform_set_drvdata(pdev, hdmi);
+
+       hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+
+       /*
+        * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
+        * which would have called the encoder cleanup.  Do it manually.
+        */
+       if (IS_ERR(hdmi->hdmi)) {
+               ret = PTR_ERR(hdmi->hdmi);
+               goto cleanup_encoder;
+       }
+
+       return 0;
+
+cleanup_encoder:
+       drm_encoder_cleanup(encoder);
+       sun8i_hdmi_phy_remove(hdmi);
+err_disable_clk_tmds:
+       clk_disable_unprepare(hdmi->clk_tmds);
+err_assert_ctrl_reset:
+       reset_control_assert(hdmi->rst_ctrl);
+
+       return ret;
+}
+
+static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
+                                void *data)
+{
+       struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+       dw_hdmi_unbind(hdmi->hdmi);
+       sun8i_hdmi_phy_remove(hdmi);
+       clk_disable_unprepare(hdmi->clk_tmds);
+       reset_control_assert(hdmi->rst_ctrl);
+}
+
+static const struct component_ops sun8i_dw_hdmi_ops = {
+       .bind   = sun8i_dw_hdmi_bind,
+       .unbind = sun8i_dw_hdmi_unbind,
+};
+
+static int sun8i_dw_hdmi_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &sun8i_dw_hdmi_ops);
+}
+
+static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &sun8i_dw_hdmi_ops);
+
+       return 0;
+}
+
+static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
+       { .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
+
+struct platform_driver sun8i_dw_hdmi_pltfm_driver = {
+       .probe  = sun8i_dw_hdmi_probe,
+       .remove = sun8i_dw_hdmi_remove,
+       .driver = {
+               .name = "sun8i-dw-hdmi",
+               .of_match_table = sun8i_dw_hdmi_dt_ids,
+       },
+};
+module_platform_driver(sun8i_dw_hdmi_pltfm_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner DW HDMI bridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
new file mode 100644 (file)
index 0000000..d8d0684
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef _SUN8I_DW_HDMI_H_
+#define _SUN8I_DW_HDMI_H_
+
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_encoder.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+struct sun8i_hdmi_phy {
+       struct clk              *clk_bus;
+       struct clk              *clk_mod;
+       struct regmap           *regs;
+       struct reset_control    *rst_phy;
+};
+
+struct sun8i_dw_hdmi {
+       struct clk                      *clk_tmds;
+       struct device                   *dev;
+       struct dw_hdmi                  *hdmi;
+       struct drm_encoder              encoder;
+       struct sun8i_hdmi_phy           *phy;
+       struct dw_hdmi_plat_data        plat_data;
+       struct reset_control            *rst_ctrl;
+};
+
+static inline struct sun8i_dw_hdmi *
+encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)
+{
+       return container_of(encoder, struct sun8i_dw_hdmi, encoder);
+}
+
+int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
+void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
+
+void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
+const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
+
+#endif /* _SUN8I_DW_HDMI_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
new file mode 100644 (file)
index 0000000..e5bfcdd
--- /dev/null
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/of_address.h>
+
+#include "sun8i_dw_hdmi.h"
+
+#define SUN8I_HDMI_PHY_DBG_CTRL_REG    0x0000
+#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK                BIT(0)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK       GENMASK(15, 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL(val)       (val << 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK      GENMASK(23, 16)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr)     (addr << 16)
+
+#define SUN8I_HDMI_PHY_REXT_CTRL_REG   0x0004
+#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN       BIT(31)
+
+#define SUN8I_HDMI_PHY_READ_EN_REG     0x0010
+#define SUN8I_HDMI_PHY_READ_EN_MAGIC           0x54524545
+
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG  0x0014
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC                0x42494E47
+
+/*
+ * Address can be actually any value. Here is set to same value as
+ * it is set in BSP driver.
+ */
+#define I2C_ADDR       0x69
+
+static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
+                                struct drm_display_mode *mode)
+{
+       struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
+       u32 val = 0;
+
+       if ((mode->flags & DRM_MODE_FLAG_NHSYNC) &&
+           (mode->flags & DRM_MODE_FLAG_NHSYNC)) {
+               val = 0x03;
+       }
+
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+                          SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK,
+                          SUN8I_HDMI_PHY_DBG_CTRL_POL(val));
+
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+                          SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
+                          SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
+
+       /* power down */
+       dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+       dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+       dw_hdmi_phy_reset(hdmi);
+
+       dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+       dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
+
+       /*
+        * Values are taken from BSP HDMI driver. Although AW didn't
+        * release any documentation, explanation of this values can
+        * be found in i.MX 6Dual/6Quad Reference Manual.
+        */
+       if (mode->crtc_clock <= 27000) {
+               dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+               dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
+               dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+       } else if (mode->crtc_clock <= 74250) {
+               dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
+               dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
+               dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+       } else if (mode->crtc_clock <= 148500) {
+               dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
+               dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
+               dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
+       } else {
+               dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
+               dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
+               dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
+               dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
+       }
+
+       dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
+       dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+       dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
+
+       dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+
+       return 0;
+};
+
+static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
+{
+       struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
+
+       dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+       dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+                          SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
+}
+
+static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
+       .init = &sun8i_hdmi_phy_config,
+       .disable = &sun8i_hdmi_phy_disable,
+       .read_hpd = &dw_hdmi_phy_read_hpd,
+       .update_hpd = &dw_hdmi_phy_update_hpd,
+       .setup_hpd = &dw_hdmi_phy_setup_hpd,
+};
+
+void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
+{
+       /* enable read access to HDMI controller */
+       regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
+                    SUN8I_HDMI_PHY_READ_EN_MAGIC);
+
+       /* unscramble register offsets */
+       regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+                    SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
+
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+                          SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
+                          SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
+
+       /*
+        * Set PHY I2C address. It must match to the address set by
+        * dw_hdmi_phy_set_slave_addr().
+        */
+       regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+                          SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK,
+                          SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
+}
+
+const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
+{
+       return &sun8i_hdmi_phy_ops;
+}
+
+static struct regmap_config sun8i_hdmi_phy_regmap_config = {
+       .reg_bits       = 32,
+       .val_bits       = 32,
+       .reg_stride     = 4,
+       .max_register   = SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+       .name           = "phy"
+};
+
+static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
+       { .compatible = "allwinner,sun8i-a83t-hdmi-phy" },
+       { /* sentinel */ }
+};
+
+int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
+{
+       struct device *dev = hdmi->dev;
+       struct sun8i_hdmi_phy *phy;
+       struct resource res;
+       void __iomem *regs;
+       int ret;
+
+       if (!of_match_node(sun8i_hdmi_phy_of_table, node)) {
+               dev_err(dev, "Incompatible HDMI PHY\n");
+               return -EINVAL;
+       }
+
+       phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return -ENOMEM;
+
+       ret = of_address_to_resource(node, 0, &res);
+       if (ret) {
+               dev_err(dev, "phy: Couldn't get our resources\n");
+               return ret;
+       }
+
+       regs = devm_ioremap_resource(dev, &res);
+       if (IS_ERR(regs)) {
+               dev_err(dev, "Couldn't map the HDMI PHY registers\n");
+               return PTR_ERR(regs);
+       }
+
+       phy->regs = devm_regmap_init_mmio(dev, regs,
+                                         &sun8i_hdmi_phy_regmap_config);
+       if (IS_ERR(phy->regs)) {
+               dev_err(dev, "Couldn't create the HDMI PHY regmap\n");
+               return PTR_ERR(phy->regs);
+       }
+
+       phy->clk_bus = of_clk_get_by_name(node, "bus");
+       if (IS_ERR(phy->clk_bus)) {
+               dev_err(dev, "Could not get bus clock\n");
+               return PTR_ERR(phy->clk_bus);
+       }
+
+       phy->clk_mod = of_clk_get_by_name(node, "mod");
+       if (IS_ERR(phy->clk_mod)) {
+               dev_err(dev, "Could not get mod clock\n");
+               ret = PTR_ERR(phy->clk_mod);
+               goto err_put_clk_bus;
+       }
+
+       phy->rst_phy = of_reset_control_get_shared(node, "phy");
+       if (IS_ERR(phy->rst_phy)) {
+               dev_err(dev, "Could not get phy reset control\n");
+               ret = PTR_ERR(phy->rst_phy);
+               goto err_put_clk_mod;
+       }
+
+       ret = reset_control_deassert(phy->rst_phy);
+       if (ret) {
+               dev_err(dev, "Cannot deassert phy reset control: %d\n", ret);
+               goto err_put_rst_phy;
+       }
+
+       ret = clk_prepare_enable(phy->clk_bus);
+       if (ret) {
+               dev_err(dev, "Cannot enable bus clock: %d\n", ret);
+               goto err_deassert_rst_phy;
+       }
+
+       ret = clk_prepare_enable(phy->clk_mod);
+       if (ret) {
+               dev_err(dev, "Cannot enable mod clock: %d\n", ret);
+               goto err_disable_clk_bus;
+       }
+
+       hdmi->phy = phy;
+
+       return 0;
+
+err_disable_clk_bus:
+       clk_disable_unprepare(phy->clk_bus);
+err_deassert_rst_phy:
+       reset_control_assert(phy->rst_phy);
+err_put_rst_phy:
+       reset_control_put(phy->rst_phy);
+err_put_clk_mod:
+       clk_put(phy->clk_mod);
+err_put_clk_bus:
+       clk_put(phy->clk_bus);
+
+       return ret;
+}
+
+void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)
+{
+       struct sun8i_hdmi_phy *phy = hdmi->phy;
+
+       clk_disable_unprepare(phy->clk_mod);
+       clk_disable_unprepare(phy->clk_bus);
+
+       reset_control_assert(phy->rst_phy);
+
+       reset_control_put(phy->rst_phy);
+
+       clk_put(phy->clk_mod);
+       clk_put(phy->clk_bus);
+}
index 2cbb2de6d39c83c372cc4db7e346c1b10ca4e823..9b0256d31a61ba8fc346af440032f9a578da6d79 100644 (file)
@@ -485,6 +485,13 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
        .vi_num         = 1,
 };
 
+static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
+       .ccsc           = 1,
+       .scaler_mask    = 0x3,
+       .ui_num         = 1,
+       .vi_num         = 1,
+};
+
 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
        .vi_num = 2,
        .ui_num = 1,
@@ -498,6 +505,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
                .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
                .data = &sun8i_a83t_mixer0_cfg,
        },
+       {
+               .compatible = "allwinner,sun8i-a83t-de2-mixer-1",
+               .data = &sun8i_a83t_mixer1_cfg,
+       },
        {
                .compatible = "allwinner,sun8i-v3s-de2-mixer",
                .data = &sun8i_v3s_mixer_cfg,
index b0e567d416b36fd71bfae437645cece685239bb9..13339be843bcbcb3127eb5ad683a2614fdad54d5 100644 (file)
@@ -3,8 +3,6 @@ menuconfig DRM_TINYDRM
        depends on DRM
        select DRM_KMS_HELPER
        select DRM_KMS_CMA_HELPER
-       select BACKLIGHT_LCD_SUPPORT
-       select BACKLIGHT_CLASS_DEVICE
        help
          Choose this option if you have a tinydrm supported display.
          If M is selected the module will be called tinydrm.
index bf96072d1b9709a11d356bc8d1e25fb6adba1d22..d1c3ce9ab294344e23bdc94b909fe4b14858c699 100644 (file)
@@ -236,101 +236,6 @@ void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(tinydrm_xrgb8888_to_gray8);
 
-/**
- * tinydrm_of_find_backlight - Find backlight device in device-tree
- * @dev: Device
- *
- * This function looks for a DT node pointed to by a property named 'backlight'
- * and uses of_find_backlight_by_node() to get the backlight device.
- * Additionally if the brightness property is zero, it is set to
- * max_brightness.
- *
- * Returns:
- * NULL if there's no backlight property.
- * Error pointer -EPROBE_DEFER if the DT node is found, but no backlight device
- * is found.
- * If the backlight device is found, a pointer to the structure is returned.
- */
-struct backlight_device *tinydrm_of_find_backlight(struct device *dev)
-{
-       struct backlight_device *backlight;
-       struct device_node *np;
-
-       np = of_parse_phandle(dev->of_node, "backlight", 0);
-       if (!np)
-               return NULL;
-
-       backlight = of_find_backlight_by_node(np);
-       of_node_put(np);
-
-       if (!backlight)
-               return ERR_PTR(-EPROBE_DEFER);
-
-       if (!backlight->props.brightness) {
-               backlight->props.brightness = backlight->props.max_brightness;
-               DRM_DEBUG_KMS("Backlight brightness set to %d\n",
-                             backlight->props.brightness);
-       }
-
-       return backlight;
-}
-EXPORT_SYMBOL(tinydrm_of_find_backlight);
-
-/**
- * tinydrm_enable_backlight - Enable backlight helper
- * @backlight: Backlight device
- *
- * Returns:
- * Zero on success, negative error code on failure.
- */
-int tinydrm_enable_backlight(struct backlight_device *backlight)
-{
-       unsigned int old_state;
-       int ret;
-
-       if (!backlight)
-               return 0;
-
-       old_state = backlight->props.state;
-       backlight->props.state &= ~BL_CORE_FBBLANK;
-       DRM_DEBUG_KMS("Backlight state: 0x%x -> 0x%x\n", old_state,
-                     backlight->props.state);
-
-       ret = backlight_update_status(backlight);
-       if (ret)
-               DRM_ERROR("Failed to enable backlight %d\n", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL(tinydrm_enable_backlight);
-
-/**
- * tinydrm_disable_backlight - Disable backlight helper
- * @backlight: Backlight device
- *
- * Returns:
- * Zero on success, negative error code on failure.
- */
-int tinydrm_disable_backlight(struct backlight_device *backlight)
-{
-       unsigned int old_state;
-       int ret;
-
-       if (!backlight)
-               return 0;
-
-       old_state = backlight->props.state;
-       backlight->props.state |= BL_CORE_FBBLANK;
-       DRM_DEBUG_KMS("Backlight state: 0x%x -> 0x%x\n", old_state,
-                     backlight->props.state);
-       ret = backlight_update_status(backlight);
-       if (ret)
-               DRM_ERROR("Failed to disable backlight %d\n", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL(tinydrm_disable_backlight);
-
 #if IS_ENABLED(CONFIG_SPI)
 
 /**
index 79cb5af5abacd33f5eca15f24944a62f73e74618..d8ed6e6f8e059d50894a19fe49205db3da3d6705 100644 (file)
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/backlight.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
@@ -195,7 +196,7 @@ static int mi0283qt_probe(struct spi_device *spi)
        if (IS_ERR(mipi->regulator))
                return PTR_ERR(mipi->regulator);
 
-       mipi->backlight = tinydrm_of_find_backlight(dev);
+       mipi->backlight = devm_of_find_backlight(dev);
        if (IS_ERR(mipi->backlight))
                return PTR_ERR(mipi->backlight);
 
index 75dd65c57e74be09804157b087484635b6fd8692..9e903812b573185f6cf96b8779b5c7acc90ac760 100644 (file)
@@ -286,7 +286,7 @@ void mipi_dbi_enable_flush(struct mipi_dbi *mipi)
        if (fb)
                fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
 
-       tinydrm_enable_backlight(mipi->backlight);
+       backlight_enable(mipi->backlight);
 }
 EXPORT_SYMBOL(mipi_dbi_enable_flush);
 
@@ -325,7 +325,7 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
        mipi->enabled = false;
 
        if (mipi->backlight)
-               tinydrm_disable_backlight(mipi->backlight);
+               backlight_disable(mipi->backlight);
        else
                mipi_dbi_blank(mipi);
 
index 08b4fb18edb657f57df55b6cedc67bccdd11d4ee..67d197ecfc4b07cf20508a6a3e874e539f68ce2f 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright 2017 David Lechner <david@lechnology.com>
  */
 
+#include <linux/backlight.h>
 #include <linux/delay.h>
 #include <linux/dma-buf.h>
 #include <linux/gpio/consumer.h>
@@ -163,7 +164,7 @@ static int st7735r_probe(struct spi_device *spi)
                return PTR_ERR(dc);
        }
 
-       mipi->backlight = tinydrm_of_find_backlight(dev);
+       mipi->backlight = devm_of_find_backlight(dev);
        if (IS_ERR(mipi->backlight))
                return PTR_ERR(mipi->backlight);
 
index 8049e7656daa758dd1bceee187426b2afc40493c..deb824bef6e21015c83d4e846f130e5ff13f59e0 100644 (file)
@@ -580,6 +580,79 @@ struct backlight_device *of_find_backlight_by_node(struct device_node *node)
 EXPORT_SYMBOL(of_find_backlight_by_node);
 #endif
 
+/**
+ * of_find_backlight - Get backlight device
+ * @dev: Device
+ *
+ * This function looks for a property named 'backlight' on the DT node
+ * connected to @dev and looks up the backlight device.
+ *
+ * Call backlight_put() to drop the reference on the backlight device.
+ *
+ * Returns:
+ * A pointer to the backlight device if found.
+ * Error pointer -EPROBE_DEFER if the DT property is set, but no backlight
+ * device is found.
+ * NULL if there's no backlight property.
+ */
+struct backlight_device *of_find_backlight(struct device *dev)
+{
+       struct backlight_device *bd = NULL;
+       struct device_node *np;
+
+       if (!dev)
+               return NULL;
+
+       if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+               np = of_parse_phandle(dev->of_node, "backlight", 0);
+               if (np) {
+                       bd = of_find_backlight_by_node(np);
+                       of_node_put(np);
+                       if (!bd)
+                               return ERR_PTR(-EPROBE_DEFER);
+                       /*
+                        * Note: gpio_backlight uses brightness as
+                        * power state during probe
+                        */
+                       if (!bd->props.brightness)
+                               bd->props.brightness = bd->props.max_brightness;
+               }
+       }
+
+       return bd;
+}
+EXPORT_SYMBOL(of_find_backlight);
+
+static void devm_backlight_release(void *data)
+{
+       backlight_put(data);
+}
+
+/**
+ * devm_of_find_backlight - Resource-managed of_find_backlight()
+ * @dev: Device
+ *
+ * Device managed version of of_find_backlight().
+ * The reference on the backlight device is automatically
+ * dropped on driver detach.
+ */
+struct backlight_device *devm_of_find_backlight(struct device *dev)
+{
+       struct backlight_device *bd;
+       int ret;
+
+       bd = of_find_backlight(dev);
+       if (IS_ERR_OR_NULL(bd))
+               return bd;
+       ret = devm_add_action(dev, devm_backlight_release, bd);
+       if (ret) {
+               backlight_put(bd);
+               return ERR_PTR(ret);
+       }
+       return bd;
+}
+EXPORT_SYMBOL(devm_of_find_backlight);
+
 static void __exit backlight_class_exit(void)
 {
        class_destroy(backlight_class);
index 182f83283e247d70a2fa592c71ec5c484a551d66..dd2a8cf7d20b8d6becb6b65bcbd38efb0fd35854 100644 (file)
@@ -143,12 +143,13 @@ struct dw_hdmi_plat_data {
                             unsigned long mpixelclock);
 };
 
-int dw_hdmi_probe(struct platform_device *pdev,
-                 const struct dw_hdmi_plat_data *plat_data);
-void dw_hdmi_remove(struct platform_device *pdev);
-void dw_hdmi_unbind(struct device *dev);
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-                const struct dw_hdmi_plat_data *plat_data);
+struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
+                             const struct dw_hdmi_plat_data *plat_data);
+void dw_hdmi_remove(struct dw_hdmi *hdmi);
+void dw_hdmi_unbind(struct dw_hdmi *hdmi);
+struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
+                            struct drm_encoder *encoder,
+                            const struct dw_hdmi_plat_data *plat_data);
 
 void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
 
@@ -157,7 +158,18 @@ void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
 void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
 
 /* PHY configuration */
+void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
 void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
                           unsigned char addr);
 
+void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable);
+void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable);
+void dw_hdmi_phy_reset(struct dw_hdmi *hdmi);
+
+enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
+                                              void *data);
+void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
+                           bool force, bool disabled, bool rxsense);
+void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
+
 #endif /* __IMX_HDMI_H__ */
index 758a176e7b571ccd5212633362fcfd4fdf71db6b..675cc3f8cf85292ce19aadee37d32f1f143771d8 100644 (file)
@@ -342,7 +342,11 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
 /**
  * struct drm_tv_connector_state - TV connector related states
  * @subconnector: selected subconnector
- * @margins: left/right/top/bottom margins
+ * @margins: margins
+ * @margins.left: left margin
+ * @margins.right: right margin
+ * @margins.top: top margin
+ * @margins.bottom: bottom margin
  * @mode: TV mode
  * @brightness: brightness in percent
  * @contrast: contrast in percent
index c239e6e24a1014504cb0a04d17a9b194782c6d41..4de97e94ef9dd980de0ae15030ca70f5fee54add 100644 (file)
 # define DP_DS_12BPC                       2
 # define DP_DS_16BPC                       3
 
+/* DP Forward error Correction Registers */
+#define DP_FEC_CAPABILITY                  0x090    /* 1.4 */
+# define DP_FEC_CAPABLE                            (1 << 0)
+# define DP_FEC_UNCORR_BLK_ERROR_COUNT_CAP  (1 << 1)
+# define DP_FEC_CORR_BLK_ERROR_COUNT_CAP    (1 << 2)
+# define DP_FEC_BIT_ERROR_COUNT_CAP        (1 << 3)
+
 /* link configuration */
 #define        DP_LINK_BW_SET                      0x100
 # define DP_LINK_RATE_TABLE                0x00    /* eDP 1.4 */
 #define DP_UPSTREAM_DEVICE_DP_PWR_NEED     0x118   /* 1.2 */
 # define DP_PWR_NOT_NEEDED                 (1 << 0)
 
+#define DP_FEC_CONFIGURATION               0x120    /* 1.4 */
+# define DP_FEC_READY                      (1 << 0)
+# define DP_FEC_ERR_COUNT_SEL_MASK         (7 << 1)
+# define DP_FEC_ERR_COUNT_DIS              (0 << 1)
+# define DP_FEC_UNCORR_BLK_ERROR_COUNT     (1 << 1)
+# define DP_FEC_CORR_BLK_ERROR_COUNT       (2 << 1)
+# define DP_FEC_BIT_ERROR_COUNT                    (3 << 1)
+# define DP_FEC_LANE_SELECT_MASK           (3 << 4)
+# define DP_FEC_LANE_0_SELECT              (0 << 4)
+# define DP_FEC_LANE_1_SELECT              (1 << 4)
+# define DP_FEC_LANE_2_SELECT              (2 << 4)
+# define DP_FEC_LANE_3_SELECT              (3 << 4)
+
 #define DP_AUX_FRAME_SYNC_VALUE                    0x15c   /* eDP 1.4 */
 # define DP_AUX_FRAME_SYNC_VALID           (1 << 0)
 
 #define DP_TEST_SINK                       0x270
 # define DP_TEST_SINK_START                (1 << 0)
 
+#define DP_FEC_STATUS                      0x280    /* 1.4 */
+# define DP_FEC_DECODE_EN_DETECTED         (1 << 0)
+# define DP_FEC_DECODE_DIS_DETECTED        (1 << 1)
+
+#define DP_FEC_ERROR_COUNT_LSB             0x0281    /* 1.4 */
+
+#define DP_FEC_ERROR_COUNT_MSB             0x0282    /* 1.4 */
+# define DP_FEC_ERROR_COUNT_MASK           0x7F
+# define DP_FEC_ERR_COUNT_VALID                    (1 << 7)
+
 #define DP_PAYLOAD_TABLE_UPDATE_STATUS      0x2c0   /* 1.2 MST */
 # define DP_PAYLOAD_TABLE_UPDATED           (1 << 0)
 # define DP_PAYLOAD_ACT_HANDLED             (1 << 1)
index 6d9adbb46293310cb09780ec509f048b94642a41..d9e4c3c3f0094015c6b8e882109e603225399cec 100644 (file)
@@ -21,6 +21,20 @@ struct drm_simple_display_pipe;
  *                                        display pipeline
  */
 struct drm_simple_display_pipe_funcs {
+       /**
+        * @mode_valid:
+        *
+        * This function is called to filter out valid modes from the
+        * suggestions suggested by the bridge or display. This optional
+        * hook is passed in when initializing the pipeline.
+        *
+        * RETURNS:
+        *
+        * drm_mode_status Enum
+        */
+       enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
+                                          const struct drm_display_mode *mode);
+
        /**
         * @enable:
         *
index 848b463a0af516ebd9894cf7917cff8eeb2cde9e..425ad80ed2ac03783a2603cf9cd8205628872498 100644 (file)
@@ -55,8 +55,24 @@ struct drm_pending_vblank_event {
         * @event: Actual event which will be sent to userspace.
         */
        union {
+               /**
+                * @event.base: DRM event base class.
+                */
                struct drm_event base;
+
+               /**
+                * @event.vbl:
+                *
+                * Event payload for vblank events, requested through
+                * either the MODE_PAGE_FLIP or MODE_ATOMIC IOCTL. Also
+                * generated by the legacy WAIT_VBLANK IOCTL, but new userspace
+                * should use MODE_QUEUE_SEQUENCE and &event.seq instead.
+                */
                struct drm_event_vblank vbl;
+
+               /**
+                * @event.seq: Event payload for the MODE_QUEUEU_SEQUENCE IOCTL.
+                */
                struct drm_event_crtc_sequence seq;
        } event;
 };
index d554ded60ee989a087fe16b6cef5b636d18e9174..0a4ddbc04c603ae3bd4052106a88d2c1e37d1e11 100644 (file)
@@ -46,10 +46,6 @@ void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
 void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
                               struct drm_clip_rect *clip);
 
-struct backlight_device *tinydrm_of_find_backlight(struct device *dev);
-int tinydrm_enable_backlight(struct backlight_device *backlight);
-int tinydrm_disable_backlight(struct backlight_device *backlight);
-
 size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len);
 bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw);
 int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz,
index af70035485937a696812925f27e8d703537f3474..2baab6f3861d20ec998266dd0d36e30b3f446262 100644 (file)
@@ -130,6 +130,48 @@ static inline int backlight_update_status(struct backlight_device *bd)
        return ret;
 }
 
+/**
+ * backlight_enable - Enable backlight
+ * @bd: the backlight device to enable
+ */
+static inline int backlight_enable(struct backlight_device *bd)
+{
+       if (!bd)
+               return 0;
+
+       bd->props.power = FB_BLANK_UNBLANK;
+       bd->props.fb_blank = FB_BLANK_UNBLANK;
+       bd->props.state &= ~BL_CORE_FBBLANK;
+
+       return backlight_update_status(bd);
+}
+
+/**
+ * backlight_disable - Disable backlight
+ * @bd: the backlight device to disable
+ */
+static inline int backlight_disable(struct backlight_device *bd)
+{
+       if (!bd)
+               return 0;
+
+       bd->props.power = FB_BLANK_POWERDOWN;
+       bd->props.fb_blank = FB_BLANK_POWERDOWN;
+       bd->props.state |= BL_CORE_FBBLANK;
+
+       return backlight_update_status(bd);
+}
+
+/**
+ * backlight_put - Drop backlight reference
+ * @bd: the backlight device to put
+ */
+static inline void backlight_put(struct backlight_device *bd)
+{
+       if (bd)
+               put_device(&bd->dev);
+}
+
 extern struct backlight_device *backlight_device_register(const char *name,
        struct device *dev, void *devdata, const struct backlight_ops *ops,
        const struct backlight_properties *props);
@@ -173,4 +215,20 @@ of_find_backlight_by_node(struct device_node *node)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+struct backlight_device *of_find_backlight(struct device *dev);
+struct backlight_device *devm_of_find_backlight(struct device *dev);
+#else
+static inline struct backlight_device *of_find_backlight(struct device *dev)
+{
+       return NULL;
+}
+
+static inline struct backlight_device *
+devm_of_find_backlight(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 #endif