Merge tag 'drm-misc-next-2017-01-23' of git://anongit.freedesktop.org/git/drm-misc...
authorDave Airlie <airlied@redhat.com>
Fri, 27 Jan 2017 02:10:24 +0000 (12:10 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 27 Jan 2017 02:10:24 +0000 (12:10 +1000)
- cleanups&fixes for dw-hdmi bride driver (Laurent)
- updates for adv bridge driver (John Stultz) for nexus
- drm_crtc_from_index helper rollout (Shawn Guo)
- removing drm_framebuffer_unregister_private from drivers&core
- target_vblank (Andrey Grodzovsky)
- misc tiny stuff

* tag 'drm-misc-next-2017-01-23' of git://anongit.freedesktop.org/git/drm-misc: (49 commits)
  drm: qxl: Open code teardown function for qxl
  drm: qxl: Open code probing sequence for qxl
  drm/bridge: adv7511: Re-write the i2c address before EDID probing
  drm/bridge: adv7511: Reuse __adv7511_power_on/off() when probing EDID
  drm/bridge: adv7511: Rework adv7511_power_on/off() so they can be reused internally
  drm/bridge: adv7511: Enable HPD interrupts to support hotplug and improve monitor detection
  drm/bridge: adv7511: Switch to using drm_kms_helper_hotplug_event()
  drm/bridge: adv7511: Use work_struct to defer hotplug handing to out of irq context
  drm: vc4: use crtc helper drm_crtc_from_index()
  drm: tegra: use crtc helper drm_crtc_from_index()
  drm: nouveau: use crtc helper drm_crtc_from_index()
  drm: mediatek: use crtc helper drm_crtc_from_index()
  drm: kirin: use crtc helper drm_crtc_from_index()
  drm: exynos: use crtc helper drm_crtc_from_index()
  dt-bindings: display: dw-hdmi: Clean up DT bindings documentation
  drm: bridge: dw-hdmi: Assert SVSRET before resetting the PHY
  drm: bridge: dw-hdmi: Fix the name of the PHY reset macros
  drm: bridge: dw-hdmi: Define and use macros for PHY register addresses
  drm: bridge: dw-hdmi: Detect PHY type at runtime
  drm: bridge: dw-hdmi: Handle overflow workaround based on device version
  ...

47 files changed:
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt
Documentation/devicetree/bindings/display/imx/hdmi.txt
Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
Documentation/gpu/drm-mm.rst
drivers/gpu/drm/Kconfig
drivers/gpu/drm/armada/Kconfig
drivers/gpu/drm/bridge/adv7511/adv7511.h
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
drivers/gpu/drm/bridge/dw-hdmi.c
drivers/gpu/drm/bridge/dw-hdmi.h
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/etnaviv/Kconfig
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/imx/dw_hdmi-imx.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/gpu/drm/mediatek/mtk_drm_drv.h
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/qxl/qxl_debugfs.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_drv.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_kms.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/selftests/test-drm_mm.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/fb.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vgem/vgem_drv.h
include/drm/bridge/dw_hdmi.h
include/drm/drmP.h
include/drm/drm_atomic_helper.h
include/drm/drm_cache.h
include/drm/drm_crtc.h
include/uapi/drm/drm_fourcc.h

index 6532a59..00ea670 100644 (file)
@@ -38,10 +38,22 @@ The following input format properties are required except in "rgb 1x" and
 - adi,input-justification: The input bit justification ("left", "evenly",
   "right").
 
+- avdd-supply: A 1.8V supply that powers up the AVDD pin on the chip.
+- dvdd-supply: A 1.8V supply that powers up the DVDD pin on the chip.
+- pvdd-supply: A 1.8V supply that powers up the PVDD pin on the chip.
+- dvdd-3v-supply: A 3.3V supply that powers up the pin called DVDD_3V
+  on the chip.
+- bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is
+  needed only for ADV7511.
+
 The following properties are required for ADV7533:
 
 - adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should
   be one of 1, 2, 3 or 4.
+- a2vdd-supply: 1.8V supply that powers up the A2VDD pin on the chip.
+- v3p3-supply: A 3.3V supply that powers up the V3P3 pin on the chip.
+- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
+  either 1.2V or 1.8V.
 
 Optional properties:
 
index 5e9a84d..33bf981 100644 (file)
@@ -1,52 +1,33 @@
-DesignWare HDMI bridge bindings
-
-Required properties:
-- compatible: platform specific such as:
-   * "snps,dw-hdmi-tx"
-   * "fsl,imx6q-hdmi"
-   * "fsl,imx6dl-hdmi"
-   * "rockchip,rk3288-dw-hdmi"
-- reg: Physical base address and length of the controller's registers.
-- interrupts: The HDMI interrupt number
-- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
-  as described in Documentation/devicetree/bindings/clock/clock-bindings.txt,
-  the clocks are soc specific, the clock-names should be "iahb", "isfr"
--port@[X]: SoC specific port nodes with endpoint definitions as defined
-   in Documentation/devicetree/bindings/media/video-interfaces.txt,
-   please refer to the SoC specific binding document:
-    * Documentation/devicetree/bindings/display/imx/hdmi.txt
-    * Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
-
-Optional properties
-- reg-io-width: the width of the reg:1,4, default set to 1 if not present
-- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing,
-  if the property is omitted, a functionally reduced I2C bus
-  controller on DW HDMI is probed
-- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
-
-Example:
-       hdmi: hdmi@0120000 {
-               compatible = "fsl,imx6q-hdmi";
-               reg = <0x00120000 0x9000>;
-               interrupts = <0 115 0x04>;
-               gpr = <&gpr>;
-               clocks = <&clks 123>, <&clks 124>;
-               clock-names = "iahb", "isfr";
-               ddc-i2c-bus = <&i2c2>;
-
-               port@0 {
-                       reg = <0>;
-
-                       hdmi_mux_0: endpoint {
-                               remote-endpoint = <&ipu1_di0_hdmi>;
-                       };
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       hdmi_mux_1: endpoint {
-                               remote-endpoint = <&ipu1_di1_hdmi>;
-                       };
-               };
-       };
+Synopsys DesignWare HDMI TX Encoder
+===================================
+
+This document defines device tree properties for the Synopsys DesignWare HDMI
+TX Encoder (DWC HDMI TX). It doesn't constitue a device tree binding
+specification by itself but is meant to be referenced by platform-specific
+device tree bindings.
+
+When referenced from platform device tree bindings the properties defined in
+this document are defined as follows. The platform device tree bindings are
+responsible for defining whether each property is required or optional.
+
+- reg: Memory mapped base address and length of the DWC HDMI TX registers.
+
+- reg-io-width: Width of the registers specified by the reg property. The
+  value is expressed in bytes and must be equal to 1 or 4 if specified. The
+  register width defaults to 1 if the property is not present.
+
+- interrupts: Reference to the DWC HDMI TX interrupt.
+
+- clocks: References to all the clocks specified in the clock-names property
+  as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt.
+
+- clock-names: The DWC HDMI TX uses the following clocks.
+
+  - "iahb" is the bus clock for either AHB and APB (mandatory).
+  - "isfr" is the internal register configuration clock (mandatory).
+  - "cec" is the HDMI CEC controller main clock (optional).
+
+- ports: The connectivity of the DWC HDMI TX with the rest of the system is
+  expressed in using ports as specified in the device graph bindings defined
+  in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
+  is platform-specific.
index 1b756cf..66a8f86 100644 (file)
@@ -1,29 +1,36 @@
-Device-Tree bindings for HDMI Transmitter
+Freescale i.MX6 DWC HDMI TX Encoder
+===================================
 
-HDMI Transmitter
-================
+The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with a companion PHY IP.
+
+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.
 
-The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
-with accompanying PHY IP.
 
 Required properties:
- - #address-cells : should be <1>
- - #size-cells : should be <0>
- - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
- - gpr : should be <&gpr>.
-   The phandle points to the iomuxc-gpr region containing the HDMI
-   multiplexer control register.
- - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
-   in Documentation/devicetree/bindings/clock/clock-bindings.txt and
-   Documentation/devicetree/bindings/clock/imx6q-clock.txt.
- - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
-   Documentation/devicetree/bindings/media/video-interfaces.txt,
-   corresponding to the four inputs to the HDMI multiplexer.
-
-Optional properties:
- - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-
-example:
+
+- compatible : Shall be one of "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
+- reg: See dw_hdmi.txt.
+- interrupts: HDMI interrupt number
+- clocks: See dw_hdmi.txt.
+- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
+- ports: See dw_hdmi.txt. The DWC HDMI shall have between one and four ports,
+  numbered 0 to 3, corresponding to the four inputs of the HDMI multiplexer.
+  Each port shall have a single endpoint.
+- gpr : Shall contain a phandle to the iomuxc-gpr region containing the HDMI
+  multiplexer control register.
+
+Optional properties
+
+- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master
+  or the functionally-reduced I2C master contained in the DWC HDMI. When
+  connected to a system I2C master this property contains a phandle to that
+  I2C master controller.
+
+
+Example:
 
        gpr: iomuxc-gpr@020e0000 {
                /* ... */
index 668091f..046076c 100644 (file)
@@ -1,24 +1,39 @@
-Rockchip specific extensions to the Synopsys Designware HDMI
-================================
+Rockchip DWC HDMI TX Encoder
+============================
+
+The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with a companion PHY IP.
+
+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: "rockchip,rk3288-dw-hdmi";
-- reg: Physical base address and length of the controller's registers.
-- clocks: phandle to hdmi iahb and isfr clocks.
-- clock-names: should be "iahb" "isfr"
-- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+
+- compatible: Shall contain "rockchip,rk3288-dw-hdmi".
+- reg: See dw_hdmi.txt.
+- reg-io-width: See dw_hdmi.txt. Shall be 4.
 - interrupts: HDMI interrupt number
-- ports: contain a port node with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt. For
-  vopb,set the reg = <0> and set the reg = <1> for vopl.
-- reg-io-width: the width of the reg:1,4, the value should be 4 on
-  rk3288 platform
+- clocks: See dw_hdmi.txt.
+- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
+- ports: See dw_hdmi.txt. The DWC HDMI shall have a single port numbered 0
+  corresponding to the video input of the controller. The port shall have two
+  endpoints, numbered 0 and 1, connected respectively to the vopb and vopl.
+- rockchip,grf: Shall reference the GRF to mux vopl/vopb.
 
 Optional properties
-- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+
+- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master
+  or the functionally-reduced I2C master contained in the DWC HDMI. When
+  connected to a system I2C master this property contains a phandle to that
+  I2C master controller.
+- clock-names: See dw_hdmi.txt. The "cec" clock is optional.
+- clock-names: May contain "cec" as defined in dw_hdmi.txt.
+
 
 Example:
+
 hdmi: hdmi@ff980000 {
        compatible = "rockchip,rk3288-dw-hdmi";
        reg = <0xff980000 0x20000>;
index 1ea94fc..91d82f3 100644 (file)
@@ -470,3 +470,9 @@ DRM MM Range Allocator Function References
 
 .. kernel-doc:: include/drm/drm_mm.h
    :internal:
+
+DRM Cache Handling
+==================
+
+.. kernel-doc:: drivers/gpu/drm/drm_cache.c
+   :export:
index 6f3f9e6..90bc65d 100644 (file)
@@ -138,7 +138,7 @@ config DRM_KMS_CMA_HELPER
 
 config DRM_VM
        bool
-       depends on DRM
+       depends on DRM && MMU
 
 source "drivers/gpu/drm/i2c/Kconfig"
 
@@ -267,7 +267,7 @@ source "drivers/gpu/drm/meson/Kconfig"
 
 menuconfig DRM_LEGACY
        bool "Enable legacy drivers (DANGEROUS)"
-       depends on DRM
+       depends on DRM && MMU
        select DRM_VM
        help
          Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous
index 15f3ecf..eafaeeb 100644 (file)
@@ -1,6 +1,6 @@
 config DRM_ARMADA
        tristate "DRM support for Marvell Armada SoCs"
-       depends on DRM && HAVE_CLK && ARM
+       depends on DRM && HAVE_CLK && ARM && MMU
        select DRM_KMS_HELPER
        help
          Support the "LCD" controllers found on the Marvell Armada 510
index 992d76c..fe18a5d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/hdmi.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_mipi_dsi.h>
@@ -317,6 +318,8 @@ struct adv7511 {
        bool edid_read;
 
        wait_queue_head_t wq;
+       struct work_struct hpd_work;
+
        struct drm_bridge bridge;
        struct drm_connector connector;
 
@@ -329,6 +332,9 @@ struct adv7511 {
 
        struct gpio_desc *gpio_pd;
 
+       struct regulator_bulk_data *supplies;
+       unsigned int num_supplies;
+
        /* ADV7533 DSI RX related params */
        struct device_node *host_node;
        struct mipi_dsi_device *dsi;
index 8dba729..f75ab62 100644 (file)
@@ -325,7 +325,7 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
        adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
-static void adv7511_power_on(struct adv7511 *adv7511)
+static void __adv7511_power_on(struct adv7511 *adv7511)
 {
        adv7511->current_edid_segment = -1;
 
@@ -338,7 +338,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
                 * Still, let's be safe and stick to the documentation.
                 */
                regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
-                            ADV7511_INT0_EDID_READY);
+                            ADV7511_INT0_EDID_READY | ADV7511_INT0_HPD);
                regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
                             ADV7511_INT1_DDC_ERROR);
        }
@@ -354,6 +354,11 @@ static void adv7511_power_on(struct adv7511 *adv7511)
        regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
                           ADV7511_REG_POWER2_HPD_SRC_MASK,
                           ADV7511_REG_POWER2_HPD_SRC_NONE);
+}
+
+static void adv7511_power_on(struct adv7511 *adv7511)
+{
+       __adv7511_power_on(adv7511);
 
        /*
         * Most of the registers are reset during power down or when HPD is low.
@@ -362,21 +367,23 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 
        if (adv7511->type == ADV7533)
                adv7533_dsi_power_on(adv7511);
-
        adv7511->powered = true;
 }
 
-static void adv7511_power_off(struct adv7511 *adv7511)
+static void __adv7511_power_off(struct adv7511 *adv7511)
 {
        /* TODO: setup additional power down modes */
        regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                           ADV7511_POWER_POWER_DOWN,
                           ADV7511_POWER_POWER_DOWN);
        regcache_mark_dirty(adv7511->regmap);
+}
 
+static void adv7511_power_off(struct adv7511 *adv7511)
+{
+       __adv7511_power_off(adv7511);
        if (adv7511->type == ADV7533)
                adv7533_dsi_power_off(adv7511);
-
        adv7511->powered = false;
 }
 
@@ -402,6 +409,27 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
        return false;
 }
 
+static void adv7511_hpd_work(struct work_struct *work)
+{
+       struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
+       enum drm_connector_status status;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
+       if (ret < 0)
+               status = connector_status_disconnected;
+       else if (val & ADV7511_STATUS_HPD)
+               status = connector_status_connected;
+       else
+               status = connector_status_disconnected;
+
+       if (adv7511->connector.status != status) {
+               adv7511->connector.status = status;
+               drm_kms_helper_hotplug_event(adv7511->connector.dev);
+       }
+}
+
 static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
 {
        unsigned int irq0, irq1;
@@ -419,7 +447,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
        regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
        if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
-               drm_helper_hpd_irq_event(adv7511->connector.dev);
+               schedule_work(&adv7511->hpd_work);
 
        if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
                adv7511->edid_read = true;
@@ -546,23 +574,20 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
 
        /* Reading the EDID only works if the device is powered */
        if (!adv7511->powered) {
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                                  ADV7511_POWER_POWER_DOWN, 0);
-               if (adv7511->i2c_main->irq) {
-                       regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
-                                    ADV7511_INT0_EDID_READY);
-                       regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
-                                    ADV7511_INT1_DDC_ERROR);
-               }
-               adv7511->current_edid_segment = -1;
+               unsigned int edid_i2c_addr =
+                                       (adv7511->i2c_main->addr << 1) + 4;
+
+               __adv7511_power_on(adv7511);
+
+               /* Reset the EDID_I2C_ADDR register as it might be cleared */
+               regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+                            edid_i2c_addr);
        }
 
        edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
 
        if (!adv7511->powered)
-               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
-                                  ADV7511_POWER_POWER_DOWN,
-                                  ADV7511_POWER_POWER_DOWN);
+               __adv7511_power_off(adv7511);
 
        kfree(adv7511->edid);
        adv7511->edid = edid;
@@ -825,6 +850,10 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
        if (adv->type == ADV7533)
                ret = adv7533_attach_dsi(adv);
 
+       if (adv->i2c_main->irq)
+               regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0),
+                            ADV7511_INT0_HPD);
+
        return ret;
 }
 
@@ -839,6 +868,58 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = {
  * Probe & remove
  */
 
+static const char * const adv7511_supply_names[] = {
+       "avdd",
+       "dvdd",
+       "pvdd",
+       "bgvdd",
+       "dvdd-3v",
+};
+
+static const char * const adv7533_supply_names[] = {
+       "avdd",
+       "dvdd",
+       "pvdd",
+       "a2vdd",
+       "v3p3",
+       "v1p2",
+};
+
+static int adv7511_init_regulators(struct adv7511 *adv)
+{
+       struct device *dev = &adv->i2c_main->dev;
+       const char * const *supply_names;
+       unsigned int i;
+       int ret;
+
+       if (adv->type == ADV7511) {
+               supply_names = adv7511_supply_names;
+               adv->num_supplies = ARRAY_SIZE(adv7511_supply_names);
+       } else {
+               supply_names = adv7533_supply_names;
+               adv->num_supplies = ARRAY_SIZE(adv7533_supply_names);
+       }
+
+       adv->supplies = devm_kcalloc(dev, adv->num_supplies,
+                                    sizeof(*adv->supplies), GFP_KERNEL);
+       if (!adv->supplies)
+               return -ENOMEM;
+
+       for (i = 0; i < adv->num_supplies; i++)
+               adv->supplies[i].supply = supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, adv->num_supplies, adv->supplies);
+       if (ret)
+               return ret;
+
+       return regulator_bulk_enable(adv->num_supplies, adv->supplies);
+}
+
+static void adv7511_uninit_regulators(struct adv7511 *adv)
+{
+       regulator_bulk_disable(adv->num_supplies, adv->supplies);
+}
+
 static int adv7511_parse_dt(struct device_node *np,
                            struct adv7511_link_config *config)
 {
@@ -939,6 +1020,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        if (!adv7511)
                return -ENOMEM;
 
+       adv7511->i2c_main = i2c;
        adv7511->powered = false;
        adv7511->status = connector_status_disconnected;
 
@@ -956,13 +1038,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        if (ret)
                return ret;
 
+       ret = adv7511_init_regulators(adv7511);
+       if (ret) {
+               dev_err(dev, "failed to init regulators\n");
+               return ret;
+       }
+
        /*
         * The power down GPIO is optional. If present, toggle it from active to
         * inactive to wake up the encoder.
         */
        adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
-       if (IS_ERR(adv7511->gpio_pd))
-               return PTR_ERR(adv7511->gpio_pd);
+       if (IS_ERR(adv7511->gpio_pd)) {
+               ret = PTR_ERR(adv7511->gpio_pd);
+               goto uninit_regulators;
+       }
 
        if (adv7511->gpio_pd) {
                mdelay(5);
@@ -970,12 +1060,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        }
 
        adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
-       if (IS_ERR(adv7511->regmap))
-               return PTR_ERR(adv7511->regmap);
+       if (IS_ERR(adv7511->regmap)) {
+               ret = PTR_ERR(adv7511->regmap);
+               goto uninit_regulators;
+       }
 
        ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
        if (ret)
-               return ret;
+               goto uninit_regulators;
        dev_dbg(dev, "Rev. %d\n", val);
 
        if (adv7511->type == ADV7511)
@@ -985,7 +1077,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        else
                ret = adv7533_patch_registers(adv7511);
        if (ret)
-               return ret;
+               goto uninit_regulators;
 
        regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
        regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
@@ -995,10 +1087,11 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
        adv7511_packet_disable(adv7511, 0xffff);
 
-       adv7511->i2c_main = i2c;
        adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
-       if (!adv7511->i2c_edid)
-               return -ENOMEM;
+       if (!adv7511->i2c_edid) {
+               ret = -ENOMEM;
+               goto uninit_regulators;
+       }
 
        if (adv7511->type == ADV7533) {
                ret = adv7533_init_cec(adv7511);
@@ -1006,6 +1099,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
                        goto err_i2c_unregister_edid;
        }
 
+       INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
+
        if (i2c->irq) {
                init_waitqueue_head(&adv7511->wq);
 
@@ -1045,6 +1140,8 @@ err_unregister_cec:
        adv7533_uninit_cec(adv7511);
 err_i2c_unregister_edid:
        i2c_unregister_device(adv7511->i2c_edid);
+uninit_regulators:
+       adv7511_uninit_regulators(adv7511);
 
        return ret;
 }
@@ -1058,6 +1155,8 @@ static int adv7511_remove(struct i2c_client *i2c)
                adv7533_uninit_cec(adv7511);
        }
 
+       adv7511_uninit_regulators(adv7511);
+
        drm_bridge_remove(&adv7511->bridge);
 
        adv7511_audio_exit(adv7511);
index f5009ae..4fda071 100644 (file)
@@ -113,13 +113,20 @@ struct dw_hdmi_i2c {
        bool                    is_regaddr;
 };
 
+struct dw_hdmi_phy_data {
+       enum dw_hdmi_phy_type type;
+       const char *name;
+       bool has_svsret;
+};
+
 struct dw_hdmi {
        struct drm_connector connector;
-       struct drm_encoder *encoder;
-       struct drm_bridge *bridge;
+       struct drm_bridge bridge;
 
-       struct platform_device *audio;
        enum dw_hdmi_devtype dev_type;
+       unsigned int version;
+
+       struct platform_device *audio;
        struct device *dev;
        struct clk *isfr_clk;
        struct clk *iahb_clk;
@@ -133,7 +140,9 @@ struct dw_hdmi {
        u8 edid[HDMI_EDID_LEN];
        bool cable_plugin;
 
+       const struct dw_hdmi_phy_data *phy;
        bool phy_enabled;
+
        struct drm_display_mode previous_mode;
 
        struct i2c_adapter *ddc;
@@ -868,7 +877,7 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
        return true;
 }
 
-static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
                                 unsigned char addr)
 {
        hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -882,13 +891,6 @@ static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
        hdmi_phy_wait_i2c_done(hdmi, 1000);
 }
 
-static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
-                             unsigned char addr)
-{
-       __hdmi_phy_i2c_write(hdmi, data, addr);
-       return 0;
-}
-
 static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
 {
        hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
@@ -903,11 +905,11 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
                         HDMI_PHY_CONF0_ENTMDS_MASK);
 }
 
-static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
 {
        hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_SPARECTRL_OFFSET,
-                        HDMI_PHY_CONF0_SPARECTRL_MASK);
+                        HDMI_PHY_CONF0_SVSRET_OFFSET,
+                        HDMI_PHY_CONF0_SVSRET_MASK);
 }
 
 static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
@@ -938,34 +940,14 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
                         HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
-static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
-                             unsigned char res, int cscon)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
 {
-       unsigned res_idx;
        u8 val, msec;
        const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
        const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
        const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
        const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
 
-       if (prep)
-               return -EINVAL;
-
-       switch (res) {
-       case 0: /* color resolution 0 is 8 bit colour depth */
-       case 8:
-               res_idx = DW_HDMI_RES_8;
-               break;
-       case 10:
-               res_idx = DW_HDMI_RES_10;
-               break;
-       case 12:
-               res_idx = DW_HDMI_RES_12;
-               break;
-       default:
-               return -EINVAL;
-       }
-
        /* PLL/MPLL Cfg - always match on final entry */
        for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
                if (hdmi->hdmi_data.video_mode.mpixelclock <=
@@ -1004,9 +986,13 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
        /* gen2 pddq */
        dw_hdmi_phy_gen2_pddq(hdmi, 1);
 
-       /* PHY reset */
-       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
-       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+       /* Leave low power consumption mode by asserting SVSRET. */
+       if (hdmi->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);
 
        hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
 
@@ -1015,21 +1001,26 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
                    HDMI_PHY_I2CM_SLAVE_ADDR);
        hdmi_phy_test_clear(hdmi, 0);
 
-       hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06);
-       hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
-
-       /* CURRCTRL */
-       hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10);
+       hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
+                          HDMI_3D_TX_PHY_CPCE_CTRL);
+       hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
+                          HDMI_3D_TX_PHY_GMPCTRL);
+       hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
+                          HDMI_3D_TX_PHY_CURRCTRL);
 
-       hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
-       hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+       hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
+       hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
+                          HDMI_3D_TX_PHY_MSM_CTRL);
 
-       hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19);  /* TXTERM */
-       hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
-       hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */
+       hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
+       hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
+                          HDMI_3D_TX_PHY_CKSYMTXCTRL);
+       hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
+                          HDMI_3D_TX_PHY_VLEVCTRL);
 
-       /* REMOVE CLK TERM */
-       hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
+       /* Override and disable clock termination. */
+       hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
+                          HDMI_3D_TX_PHY_CKCALCTRL);
 
        dw_hdmi_phy_enable_powerdown(hdmi, false);
 
@@ -1041,10 +1032,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
        dw_hdmi_phy_gen2_txpwron(hdmi, 1);
        dw_hdmi_phy_gen2_pddq(hdmi, 0);
 
-       if (hdmi->dev_type == RK3288_HDMI)
-               dw_hdmi_phy_enable_spare(hdmi, 1);
-
-       /*Wait for PHY PLL lock */
+       /* Wait for PHY PLL lock */
        msec = 5;
        do {
                val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
@@ -1079,7 +1067,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
                dw_hdmi_phy_enable_powerdown(hdmi, true);
 
                /* Enable CSC */
-               ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+               ret = hdmi_phy_configure(hdmi, cscon);
                if (ret)
                        return ret;
        }
@@ -1351,19 +1339,38 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
 /* Workaround to clear the overflow condition */
 static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 {
-       int count;
+       unsigned int count;
+       unsigned int i;
        u8 val;
 
-       /* TMDS software reset */
-       hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+       /*
+        * Under some circumstances the Frame Composer arithmetic unit can miss
+        * an FC register write due to being busy processing the previous one.
+        * The issue can be worked around by issuing a TMDS software reset and
+        * 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.
+        */
 
-       val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
-       if (hdmi->dev_type == IMX6DL_HDMI) {
-               hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+       switch (hdmi->version) {
+       case 0x130a:
+               count = 4;
+               break;
+       case 0x131a:
+               count = 1;
+               break;
+       default:
                return;
        }
 
-       for (count = 0; count < 4; count++)
+       /* TMDS software reset */
+       hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+       val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+       for (i = 0; i < count; i++)
                hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
 }
 
@@ -1586,42 +1593,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
                hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
 }
 
-static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
-                                   struct drm_display_mode *orig_mode,
-                                   struct drm_display_mode *mode)
-{
-       struct dw_hdmi *hdmi = bridge->driver_private;
-
-       mutex_lock(&hdmi->mutex);
-
-       /* Store the display mode for plugin/DKMS poweron events */
-       memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-
-       mutex_unlock(&hdmi->mutex);
-}
-
-static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
-{
-       struct dw_hdmi *hdmi = bridge->driver_private;
-
-       mutex_lock(&hdmi->mutex);
-       hdmi->disabled = true;
-       dw_hdmi_update_power(hdmi);
-       dw_hdmi_update_phy_mask(hdmi);
-       mutex_unlock(&hdmi->mutex);
-}
-
-static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
-{
-       struct dw_hdmi *hdmi = bridge->driver_private;
-
-       mutex_lock(&hdmi->mutex);
-       hdmi->disabled = false;
-       dw_hdmi_update_power(hdmi);
-       dw_hdmi_update_phy_mask(hdmi);
-       mutex_unlock(&hdmi->mutex);
-}
-
 static enum drm_connector_status
 dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -1714,7 +1685,63 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
        .best_encoder = drm_atomic_helper_best_encoder,
 };
 
+static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
+{
+       struct dw_hdmi *hdmi = bridge->driver_private;
+       struct drm_encoder *encoder = bridge->encoder;
+       struct drm_connector *connector = &hdmi->connector;
+
+       connector->interlace_allowed = 1;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
+
+       drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,
+                          DRM_MODE_CONNECTOR_HDMIA);
+
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       return 0;
+}
+
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+                                   struct drm_display_mode *orig_mode,
+                                   struct drm_display_mode *mode)
+{
+       struct dw_hdmi *hdmi = bridge->driver_private;
+
+       mutex_lock(&hdmi->mutex);
+
+       /* Store the display mode for plugin/DKMS poweron events */
+       memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+
+       mutex_unlock(&hdmi->mutex);
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+       struct dw_hdmi *hdmi = bridge->driver_private;
+
+       mutex_lock(&hdmi->mutex);
+       hdmi->disabled = true;
+       dw_hdmi_update_power(hdmi);
+       dw_hdmi_update_phy_mask(hdmi);
+       mutex_unlock(&hdmi->mutex);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+       struct dw_hdmi *hdmi = bridge->driver_private;
+
+       mutex_lock(&hdmi->mutex);
+       hdmi->disabled = false;
+       dw_hdmi_update_power(hdmi);
+       dw_hdmi_update_phy_mask(hdmi);
+       mutex_unlock(&hdmi->mutex);
+}
+
 static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+       .attach = dw_hdmi_bridge_attach,
        .enable = dw_hdmi_bridge_enable,
        .disable = dw_hdmi_bridge_disable,
        .mode_set = dw_hdmi_bridge_mode_set,
@@ -1816,7 +1843,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
        if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
                dev_dbg(hdmi->dev, "EVENT=%s\n",
                        phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
-               drm_helper_hpd_irq_event(hdmi->bridge->dev);
+               if (hdmi->bridge.dev)
+                       drm_helper_hpd_irq_event(hdmi->bridge.dev);
        }
 
        hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
@@ -1826,67 +1854,80 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
-{
-       struct drm_encoder *encoder = hdmi->encoder;
-       struct drm_bridge *bridge;
-       int ret;
-
-       bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
-       if (!bridge) {
-               DRM_ERROR("Failed to allocate drm bridge\n");
-               return -ENOMEM;
-       }
-
-       hdmi->bridge = bridge;
-       bridge->driver_private = hdmi;
-       bridge->funcs = &dw_hdmi_bridge_funcs;
-       ret = drm_bridge_attach(encoder, bridge, NULL);
-       if (ret) {
-               DRM_ERROR("Failed to initialize bridge with drm\n");
-               return -EINVAL;
+static const struct dw_hdmi_phy_data dw_hdmi_phys[] = {
+       {
+               .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
+               .name = "DWC HDMI TX PHY",
+       }, {
+               .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
+               .name = "DWC MHL PHY + HEAC PHY",
+               .has_svsret = true,
+       }, {
+               .type = DW_HDMI_PHY_DWC_MHL_PHY,
+               .name = "DWC MHL PHY",
+               .has_svsret = true,
+       }, {
+               .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
+               .name = "DWC HDMI 3D TX PHY + HEAC PHY",
+       }, {
+               .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
+               .name = "DWC HDMI 3D TX PHY",
+       }, {
+               .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
+               .name = "DWC HDMI 2.0 TX PHY",
+               .has_svsret = true,
        }
+};
 
-       hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
+{
+       unsigned int i;
+       u8 phy_type;
 
-       drm_connector_helper_add(&hdmi->connector,
-                                &dw_hdmi_connector_helper_funcs);
+       phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
 
-       drm_connector_init(drm, &hdmi->connector,
-                          &dw_hdmi_connector_funcs,
-                          DRM_MODE_CONNECTOR_HDMIA);
+       for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
+               if (dw_hdmi_phys[i].type == phy_type) {
+                       hdmi->phy = &dw_hdmi_phys[i];
+                       return 0;
+               }
+       }
 
-       drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+       if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
+               dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
+       else
+               dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
+                       phy_type);
 
-       return 0;
+       return -ENODEV;
 }
 
-int dw_hdmi_bind(struct device *dev, struct device *master,
-                void *data, struct drm_encoder *encoder,
-                struct resource *iores, int irq,
-                const struct dw_hdmi_plat_data *plat_data)
+static struct dw_hdmi *
+__dw_hdmi_probe(struct platform_device *pdev,
+               const struct dw_hdmi_plat_data *plat_data)
 {
-       struct drm_device *drm = data;
+       struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct platform_device_info pdevinfo;
        struct device_node *ddc_node;
        struct dw_hdmi *hdmi;
+       struct resource *iores;
+       int irq;
        int ret;
        u32 val = 1;
+       u8 prod_id0;
+       u8 prod_id1;
        u8 config0;
-       u8 config1;
+       u8 config3;
 
        hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi)
-               return -ENOMEM;
-
-       hdmi->connector.interlace_allowed = 1;
+               return ERR_PTR(-ENOMEM);
 
        hdmi->plat_data = plat_data;
        hdmi->dev = dev;
        hdmi->dev_type = plat_data->dev_type;
        hdmi->sample_rate = 48000;
-       hdmi->encoder = encoder;
        hdmi->disabled = true;
        hdmi->rxsense = true;
        hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
@@ -1908,7 +1949,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
                break;
        default:
                dev_err(dev, "reg-io-width must be 1 or 4\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
 
        ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
@@ -1917,13 +1958,14 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
                of_node_put(ddc_node);
                if (!hdmi->ddc) {
                        dev_dbg(hdmi->dev, "failed to read ddc node\n");
-                       return -EPROBE_DEFER;
+                       return ERR_PTR(-EPROBE_DEFER);
                }
 
        } else {
                dev_dbg(hdmi->dev, "no ddc property found\n");
        }
 
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        hdmi->regs = devm_ioremap_resource(dev, iores);
        if (IS_ERR(hdmi->regs)) {
                ret = PTR_ERR(hdmi->regs);
@@ -1957,15 +1999,36 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
        }
 
        /* Product and revision IDs */
-       dev_info(dev,
-                "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
-                hdmi_readb(hdmi, HDMI_DESIGN_ID),
-                hdmi_readb(hdmi, HDMI_REVISION_ID),
-                hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
-                hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+       hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
+                     | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
+       prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0);
+       prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1);
+
+       if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX ||
+           (prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) {
+               dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n",
+                       hdmi->version, prod_id0, prod_id1);
+               ret = -ENODEV;
+               goto err_iahb;
+       }
+
+       ret = dw_hdmi_detect_phy(hdmi);
+       if (ret < 0)
+               goto err_iahb;
+
+       dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
+                hdmi->version >> 12, hdmi->version & 0xfff,
+                prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
+                hdmi->phy->name);
 
        initialize_hdmi_ih_mutes(hdmi);
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto err_iahb;
+       }
+
        ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
                                        dw_hdmi_irq, IRQF_SHARED,
                                        dev_name(dev), hdmi);
@@ -1995,11 +2058,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
        hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
                    HDMI_IH_PHY_STAT0);
 
-       ret = dw_hdmi_fb_registered(hdmi);
-       if (ret)
-               goto err_iahb;
+       hdmi->bridge.driver_private = hdmi;
+       hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
+       hdmi->bridge.of_node = pdev->dev.of_node;
 
-       ret = dw_hdmi_register(drm, hdmi);
+       ret = dw_hdmi_fb_registered(hdmi);
        if (ret)
                goto err_iahb;
 
@@ -2012,9 +2075,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
        pdevinfo.id = PLATFORM_DEVID_AUTO;
 
        config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
-       config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+       config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
 
-       if (config1 & HDMI_CONFIG1_AHB) {
+       if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
                struct dw_hdmi_audio_data audio;
 
                audio.phys = iores->start;
@@ -2046,9 +2109,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
        if (hdmi->i2c)
                dw_hdmi_i2c_init(hdmi);
 
-       dev_set_drvdata(dev, hdmi);
+       platform_set_drvdata(pdev, hdmi);
 
-       return 0;
+       return hdmi;
 
 err_iahb:
        if (hdmi->i2c) {
@@ -2062,14 +2125,11 @@ err_isfr:
 err_res:
        i2c_put_adapter(hdmi->ddc);
 
-       return ret;
+       return ERR_PTR(ret);
 }
-EXPORT_SYMBOL_GPL(dw_hdmi_bind);
 
-void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
+static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 {
-       struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
        if (hdmi->audio && !IS_ERR(hdmi->audio))
                platform_device_unregister(hdmi->audio);
 
@@ -2084,6 +2144,70 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
        else
                i2c_put_adapter(hdmi->ddc);
 }
+
+/* -----------------------------------------------------------------------------
+ * 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 *hdmi;
+       int ret;
+
+       hdmi = __dw_hdmi_probe(pdev, plat_data);
+       if (IS_ERR(hdmi))
+               return PTR_ERR(hdmi);
+
+       ret = drm_bridge_add(&hdmi->bridge);
+       if (ret < 0) {
+               __dw_hdmi_remove(hdmi);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_probe);
+
+void dw_hdmi_remove(struct platform_device *pdev)
+{
+       struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+
+       drm_bridge_remove(&hdmi->bridge);
+
+       __dw_hdmi_remove(hdmi);
+}
+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 *hdmi;
+       int ret;
+
+       hdmi = __dw_hdmi_probe(pdev, plat_data);
+       if (IS_ERR(hdmi))
+               return PTR_ERR(hdmi);
+
+       ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
+       if (ret) {
+               dw_hdmi_remove(pdev);
+               DRM_ERROR("Failed to initialize bridge with drm\n");
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
+
+void dw_hdmi_unbind(struct device *dev)
+{
+       struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+       __dw_hdmi_remove(hdmi);
+}
 EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
index 55135bb..325b0b8 100644 (file)
 #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
 
 enum {
+/* PRODUCT_ID0 field values */
+       HDMI_PRODUCT_ID0_HDMI_TX = 0xa0,
+
+/* PRODUCT_ID1 field values */
+       HDMI_PRODUCT_ID1_HDCP = 0xc0,
+       HDMI_PRODUCT_ID1_HDMI_RX = 0x02,
+       HDMI_PRODUCT_ID1_HDMI_TX = 0x01,
+
 /* CONFIG0_ID field values */
        HDMI_CONFIG0_I2S = 0x10,
 
 /* CONFIG1_ID field values */
        HDMI_CONFIG1_AHB = 0x01,
 
+/* CONFIG3_ID field values */
+       HDMI_CONFIG3_AHBAUDDMA = 0x02,
+       HDMI_CONFIG3_GPAUD = 0x01,
+
 /* IH_FC_INT2 field values */
        HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
        HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
@@ -847,8 +859,8 @@ enum {
        HDMI_PHY_CONF0_PDZ_OFFSET = 7,
        HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
        HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
-       HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
-       HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
+       HDMI_PHY_CONF0_SVSRET_MASK = 0x20,
+       HDMI_PHY_CONF0_SVSRET_OFFSET = 5,
        HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
        HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
        HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
@@ -977,8 +989,7 @@ enum {
        HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
 
 /* MC_PHYRSTZ field values */
-       HDMI_MC_PHYRSTZ_ASSERT = 0x0,
-       HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+       HDMI_MC_PHYRSTZ_PHYRSTZ = 0x01,
 
 /* MC_HEACPHY_RST field values */
        HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
@@ -1073,4 +1084,70 @@ enum {
        HDMI_I2CM_CTLINT_ARB_MASK = 0x4,
 };
 
+/*
+ * HDMI 3D TX PHY registers
+ */
+#define HDMI_3D_TX_PHY_PWRCTRL                 0x00
+#define HDMI_3D_TX_PHY_SERDIVCTRL              0x01
+#define HDMI_3D_TX_PHY_SERCKCTRL               0x02
+#define HDMI_3D_TX_PHY_SERCKKILLCTRL           0x03
+#define HDMI_3D_TX_PHY_TXRESCTRL               0x04
+#define HDMI_3D_TX_PHY_CKCALCTRL               0x05
+#define HDMI_3D_TX_PHY_CPCE_CTRL               0x06
+#define HDMI_3D_TX_PHY_TXCLKMEASCTRL           0x07
+#define HDMI_3D_TX_PHY_TXMEASCTRL              0x08
+#define HDMI_3D_TX_PHY_CKSYMTXCTRL             0x09
+#define HDMI_3D_TX_PHY_CMPSEQCTRL              0x0a
+#define HDMI_3D_TX_PHY_CMPPWRCTRL              0x0b
+#define HDMI_3D_TX_PHY_CMPMODECTRL             0x0c
+#define HDMI_3D_TX_PHY_MEASCTRL                        0x0d
+#define HDMI_3D_TX_PHY_VLEVCTRL                        0x0e
+#define HDMI_3D_TX_PHY_D2ACTRL                 0x0f
+#define HDMI_3D_TX_PHY_CURRCTRL                        0x10
+#define HDMI_3D_TX_PHY_DRVANACTRL              0x11
+#define HDMI_3D_TX_PHY_PLLMEASCTRL             0x12
+#define HDMI_3D_TX_PHY_PLLPHBYCTRL             0x13
+#define HDMI_3D_TX_PHY_GRP_CTRL                        0x14
+#define HDMI_3D_TX_PHY_GMPCTRL                 0x15
+#define HDMI_3D_TX_PHY_MPLLMEASCTRL            0x16
+#define HDMI_3D_TX_PHY_MSM_CTRL                        0x17
+#define HDMI_3D_TX_PHY_SCRPB_STATUS            0x18
+#define HDMI_3D_TX_PHY_TXTERM                  0x19
+#define HDMI_3D_TX_PHY_PTRPT_ENBL              0x1a
+#define HDMI_3D_TX_PHY_PATTERNGEN              0x1b
+#define HDMI_3D_TX_PHY_SDCAP_MODE              0x1c
+#define HDMI_3D_TX_PHY_SCOPEMODE               0x1d
+#define HDMI_3D_TX_PHY_DIGTXMODE               0x1e
+#define HDMI_3D_TX_PHY_STR_STATUS              0x1f
+#define HDMI_3D_TX_PHY_SCOPECNT0               0x20
+#define HDMI_3D_TX_PHY_SCOPECNT1               0x21
+#define HDMI_3D_TX_PHY_SCOPECNT2               0x22
+#define HDMI_3D_TX_PHY_SCOPECNTCLK             0x23
+#define HDMI_3D_TX_PHY_SCOPESAMPLE             0x24
+#define HDMI_3D_TX_PHY_SCOPECNTMSB01           0x25
+#define HDMI_3D_TX_PHY_SCOPECNTMSB2CK          0x26
+
+/* HDMI_3D_TX_PHY_CKCALCTRL values */
+#define HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE              BIT(15)
+
+/* HDMI_3D_TX_PHY_MSM_CTRL values */
+#define HDMI_3D_TX_PHY_MSM_CTRL_MPLL_PH_SEL_CK         BIT(13)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_CLK_REF_MPLL   (0 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_OFF            (1 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_PCLK           (2 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK         (3 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_SCOPE_CK_SEL           BIT(0)
+
+/* HDMI_3D_TX_PHY_PTRPT_ENBL values */
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_OVERRIDE             BIT(15)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT2         BIT(8)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT1         BIT(7)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT0         BIT(6)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_CK_REF_ENB           BIT(5)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_RCAL_ENB             BIT(4)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_CLK_ALIGN_ENB     BIT(3)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_READY             BIT(2)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_CKO_WORD_ENB         BIT(1)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_REFCLK_ENB           BIT(0)
+
 #endif /* __DW_HDMI_H__ */
index 7b71ac4..b26e341 100644 (file)
@@ -2708,6 +2708,44 @@ backoff:
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
 
+static int page_flip_common(
+                               struct drm_atomic_state *state,
+                               struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               struct drm_pending_vblank_event *event)
+{
+       struct drm_plane *plane = crtc->primary;
+       struct drm_plane_state *plane_state;
+       struct drm_crtc_state *crtc_state;
+       int ret = 0;
+
+       crtc_state = drm_atomic_get_crtc_state(state, crtc);
+       if (IS_ERR(crtc_state))
+               return PTR_ERR(crtc_state);
+
+       crtc_state->event = event;
+
+       plane_state = drm_atomic_get_plane_state(state, plane);
+       if (IS_ERR(plane_state))
+               return PTR_ERR(plane_state);
+
+
+       ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+       if (ret != 0)
+               return ret;
+       drm_atomic_set_fb_for_plane(plane_state, fb);
+
+       /* Make sure we don't accidentally do a full modeset. */
+       state->allow_modeset = false;
+       if (!crtc_state->active) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
 /**
  * drm_atomic_helper_page_flip - execute a legacy page flip
  * @crtc: DRM crtc
@@ -2715,7 +2753,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
  * @event: optional DRM event to signal upon completion
  * @flags: flip flags for non-vblank sync'ed updates
  *
- * Provides a default page flip implementation using the atomic driver interface.
+ * Provides a default &drm_crtc_funcs.page_flip implementation
+ * using the atomic driver interface.
  *
  * Note that for now so called async page flips (i.e. updates which are not
  * synchronized to vblank) are not supported, since the atomic interfaces have
@@ -2723,6 +2762,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property);
  *
  * Returns:
  * Returns 0 on success, negative errno numbers on failure.
+ *
+ * See also:
+ * drm_atomic_helper_page_flip_target()
  */
 int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
@@ -2731,8 +2773,6 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
 {
        struct drm_plane *plane = crtc->primary;
        struct drm_atomic_state *state;
-       struct drm_plane_state *plane_state;
-       struct drm_crtc_state *crtc_state;
        int ret = 0;
 
        if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
@@ -2743,35 +2783,86 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                return -ENOMEM;
 
        state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+
 retry:
-       crtc_state = drm_atomic_get_crtc_state(state, crtc);
-       if (IS_ERR(crtc_state)) {
-               ret = PTR_ERR(crtc_state);
+       ret = page_flip_common(state, crtc, fb, event);
+       if (ret != 0)
                goto fail;
-       }
-       crtc_state->event = event;
 
-       plane_state = drm_atomic_get_plane_state(state, plane);
-       if (IS_ERR(plane_state)) {
-               ret = PTR_ERR(plane_state);
-               goto fail;
-       }
+       ret = drm_atomic_nonblocking_commit(state);
 
-       ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+fail:
+       if (ret == -EDEADLK)
+               goto backoff;
+
+       drm_atomic_state_put(state);
+       return ret;
+
+backoff:
+       drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
+
+       /*
+        * Someone might have exchanged the framebuffer while we dropped locks
+        * in the backoff code. We need to fix up the fb refcount tracking the
+        * core does for us.
+        */
+       plane->old_fb = plane->fb;
+
+       goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_page_flip);
+
+/**
+ * drm_atomic_helper_page_flip_target - do page flip on target vblank period.
+ * @crtc: DRM crtc
+ * @fb: DRM framebuffer
+ * @event: optional DRM event to signal upon completion
+ * @flags: flip flags for non-vblank sync'ed updates
+ * @target: specifying the target vblank period when the flip to take effect
+ *
+ * Provides a default &drm_crtc_funcs.page_flip_target implementation.
+ * Similar to drm_atomic_helper_page_flip() with extra parameter to specify
+ * target vblank period to flip.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int drm_atomic_helper_page_flip_target(
+                               struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               struct drm_pending_vblank_event *event,
+                               uint32_t flags,
+                               uint32_t target)
+{
+       struct drm_plane *plane = crtc->primary;
+       struct drm_atomic_state *state;
+       struct drm_crtc_state *crtc_state;
+       int ret = 0;
+
+       if (flags & DRM_MODE_PAGE_FLIP_ASYNC)
+               return -EINVAL;
+
+       state = drm_atomic_state_alloc(plane->dev);
+       if (!state)
+               return -ENOMEM;
+
+       state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+
+retry:
+       ret = page_flip_common(state, crtc, fb, event);
        if (ret != 0)
                goto fail;
-       drm_atomic_set_fb_for_plane(plane_state, fb);
 
-       /* Make sure we don't accidentally do a full modeset. */
-       state->allow_modeset = false;
-       if (!crtc_state->active) {
-               DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
-                                crtc->base.id);
+       crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+       if (WARN_ON(!crtc_state)) {
                ret = -EINVAL;
                goto fail;
        }
+       crtc_state->target_vblank = target;
 
        ret = drm_atomic_nonblocking_commit(state);
+
 fail:
        if (ret == -EDEADLK)
                goto backoff;
@@ -2792,7 +2883,7 @@ backoff:
 
        goto retry;
 }
-EXPORT_SYMBOL(drm_atomic_helper_page_flip);
+EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
 
 /**
  * drm_atomic_helper_connector_dpms() - connector dpms helper implementation
index a7916e5..5066638 100644 (file)
@@ -67,6 +67,14 @@ static void drm_cache_flush_clflush(struct page *pages[],
 }
 #endif
 
+/**
+ * drm_clflush_pages - Flush dcache lines of a set of pages.
+ * @pages: List of pages to be flushed.
+ * @num_pages: Number of pages in the array.
+ *
+ * Flush every data cache line entry that points to an address belonging
+ * to a page in the array.
+ */
 void
 drm_clflush_pages(struct page *pages[], unsigned long num_pages)
 {
@@ -101,6 +109,13 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
 }
 EXPORT_SYMBOL(drm_clflush_pages);
 
+/**
+ * drm_clflush_sg - Flush dcache lines pointing to a scather-gather.
+ * @st: struct sg_table.
+ *
+ * Flush every data cache line entry that points to an address in the
+ * sg.
+ */
 void
 drm_clflush_sg(struct sg_table *st)
 {
@@ -125,6 +140,14 @@ drm_clflush_sg(struct sg_table *st)
 }
 EXPORT_SYMBOL(drm_clflush_sg);
 
+/**
+ * drm_clflush_virt_range - Flush dcache lines of a region
+ * @addr: Initial kernel memory address.
+ * @length: Region size.
+ *
+ * Flush every data cache line entry that points to an address in the
+ * region requested.
+ */
 void
 drm_clflush_virt_range(void *addr, unsigned long length)
 {
index 20a4011..4364abf 100644 (file)
@@ -473,8 +473,7 @@ drm_fbdev_cma_create(struct drm_fb_helper *helper,
        return 0;
 
 err_cma_destroy:
-       drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
-       drm_fb_cma_destroy(&fbdev_cma->fb->fb);
+       drm_framebuffer_remove(&fbdev_cma->fb->fb);
 err_fb_info_destroy:
        drm_fb_helper_release_fbi(helper);
 err_gem_free_object:
@@ -574,10 +573,8 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
                drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev);
        drm_fb_helper_release_fbi(&fbdev_cma->fb_helper);
 
-       if (fbdev_cma->fb) {
-               drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
-               drm_fb_cma_destroy(&fbdev_cma->fb->fb);
-       }
+       if (fbdev_cma->fb)
+               drm_framebuffer_remove(&fbdev_cma->fb->fb);
 
        drm_fb_helper_fini(&fbdev_cma->fb_helper);
        kfree(fbdev_cma);
index 2cde7a5..656c061 100644 (file)
@@ -3,6 +3,7 @@ config DRM_ETNAVIV
        tristate "ETNAVIV (DRM support for Vivante GPU IP cores)"
        depends on DRM
        depends on ARCH_MXC || ARCH_DOVE
+       depends on MMU
        select SHMEM
        select TMPFS
        select IOMMU_API
index c6745a1..d69af00 100644 (file)
@@ -467,7 +467,7 @@ err:
                clk_disable_unprepare(ctx->clks[i]);
 }
 
-static struct exynos_drm_crtc_ops decon_crtc_ops = {
+static const struct exynos_drm_crtc_ops decon_crtc_ops = {
        .enable                 = decon_enable,
        .disable                = decon_disable,
        .enable_vblank          = decon_enable_vblank,
index 2530bf5..309c8ee 100644 (file)
@@ -109,9 +109,6 @@ static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-       struct exynos_drm_private *private = crtc->dev->dev_private;
-
-       private->crtc[exynos_crtc->pipe] = NULL;
 
        drm_crtc_cleanup(crtc);
        kfree(exynos_crtc);
@@ -134,7 +131,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
                                        void *ctx)
 {
        struct exynos_drm_crtc *exynos_crtc;
-       struct exynos_drm_private *private = drm_dev->dev_private;
        struct drm_crtc *crtc;
        int ret;
 
@@ -149,8 +145,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
 
        crtc = &exynos_crtc->base;
 
-       private->crtc[pipe] = crtc;
-
        ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
                                        &exynos_crtc_funcs, NULL);
        if (ret < 0)
index 80c4d5b..cf6e08c 100644 (file)
@@ -211,12 +211,6 @@ struct drm_exynos_file_private {
 struct exynos_drm_private {
        struct drm_fb_helper *fb_helper;
 
-       /*
-        * created crtc object would be contained at this array and
-        * this array is used to be aware of which crtc did it request vblank.
-        */
-       struct drm_crtc *crtc[MAX_CRTC];
-
        struct device *dma_dev;
        void *mapping;
 
@@ -231,9 +225,9 @@ struct exynos_drm_private {
 static inline struct exynos_drm_crtc *
 exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe)
 {
-       struct exynos_drm_private *private = dev->dev_private;
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
 
-       return to_exynos_crtc(private->crtc[pipe]);
+       return to_exynos_crtc(crtc);
 }
 
 static inline struct device *to_dma_dev(struct drm_device *dev)
index 307d460..9a0678a 100644 (file)
@@ -304,8 +304,8 @@ static void ade_set_medianoc_qos(struct ade_crtc *acrtc)
 
 static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
-       struct kirin_drm_private *priv = dev->dev_private;
-       struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
+       struct ade_crtc *acrtc = to_ade_crtc(crtc);
        struct ade_hw_ctx *ctx = acrtc->ctx;
        void __iomem *base = ctx->base;
 
@@ -320,8 +320,8 @@ static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
 
 static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
-       struct kirin_drm_private *priv = dev->dev_private;
-       struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
+       struct ade_crtc *acrtc = to_ade_crtc(crtc);
        struct ade_hw_ctx *ctx = acrtc->ctx;
        void __iomem *base = ctx->base;
 
@@ -575,7 +575,6 @@ static const struct drm_crtc_funcs ade_crtc_funcs = {
 static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
                         struct drm_plane *plane)
 {
-       struct kirin_drm_private *priv = dev->dev_private;
        struct device_node *port;
        int ret;
 
@@ -599,7 +598,6 @@ static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
        }
 
        drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
-       priv->crtc[drm_crtc_index(crtc)] = crtc;
 
        return 0;
 }
index a0bb217..7f60c64 100644 (file)
@@ -20,7 +20,6 @@ struct kirin_dc_ops {
 };
 
 struct kirin_drm_private {
-       struct drm_crtc *crtc[MAX_CRTC];
 #ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_fbdev_cma *fbdev;
 #endif
index ead3b64..2446280 100644 (file)
@@ -49,6 +49,7 @@
 #include <drm/drm_legacy.h> /* for struct drm_dma_handle */
 #include <drm/drm_gem.h>
 #include <drm/drm_auth.h>
+#include <drm/drm_cache.h>
 
 #include "i915_params.h"
 #include "i915_reg.h"
index 359cd27..f645275 100644 (file)
@@ -207,8 +207,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
        struct drm_device *drm = data;
        struct drm_encoder *encoder;
        struct imx_hdmi *hdmi;
-       struct resource *iores;
-       int irq;
        int ret;
 
        if (!pdev->dev.of_node)
@@ -223,14 +221,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
        hdmi->dev = &pdev->dev;
        encoder = &hdmi->encoder;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -ENXIO;
-
        encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
        /*
         * If we failed to find the CRTC(s) which this encoder is
@@ -249,7 +239,7 @@ 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(dev, master, data, encoder, iores, irq, plat_data);
+       ret = dw_hdmi_bind(pdev, encoder, plat_data);
 
        /*
         * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -264,7 +254,7 @@ 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, master, data);
+       return dw_hdmi_unbind(dev);
 }
 
 static const struct component_ops dw_hdmi_imx_ops = {
index 01a21dd..a73de1e 100644 (file)
@@ -170,8 +170,8 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
 
 int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
 {
-       struct mtk_drm_private *priv = drm->dev_private;
-       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+       struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
        struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
 
        mtk_ddp_comp_enable_vblank(ovl, &mtk_crtc->base);
@@ -181,8 +181,8 @@ int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
 
 void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
 {
-       struct mtk_drm_private *priv = drm->dev_private;
-       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+       struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
        struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0];
 
        mtk_ddp_comp_disable_vblank(ovl);
@@ -588,7 +588,6 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                goto unprepare;
        drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE);
        drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE);
-       priv->crtc[pipe] = &mtk_crtc->base;
        priv->num_pipes++;
 
        return 0;
index aa93894..df322a7 100644 (file)
@@ -32,7 +32,6 @@ struct mtk_drm_private {
        struct drm_device *drm;
        struct device *dma_dev;
 
-       struct drm_crtc *crtc[MAX_CRTC];
        unsigned int num_pipes;
 
        struct device_node *mutex_node;
index d96b2b6..7f78da6 100644 (file)
@@ -4,6 +4,7 @@ config DRM_MSM
        depends on DRM
        depends on ARCH_QCOM || (ARM && COMPILE_TEST)
        depends on OF && COMMON_CLK
+       depends on MMU
        select REGULATOR
        select DRM_KMS_HELPER
        select DRM_PANEL
index 5d68ab3..f8a587e 100644 (file)
@@ -174,10 +174,8 @@ fail_unlock:
 fail:
 
        if (ret) {
-               if (fb) {
-                       drm_framebuffer_unregister_private(fb);
+               if (fb)
                        drm_framebuffer_remove(fb);
-               }
        }
 
        return ret;
@@ -247,7 +245,6 @@ void msm_fbdev_free(struct drm_device *dev)
        /* this will free the backing object */
        if (fbdev->fb) {
                msm_gem_put_vaddr(fbdev->bo);
-               drm_framebuffer_unregister_private(fbdev->fb);
                drm_framebuffer_remove(fbdev->fb);
        }
 
index add353e..6b57007 100644 (file)
@@ -58,27 +58,30 @@ int
 nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
 {
        struct drm_crtc *crtc;
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-               if (nv_crtc->index == pipe) {
-                       nvif_notify_get(&nv_crtc->vblank);
-                       return 0;
-               }
-       }
-       return -EINVAL;
+       struct nouveau_crtc *nv_crtc;
+
+       crtc = drm_crtc_from_index(dev, pipe);
+       if (!crtc)
+               return -EINVAL;
+
+       nv_crtc = nouveau_crtc(crtc);
+       nvif_notify_get(&nv_crtc->vblank);
+
+       return 0;
 }
 
 void
 nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
 {
        struct drm_crtc *crtc;
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-               if (nv_crtc->index == pipe) {
-                       nvif_notify_put(&nv_crtc->vblank);
-                       return;
-               }
-       }
+       struct nouveau_crtc *nv_crtc;
+
+       crtc = drm_crtc_from_index(dev, pipe);
+       if (!crtc)
+               return;
+
+       nv_crtc = nouveau_crtc(crtc);
+       nvif_notify_put(&nv_crtc->vblank);
 }
 
 static inline int
index aed99a0..2a83995 100644 (file)
@@ -225,10 +225,8 @@ fail:
 
                drm_fb_helper_release_fbi(helper);
 
-               if (fb) {
-                       drm_framebuffer_unregister_private(fb);
+               if (fb)
                        drm_framebuffer_remove(fb);
-               }
        }
 
        return ret;
@@ -314,10 +312,8 @@ void omap_fbdev_free(struct drm_device *dev)
        omap_gem_put_paddr(fbdev->bo);
 
        /* this will free the backing object */
-       if (fbdev->fb) {
-               drm_framebuffer_unregister_private(fbdev->fb);
+       if (fbdev->fb)
                drm_framebuffer_remove(fbdev->fb);
-       }
 
        kfree(fbdev);
 
index 241af91..057b2b5 100644 (file)
@@ -84,8 +84,18 @@ int
 qxl_debugfs_init(struct drm_minor *minor)
 {
 #if defined(CONFIG_DEBUG_FS)
+       int r;
+       struct qxl_device *dev =
+               (struct qxl_device *) minor->dev->dev_private;
+
        drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES,
                                 minor->debugfs_root, minor);
+
+       r = qxl_ttm_debugfs_init(dev);
+       if (r) {
+               DRM_ERROR("Failed to init TTM debugfs\n");
+               return r;
+       }
 #endif
        return 0;
 }
index 659c777..416ade8 100644 (file)
@@ -1077,7 +1077,6 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
                                   dev->mode_config.suggested_x_property, 0);
        drm_object_attach_property(&connector->base,
                                   dev->mode_config.suggested_y_property, 0);
-       drm_connector_register(connector);
        return 0;
 }
 
index 460bbce..6e0f8a2 100644 (file)
@@ -62,20 +62,83 @@ static struct pci_driver qxl_pci_driver;
 static int
 qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       struct drm_device *drm;
+       struct qxl_device *qdev;
+       int ret;
+
        if (pdev->revision < 4) {
                DRM_ERROR("qxl too old, doesn't support client_monitors_config,"
                          " use xf86-video-qxl in user mode");
                return -EINVAL; /* TODO: ENODEV ? */
        }
-       return drm_get_pci_dev(pdev, ent, &qxl_driver);
+
+       drm = drm_dev_alloc(&qxl_driver, &pdev->dev);
+       if (IS_ERR(drm))
+               return -ENOMEM;
+
+       qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
+       if (!qdev) {
+               ret = -ENOMEM;
+               goto free_drm_device;
+       }
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto free_drm_device;
+
+       drm->pdev = pdev;
+       pci_set_drvdata(pdev, drm);
+       drm->dev_private = qdev;
+
+       ret = qxl_device_init(qdev, drm, pdev, ent->driver_data);
+       if (ret)
+               goto disable_pci;
+
+       ret = drm_vblank_init(drm, 1);
+       if (ret)
+               goto unload;
+
+       ret = qxl_modeset_init(qdev);
+       if (ret)
+               goto vblank_cleanup;
+
+       drm_kms_helper_poll_init(qdev->ddev);
+
+       /* Complete initialization. */
+       ret = drm_dev_register(drm, ent->driver_data);
+       if (ret)
+               goto modeset_cleanup;
+
+       return 0;
+
+modeset_cleanup:
+       qxl_modeset_fini(qdev);
+vblank_cleanup:
+       drm_vblank_cleanup(drm);
+unload:
+       qxl_device_fini(qdev);
+disable_pci:
+       pci_disable_device(pdev);
+free_drm_device:
+       kfree(qdev);
+       kfree(drm);
+       return ret;
 }
 
 static void
 qxl_pci_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
+       struct qxl_device *qdev = dev->dev_private;
+
+       drm_dev_unregister(dev);
+
+       qxl_modeset_fini(qdev);
+       qxl_device_fini(qdev);
 
-       drm_put_dev(dev);
+       dev->dev_private = NULL;
+       kfree(qdev);
+       drm_dev_unref(dev);
 }
 
 static const struct file_operations qxl_fops = {
@@ -230,8 +293,6 @@ static struct pci_driver qxl_pci_driver = {
 static struct drm_driver qxl_driver = {
        .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
                           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
-       .load = qxl_driver_load,
-       .unload = qxl_driver_unload,
        .get_vblank_counter = qxl_noop_get_vblank_counter,
        .enable_vblank = qxl_noop_enable_vblank,
        .disable_vblank = qxl_noop_disable_vblank,
index 883d863..0d877fa 100644 (file)
@@ -336,8 +336,9 @@ __printf(2,3) void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...);
 extern const struct drm_ioctl_desc qxl_ioctls[];
 extern int qxl_max_ioctl;
 
-int qxl_driver_load(struct drm_device *dev, unsigned long flags);
-void qxl_driver_unload(struct drm_device *dev);
+int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev,
+                   struct pci_dev *pdev,  unsigned long flags);
+void qxl_device_fini(struct qxl_device *qdev);
 
 int qxl_modeset_init(struct qxl_device *qdev);
 void qxl_modeset_fini(struct qxl_device *qdev);
@@ -531,6 +532,7 @@ int qxl_garbage_collect(struct qxl_device *qdev);
 
 int qxl_debugfs_init(struct drm_minor *minor);
 void qxl_debugfs_takedown(struct drm_minor *minor);
+int qxl_ttm_debugfs_init(struct qxl_device *qdev);
 
 /* qxl_prime.c */
 int qxl_gem_prime_pin(struct drm_gem_object *obj);
index b249140..d0666f5 100644 (file)
@@ -115,7 +115,7 @@ static void qxl_gc_work(struct work_struct *work)
        qxl_garbage_collect(qdev);
 }
 
-static int qxl_device_init(struct qxl_device *qdev,
+int qxl_device_init(struct qxl_device *qdev,
                    struct drm_device *ddev,
                    struct pci_dev *pdev,
                    unsigned long flags)
@@ -263,7 +263,7 @@ static int qxl_device_init(struct qxl_device *qdev,
        return 0;
 }
 
-static void qxl_device_fini(struct qxl_device *qdev)
+void qxl_device_fini(struct qxl_device *qdev)
 {
        if (qdev->current_release_bo[0])
                qxl_bo_unref(&qdev->current_release_bo[0]);
@@ -284,55 +284,3 @@ static void qxl_device_fini(struct qxl_device *qdev)
        qdev->mode_info.num_modes = 0;
        qxl_debugfs_remove_files(qdev);
 }
-
-void qxl_driver_unload(struct drm_device *dev)
-{
-       struct qxl_device *qdev = dev->dev_private;
-
-       if (qdev == NULL)
-               return;
-
-       drm_vblank_cleanup(dev);
-
-       qxl_modeset_fini(qdev);
-       qxl_device_fini(qdev);
-
-       kfree(qdev);
-       dev->dev_private = NULL;
-}
-
-int qxl_driver_load(struct drm_device *dev, unsigned long flags)
-{
-       struct qxl_device *qdev;
-       int r;
-
-       qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
-       if (qdev == NULL)
-               return -ENOMEM;
-
-       dev->dev_private = qdev;
-
-       r = qxl_device_init(qdev, dev, dev->pdev, flags);
-       if (r)
-               goto out;
-
-       r = drm_vblank_init(dev, 1);
-       if (r)
-               goto unload;
-
-       r = qxl_modeset_init(qdev);
-       if (r)
-               goto unload;
-
-       drm_kms_helper_poll_init(qdev->ddev);
-
-       return 0;
-unload:
-       qxl_driver_unload(dev);
-
-out:
-       kfree(qdev);
-       return r;
-}
-
-
index 1b096c5..bc1c896 100644 (file)
@@ -35,7 +35,6 @@
 #include "qxl_object.h"
 
 #include <linux/delay.h>
-static int qxl_ttm_debugfs_init(struct qxl_device *qdev);
 
 static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
 {
@@ -436,11 +435,6 @@ int qxl_ttm_init(struct qxl_device *qdev)
                 ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
        DRM_INFO("qxl: %uM of Surface memory size\n",
                 (unsigned)qdev->surfaceram_size / (1024 * 1024));
-       r = qxl_ttm_debugfs_init(qdev);
-       if (r) {
-               DRM_ERROR("Failed to init debugfs\n");
-               return r;
-       }
        return 0;
 }
 
@@ -473,7 +467,7 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data)
 }
 #endif
 
-static int qxl_ttm_debugfs_init(struct qxl_device *qdev)
+int qxl_ttm_debugfs_init(struct qxl_device *qdev)
 {
 #if defined(CONFIG_DEBUG_FS)
        static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
index 0665fb9..a6d4a02 100644 (file)
@@ -257,8 +257,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
        struct drm_device *drm = data;
        struct drm_encoder *encoder;
        struct rockchip_hdmi *hdmi;
-       struct resource *iores;
-       int irq;
        int ret;
 
        if (!pdev->dev.of_node)
@@ -273,14 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
        hdmi->dev = &pdev->dev;
        encoder = &hdmi->encoder;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -ENXIO;
-
        encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
        /*
         * If we failed to find the CRTC(s) which this encoder is
@@ -301,7 +291,7 @@ 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(dev, master, data, encoder, iores, irq, plat_data);
+       ret = dw_hdmi_bind(pdev, encoder, plat_data);
 
        /*
         * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -316,7 +306,7 @@ 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, master, data);
+       return dw_hdmi_unbind(dev);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
index 6d2a5cd..6df53e6 100644 (file)
@@ -1274,13 +1274,19 @@ static bool evict_everything(struct drm_mm *mm,
                if (drm_mm_scan_add_block(&scan, &e->node))
                        break;
        }
+
+       err = 0;
        list_for_each_entry(e, &evict_list, link) {
                if (!drm_mm_scan_remove_block(&scan, &e->node)) {
-                       pr_err("Node %lld not marked for eviction!\n",
-                              e->node.start);
-                       list_del(&e->link);
+                       if (!err) {
+                               pr_err("Node %lld not marked for eviction!\n",
+                                      e->node.start);
+                               err = -EINVAL;
+                       }
                }
        }
+       if (err)
+               return false;
 
        list_for_each_entry(e, &evict_list, link)
                drm_mm_remove_node(&e->node);
index 0f4eacb..2d57f62 100644 (file)
@@ -804,23 +804,10 @@ static const struct file_operations tegra_drm_fops = {
        .llseek = noop_llseek,
 };
 
-static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
-                                            unsigned int pipe)
-{
-       struct drm_crtc *crtc;
-
-       list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
-               if (pipe == drm_crtc_index(crtc))
-                       return crtc;
-       }
-
-       return NULL;
-}
-
 static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
                                        unsigned int pipe)
 {
-       struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+       struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
        struct tegra_dc *dc = to_tegra_dc(crtc);
 
        if (!crtc)
@@ -831,7 +818,7 @@ static u32 tegra_drm_get_vblank_counter(struct drm_device *drm,
 
 static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
 {
-       struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+       struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
        struct tegra_dc *dc = to_tegra_dc(crtc);
 
        if (!crtc)
@@ -844,7 +831,7 @@ static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
 
 static void tegra_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
 {
-       struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+       struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe);
        struct tegra_dc *dc = to_tegra_dc(crtc);
 
        if (crtc)
index 8df7783..f896e2f 100644 (file)
@@ -271,8 +271,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
        return 0;
 
 destroy:
-       drm_framebuffer_unregister_private(fb);
-       tegra_fb_destroy(fb);
+       drm_framebuffer_remove(fb);
 release:
        drm_fb_helper_release_fbi(helper);
        return err;
@@ -342,10 +341,8 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
        drm_fb_helper_unregister_fbi(&fbdev->base);
        drm_fb_helper_release_fbi(&fbdev->base);
 
-       if (fbdev->fb) {
-               drm_framebuffer_unregister_private(&fbdev->fb->base);
+       if (fbdev->fb)
                drm_framebuffer_remove(&fbdev->fb->base);
-       }
 
        drm_fb_helper_fini(&fbdev->base);
        tegra_fbdev_free(fbdev);
index a0fd3e6..75b708b 100644 (file)
@@ -156,7 +156,8 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
                            const struct drm_display_mode *mode)
 {
        struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
        u32 val;
        int fifo_lines;
        int vblank_lines;
@@ -272,9 +273,7 @@ int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id,
                                  int *max_error, struct timeval *vblank_time,
                                  unsigned flags)
 {
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
-       struct drm_crtc *crtc = &vc4_crtc->base;
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
        struct drm_crtc_state *state = crtc->state;
 
        /* Helper routine in DRM core does all the work: */
@@ -652,8 +651,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
 
 int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
 {
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
 
        CRTC_WRITE(PV_INTEN, PV_INT_VFP_START);
 
@@ -662,8 +661,8 @@ int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id)
 
 void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id)
 {
-       struct vc4_dev *vc4 = to_vc4_dev(dev);
-       struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id];
+       struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
 
        CRTC_WRITE(PV_INTEN, 0);
 }
@@ -937,7 +936,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct drm_device *drm = dev_get_drvdata(master);
-       struct vc4_dev *vc4 = to_vc4_dev(drm);
        struct vc4_crtc *vc4_crtc;
        struct drm_crtc *crtc;
        struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
@@ -975,7 +973,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
                                  &vc4_crtc_funcs, NULL);
        drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
        primary_plane->crtc = crtc;
-       vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc;
        vc4_crtc->channel = vc4_crtc->data->hvs_channel;
        drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
 
index 489956e..affcdeb 100644 (file)
@@ -16,7 +16,6 @@ struct vc4_dev {
 
        struct vc4_hdmi *hdmi;
        struct vc4_hvs *hvs;
-       struct vc4_crtc *crtc[3];
        struct vc4_v3d *v3d;
        struct vc4_dpi *dpi;
        struct vc4_vec *vec;
index 1f8798a..cb59c7a 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
+#include <drm/drm_cache.h>
 
 #include <uapi/drm/vgem_drm.h>
 
index bae79f3..b080a17 100644 (file)
@@ -27,6 +27,16 @@ enum dw_hdmi_devtype {
        RK3288_HDMI,
 };
 
+enum dw_hdmi_phy_type {
+       DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
+       DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
+       DW_HDMI_PHY_DWC_MHL_PHY = 0xc2,
+       DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC = 0xe2,
+       DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY = 0xf2,
+       DW_HDMI_PHY_DWC_HDMI20_TX_PHY = 0xf3,
+       DW_HDMI_PHY_VENDOR_PHY = 0xfe,
+};
+
 struct dw_hdmi_mpll_config {
        unsigned long mpixelclock;
        struct {
@@ -56,10 +66,11 @@ struct dw_hdmi_plat_data {
                                           struct drm_display_mode *mode);
 };
 
-void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
-int dw_hdmi_bind(struct device *dev, struct device *master,
-                void *data, struct drm_encoder *encoder,
-                struct resource *iores, int irq,
+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);
 
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
index 9af3bb1..e5882d5 100644 (file)
@@ -731,11 +731,6 @@ int drm_noop(struct drm_device *dev, void *data,
 int drm_invalid_op(struct drm_device *dev, void *data,
                   struct drm_file *file_priv);
 
-/* Cache management (drm_cache.c) */
-void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
-void drm_clflush_sg(struct sg_table *st);
-void drm_clflush_virt_range(void *addr, unsigned long length);
-
 /*
  * These are exported to drivers so that they can implement fencing using
  * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
index 4b2353d..9afcd38 100644 (file)
@@ -121,6 +121,12 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event,
                                uint32_t flags);
+int drm_atomic_helper_page_flip_target(
+                               struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               struct drm_pending_vblank_event *event,
+                               uint32_t flags,
+                               uint32_t target);
 int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
                                     int mode);
 struct drm_encoder *
index cebecff..beab0f0 100644 (file)
 #ifndef _DRM_CACHE_H_
 #define _DRM_CACHE_H_
 
+#include <linux/scatterlist.h>
+
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
+void drm_clflush_sg(struct sg_table *st);
+void drm_clflush_virt_range(void *addr, unsigned long length);
 
 static inline bool drm_arch_can_wc_memory(void)
 {
index 17c9f52..06c943d 100644 (file)
@@ -149,6 +149,15 @@ struct drm_crtc_state {
        struct drm_property_blob *gamma_lut;
 
        /**
+        * @target_vblank:
+        *
+        * Target vertical blank period when a page flip
+        * should take effect.
+        */
+
+       u32 target_vblank;
+
+       /**
         * @event:
         *
         * Optional pointer to a DRM event to signal upon completion of the
index 9e1bb7f..1596d53 100644 (file)
@@ -41,10 +41,17 @@ extern "C" {
 /* 8 bpp Red */
 #define DRM_FORMAT_R8          fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
 
+/* 16 bpp Red */
+#define DRM_FORMAT_R16         fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
+
 /* 16 bpp RG */
 #define DRM_FORMAT_RG88                fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
 #define DRM_FORMAT_GR88                fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
 
+/* 32 bpp RG */
+#define DRM_FORMAT_RG1616      fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
+#define DRM_FORMAT_GR1616      fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
+
 /* 8 bpp RGB */
 #define DRM_FORMAT_RGB332      fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
 #define DRM_FORMAT_BGR233      fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */