]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge airlied/drm-next into drm-misc-next
authorSean Paul <seanpaul@chromium.org>
Wed, 21 Mar 2018 13:40:55 +0000 (09:40 -0400)
committerSean Paul <seanpaul@chromium.org>
Wed, 21 Mar 2018 13:40:55 +0000 (09:40 -0400)
Refresh -misc-next

Signed-off-by: Sean Paul <seanpaul@chromium.org>
85 files changed:
Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/display-timing.txt
Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt
Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/panel/simple-panel.txt
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/gpu/drivers.rst [new file with mode: 0644]
Documentation/gpu/drm-kms.rst
Documentation/gpu/index.rst
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_plane.c
drivers/gpu/drm/drm_print.c
drivers/gpu/drm/drm_property.c
drivers/gpu/drm/i915/intel_color.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/meson/meson_drv.c
drivers/gpu/drm/meson/meson_dw_hdmi.c
drivers/gpu/drm/meson/meson_vclk.c
drivers/gpu/drm/meson/meson_venc.c
drivers/gpu/drm/meson/meson_venc.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-ilitek-ili9322.c
drivers/gpu/drm/panel/panel-lvds.c
drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
drivers/gpu/drm/panel/panel-raydium-rm68200.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_dumb.c
drivers/gpu/drm/qxl/qxl_fb.c
drivers/gpu/drm/qxl/qxl_gem.c
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/rockchip/cdn-dp-core.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/sun4i/sun4i_backend.c
drivers/gpu/drm/sun4i/sun4i_backend.h
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_layer.c
drivers/gpu/drm/sun4i/sun4i_lvds.c
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h
drivers/gpu/drm/sun4i/sun6i_drc.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/vc4/vc4_regs.h
drivers/gpu/drm/vc4/vc4_validate.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/vga/vga_switcheroo.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/quirks.c
include/drm/bridge/analogix_dp.h
include/drm/drm_color_mgmt.h
include/drm/drm_dp_helper.h
include/drm/drm_mode_object.h
include/drm/drm_print.h
include/drm/drm_property.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/vga_switcheroo.h
include/sound/hdaudio.h
scripts/coccinelle/api/drm-get-put.cocci
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.h

diff --git a/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt b/Documentation/devicetree/bindings/display/panel/auo,g104sn02.txt
new file mode 100644 (file)
index 0000000..85626ed
--- /dev/null
@@ -0,0 +1,12 @@
+AU Optronics Corporation 10.4" (800x600) color TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,g104sn02"
+- power-supply: as specified in the base binding
+
+Optional properties:
+- backlight: as specified in the base binding
+- enable-gpios: as specified in the base binding
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
index 58fa3e48481dee38f97e42523f0ce9eb7c2d6ec6..78222ced187436503382c0241f39a438af842c16 100644 (file)
@@ -80,6 +80,11 @@ The parameters are defined as:
   |          |        v                            |          |       |
   +----------+-------------------------------------+----------+-------+
 
+Note: In addition to being used as subnode(s) of display-timings, the timing
+      subnode may also be used on its own. This is appropriate if only one mode
+      need be conveyed. In this case, the node should be named 'panel-timing'.
+
+
 Example:
 
        display-timings {
diff --git a/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt b/Documentation/devicetree/bindings/display/panel/koe,tx31d200vm0baa.txt
new file mode 100644 (file)
index 0000000..6a036ed
--- /dev/null
@@ -0,0 +1,25 @@
+Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS panel
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
+
+Required properties:
+- compatible: should be "koe,tx31d200vm0baa"
+
+Optional properties:
+- backlight: phandle of the backlight device attached to the panel
+
+Optional nodes:
+- Video port for LVDS panel input.
+
+Example:
+       panel {
+               compatible = "koe,tx31d200vm0baa";
+               backlight = <&backlight_lvds>;
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&lvds0_out>;
+                       };
+               };
+       };
index 6862028e7b2ecd9b1ef65079b02fc790ef412f3d..203b03eefb688aa0c1ba6e44578e98acc435a2d6 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
 
 Optional properties:
   - reset-gpios: a GPIO spec for the reset pin (active low).
+  - power-supply: phandle of the regulator that provides the supply voltage.
 
 Example:
 &dsi {
@@ -17,5 +18,6 @@ Example:
                compatible = "orisetech,otm8009a";
                reg = <0>;
                reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>;
+               power-supply = <&v1v8>;
        };
 };
diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt
new file mode 100644 (file)
index 0000000..cbb79ef
--- /dev/null
@@ -0,0 +1,25 @@
+Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel
+
+The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD
+panel connected using a MIPI-DSI video interface.
+
+Required properties:
+  - compatible: "raydium,rm68200"
+  - reg: the virtual channel number of a DSI peripheral
+
+Optional properties:
+  - reset-gpios: a GPIO spec for the reset pin (active low).
+  - power-supply: phandle of the regulator that provides the supply voltage.
+  - backlight: phandle of the backlight device attached to the panel.
+
+Example:
+&dsi {
+       ...
+       panel@0 {
+               compatible = "raydium,rm68200";
+               reg = <0>;
+               reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>;
+               power-supply = <&v1v8>;
+               backlight = <&pwm_backlight>;
+       };
+};
index 16d8ff088b7d15504afd58984b291ded9a4b7f15..45a457ad38f0f078eed709424e1e237ebcfe420f 100644 (file)
@@ -1,4 +1,8 @@
 Simple display panel
+====================
+
+panel node
+----------
 
 Required properties:
 - power-supply: See panel-common.txt
index 8bdef4920edc475f60c7b123fd09a83d31a0096a..3346c1e2a7a00a8ed0a7cf7685d53cf354397aa8 100644 (file)
@@ -146,13 +146,16 @@ Required properties:
    * allwinner,sun8i-a83t-tcon-lcd
    * allwinner,sun8i-a83t-tcon-tv
    * allwinner,sun8i-v3s-tcon
+   * allwinner,sun9i-a80-tcon-lcd
+   * allwinner,sun9i-a80-tcon-tv
  - reg: base address and size of memory-mapped region
  - interrupts: interrupt associated to this IP
  - clocks: phandles to the clocks feeding the TCON.
    - 'ahb': the interface clocks
-   - 'tcon-ch0': The clock driving the TCON channel 0, except for A83T TV TCON
+   - 'tcon-ch0': The clock driving the TCON channel 0, if supported
  - resets: phandles to the reset controllers driving the encoder
-   - "lcd": the reset line for the TCON channel 0
+   - "lcd": the reset line for the TCON
+   - "edp": the reset line for the eDP block (A80 only)
 
  - clock-names: the clock names mentioned above
  - reset-names: the reset names mentioned above
@@ -171,7 +174,9 @@ Required properties:
   channel the endpoint is associated to. If that property is not
   present, the endpoint number will be used as the channel number.
 
-On SoCs other than the A33 and V3s, there is one more clock required:
+For TCONs with channel 0, there is one more clock required:
+   - 'tcon-ch0': The clock driving the TCON channel 0
+For TCONs with channel 1, there is one more clock required:
    - 'tcon-ch1': The clock driving the TCON channel 1
 
 When TCON support LVDS (all TCONs except TV TCON on A83T and those found
@@ -186,7 +191,7 @@ DRC
 ---
 
 The DRC (Dynamic Range Controller), found in the latest Allwinner SoCs
-(A31, A23, A33), allows to dynamically adjust pixel
+(A31, A23, A33, A80), allows to dynamically adjust pixel
 brightness/contrast based on histogram measurements for LCD content
 adaptive backlight control.
 
@@ -196,6 +201,7 @@ Required properties:
     * allwinner,sun6i-a31-drc
     * allwinner,sun6i-a31s-drc
     * allwinner,sun8i-a33-drc
+    * allwinner,sun9i-a80-drc
   - reg: base address and size of the memory-mapped region.
   - interrupts: interrupt associated to this IP
   - clocks: phandles to the clocks feeding the DRC
@@ -222,6 +228,7 @@ Required properties:
     * allwinner,sun6i-a31-display-backend
     * allwinner,sun7i-a20-display-backend
     * allwinner,sun8i-a33-display-backend
+    * allwinner,sun9i-a80-display-backend
   - reg: base address and size of the memory-mapped region.
   - interrupts: interrupt associated to this IP
   - clocks: phandles to the clocks feeding the frontend and backend
@@ -243,6 +250,28 @@ On the A33, some additional properties are required:
   - resets and reset-names need to have a phandle to the SAT bus
     resets, whose name will be "sat"
 
+DEU
+---
+
+The DEU (Detail Enhancement Unit), found in the Allwinner A80 SoC,
+can sharpen the display content in both luma and chroma channels.
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun9i-a80-deu
+  - reg: base address and size of the memory-mapped region.
+  - interrupts: interrupt associated to this IP
+  - clocks: phandles to the clocks feeding the DEU
+    * ahb: the DEU interface clock
+    * mod: the DEU module clock
+    * ram: the DEU DRAM clock
+  - clock-names: the clock names mentioned above
+  - resets: phandles to the reset line driving the DEU
+
+- ports: A ports node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. The
+  first port should be the input endpoints, the second one the outputs
+
 Display Engine Frontend
 -----------------------
 
@@ -256,6 +285,7 @@ Required properties:
     * allwinner,sun6i-a31-display-frontend
     * allwinner,sun7i-a20-display-frontend
     * allwinner,sun8i-a33-display-frontend
+    * allwinner,sun9i-a80-display-frontend
   - reg: base address and size of the memory-mapped region.
   - interrupts: interrupt associated to this IP
   - clocks: phandles to the clocks feeding the frontend and backend
@@ -312,6 +342,7 @@ Required properties:
     * allwinner,sun8i-a83t-display-engine
     * allwinner,sun8i-h3-display-engine
     * allwinner,sun8i-v3s-display-engine
+    * allwinner,sun9i-a80-display-engine
 
   - allwinner,pipelines: list of phandle to the display engine
     frontends (DE 1.0) or mixers (DE 2.0) available.
index ae850d6c0ad3779f2e9fa0f1ba60f49b5b864e8a..12e8b3e576b078dba7e46fb5671f3fca3c5bbff3 100644 (file)
@@ -104,6 +104,7 @@ eeti        eGalax_eMPIA Technology Inc
 elan   Elan Microelectronic Corp.
 embest Shenzhen Embest Technology Co., Ltd.
 emmicro        EM Microelectronic
+emtrion        emtrion GmbH
 energymicro    Silicon Laboratories (formerly Energy Micro AS)
 engicam        Engicam S.r.l.
 epcos  EPCOS AG
diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
new file mode 100644 (file)
index 0000000..e8c8441
--- /dev/null
@@ -0,0 +1,21 @@
+========================
+GPU Driver Documentation
+========================
+
+.. toctree::
+
+   i915
+   meson
+   pl111
+   tegra
+   tinydrm
+   tve200
+   vc4
+   bridge/dw-hdmi
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 56a3780e39b8ec86e1adecf5811ad3305aa53ce9..1dffd1ac4cd44be310fa7b8855c265cc57cd30ae 100644 (file)
@@ -286,6 +286,9 @@ Atomic Mode Setting Function Reference
 .. kernel-doc:: drivers/gpu/drm/drm_atomic.c
    :export:
 
+.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
+   :internal:
+
 CRTC Abstraction
 ================
 
index c36586dad29d20bf7b1704efa87f69945c31a542..00288f34c5a6322835877770fb86c2cd8d380a22 100644 (file)
@@ -10,16 +10,9 @@ Linux GPU Driver Developer's Guide
    drm-kms
    drm-kms-helpers
    drm-uapi
-   i915
-   meson
-   pl111
-   tegra
-   tinydrm
-   tve200
-   vc4
+   drivers
    vga-switcheroo
    vgaarbiter
-   bridge/dw-hdmi
    todo
 
 .. only::  subproject and html
index e6709362994a3e331c45c9622e6f94e3dffd6de7..2337d4bfd85c7f34ff6432bcb1eaf518edf5789a 100644 (file)
@@ -738,7 +738,6 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
 
        drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
        drm_kms_helper_poll_disable(drm_dev);
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
 
        ret = amdgpu_device_suspend(drm_dev, false, false);
        pci_save_state(pdev);
@@ -775,7 +774,6 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
 
        ret = amdgpu_device_resume(drm_dev, false, false);
        drm_kms_helper_poll_enable(drm_dev);
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
        drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
        return 0;
 }
index a693ab3078f0fd1e3bef19dbda9a716b38070bbb..5c52307146c7c3a09c22b6def2a469ac921b388b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
@@ -35,6 +36,8 @@
 
 #define to_dp(nm)      container_of(nm, struct analogix_dp_device, nm)
 
+static const bool verify_fast_training;
+
 struct bridge_init {
        struct i2c_client *client;
        struct device_node *node;
@@ -98,18 +101,18 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
        return 0;
 }
 
-int analogix_dp_psr_supported(struct analogix_dp_device *dp)
+int analogix_dp_psr_enabled(struct analogix_dp_device *dp)
 {
 
-       return dp->psr_support;
+       return dp->psr_enable;
 }
-EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
+EXPORT_SYMBOL_GPL(analogix_dp_psr_enabled);
 
 int analogix_dp_enable_psr(struct analogix_dp_device *dp)
 {
        struct edp_vsc_psr psr_vsc;
 
-       if (!dp->psr_support)
+       if (!dp->psr_enable)
                return 0;
 
        /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
@@ -122,8 +125,7 @@ int analogix_dp_enable_psr(struct analogix_dp_device *dp)
        psr_vsc.DB0 = 0;
        psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-       analogix_dp_send_psr_spd(dp, &psr_vsc);
-       return 0;
+       return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -132,7 +134,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
        struct edp_vsc_psr psr_vsc;
        int ret;
 
-       if (!dp->psr_support)
+       if (!dp->psr_enable)
                return 0;
 
        /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
@@ -149,8 +151,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
        if (ret != 1)
                dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret);
 
-       analogix_dp_send_psr_spd(dp, &psr_vsc);
-       return 0;
+       return analogix_dp_send_psr_spd(dp, &psr_vsc, false);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
@@ -530,7 +531,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
 {
        int lane, lane_count, retval;
        u32 reg;
-       u8 link_align, link_status[2], adjust_request[2];
+       u8 link_align, link_status[2], adjust_request[2], spread;
 
        usleep_range(400, 401);
 
@@ -573,6 +574,20 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
                dev_dbg(dp->dev, "final lane count = %.2x\n",
                        dp->link_train.lane_count);
 
+               retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD,
+                                          &spread);
+               if (retval != 1) {
+                       dev_err(dp->dev, "failed to read downspread %d\n",
+                               retval);
+                       dp->fast_train_support = false;
+               } else {
+                       dp->fast_train_support =
+                               (spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ?
+                                       true : false;
+               }
+               dev_dbg(dp->dev, "fast link training %s\n",
+                       dp->fast_train_support ? "supported" : "unsupported");
+
                /* set enhanced mode if available */
                analogix_dp_set_enhanced_mode(dp);
                dp->link_train.lt_state = FINISHED;
@@ -629,10 +644,12 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp,
        *lane_count = DPCD_MAX_LANE_COUNT(data);
 }
 
-static void analogix_dp_init_training(struct analogix_dp_device *dp,
-                                     enum link_lane_count_type max_lane,
-                                     int max_rate)
+static int analogix_dp_full_link_train(struct analogix_dp_device *dp,
+                                      u32 max_lanes, u32 max_rate)
 {
+       int retval = 0;
+       bool training_finished = false;
+
        /*
         * MACRO_RST must be applied after the PLL_LOCK to avoid
         * the DP inter pair skew issue for at least 10 us
@@ -658,18 +675,13 @@ static void analogix_dp_init_training(struct analogix_dp_device *dp,
        }
 
        /* Setup TX lane count & rate */
-       if (dp->link_train.lane_count > max_lane)
-               dp->link_train.lane_count = max_lane;
+       if (dp->link_train.lane_count > max_lanes)
+               dp->link_train.lane_count = max_lanes;
        if (dp->link_train.link_rate > max_rate)
                dp->link_train.link_rate = max_rate;
 
        /* All DP analog module power up */
        analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
-}
-
-static int analogix_dp_sw_link_training(struct analogix_dp_device *dp)
-{
-       int retval = 0, training_finished = 0;
 
        dp->link_train.lt_state = START;
 
@@ -704,22 +716,88 @@ static int analogix_dp_sw_link_training(struct analogix_dp_device *dp)
        return retval;
 }
 
-static int analogix_dp_set_link_train(struct analogix_dp_device *dp,
-                                     u32 count, u32 bwtype)
+static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
 {
-       int i;
-       int retval;
+       int i, ret;
+       u8 link_align, link_status[2];
+       enum pll_status status;
 
-       for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
-               analogix_dp_init_training(dp, count, bwtype);
-               retval = analogix_dp_sw_link_training(dp);
-               if (retval == 0)
-                       break;
+       analogix_dp_reset_macro(dp);
+
+       analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
+       analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
 
-               usleep_range(100, 110);
+       for (i = 0; i < dp->link_train.lane_count; i++) {
+               analogix_dp_set_lane_link_training(dp,
+                       dp->link_train.training_lane[i], i);
        }
 
-       return retval;
+       ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status,
+                                status != PLL_UNLOCKED, 120,
+                                120 * DP_TIMEOUT_LOOP_COUNT);
+       if (ret) {
+               DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret);
+               return ret;
+       }
+
+       /* source Set training pattern 1 */
+       analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
+       /* From DP spec, pattern must be on-screen for a minimum 500us */
+       usleep_range(500, 600);
+
+       analogix_dp_set_training_pattern(dp, TRAINING_PTN2);
+       /* From DP spec, pattern must be on-screen for a minimum 500us */
+       usleep_range(500, 600);
+
+       /* TODO: enhanced_mode?*/
+       analogix_dp_set_training_pattern(dp, DP_NONE);
+
+       /*
+        * Useful for debugging issues with fast link training, disable for more
+        * speed
+        */
+       if (verify_fast_training) {
+               ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED,
+                                       &link_align);
+               if (ret < 0) {
+                       DRM_DEV_ERROR(dp->dev, "Read align status failed %d\n",
+                                     ret);
+                       return ret;
+               }
+
+               ret = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status,
+                                      2);
+               if (ret < 0) {
+                       DRM_DEV_ERROR(dp->dev, "Read link status failed %d\n",
+                                     ret);
+                       return ret;
+               }
+
+               if (analogix_dp_clock_recovery_ok(link_status,
+                                                 dp->link_train.lane_count)) {
+                       DRM_DEV_ERROR(dp->dev, "Clock recovery failed\n");
+                       analogix_dp_reduce_link_rate(dp);
+                       return -EIO;
+               }
+
+               if (analogix_dp_channel_eq_ok(link_status, link_align,
+                                             dp->link_train.lane_count)) {
+                       DRM_DEV_ERROR(dp->dev, "Channel EQ failed\n");
+                       analogix_dp_reduce_link_rate(dp);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int analogix_dp_train_link(struct analogix_dp_device *dp)
+{
+       if (dp->fast_train_support)
+               return analogix_dp_fast_link_train(dp);
+
+       return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count,
+                                          dp->video_info.max_link_rate);
 }
 
 static int analogix_dp_config_video(struct analogix_dp_device *dp)
@@ -848,10 +926,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
                        DRM_ERROR("failed to disable the panel\n");
        }
 
-       ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count,
-                                        dp->video_info.max_link_rate);
+       ret = readx_poll_timeout(analogix_dp_train_link, dp, ret, !ret, 100,
+                                DP_TIMEOUT_TRAINING_US * 5);
        if (ret) {
-               dev_err(dp->dev, "unable to do link train\n");
+               dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
                return;
        }
 
@@ -873,8 +951,8 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
        /* Enable video */
        analogix_dp_start_video(dp);
 
-       dp->psr_support = analogix_dp_detect_sink_psr(dp);
-       if (dp->psr_support)
+       dp->psr_enable = analogix_dp_detect_sink_psr(dp);
+       if (dp->psr_enable)
                analogix_dp_enable_sink_psr(dp);
 }
 
@@ -1119,6 +1197,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
        if (ret)
                DRM_ERROR("failed to setup the panel ret = %d\n", ret);
 
+       dp->psr_enable = false;
        dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
index 5c6a28806129a4e6d2eb668db7e306f9d772877c..6a96ef7e6934692ba0e38dc5586356212acebd57 100644 (file)
 #define MAX_CR_LOOP 5
 #define MAX_EQ_LOOP 5
 
+/* Training takes 22ms if AUX channel comm fails. Use this as retry interval */
+#define DP_TIMEOUT_TRAINING_US                 22000
+#define DP_TIMEOUT_PSR_LOOP_MS                 300
+
 /* DP_MAX_LANE_COUNT */
 #define DPCD_ENHANCED_FRAME_CAP(x)             (((x) >> 7) & 0x1)
 #define DPCD_MAX_LANE_COUNT(x)                 ((x) & 0x1f)
@@ -168,7 +172,8 @@ struct analogix_dp_device {
        int                     dpms_mode;
        int                     hpd_gpio;
        bool                    force_hpd;
-       bool                    psr_support;
+       bool                    psr_enable;
+       bool                    fast_train_support;
 
        struct mutex            panel_lock;
        bool                    panel_is_modeset;
@@ -247,8 +252,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
-                             struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+                            struct edp_vsc_psr *vsc, bool blocking);
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
                             struct drm_dp_aux_msg *msg);
 
index 303083ad28e3fe1be042948db909579ccb814819..9df2f3ef000ca63f00114944a81496d6af59535f 100644 (file)
  * option) any later version.
  */
 
-#include <linux/device.h>
-#include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
 
 #include <drm/bridge/analogix_dp.h>
 
@@ -992,10 +993,25 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp)
        writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
-                             struct edp_vsc_psr *vsc)
+static ssize_t analogix_dp_get_psr_status(struct analogix_dp_device *dp)
+{
+       ssize_t val;
+       u8 status;
+
+       val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &status);
+       if (val < 0) {
+               dev_err(dp->dev, "PSR_STATUS read failed ret=%zd", val);
+               return val;
+       }
+       return status;
+}
+
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+                            struct edp_vsc_psr *vsc, bool blocking)
 {
        unsigned int val;
+       int ret;
+       ssize_t psr_status;
 
        /* don't send info frame */
        val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1036,6 +1052,20 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
        val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
        val |= IF_EN;
        writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+       if (!blocking)
+               return 0;
+
+       ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status,
+               psr_status >= 0 &&
+               ((vsc->DB1 && psr_status == DP_PSR_SINK_ACTIVE_RFB) ||
+               (!vsc->DB1 && psr_status == DP_PSR_SINK_INACTIVE)), 1500,
+               DP_TIMEOUT_PSR_LOOP_MS * 1000);
+       if (ret) {
+               dev_warn(dp->dev, "Failed to apply PSR %d\n", ret);
+               return ret;
+       }
+       return 0;
 }
 
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
index 53ebbe2904b66bcd6c74c0209ab82ba1d2424825..ec8d0006ef7cc1dbba52e5933bd03b6199039f4d 100644 (file)
@@ -147,7 +147,6 @@ struct dw_hdmi {
        int vic;
 
        u8 edid[HDMI_EDID_LEN];
-       bool cable_plugin;
 
        struct {
                const struct dw_hdmi_phy_ops *ops;
@@ -1679,12 +1678,6 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
                hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
 }
 
-static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
-{
-       hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
-       hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
-}
-
 static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
 {
        hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
@@ -1774,8 +1767,6 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
        hdmi_tx_hdcp_config(hdmi);
 
        dw_hdmi_clear_overflow(hdmi);
-       if (hdmi->cable_plugin && hdmi->sink_is_hdmi)
-               hdmi_enable_overflow_interrupts(hdmi);
 
        return 0;
 }
index 34b7d420e555e292b81388a4fda5c1e9c17993c3..7d25c42f22dbcf8d3efc8949b1db59999eda693e 100644 (file)
@@ -391,8 +391,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
        if (blob) {
                if (blob->length != sizeof(struct drm_mode_modeinfo) ||
                    drm_mode_convert_umode(state->crtc->dev, &state->mode,
-                                          (const struct drm_mode_modeinfo *)
-                                           blob->data))
+                                          blob->data))
                        return -EINVAL;
 
                state->mode_blob = drm_property_blob_get(blob);
@@ -409,11 +408,36 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
 
+/**
+ * drm_atomic_replace_property_blob_from_id - lookup the new blob and replace the old one with it
+ * @dev: DRM device
+ * @blob: a pointer to the member blob to be replaced
+ * @blob_id: ID of the new blob
+ * @expected_size: total expected size of the blob data (in bytes)
+ * @expected_elem_size: expected element size of the blob data (in bytes)
+ * @replaced: did the blob get replaced?
+ *
+ * Replace @blob with another blob with the ID @blob_id. If @blob_id is zero
+ * @blob becomes NULL.
+ *
+ * If @expected_size is positive the new blob length is expected to be equal
+ * to @expected_size bytes. If @expected_elem_size is positive the new blob
+ * length is expected to be a multiple of @expected_elem_size bytes. Otherwise
+ * an error is returned.
+ *
+ * @replaced will indicate to the caller whether the blob was replaced or not.
+ * If the old and new blobs were in fact the same blob @replaced will be false
+ * otherwise it will be true.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
+ */
 static int
 drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
                                         struct drm_property_blob **blob,
                                         uint64_t blob_id,
                                         ssize_t expected_size,
+                                        ssize_t expected_elem_size,
                                         bool *replaced)
 {
        struct drm_property_blob *new_blob = NULL;
@@ -423,7 +447,13 @@ drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
                if (new_blob == NULL)
                        return -EINVAL;
 
-               if (expected_size > 0 && expected_size != new_blob->length) {
+               if (expected_size > 0 &&
+                   new_blob->length != expected_size) {
+                       drm_property_blob_put(new_blob);
+                       return -EINVAL;
+               }
+               if (expected_elem_size > 0 &&
+                   new_blob->length % expected_elem_size != 0) {
                        drm_property_blob_put(new_blob);
                        return -EINVAL;
                }
@@ -471,7 +501,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
                ret = drm_atomic_replace_property_blob_from_id(dev,
                                        &state->degamma_lut,
                                        val,
-                                       -1,
+                                       -1, sizeof(struct drm_color_lut),
                                        &replaced);
                state->color_mgmt_changed |= replaced;
                return ret;
@@ -479,7 +509,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
                ret = drm_atomic_replace_property_blob_from_id(dev,
                                        &state->ctm,
                                        val,
-                                       sizeof(struct drm_color_ctm),
+                                       sizeof(struct drm_color_ctm), -1,
                                        &replaced);
                state->color_mgmt_changed |= replaced;
                return ret;
@@ -487,7 +517,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
                ret = drm_atomic_replace_property_blob_from_id(dev,
                                        &state->gamma_lut,
                                        val,
-                                       -1,
+                                       -1, sizeof(struct drm_color_lut),
                                        &replaced);
                state->color_mgmt_changed |= replaced;
                return ret;
index 00c78c1c968196241be1302d06f45f4cff360709..c35654591c124c267656860189973a5886d563d8 100644 (file)
@@ -3818,7 +3818,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
        }
 
        /* Prepare GAMMA_LUT with the legacy values. */
-       blob_data = (struct drm_color_lut *) blob->data;
+       blob_data = blob->data;
        for (i = 0; i < size; i++) {
                blob_data[i].red = red[i];
                blob_data[i].green = green[i];
index 1ee84dd802d4d7cc88f0cab975bf5e9b4ce0181c..ba8cfe65c65bd424297e2610ee0975e8b693862b 100644 (file)
@@ -129,10 +129,10 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
  * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
  * applicable and if supported by the kernel.
  */
-static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
+static int drm_addmap_core(struct drm_device *dev, resource_size_t offset,
                           unsigned int size, enum drm_map_type type,
                           enum drm_map_flags flags,
-                          struct drm_map_list ** maplist)
+                          struct drm_map_list **maplist)
 {
        struct drm_local_map *map;
        struct drm_map_list *list;
@@ -224,7 +224,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
        case _DRM_SHM:
                list = drm_find_matching_map(dev, map);
                if (list != NULL) {
-                       if(list->map->size != map->size) {
+                       if (list->map->size != map->size) {
                                DRM_DEBUG("Matching maps of type %d with "
                                          "mismatched sizes, (%ld vs %ld)\n",
                                          map->type, map->size, list->map->size);
@@ -361,7 +361,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
        return 0;
 }
 
-int drm_legacy_addmap(struct drm_device * dev, resource_size_t offset,
+int drm_legacy_addmap(struct drm_device *dev, resource_size_t offset,
                      unsigned int size, enum drm_map_type type,
                      enum drm_map_flags flags, struct drm_local_map **map_ptr)
 {
@@ -637,8 +637,8 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data,
  *
  * Frees any pages and buffers associated with the given entry.
  */
-static void drm_cleanup_buf_error(struct drm_device * dev,
-                                 struct drm_buf_entry * entry)
+static void drm_cleanup_buf_error(struct drm_device *dev,
+                                 struct drm_buf_entry *entry)
 {
        int i;
 
@@ -1446,8 +1446,8 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
 int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p,
                         void __user **v,
                         int (*f)(void *, int, unsigned long,
-                                 struct drm_buf *),
-                        struct drm_file *file_priv)
+                                struct drm_buf *),
+                                struct drm_file *file_priv)
 {
        struct drm_device_dma *dma = dev->dma;
        int retcode = 0;
index a797bbf1cab83bd57ea7b201349aabb506031015..49147b2aa288c820dd6f40741ca184bbbeeddab1 100644 (file)
@@ -1554,8 +1554,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
        struct edid *override = NULL;
 
        if (connector->override_edid)
-               override = drm_edid_duplicate((const struct edid *)
-                                             connector->edid_blob_ptr->data);
+               override = drm_edid_duplicate(connector->edid_blob_ptr->data);
 
        if (!override)
                override = drm_load_edid_firmware(connector);
index 035784ddd13363eec627425cf7e6a2600b9b7469..0646b108030ba5d1d41040af3fffa7386be7853d 100644 (file)
@@ -1351,7 +1351,7 @@ static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
        if (IS_ERR(gamma_lut))
                return gamma_lut;
 
-       lut = (struct drm_color_lut *)gamma_lut->data;
+       lut = gamma_lut->data;
        if (cmap->start || cmap->len != size) {
                u16 *r = crtc->gamma_store;
                u16 *g = r + crtc->gamma_size;
index 5a13ff29f4f04af99c61fa07261a35a44ac0dd8e..0eebe8ba8a2c3eeccc829d6e33474e8480fbed7d 100644 (file)
@@ -158,9 +158,10 @@ static int framebuffer_check(struct drm_device *dev,
        info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN);
        if (!info) {
                struct drm_format_name_buf format_name;
+
                DRM_DEBUG_KMS("bad framebuffer format %s\n",
-                             drm_get_format_name(r->pixel_format,
-                                                 &format_name));
+                             drm_get_format_name(r->pixel_format,
+                                                 &format_name));
                return -EINVAL;
        }
 
index 5a8033fda4e321a638a658a02cd98dc590ebca36..f6b7c0e36a1a988180df3d16af7c490e457d44a0 100644 (file)
@@ -773,24 +773,23 @@ EXPORT_SYMBOL(drm_mode_hsync);
 int drm_mode_vrefresh(const struct drm_display_mode *mode)
 {
        int refresh = 0;
-       unsigned int calc_val;
 
        if (mode->vrefresh > 0)
                refresh = mode->vrefresh;
        else if (mode->htotal > 0 && mode->vtotal > 0) {
-               int vtotal;
-               vtotal = mode->vtotal;
-               /* work out vrefresh the value will be x1000 */
-               calc_val = (mode->clock * 1000);
-               calc_val /= mode->htotal;
-               refresh = (calc_val + vtotal / 2) / vtotal;
+               unsigned int num, den;
+
+               num = mode->clock * 1000;
+               den = mode->htotal * mode->vtotal;
 
                if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-                       refresh *= 2;
+                       num *= 2;
                if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-                       refresh /= 2;
+                       den *= 2;
                if (mode->vscan > 1)
-                       refresh /= mode->vscan;
+                       den *= mode->vscan;
+
+               refresh = DIV_ROUND_CLOSEST(num, den);
        }
        return refresh;
 }
@@ -1596,12 +1595,8 @@ int drm_mode_convert_umode(struct drm_device *dev,
                           struct drm_display_mode *out,
                           const struct drm_mode_modeinfo *in)
 {
-       int ret = -EINVAL;
-
-       if (in->clock > INT_MAX || in->vrefresh > INT_MAX) {
-               ret = -ERANGE;
-               goto out;
-       }
+       if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
+               return -ERANGE;
 
        out->clock = in->clock;
        out->hdisplay = in->hdisplay;
@@ -1622,14 +1617,11 @@ int drm_mode_convert_umode(struct drm_device *dev,
 
        out->status = drm_mode_validate_driver(dev, out);
        if (out->status != MODE_OK)
-               goto out;
+               return -EINVAL;
 
        drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
 
-       ret = 0;
-
-out:
-       return ret;
+       return 0;
 }
 
 /**
index a5d1fc7e8a37bece80bd8682c19b9b4e3eb4461d..6d2a6e428a3eac751877507f258d932e3112f5a8 100644 (file)
@@ -104,7 +104,7 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
        if (IS_ERR(blob))
                return -1;
 
-       blob_data = (struct drm_format_modifier_blob *)blob->data;
+       blob_data = blob->data;
        blob_data->version = FORMAT_BLOB_CURRENT;
        blob_data->count_formats = plane->format_count;
        blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
index 781518fd88e36849f5b5f80a277202d3e113aa2e..b25f98f33f6cb55e311b237b3c31d26f554edbc3 100644 (file)
@@ -63,16 +63,34 @@ void drm_printf(struct drm_printer *p, const char *f, ...)
 }
 EXPORT_SYMBOL(drm_printf);
 
-#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV"
-
 void drm_dev_printk(const struct device *dev, const char *level,
-                   unsigned int category, const char *function_name,
-                   const char *prefix, const char *format, ...)
+                   const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
 
-       if (category != DRM_UT_NONE && !(drm_debug & category))
+       va_start(args, format);
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       if (dev)
+               dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
+                          __builtin_return_address(0), &vaf);
+       else
+               printk("%s" "[" DRM_NAME ":%ps] %pV",
+                      level, __builtin_return_address(0), &vaf);
+
+       va_end(args);
+}
+EXPORT_SYMBOL(drm_dev_printk);
+
+void drm_dev_dbg(const struct device *dev, unsigned int category,
+                const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       if (!(drm_debug & category))
                return;
 
        va_start(args, format);
@@ -80,32 +98,47 @@ void drm_dev_printk(const struct device *dev, const char *level,
        vaf.va = &args;
 
        if (dev)
-               dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix,
-                          &vaf);
+               dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV",
+                          __builtin_return_address(0), &vaf);
        else
-               printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf);
+               printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
+                      __builtin_return_address(0), &vaf);
 
        va_end(args);
 }
-EXPORT_SYMBOL(drm_dev_printk);
+EXPORT_SYMBOL(drm_dev_dbg);
 
-void drm_printk(const char *level, unsigned int category,
-               const char *format, ...)
+void drm_dbg(unsigned int category, const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
 
-       if (category != DRM_UT_NONE && !(drm_debug & category))
+       if (!(drm_debug & category))
                return;
 
        va_start(args, format);
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk("%s" "[" DRM_NAME ":%ps]%s %pV",
-              level, __builtin_return_address(0),
-              strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf);
+       printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
+              __builtin_return_address(0), &vaf);
+
+       va_end(args);
+}
+EXPORT_SYMBOL(drm_dbg);
+
+void drm_err(const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, format);
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
+              __builtin_return_address(0), &vaf);
 
        va_end(args);
 }
-EXPORT_SYMBOL(drm_printk);
+EXPORT_SYMBOL(drm_err);
index 6ac6ee41a6a36ec28c02e2e27c214f5652a02b66..8f4672daac7fa3fb402ed6d7c69e3130804b81fd 100644 (file)
@@ -567,6 +567,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
        /* This must be explicitly initialised, so we can safely call list_del
         * on it in the removal handler, even if it isn't in a file list. */
        INIT_LIST_HEAD(&blob->head_file);
+       blob->data = (void *)blob + sizeof(*blob);
        blob->length = length;
        blob->dev = dev;
 
index 89ab0f70aa2203827933313c0c16d1a828e7b79a..c6a7beabd58d1f636af7f3fb53a16214b4a7e6a1 100644 (file)
@@ -39,7 +39,7 @@
 #define CTM_COEFF_NEGATIVE(coeff)      (((coeff) & CTM_COEFF_SIGN) != 0)
 #define CTM_COEFF_ABS(coeff)           ((coeff) & (CTM_COEFF_SIGN - 1))
 
-#define LEGACY_LUT_LENGTH              (sizeof(struct drm_color_lut) * 256)
+#define LEGACY_LUT_LENGTH              256
 
 /* Post offset values for RGB->YCBCR conversion */
 #define POSTOFF_RGB_TO_YUV_HI 0x800
@@ -79,7 +79,7 @@ static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state)
        return !state->degamma_lut &&
                !state->ctm &&
                state->gamma_lut &&
-               state->gamma_lut->length == LEGACY_LUT_LENGTH;
+               drm_color_lut_size(state->gamma_lut) == LEGACY_LUT_LENGTH;
 }
 
 /*
@@ -153,8 +153,7 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state)
                ilk_load_ycbcr_conversion_matrix(intel_crtc);
                return;
        } else if (crtc_state->ctm) {
-               struct drm_color_ctm *ctm =
-                       (struct drm_color_ctm *)crtc_state->ctm->data;
+               struct drm_color_ctm *ctm = crtc_state->ctm->data;
                const u64 *input;
                u64 temp[9];
 
@@ -262,8 +261,7 @@ static void cherryview_load_csc_matrix(struct drm_crtc_state *state)
        uint32_t mode;
 
        if (state->ctm) {
-               struct drm_color_ctm *ctm =
-                       (struct drm_color_ctm *) state->ctm->data;
+               struct drm_color_ctm *ctm = state->ctm->data;
                uint16_t coeffs[9] = { 0, };
                int i;
 
@@ -330,7 +328,7 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc,
        }
 
        if (blob) {
-               struct drm_color_lut *lut = (struct drm_color_lut *) blob->data;
+               struct drm_color_lut *lut = blob->data;
                for (i = 0; i < 256; i++) {
                        uint32_t word =
                                (drm_color_lut_extract(lut[i].red, 8) << 16) |
@@ -400,8 +398,7 @@ static void bdw_load_degamma_lut(struct drm_crtc_state *state)
                   PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT);
 
        if (state->degamma_lut) {
-               struct drm_color_lut *lut =
-                       (struct drm_color_lut *) state->degamma_lut->data;
+               struct drm_color_lut *lut = state->degamma_lut->data;
 
                for (i = 0; i < lut_size; i++) {
                        uint32_t word =
@@ -435,8 +432,7 @@ static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset)
                   offset);
 
        if (state->gamma_lut) {
-               struct drm_color_lut *lut =
-                       (struct drm_color_lut *) state->gamma_lut->data;
+               struct drm_color_lut *lut = state->gamma_lut->data;
 
                for (i = 0; i < lut_size; i++) {
                        uint32_t word =
@@ -568,7 +564,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
        }
 
        if (state->degamma_lut) {
-               lut = (struct drm_color_lut *) state->degamma_lut->data;
+               lut = state->degamma_lut->data;
                lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size;
                for (i = 0; i < lut_size; i++) {
                        /* Write LUT in U0.14 format. */
@@ -583,7 +579,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
        }
 
        if (state->gamma_lut) {
-               lut = (struct drm_color_lut *) state->gamma_lut->data;
+               lut = state->gamma_lut->data;
                lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
                for (i = 0; i < lut_size; i++) {
                        /* Write LUT in U0.10 format. */
@@ -623,19 +619,17 @@ int intel_color_check(struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
        size_t gamma_length, degamma_length;
 
-       degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size *
-               sizeof(struct drm_color_lut);
-       gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size *
-               sizeof(struct drm_color_lut);
+       degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size;
+       gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size;
 
        /*
         * We allow both degamma & gamma luts at the right size or
         * NULL.
         */
        if ((!crtc_state->degamma_lut ||
-            crtc_state->degamma_lut->length == degamma_length) &&
+            drm_color_lut_size(crtc_state->degamma_lut) == degamma_length) &&
            (!crtc_state->gamma_lut ||
-            crtc_state->gamma_lut->length == gamma_length))
+            drm_color_lut_size(crtc_state->gamma_lut) == gamma_length))
                return 0;
 
        /*
index 331084082545cfb5fbc4351067148f490a66b512..3b48fd2561feccc48b5e0c549ee68e5d25214555 100644 (file)
@@ -11059,24 +11059,17 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
 static void __printf(3, 4)
 pipe_config_err(bool adjust, const char *name, const char *format, ...)
 {
-       char *level;
-       unsigned int category;
        struct va_format vaf;
        va_list args;
 
-       if (adjust) {
-               level = KERN_DEBUG;
-               category = DRM_UT_KMS;
-       } else {
-               level = KERN_ERR;
-               category = DRM_UT_NONE;
-       }
-
        va_start(args, format);
        vaf.fmt = format;
        vaf.va = &args;
 
-       drm_printk(level, category, "mismatch in %s %pV", name, &vaf);
+       if (adjust)
+               drm_dbg(DRM_UT_KMS, "mismatch in %s %pV", name, &vaf);
+       else
+               drm_err("mismatch in %s %pV", name, &vaf);
 
        va_end(args);
 }
index f9ad0e960263fd6e112c9f42f88df611774fd5c5..32b1a6cdecfc05133147e6ff85c959f4668362f1 100644 (file)
@@ -189,40 +189,55 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
        regs = devm_ioremap_resource(dev, res);
-       if (IS_ERR(regs))
-               return PTR_ERR(regs);
+       if (IS_ERR(regs)) {
+               ret = PTR_ERR(regs);
+               goto free_drm;
+       }
 
        priv->io_base = regs;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
+       if (!res)
+               return -EINVAL;
        /* Simply ioremap since it may be a shared register zone */
        regs = devm_ioremap(dev, res->start, resource_size(res));
-       if (!regs)
-               return -EADDRNOTAVAIL;
+       if (!regs) {
+               ret = -EADDRNOTAVAIL;
+               goto free_drm;
+       }
 
        priv->hhi = devm_regmap_init_mmio(dev, regs,
                                          &meson_regmap_config);
        if (IS_ERR(priv->hhi)) {
                dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
-               return PTR_ERR(priv->hhi);
+               ret = PTR_ERR(priv->hhi);
+               goto free_drm;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
+       if (!res)
+               return -EINVAL;
        /* Simply ioremap since it may be a shared register zone */
        regs = devm_ioremap(dev, res->start, resource_size(res));
-       if (!regs)
-               return -EADDRNOTAVAIL;
+       if (!regs) {
+               ret = -EADDRNOTAVAIL;
+               goto free_drm;
+       }
 
        priv->dmc = devm_regmap_init_mmio(dev, regs,
                                          &meson_regmap_config);
        if (IS_ERR(priv->dmc)) {
                dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
-               return PTR_ERR(priv->dmc);
+               ret = PTR_ERR(priv->dmc);
+               goto free_drm;
        }
 
        priv->vsync_irq = platform_get_irq(pdev, 0);
 
-       drm_vblank_init(drm, 1);
+       ret = drm_vblank_init(drm, 1);
+       if (ret)
+               goto free_drm;
+
        drm_mode_config_init(drm);
        drm->mode_config.max_width = 3840;
        drm->mode_config.max_height = 2160;
@@ -281,7 +296,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
        return 0;
 
 free_drm:
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
        return ret;
 }
@@ -300,7 +315,7 @@ static void meson_drv_unbind(struct device *dev)
        drm_kms_helper_poll_fini(drm);
        drm_fbdev_cma_fini(priv->fbdev);
        drm_mode_config_cleanup(drm);
-       drm_dev_unref(drm);
+       drm_dev_put(drm);
 
 }
 
index d49af17310c99229a6af937f4f5adc3b5eccf212..a393095aac1a695ce757b7e9efc7c6bc311d693b 100644 (file)
@@ -538,7 +538,6 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* TOFIX Enable support for non-vic modes */
 static enum drm_mode_status
 dw_hdmi_mode_valid(struct drm_connector *connector,
                   const struct drm_display_mode *mode)
@@ -555,12 +554,12 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
                mode->vdisplay, mode->vsync_start,
                mode->vsync_end, mode->vtotal, mode->type, mode->flags);
 
-       /* For now, only accept VIC modes */
-       if (!vic)
-               return MODE_BAD;
-
-       /* For now, filter by supported VIC modes */
-       if (!meson_venc_hdmi_supported_vic(vic))
+       /* Check against non-VIC supported modes */
+       if (!vic) {
+               if (!meson_venc_hdmi_supported_mode(mode))
+                       return MODE_BAD;
+       /* Check against supported VIC modes */
+       } else if (!meson_venc_hdmi_supported_vic(vic))
                return MODE_BAD;
 
        vclk_freq = mode->clock;
@@ -586,9 +585,14 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
 
        /* Finally filter by configurable vclk frequencies */
        switch (vclk_freq) {
+       case 25175:
+       case 40000:
        case 54000:
+       case 65000:
        case 74250:
+       case 108000:
        case 148500:
+       case 162000:
        case 297000:
        case 594000:
                return MODE_OK;
@@ -653,10 +657,6 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
                         mode->base.id, mode->name, vic);
 
-       /* Should have been filtered */
-       if (!vic)
-               return;
-
        /* VENC + VENC-DVI Mode setup */
        meson_venc_hdmi_mode_set(priv, vic, mode);
 
index 47677047e42dd611f5b8e592b178283b2f01ad21..f0511220317f98ab211b80152de26abae92ea175 100644 (file)
@@ -328,14 +328,24 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
 #define MESON_VCLK_HDMI_DDR_54000      2
 /* 2970 /4 /1 /1 /5 /1  => /1 /2 */
 #define MESON_VCLK_HDMI_DDR_148500     3
+/* 4028 /4 /4 /1 /5 /2  => /1 /1 */
+#define MESON_VCLK_HDMI_25175          4
+/* 3200 /4 /2 /1 /5 /2  => /1 /1 */
+#define MESON_VCLK_HDMI_40000          5
+/* 5200 /4 /2 /1 /5 /2  => /1 /1 */
+#define MESON_VCLK_HDMI_65000          6
 /* 2970 /2 /2 /2 /5 /1  => /1 /1 */
-#define MESON_VCLK_HDMI_74250          4
+#define MESON_VCLK_HDMI_74250          7
+/* 4320 /4 /1 /1 /5 /2  => /1 /1 */
+#define MESON_VCLK_HDMI_108000         8
 /* 2970 /1 /2 /2 /5 /1  => /1 /1 */
-#define MESON_VCLK_HDMI_148500         5
+#define MESON_VCLK_HDMI_148500         9
+/* 3240 /2 /1 /1 /5 /2  => /1 /1 */
+#define MESON_VCLK_HDMI_162000         10
 /* 2970 /1 /1 /1 /5 /2  => /1 /1 */
-#define MESON_VCLK_HDMI_297000         6
+#define MESON_VCLK_HDMI_297000         11
 /* 5940 /1 /1 /2 /5 /1  => /1 /1 */
-#define MESON_VCLK_HDMI_594000         7
+#define MESON_VCLK_HDMI_594000         12
 
 struct meson_vclk_params {
        unsigned int pll_base_freq;
@@ -401,6 +411,46 @@ struct meson_vclk_params {
                .vid_pll_div = VID_PLL_DIV_5,
                .vclk_div = 1,
        },
+       [MESON_VCLK_HDMI_25175] = {
+               .pll_base_freq = 4028000,
+               .pll_od1 = 4,
+               .pll_od2 = 4,
+               .pll_od3 = 1,
+               .vid_pll_div = VID_PLL_DIV_5,
+               .vclk_div = 2,
+       },
+       [MESON_VCLK_HDMI_40000] = {
+               .pll_base_freq = 3200000,
+               .pll_od1 = 4,
+               .pll_od2 = 2,
+               .pll_od3 = 1,
+               .vid_pll_div = VID_PLL_DIV_5,
+               .vclk_div = 2,
+       },
+       [MESON_VCLK_HDMI_65000] = {
+               .pll_base_freq = 5200000,
+               .pll_od1 = 4,
+               .pll_od2 = 2,
+               .pll_od3 = 1,
+               .vid_pll_div = VID_PLL_DIV_5,
+               .vclk_div = 2,
+       },
+       [MESON_VCLK_HDMI_108000] = {
+               .pll_base_freq = 4320000,
+               .pll_od1 = 4,
+               .pll_od2 = 1,
+               .pll_od3 = 1,
+               .vid_pll_div = VID_PLL_DIV_5,
+               .vclk_div = 2,
+       },
+       [MESON_VCLK_HDMI_162000] = {
+               .pll_base_freq = 3240000,
+               .pll_od1 = 2,
+               .pll_od2 = 1,
+               .pll_od3 = 1,
+               .vid_pll_div = VID_PLL_DIV_5,
+               .vclk_div = 2,
+       },
 };
 
 static inline unsigned int pll_od_to_reg(unsigned int od)
@@ -451,6 +501,90 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
                                                0xFFFF,  0x4e00);
                        break;
 
+               case 3200000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+                       /* unreset */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                               BIT(28), 0);
+
+                       /* Poll for lock bit */
+                       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                       val, (val & HDMI_PLL_LOCK), 10, 0);
+
+                       /* div_frac */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                                               0xFFFF,  0x4aab);
+                       break;
+
+               case 3240000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+                       /* unreset */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                               BIT(28), 0);
+
+                       /* Poll for lock bit */
+                       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                       val, (val & HDMI_PLL_LOCK), 10, 0);
+
+                       /* div_frac */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                                               0xFFFF,  0x4800);
+                       break;
+
+               case 3865000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+                       /* unreset */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                               BIT(28), 0);
+
+                       /* Poll for lock bit */
+                       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                       val, (val & HDMI_PLL_LOCK), 10, 0);
+
+                       /* div_frac */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                                               0xFFFF,  0x4855);
+                       break;
+
+               case 4028000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+                       /* unreset */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                               BIT(28), 0);
+
+                       /* Poll for lock bit */
+                       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                       val, (val & HDMI_PLL_LOCK), 10, 0);
+
+                       /* div_frac */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                                               0xFFFF,  0x4eab);
+                       break;
+
                case 4320000:
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a);
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
@@ -477,6 +611,23 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
 
+                       /* unreset */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                               BIT(28), 0);
+
+                       /* Poll for lock bit */
+                       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                       val, (val & HDMI_PLL_LOCK), 10, 0);
+                       break;
+
+               case 5200000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
                        /* unreset */
                        regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
                                                BIT(28), 0);
@@ -498,6 +649,42 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
                        break;
 
+               case 3200000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+                       break;
+
+               case 3240000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+                       break;
+
+               case 3865000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+                       break;
+
+               case 4028000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+                       break;
+
                case 4320000:
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4);
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
@@ -516,6 +703,15 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
                        regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
                        break;
 
+               case 5200000:
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+                       break;
+
                };
 
                /* Reset PLL */
@@ -590,15 +786,30 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                else
                        freq = MESON_VCLK_HDMI_DDR_54000;
                break;
+       case 25175:
+               freq = MESON_VCLK_HDMI_25175;
+               break;
+       case 40000:
+               freq = MESON_VCLK_HDMI_40000;
+               break;
+       case 65000:
+               freq = MESON_VCLK_HDMI_65000;
+               break;
        case 74250:
                freq = MESON_VCLK_HDMI_74250;
                break;
+       case 108000:
+               freq = MESON_VCLK_HDMI_108000;
+               break;
        case 148500:
                if (dac_freq != 148500)
                        freq = MESON_VCLK_HDMI_DDR_148500;
                else
                        freq = MESON_VCLK_HDMI_148500;
                break;
+       case 162000:
+               freq = MESON_VCLK_HDMI_162000;
+               break;
        case 297000:
                freq = MESON_VCLK_HDMI_297000;
                break;
index 9509017dbded1235866df8b096d1f5dfdcc3be45..6e2701389801383172904fb3f4f628a6edb24a4f 100644 (file)
@@ -697,6 +697,314 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
        },
 };
 
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = {
+       .encp = {
+               .dvi_settings = 0x21,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x18,
+               /* video_prog_mode */
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               /* video_filt_ctrl */
+               /* video_ofld_voav_ofst */
+               /* yfp1_htime */
+               /* yfp2_htime */
+               .max_pxcnt = 0x31f,
+               /* hspuls_begin */
+               /* hspuls_end */
+               /* hspuls_switch */
+               /* vspuls_begin */
+               /* vspuls_end */
+               /* vspuls_bline */
+               /* vspuls_eline */
+               .havon_begin = 0x90,
+               .havon_end = 0x30f,
+               .vavon_bline = 0x23,
+               .vavon_eline = 0x202,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 0,
+               .hso_end = 0x60,
+               .vso_begin = 0x1e,
+               .vso_end = 0x32,
+               .vso_bline = 0,
+               .vso_eline = 2,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 0x20c,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = {
+       .encp = {
+               .dvi_settings = 0x21,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x18,
+               /* video_prog_mode */
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               /* video_filt_ctrl */
+               /* video_ofld_voav_ofst */
+               /* yfp1_htime */
+               /* yfp2_htime */
+               .max_pxcnt = 0x41f,
+               /* hspuls_begin */
+               /* hspuls_end */
+               /* hspuls_switch */
+               /* vspuls_begin */
+               /* vspuls_end */
+               /* vspuls_bline */
+               /* vspuls_eline */
+               .havon_begin = 0xD8,
+               .havon_end = 0x3f7,
+               .vavon_bline = 0x1b,
+               .vavon_eline = 0x272,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 0,
+               .hso_end = 0x80,
+               .vso_begin = 0x1e,
+               .vso_end = 0x32,
+               .vso_bline = 0,
+               .vso_eline = 4,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 0x273,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = {
+       .encp = {
+               .dvi_settings = 0x21,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x18,
+               /* video_prog_mode */
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               /* video_filt_ctrl */
+               /* video_ofld_voav_ofst */
+               /* yfp1_htime */
+               /* yfp2_htime */
+               .max_pxcnt = 1343,
+               /* hspuls_begin */
+               /* hspuls_end */
+               /* hspuls_switch */
+               /* vspuls_begin */
+               /* vspuls_end */
+               /* vspuls_bline */
+               /* vspuls_eline */
+               .havon_begin = 296,
+               .havon_end = 1319,
+               .vavon_bline = 35,
+               .vavon_eline = 802,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 0,
+               .hso_end = 136,
+               .vso_begin = 30,
+               .vso_end = 50,
+               .vso_bline = 0,
+               .vso_eline = 6,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 805,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = {
+       .encp = {
+               .dvi_settings = 0x21,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x18,
+               /* video_prog_mode */
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               /* video_filt_ctrl */
+               /* video_ofld_voav_ofst */
+               /* yfp1_htime */
+               /* yfp2_htime */
+               .max_pxcnt = 0x63f,
+               /* hspuls_begin */
+               /* hspuls_end */
+               /* hspuls_switch */
+               /* vspuls_begin */
+               /* vspuls_end */
+               /* vspuls_bline */
+               /* vspuls_eline */
+               .havon_begin = 0x180,
+               .havon_end = 0x5ff,
+               .vavon_bline = 0x23,
+               .vavon_eline = 0x382,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 0,
+               .hso_end = 0x80,
+               .vso_begin = 0x1e,
+               .vso_end = 0x32,
+               .vso_bline = 0,
+               .vso_eline = 3,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 0x383,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = {
+       .encp = {
+               .dvi_settings = 0x21,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x18,
+               /* video_prog_mode */
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               /* video_filt_ctrl */
+               /* video_ofld_voav_ofst */
+               /* yfp1_htime */
+               /* yfp2_htime */
+               .max_pxcnt = 0x697,
+               /* hspuls_begin */
+               /* hspuls_end */
+               /* hspuls_switch */
+               /* vspuls_begin */
+               /* vspuls_end */
+               /* vspuls_bline */
+               /* vspuls_eline */
+               .havon_begin = 0x168,
+               .havon_end = 0x667,
+               .vavon_bline = 0x29,
+               .vavon_eline = 0x428,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 0,
+               .hso_end = 0x70,
+               .vso_begin = 0x1e,
+               .vso_end = 0x32,
+               .vso_bline = 0,
+               .vso_eline = 3,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 0x429,
+       },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = {
+       .encp = {
+               .dvi_settings = 0x21,
+               .video_mode = 0x4040,
+               .video_mode_adv = 0x18,
+               /* video_prog_mode */
+               /* video_sync_mode */
+               /* video_yc_dly */
+               /* video_rgb_ctrl */
+               /* video_filt_ctrl */
+               /* video_ofld_voav_ofst */
+               /* yfp1_htime */
+               /* yfp2_htime */
+               .max_pxcnt = 0x86f,
+               /* hspuls_begin */
+               /* hspuls_end */
+               /* hspuls_switch */
+               /* vspuls_begin */
+               /* vspuls_end */
+               /* vspuls_bline */
+               /* vspuls_eline */
+               .havon_begin = 0x1f0,
+               .havon_end = 0x82f,
+               .vavon_bline = 0x31,
+               .vavon_eline = 0x4e0,
+               /* eqpuls_begin */
+               /* eqpuls_end */
+               /* eqpuls_bline */
+               /* eqpuls_eline */
+               .hso_begin = 0,
+               .hso_end = 0xc0,
+               .vso_begin = 0x1e,
+               .vso_end = 0x32,
+               .vso_bline = 0,
+               .vso_eline = 3,
+               .vso_eline_present = true,
+               /* sy_val */
+               /* sy2_val */
+               .max_lncnt = 0x4e1,
+       },
+};
+
+struct meson_hdmi_venc_dmt_mode {
+       struct drm_display_mode drm_mode;
+       union meson_hdmi_venc_mode *mode;
+} meson_hdmi_venc_dmt_modes[] = {
+       /* 640x480@60Hz */
+       {
+               { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+                 752, 800, 0, 480, 490, 492, 525, 0,
+                 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+               &meson_hdmi_encp_mode_640x480_60,
+       },
+       /* 800x600@60Hz */
+       {
+               { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+                 968, 1056, 0, 600, 601, 605, 628, 0,
+                 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+               &meson_hdmi_encp_mode_800x600_60,
+       },
+       /* 1024x768@60Hz */
+       {
+               { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024,
+                 1048, 1184, 1344, 0, 768, 771, 777, 806, 0,
+                 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+               &meson_hdmi_encp_mode_1024x768_60,
+       },
+       /* 1152x864@75Hz */
+       {
+               { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152,
+                 1216, 1344, 1600, 0, 864, 865, 868, 900, 0,
+                 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+               &meson_hdmi_encp_mode_1152x864_75,
+       },
+       /* 1280x1024@60Hz */
+       {
+               { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280,
+                 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+               &meson_hdmi_encp_mode_1280x1024_60,
+       },
+       /* 1600x1200@60Hz */
+       {
+               { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
+                 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+                 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+               &meson_hdmi_encp_mode_1600x1200_60,
+       },
+       /* 1920x1080@60Hz */
+       {
+               { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920,
+                 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+                 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+               &meson_hdmi_encp_mode_1080p60
+       },
+       { }, /* sentinel */
+};
+
 struct meson_hdmi_venc_vic_mode {
        unsigned int vic;
        union meson_hdmi_venc_mode *mode;
@@ -736,6 +1044,20 @@ static unsigned long modulo(unsigned long a, unsigned long b)
                return a;
 }
 
+bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
+{
+       struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
+
+       while (vmode->mode) {
+               if (drm_mode_equal(&vmode->drm_mode, mode))
+                       return true;
+               vmode++;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
+
 bool meson_venc_hdmi_supported_vic(int vic)
 {
        struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
@@ -750,6 +1072,20 @@ bool meson_venc_hdmi_supported_vic(int vic)
 }
 EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
 
+static union meson_hdmi_venc_mode
+*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode)
+{
+       struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
+
+       while (vmode->mode) {
+               if (drm_mode_equal(&vmode->drm_mode, mode))
+                       return vmode->mode;
+               vmode++;
+       }
+
+       return NULL;
+}
+
 static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
 {
        struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
@@ -811,10 +1147,13 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
        unsigned int sof_lines;
        unsigned int vsync_lines;
 
-       vmode = meson_venc_hdmi_get_vic_vmode(vic);
+       if (meson_venc_hdmi_supported_vic(vic))
+               vmode = meson_venc_hdmi_get_vic_vmode(vic);
+       else
+               vmode = meson_venc_hdmi_get_dmt_vmode(mode);
        if (!vmode) {
-               dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n",
-                       __func__, vic);
+               dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
+                       DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode));
                return;
        }
 
@@ -864,7 +1203,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
                hsync_pixels_venc *= 2;
 
        /* Disable VDACs */
-       writel_bits_relaxed(0x1f, 0x1f,
+       writel_bits_relaxed(0xff, 0xff,
                        priv->io_base + _REG(VENC_VDAC_SETTING));
 
        writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
index a1b96e898c14e1ba59eb272977f5c3e5534665fd..7c18a36a0dd0c1e975c33931557ee60dc4e463ae 100644 (file)
@@ -58,6 +58,7 @@ struct meson_cvbs_enci_mode {
 };
 
 /* HDMI Clock parameters */
+bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
 bool meson_venc_hdmi_supported_vic(int vic);
 bool meson_venc_hdmi_venc_repeat(int vic);
 
index 3e293029e3a69d3a5296df6abbd82b518435d9fa..bbbf353682e1c51117ff2ba0d7f3256549d1efda 100644 (file)
@@ -510,37 +510,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        return 0;
 }
 
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
-
-static void
-nouveau_get_hdmi_dev(struct nouveau_drm *drm)
-{
-       struct pci_dev *pdev = drm->dev->pdev;
-
-       if (!pdev) {
-               NV_DEBUG(drm, "not a PCI device; no HDMI\n");
-               drm->hdmi_device = NULL;
-               return;
-       }
-
-       /* subfunction one is a hdmi audio device? */
-       drm->hdmi_device = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
-                                               (unsigned int)pdev->bus->number,
-                                               PCI_DEVFN(PCI_SLOT(pdev->devfn), 1));
-
-       if (!drm->hdmi_device) {
-               NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1);
-               return;
-       }
-
-       if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) {
-               NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class);
-               pci_dev_put(drm->hdmi_device);
-               drm->hdmi_device = NULL;
-               return;
-       }
-}
-
 static int
 nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 {
@@ -568,8 +537,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        INIT_LIST_HEAD(&drm->clients);
        spin_lock_init(&drm->tile.lock);
 
-       nouveau_get_hdmi_dev(drm);
-
        /* workaround an odd issue on nvc1 by disabling the device's
         * nosnoop capability.  hopefully won't cause issues until a
         * better fix is found - assuming there is one...
@@ -655,8 +622,6 @@ nouveau_drm_unload(struct drm_device *dev)
        nouveau_ttm_fini(drm);
        nouveau_vga_fini(drm);
 
-       if (drm->hdmi_device)
-               pci_dev_put(drm->hdmi_device);
        nouveau_cli_fini(&drm->client);
        nouveau_cli_fini(&drm->master);
        kfree(drm);
@@ -856,7 +821,6 @@ nouveau_pmops_runtime_suspend(struct device *dev)
        }
 
        drm_kms_helper_poll_disable(drm_dev);
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
        nouveau_switcheroo_optimus_dsm();
        ret = nouveau_do_suspend(drm_dev, true);
        pci_save_state(pdev);
@@ -891,7 +855,6 @@ nouveau_pmops_runtime_resume(struct device *dev)
 
        /* do magic */
        nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25));
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
        drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
 
        /* Monitors may have been connected / disconnected during suspend */
@@ -913,15 +876,6 @@ nouveau_pmops_runtime_idle(struct device *dev)
                return -EBUSY;
        }
 
-       /* if we have a hdmi audio device - make sure it has a driver loaded */
-       if (drm->hdmi_device) {
-               if (!drm->hdmi_device->driver) {
-                       DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n");
-                       pm_runtime_mark_last_busy(dev);
-                       return -EBUSY;
-               }
-       }
-
        list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
                if (crtc->enabled) {
                        DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
index 96f6bd8aee5d3a248d76c683b6146ebb8ef673c7..881b44b89a01831ffa45549d922a7a1e882a59eb 100644 (file)
@@ -208,7 +208,6 @@ struct nouveau_drm {
        bool have_disp_power_ref;
 
        struct dev_pm_domain vga_pm_domain;
-       struct pci_dev *hdmi_device;
 };
 
 static inline struct nouveau_drm *
index 988048ebcc22ab173975921e8ad9fe18f492c598..25682ff3449a43e45da5e5440a631fb665073697 100644 (file)
@@ -108,6 +108,15 @@ config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN
          Pi 7" Touchscreen.  To compile this driver as a module,
          choose M here.
 
+config DRM_PANEL_RAYDIUM_RM68200
+       tristate "Raydium RM68200 720x1280 DSI video mode panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y here if you want to enable support for Raydium RM68200
+         720x1280 DSI video mode panel.
+
 config DRM_PANEL_SAMSUNG_S6E3HA2
        tristate "Samsung S6E3HA2 DSI video mode panel"
        depends on OF
index 3d2a88d0e9656f5c409a313e2a82116c3e0240f8..f26efc11d746d3acc9360da619d8e0b35d1f5663 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
 obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
 obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
 obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
+obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
index b4ec0ecff8079e6e21de6b3c2089943064e5d22f..bd38bf4f1ba6450c6dd63035cda7943e08377a6b 100644 (file)
@@ -179,7 +179,7 @@ enum ili9322_input {
        ILI9322_INPUT_UNKNOWN = 0xc,
 };
 
-const char *ili9322_inputs[] = {
+static const char * const ili9322_inputs[] = {
        "8 bit serial RGB through",
        "8 bit serial RGB aligned",
        "8 bit serial RGB dummy 320x240",
@@ -340,7 +340,7 @@ static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
        return true;
 }
 
-const struct regmap_config ili9322_regmap_config = {
+static const struct regmap_config ili9322_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
        .max_register = 0x44,
index b5e3994f0aa8c69929d3f88cb7a3be5acc272a93..5185819c5b797c0d834d64fa4d8951b56c01f4f7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * rcar_du_crtc.c  --  R-Car Display Unit CRTCs
+ * Generic LVDS panel driver
  *
  * Copyright (C) 2016 Laurent Pinchart
  * Copyright (C) 2016 Renesas Electronics Corporation
index c189cd6329c8d1db541f4a59b28a3df1a1c8b3e6..90f1ae4af93c0d3ec92abe04c38850eafbc16e57 100644 (file)
@@ -1,16 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) STMicroelectronics SA 2017
  *
  * Authors: Philippe Cornu <philippe.cornu@st.com>
  *          Yannick Fertre <yannick.fertre@st.com>
- *
- * License terms:  GNU General Public License (GPL), version 2
  */
+
 #include <drm/drmP.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 #include <linux/backlight.h>
 #include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
 #include <video/mipi_display.h>
 
 #define DRV_NAME "orisetech_otm8009a"
@@ -62,6 +63,7 @@ struct otm8009a {
        struct drm_panel panel;
        struct backlight_device *bl_dev;
        struct gpio_desc *reset_gpio;
+       struct regulator *supply;
        bool prepared;
        bool enabled;
 };
@@ -279,6 +281,8 @@ static int otm8009a_unprepare(struct drm_panel *panel)
                msleep(20);
        }
 
+       regulator_disable(ctx->supply);
+
        ctx->prepared = false;
 
        return 0;
@@ -292,6 +296,12 @@ static int otm8009a_prepare(struct drm_panel *panel)
        if (ctx->prepared)
                return 0;
 
+       ret = regulator_enable(ctx->supply);
+       if (ret < 0) {
+               DRM_ERROR("failed to enable supply: %d\n", ret);
+               return ret;
+       }
+
        if (ctx->reset_gpio) {
                gpiod_set_value_cansleep(ctx->reset_gpio, 0);
                gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -414,6 +424,13 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi)
                return PTR_ERR(ctx->reset_gpio);
        }
 
+       ctx->supply = devm_regulator_get(dev, "power");
+       if (IS_ERR(ctx->supply)) {
+               ret = PTR_ERR(ctx->supply);
+               dev_err(dev, "failed to request regulator: %d\n", ret);
+               return ret;
+       }
+
        mipi_dsi_set_drvdata(dsi, ctx);
 
        ctx->dev = dev;
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c
new file mode 100644 (file)
index 0000000..7759353
--- /dev/null
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics SA 2017
+ *
+ * Authors: Philippe Cornu <philippe.cornu@st.com>
+ *          Yannick Fertre <yannick.fertre@st.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+/*** Manufacturer Command Set ***/
+#define MCS_CMD_MODE_SW                0xFE /* CMD Mode Switch */
+#define MCS_CMD1_UCS           0x00 /* User Command Set (UCS = CMD1) */
+#define MCS_CMD2_P0            0x01 /* Manufacture Command Set Page0 (CMD2 P0) */
+#define MCS_CMD2_P1            0x02 /* Manufacture Command Set Page1 (CMD2 P1) */
+#define MCS_CMD2_P2            0x03 /* Manufacture Command Set Page2 (CMD2 P2) */
+#define MCS_CMD2_P3            0x04 /* Manufacture Command Set Page3 (CMD2 P3) */
+
+/* CMD2 P0 commands (Display Options and Power) */
+#define MCS_STBCTR             0x12 /* TE1 Output Setting Zig-Zag Connection */
+#define MCS_SGOPCTR            0x16 /* Source Bias Current */
+#define MCS_SDCTR              0x1A /* Source Output Delay Time */
+#define MCS_INVCTR             0x1B /* Inversion Type */
+#define MCS_EXT_PWR_IC         0x24 /* External PWR IC Control */
+#define MCS_SETAVDD            0x27 /* PFM Control for AVDD Output */
+#define MCS_SETAVEE            0x29 /* PFM Control for AVEE Output */
+#define MCS_BT2CTR             0x2B /* DDVDL Charge Pump Control */
+#define MCS_BT3CTR             0x2F /* VGH Charge Pump Control */
+#define MCS_BT4CTR             0x34 /* VGL Charge Pump Control */
+#define MCS_VCMCTR             0x46 /* VCOM Output Level Control */
+#define MCS_SETVGN             0x52 /* VG M/S N Control */
+#define MCS_SETVGP             0x54 /* VG M/S P Control */
+#define MCS_SW_CTRL            0x5F /* Interface Control for PFM and MIPI */
+
+/* CMD2 P2 commands (GOA Timing Control) - no description in datasheet */
+#define GOA_VSTV1              0x00
+#define GOA_VSTV2              0x07
+#define GOA_VCLK1              0x0E
+#define GOA_VCLK2              0x17
+#define GOA_VCLK_OPT1          0x20
+#define GOA_BICLK1             0x2A
+#define GOA_BICLK2             0x37
+#define GOA_BICLK3             0x44
+#define GOA_BICLK4             0x4F
+#define GOA_BICLK_OPT1         0x5B
+#define GOA_BICLK_OPT2         0x60
+#define MCS_GOA_GPO1           0x6D
+#define MCS_GOA_GPO2           0x71
+#define MCS_GOA_EQ             0x74
+#define MCS_GOA_CLK_GALLON     0x7C
+#define MCS_GOA_FS_SEL0                0x7E
+#define MCS_GOA_FS_SEL1                0x87
+#define MCS_GOA_FS_SEL2                0x91
+#define MCS_GOA_FS_SEL3                0x9B
+#define MCS_GOA_BS_SEL0                0xAC
+#define MCS_GOA_BS_SEL1                0xB5
+#define MCS_GOA_BS_SEL2                0xBF
+#define MCS_GOA_BS_SEL3                0xC9
+#define MCS_GOA_BS_SEL4                0xD3
+
+/* CMD2 P3 commands (Gamma) */
+#define MCS_GAMMA_VP           0x60 /* Gamma VP1~VP16 */
+#define MCS_GAMMA_VN           0x70 /* Gamma VN1~VN16 */
+
+struct rm68200 {
+       struct device *dev;
+       struct drm_panel panel;
+       struct gpio_desc *reset_gpio;
+       struct regulator *supply;
+       struct backlight_device *backlight;
+       bool prepared;
+       bool enabled;
+};
+
+static const struct drm_display_mode default_mode = {
+       .clock = 52582,
+       .hdisplay = 720,
+       .hsync_start = 720 + 38,
+       .hsync_end = 720 + 38 + 8,
+       .htotal = 720 + 38 + 8 + 38,
+       .vdisplay = 1280,
+       .vsync_start = 1280 + 12,
+       .vsync_end = 1280 + 12 + 4,
+       .vtotal = 1280 + 12 + 4 + 12,
+       .vrefresh = 50,
+       .flags = 0,
+       .width_mm = 68,
+       .height_mm = 122,
+};
+
+static inline struct rm68200 *panel_to_rm68200(struct drm_panel *panel)
+{
+       return container_of(panel, struct rm68200, panel);
+}
+
+static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data,
+                                 size_t len)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       int err;
+
+       err = mipi_dsi_dcs_write_buffer(dsi, data, len);
+       if (err < 0)
+               DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n",
+                                     err);
+}
+
+static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       int err;
+
+       err = mipi_dsi_dcs_write(dsi, cmd, &value, 1);
+       if (err < 0)
+               DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err);
+}
+
+#define dcs_write_seq(ctx, seq...)                             \
+({                                                             \
+       static const u8 d[] = { seq };                          \
+                                                               \
+       rm68200_dcs_write_buf(ctx, d, ARRAY_SIZE(d));           \
+})
+
+/*
+ * This panel is not able to auto-increment all cmd addresses so for some of
+ * them, we need to send them one by one...
+ */
+#define dcs_write_cmd_seq(ctx, cmd, seq...)                    \
+({                                                             \
+       static const u8 d[] = { seq };                          \
+       unsigned int i;                                         \
+                                                               \
+       for (i = 0; i < ARRAY_SIZE(d) ; i++)                    \
+               rm68200_dcs_write_cmd(ctx, cmd + i, d[i]);      \
+})
+
+static void rm68200_init_sequence(struct rm68200 *ctx)
+{
+       /* Enter CMD2 with page 0 */
+       dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P0);
+       dcs_write_cmd_seq(ctx, MCS_EXT_PWR_IC, 0xC0, 0x53, 0x00);
+       dcs_write_seq(ctx, MCS_BT2CTR, 0xE5);
+       dcs_write_seq(ctx, MCS_SETAVDD, 0x0A);
+       dcs_write_seq(ctx, MCS_SETAVEE, 0x0A);
+       dcs_write_seq(ctx, MCS_SGOPCTR, 0x52);
+       dcs_write_seq(ctx, MCS_BT3CTR, 0x53);
+       dcs_write_seq(ctx, MCS_BT4CTR, 0x5A);
+       dcs_write_seq(ctx, MCS_INVCTR, 0x00);
+       dcs_write_seq(ctx, MCS_STBCTR, 0x0A);
+       dcs_write_seq(ctx, MCS_SDCTR, 0x06);
+       dcs_write_seq(ctx, MCS_VCMCTR, 0x56);
+       dcs_write_seq(ctx, MCS_SETVGN, 0xA0, 0x00);
+       dcs_write_seq(ctx, MCS_SETVGP, 0xA0, 0x00);
+       dcs_write_seq(ctx, MCS_SW_CTRL, 0x11); /* 2 data lanes, see doc */
+
+       dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P2);
+       dcs_write_seq(ctx, GOA_VSTV1, 0x05);
+       dcs_write_seq(ctx, 0x02, 0x0B);
+       dcs_write_seq(ctx, 0x03, 0x0F);
+       dcs_write_seq(ctx, 0x04, 0x7D, 0x00, 0x50);
+       dcs_write_cmd_seq(ctx, GOA_VSTV2, 0x05, 0x16, 0x0D, 0x11, 0x7D, 0x00,
+                         0x50);
+       dcs_write_cmd_seq(ctx, GOA_VCLK1, 0x07, 0x08, 0x01, 0x02, 0x00, 0x7D,
+                         0x00, 0x85, 0x08);
+       dcs_write_cmd_seq(ctx, GOA_VCLK2, 0x03, 0x04, 0x05, 0x06, 0x00, 0x7D,
+                         0x00, 0x85, 0x08);
+       dcs_write_seq(ctx, GOA_VCLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                     0x00, 0x00, 0x00, 0x00);
+       dcs_write_cmd_seq(ctx, GOA_BICLK1, 0x07, 0x08);
+       dcs_write_seq(ctx, 0x2D, 0x01);
+       dcs_write_seq(ctx, 0x2F, 0x02, 0x00, 0x40, 0x05, 0x08, 0x54, 0x7D,
+                     0x00);
+       dcs_write_cmd_seq(ctx, GOA_BICLK2, 0x03, 0x04, 0x05, 0x06, 0x00);
+       dcs_write_seq(ctx, 0x3D, 0x40);
+       dcs_write_seq(ctx, 0x3F, 0x05, 0x08, 0x54, 0x7D, 0x00);
+       dcs_write_seq(ctx, GOA_BICLK3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                     0x00, 0x00, 0x00, 0x00, 0x00);
+       dcs_write_seq(ctx, GOA_BICLK4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                     0x00, 0x00);
+       dcs_write_seq(ctx, 0x58, 0x00, 0x00, 0x00);
+       dcs_write_seq(ctx, GOA_BICLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00);
+       dcs_write_seq(ctx, GOA_BICLK_OPT2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+       dcs_write_seq(ctx, MCS_GOA_GPO1, 0x00, 0x00, 0x00, 0x00);
+       dcs_write_seq(ctx, MCS_GOA_GPO2, 0x00, 0x20, 0x00);
+       dcs_write_seq(ctx, MCS_GOA_EQ, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+                     0x00, 0x00);
+       dcs_write_seq(ctx, MCS_GOA_CLK_GALLON, 0x00, 0x00);
+       dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL0, 0xBF, 0x02, 0x06, 0x14, 0x10,
+                         0x16, 0x12, 0x08, 0x3F);
+       dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0C,
+                         0x0A, 0x0E, 0x3F, 0x3F, 0x00);
+       dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL2, 0x04, 0x3F, 0x3F, 0x3F, 0x3F,
+                         0x05, 0x01, 0x3F, 0x3F, 0x0F);
+       dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL3, 0x0B, 0x0D, 0x3F, 0x3F, 0x3F,
+                         0x3F);
+       dcs_write_cmd_seq(ctx, 0xA2, 0x3F, 0x09, 0x13, 0x17, 0x11, 0x15);
+       dcs_write_cmd_seq(ctx, 0xA9, 0x07, 0x03, 0x3F);
+       dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL0, 0x3F, 0x05, 0x01, 0x17, 0x13,
+                         0x15, 0x11, 0x0F, 0x3F);
+       dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0B,
+                         0x0D, 0x09, 0x3F, 0x3F, 0x07);
+       dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL2, 0x03, 0x3F, 0x3F, 0x3F, 0x3F,
+                         0x02, 0x06, 0x3F, 0x3F, 0x08);
+       dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL3, 0x0C, 0x0A, 0x3F, 0x3F, 0x3F,
+                         0x3F, 0x3F, 0x0E, 0x10, 0x14);
+       dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL4, 0x12, 0x16, 0x00, 0x04, 0x3F);
+       dcs_write_seq(ctx, 0xDC, 0x02);
+       dcs_write_seq(ctx, 0xDE, 0x12);
+
+       dcs_write_seq(ctx, MCS_CMD_MODE_SW, 0x0E); /* No documentation */
+       dcs_write_seq(ctx, 0x01, 0x75);
+
+       dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P3);
+       dcs_write_cmd_seq(ctx, MCS_GAMMA_VP, 0x00, 0x0C, 0x12, 0x0E, 0x06,
+                         0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F,
+                         0x12, 0x0C, 0x00);
+       dcs_write_cmd_seq(ctx, MCS_GAMMA_VN, 0x00, 0x0C, 0x12, 0x0E, 0x06,
+                         0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F,
+                         0x12, 0x0C, 0x00);
+
+       /* Exit CMD2 */
+       dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD1_UCS);
+}
+
+static int rm68200_disable(struct drm_panel *panel)
+{
+       struct rm68200 *ctx = panel_to_rm68200(panel);
+
+       if (!ctx->enabled)
+               return 0;
+
+       backlight_disable(ctx->backlight);
+
+       ctx->enabled = false;
+
+       return 0;
+}
+
+static int rm68200_unprepare(struct drm_panel *panel)
+{
+       struct rm68200 *ctx = panel_to_rm68200(panel);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       int ret;
+
+       if (!ctx->prepared)
+               return 0;
+
+       ret = mipi_dsi_dcs_set_display_off(dsi);
+       if (ret)
+               DRM_WARN("failed to set display off: %d\n", ret);
+
+       ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+       if (ret)
+               DRM_WARN("failed to enter sleep mode: %d\n", ret);
+
+       msleep(120);
+
+       if (ctx->reset_gpio) {
+               gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+               msleep(20);
+       }
+
+       regulator_disable(ctx->supply);
+
+       ctx->prepared = false;
+
+       return 0;
+}
+
+static int rm68200_prepare(struct drm_panel *panel)
+{
+       struct rm68200 *ctx = panel_to_rm68200(panel);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       int ret;
+
+       if (ctx->prepared)
+               return 0;
+
+       ret = regulator_enable(ctx->supply);
+       if (ret < 0) {
+               DRM_ERROR("failed to enable supply: %d\n", ret);
+               return ret;
+       }
+
+       if (ctx->reset_gpio) {
+               gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+               msleep(20);
+               gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+               msleep(100);
+       }
+
+       rm68200_init_sequence(ctx);
+
+       ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+       if (ret)
+               return ret;
+
+       msleep(125);
+
+       ret = mipi_dsi_dcs_set_display_on(dsi);
+       if (ret)
+               return ret;
+
+       msleep(20);
+
+       ctx->prepared = true;
+
+       return 0;
+}
+
+static int rm68200_enable(struct drm_panel *panel)
+{
+       struct rm68200 *ctx = panel_to_rm68200(panel);
+
+       if (ctx->enabled)
+               return 0;
+
+       backlight_enable(ctx->backlight);
+
+       ctx->enabled = true;
+
+       return 0;
+}
+
+static int rm68200_get_modes(struct drm_panel *panel)
+{
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(panel->drm, &default_mode);
+       if (!mode) {
+               DRM_ERROR("failed to add mode %ux%ux@%u\n",
+                         default_mode.hdisplay, default_mode.vdisplay,
+                         default_mode.vrefresh);
+               return -ENOMEM;
+       }
+
+       drm_mode_set_name(mode);
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(panel->connector, mode);
+
+       panel->connector->display_info.width_mm = mode->width_mm;
+       panel->connector->display_info.height_mm = mode->height_mm;
+
+       return 1;
+}
+
+static const struct drm_panel_funcs rm68200_drm_funcs = {
+       .disable = rm68200_disable,
+       .unprepare = rm68200_unprepare,
+       .prepare = rm68200_prepare,
+       .enable = rm68200_enable,
+       .get_modes = rm68200_get_modes,
+};
+
+static int rm68200_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct rm68200 *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(ctx->reset_gpio)) {
+               ret = PTR_ERR(ctx->reset_gpio);
+               dev_err(dev, "cannot get reset GPIO: %d\n", ret);
+               return ret;
+       }
+
+       ctx->supply = devm_regulator_get(dev, "power");
+       if (IS_ERR(ctx->supply)) {
+               ret = PTR_ERR(ctx->supply);
+               dev_err(dev, "cannot get regulator: %d\n", ret);
+               return ret;
+       }
+
+       ctx->backlight = devm_of_find_backlight(dev);
+       if (IS_ERR(ctx->backlight))
+               return PTR_ERR(ctx->backlight);
+
+       mipi_dsi_set_drvdata(dsi, ctx);
+
+       ctx->dev = dev;
+
+       dsi->lanes = 2;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                         MIPI_DSI_MODE_LPM;
+
+       drm_panel_init(&ctx->panel);
+       ctx->panel.dev = dev;
+       ctx->panel.funcs = &rm68200_drm_funcs;
+
+       drm_panel_add(&ctx->panel);
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0) {
+               dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
+               drm_panel_remove(&ctx->panel);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rm68200_remove(struct mipi_dsi_device *dsi)
+{
+       struct rm68200 *ctx = mipi_dsi_get_drvdata(dsi);
+
+       mipi_dsi_detach(dsi);
+       drm_panel_remove(&ctx->panel);
+
+       return 0;
+}
+
+static const struct of_device_id raydium_rm68200_of_match[] = {
+       { .compatible = "raydium,rm68200" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, raydium_rm68200_of_match);
+
+static struct mipi_dsi_driver raydium_rm68200_driver = {
+       .probe = rm68200_probe,
+       .remove = rm68200_remove,
+       .driver = {
+               .name = "panel-raydium-rm68200",
+               .of_match_table = raydium_rm68200_of_match,
+       },
+};
+module_mipi_dsi_driver(raydium_rm68200_driver);
+
+MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
+MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
+MODULE_DESCRIPTION("DRM Driver for Raydium RM68200 MIPI DSI panel");
+MODULE_LICENSE("GPL v2");
index 5591984a392b7e63f049a175072793dcbe51fe1f..cbf1ab404ee77316ac6edd504df143bdb1cd39ef 100644 (file)
@@ -581,6 +581,29 @@ static const struct panel_desc auo_b133htn01 = {
        },
 };
 
+static const struct drm_display_mode auo_g104sn02_mode = {
+       .clock = 40000,
+       .hdisplay = 800,
+       .hsync_start = 800 + 40,
+       .hsync_end = 800 + 40 + 216,
+       .htotal = 800 + 40 + 216 + 128,
+       .vdisplay = 600,
+       .vsync_start = 600 + 10,
+       .vsync_end = 600 + 10 + 35,
+       .vtotal = 600 + 10 + 35 + 2,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_g104sn02 = {
+       .modes = &auo_g104sn02_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 211,
+               .height = 158,
+       },
+};
+
 static const struct display_timing auo_g133han01_timings = {
        .pixelclock = { 134000000, 141200000, 149000000 },
        .hactive = { 1920, 1920, 1920 },
@@ -1217,6 +1240,30 @@ static const struct panel_desc innolux_zj070na_01p = {
        },
 };
 
+static const struct display_timing koe_tx31d200vm0baa_timing = {
+       .pixelclock = { 39600000, 43200000, 48000000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 16, 36, 56 },
+       .hback_porch = { 16, 36, 56 },
+       .hsync_len = { 8, 8, 8 },
+       .vactive = { 480, 480, 480 },
+       .vfront_porch = { 6, 21, 33.5 },
+       .vback_porch = { 6, 21, 33.5 },
+       .vsync_len = { 8, 8, 8 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc koe_tx31d200vm0baa = {
+       .timings = &koe_tx31d200vm0baa_timing,
+       .num_timings = 1,
+       .bpc = 6,
+       .size = {
+               .width = 292,
+               .height = 109,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+};
+
 static const struct display_timing kyo_tcg121xglp_timing = {
        .pixelclock = { 52000000, 65000000, 71000000 },
        .hactive = { 1024, 1024, 1024 },
@@ -1597,7 +1644,7 @@ static const struct panel_desc ontat_yx700wv03 = {
                .width = 154,
                .height = 83,
        },
-       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
 };
 
 static const struct drm_display_mode ortustech_com43h4m85ulc_mode  = {
@@ -1741,23 +1788,22 @@ static const struct panel_desc sharp_lq101k1ly04 = {
        .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
 };
 
-static const struct drm_display_mode sharp_lq123p1jx31_mode = {
-       .clock = 252750,
-       .hdisplay = 2400,
-       .hsync_start = 2400 + 48,
-       .hsync_end = 2400 + 48 + 32,
-       .htotal = 2400 + 48 + 32 + 80,
-       .vdisplay = 1600,
-       .vsync_start = 1600 + 3,
-       .vsync_end = 1600 + 3 + 10,
-       .vtotal = 1600 + 3 + 10 + 33,
-       .vrefresh = 60,
-       .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+static const struct display_timing sharp_lq123p1jx31_timing = {
+       .pixelclock = { 252750000, 252750000, 266604720 },
+       .hactive = { 2400, 2400, 2400 },
+       .hfront_porch = { 48, 48, 48 },
+       .hback_porch = { 80, 80, 84 },
+       .hsync_len = { 32, 32, 32 },
+       .vactive = { 1600, 1600, 1600 },
+       .vfront_porch = { 3, 3, 3 },
+       .vback_porch = { 33, 33, 120 },
+       .vsync_len = { 10, 10, 10 },
+       .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
 };
 
 static const struct panel_desc sharp_lq123p1jx31 = {
-       .modes = &sharp_lq123p1jx31_mode,
-       .num_modes = 1,
+       .timings = &sharp_lq123p1jx31_timing,
+       .num_timings = 1,
        .bpc = 8,
        .size = {
                .width = 259,
@@ -2048,6 +2094,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "auo,b133xtn01",
                .data = &auo_b133xtn01,
+       }, {
+               .compatible = "auo,g104sn02",
+               .data = &auo_g104sn02,
        }, {
                .compatible = "auo,g133han01",
                .data = &auo_g133han01,
@@ -2123,6 +2172,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "innolux,zj070na-01p",
                .data = &innolux_zj070na_01p,
+       }, {
+               .compatible = "koe,tx31d200vm0baa",
+               .data = &koe_tx31d200vm0baa,
        }, {
                .compatible = "kyo,tcg121xglp",
                .data = &kyo_tcg121xglp,
index 9a9214ae0fb50de379c68c433da3bf8337c3093a..ecb35ed0eac89ea3c5113a674bbd17383070a75d 100644 (file)
@@ -309,7 +309,7 @@ void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb)
        struct qxl_bo *bo = gem_to_qxl_bo(qxl_fb->obj);
 
        WARN_ON(bo->shadow);
-       drm_gem_object_unreference_unlocked(qxl_fb->obj);
+       drm_gem_object_put_unlocked(qxl_fb->obj);
        drm_framebuffer_cleanup(fb);
        kfree(qxl_fb);
 }
@@ -1215,7 +1215,7 @@ qxl_user_framebuffer_create(struct drm_device *dev,
        ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj, &qxl_fb_funcs);
        if (ret) {
                kfree(qxl_fb);
-               drm_gem_object_unreference_unlocked(obj);
+               drm_gem_object_put_unlocked(obj);
                return NULL;
        }
 
index 11085ab0137425cae14eda185a4ce86df487e21e..c666b89eed5d12d77c3be77ac3c23290895a9424 100644 (file)
@@ -82,6 +82,6 @@ int qxl_mode_dumb_mmap(struct drm_file *file_priv,
                return -ENOENT;
        qobj = gem_to_qxl_bo(gobj);
        *offset_p = qxl_bo_mmap_offset(qobj);
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
        return 0;
 }
index 23af3e352673e3b3e4712c68544e8c1d35fa9d00..338891401f3530864ce18780f8f4d37b2aea3860 100644 (file)
@@ -95,7 +95,7 @@ static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj)
        qxl_bo_kunmap(qbo);
        qxl_bo_unpin(qbo);
 
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
 }
 
 int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
@@ -316,11 +316,11 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
                qxl_bo_unpin(qbo);
        }
        if (fb && ret) {
-               drm_gem_object_unreference_unlocked(gobj);
+               drm_gem_object_put_unlocked(gobj);
                drm_framebuffer_cleanup(fb);
                kfree(fb);
        }
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
        return ret;
 }
 
index 85f546719adb073b8da05d4beeb49779c052d28a..f5c1e7872e920d3a0a3c9e7ec0b0bcfa5779def8 100644 (file)
@@ -98,7 +98,7 @@ int qxl_gem_object_create_with_handle(struct qxl_device *qdev,
                return r;
        /* drop reference from allocate - handle holds it now */
        *qobj = gem_to_qxl_bo(gobj);
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
        return 0;
 }
 
index e8c0b10372301784956c9c32282041f9424102bf..e238a1a2eca1cf47c88248ff3b7419579055a5bc 100644 (file)
@@ -121,7 +121,7 @@ static int qxlhw_handle_to_bo(struct drm_file *file_priv, uint64_t handle,
        qobj = gem_to_qxl_bo(gobj);
 
        ret = qxl_release_list_add(release, qobj);
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
        if (ret)
                return ret;
 
@@ -343,7 +343,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
        qxl_bo_unreserve(qobj);
 
 out:
-       drm_gem_object_unreference_unlocked(gobj);
+       drm_gem_object_put_unlocked(gobj);
        return ret;
 }
 
index af62824ed4ccb5bee68cc4cd28f8dc139b979097..6a30196e9d6c1a371c0b74071b4369b5c237cc4f 100644 (file)
@@ -211,13 +211,13 @@ void qxl_bo_unref(struct qxl_bo **bo)
        if ((*bo) == NULL)
                return;
 
-       drm_gem_object_unreference_unlocked(&(*bo)->gem_base);
+       drm_gem_object_put_unlocked(&(*bo)->gem_base);
        *bo = NULL;
 }
 
 struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
 {
-       drm_gem_object_reference(&bo->gem_base);
+       drm_gem_object_get(&bo->gem_base);
        return bo;
 }
 
@@ -318,7 +318,7 @@ void qxl_bo_force_delete(struct qxl_device *qdev)
                list_del_init(&bo->list);
                mutex_unlock(&qdev->gem.mutex);
                /* this should unref the ttm bo */
-               drm_gem_object_unreference_unlocked(&bo->gem_base);
+               drm_gem_object_put_unlocked(&bo->gem_base);
        }
 }
 
index 31dd04f6baa1b78898f549c2a8393fd95ac48c85..b28288a781ef2887dae7063a29b78e7067259128 100644 (file)
@@ -415,7 +415,6 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
 
        drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
        drm_kms_helper_poll_disable(drm_dev);
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
 
        ret = radeon_suspend_kms(drm_dev, false, false, false);
        pci_save_state(pdev);
@@ -452,7 +451,6 @@ static int radeon_pmops_runtime_resume(struct device *dev)
 
        ret = radeon_resume_kms(drm_dev, false, false);
        drm_kms_helper_poll_enable(drm_dev);
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
        drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
        return 0;
 }
index 7d76ff47028d76d71dbed025011a00bad49b015c..3e8bf79bea58a5658300c2f6981ba550a9b94b16 100644 (file)
@@ -71,10 +71,6 @@ struct rockchip_dp_device {
        struct regmap            *grf;
        struct reset_control     *rst;
 
-       struct work_struct       psr_work;
-       struct mutex             psr_lock;
-       unsigned int             psr_state;
-
        const struct rockchip_dp_chip_data *data;
 
        struct analogix_dp_device *adp;
@@ -84,28 +80,13 @@ struct rockchip_dp_device {
 static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 {
        struct rockchip_dp_device *dp = to_dp(encoder);
+       int ret;
 
-       if (!analogix_dp_psr_supported(dp->adp))
+       if (!analogix_dp_psr_enabled(dp->adp))
                return;
 
        DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
 
-       mutex_lock(&dp->psr_lock);
-       if (enabled)
-               dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
-       else
-               dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
-
-       schedule_work(&dp->psr_work);
-       mutex_unlock(&dp->psr_lock);
-}
-
-static void analogix_dp_psr_work(struct work_struct *work)
-{
-       struct rockchip_dp_device *dp =
-                               container_of(work, typeof(*dp), psr_work);
-       int ret;
-
        ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
                                         PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
        if (ret) {
@@ -113,12 +94,10 @@ static void analogix_dp_psr_work(struct work_struct *work)
                return;
        }
 
-       mutex_lock(&dp->psr_lock);
-       if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+       if (enabled)
                analogix_dp_enable_psr(dp->adp);
        else
                analogix_dp_disable_psr(dp->adp);
-       mutex_unlock(&dp->psr_lock);
 }
 
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
@@ -135,8 +114,6 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
        struct rockchip_dp_device *dp = to_dp(plat_data);
        int ret;
 
-       cancel_work_sync(&dp->psr_work);
-
        ret = clk_prepare_enable(dp->pclk);
        if (ret < 0) {
                DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
@@ -355,10 +332,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
        dp->plat_data.power_off = rockchip_dp_powerdown;
        dp->plat_data.get_modes = rockchip_dp_get_modes;
 
-       mutex_init(&dp->psr_lock);
-       dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
-       INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
-
        ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
        if (ret < 0)
                goto err_cleanup_encoder;
index ec999d9f15f6dac1629d651d0fe2bbd0e5707647..c6fbdcd87c16d3b8727ac2618a591a23fd910eaf 100644 (file)
@@ -43,8 +43,6 @@
 #define GRF_SOC_CON9           0x6224
 #define DP_SEL_VOP_LIT         BIT(12)
 #define GRF_SOC_CON26          0x6268
-#define UPHY_SEL_BIT           3
-#define UPHY_SEL_MASK          BIT(19)
 #define DPTX_HPD_SEL           (3 << 12)
 #define DPTX_HPD_DEL           (2 << 12)
 #define DPTX_HPD_SEL_MASK      (3 << 28)
@@ -394,11 +392,6 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
        union extcon_property_value property;
        int ret;
 
-       ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
-                              (port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK);
-       if (ret)
-               return ret;
-
        if (!port->phy_enabled) {
                ret = phy_power_on(port->phy);
                if (ret) {
index 158e79e5062e0b56cffbb41a9bece155ec6f2bf8..53d4afe15278c946a3bc2f27ed063369ea9488e2 100644 (file)
@@ -117,6 +117,8 @@ struct vop {
        spinlock_t reg_lock;
        /* lock vop irq reg */
        spinlock_t irq_lock;
+       /* protects crtc enable/disable */
+       struct mutex vop_lock;
 
        unsigned int irq;
 
@@ -517,7 +519,10 @@ static int vop_enable(struct drm_crtc *crtc)
                goto err_disable_aclk;
        }
 
-       memcpy(vop->regs, vop->regsbak, vop->len);
+       spin_lock(&vop->reg_lock);
+       for (i = 0; i < vop->len; i += 4)
+               writel_relaxed(vop->regsbak[i / 4], vop->regs + i);
+
        /*
         * We need to make sure that all windows are disabled before we
         * enable the crtc. Otherwise we might try to scan from a destroyed
@@ -527,10 +532,9 @@ static int vop_enable(struct drm_crtc *crtc)
                struct vop_win *vop_win = &vop->win[i];
                const struct vop_win_data *win = vop_win->data;
 
-               spin_lock(&vop->reg_lock);
                VOP_WIN_SET(vop, win, enable, 0);
-               spin_unlock(&vop->reg_lock);
        }
+       spin_unlock(&vop->reg_lock);
 
        vop_cfg_done(vop);
 
@@ -569,6 +573,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
 
        WARN_ON(vop->event);
 
+       mutex_lock(&vop->vop_lock);
        drm_crtc_vblank_off(crtc);
 
        /*
@@ -604,6 +609,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
        clk_disable(vop->aclk);
        clk_disable(vop->hclk);
        pm_runtime_put(vop->dev);
+       mutex_unlock(&vop->vop_lock);
 
        if (crtc->state->event && !crtc->state->active) {
                spin_lock_irq(&crtc->dev->event_lock);
@@ -868,10 +874,13 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
        uint32_t pin_pol, val;
        int ret;
 
+       mutex_lock(&vop->vop_lock);
+
        WARN_ON(vop->event);
 
        ret = vop_enable(crtc);
        if (ret) {
+               mutex_unlock(&vop->vop_lock);
                DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret);
                return;
        }
@@ -935,6 +944,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
        clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
 
        VOP_REG_SET(vop, common, standby, 0);
+       mutex_unlock(&vop->vop_lock);
 }
 
 static bool vop_fs_irq_is_pending(struct vop *vop)
@@ -1137,15 +1147,14 @@ static void vop_handle_vblank(struct vop *vop)
 {
        struct drm_device *drm = vop->drm_dev;
        struct drm_crtc *crtc = &vop->crtc;
-       unsigned long flags;
 
-       spin_lock_irqsave(&drm->event_lock, flags);
+       spin_lock(&drm->event_lock);
        if (vop->event) {
                drm_crtc_send_vblank_event(crtc, vop->event);
                drm_crtc_vblank_put(crtc);
                vop->event = NULL;
        }
-       spin_unlock_irqrestore(&drm->event_lock, flags);
+       spin_unlock(&drm->event_lock);
 
        if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending))
                drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq);
@@ -1156,21 +1165,20 @@ static irqreturn_t vop_isr(int irq, void *data)
        struct vop *vop = data;
        struct drm_crtc *crtc = &vop->crtc;
        uint32_t active_irqs;
-       unsigned long flags;
        int ret = IRQ_NONE;
 
        /*
         * interrupt register has interrupt status, enable and clear bits, we
         * must hold irq_lock to avoid a race with enable/disable_vblank().
        */
-       spin_lock_irqsave(&vop->irq_lock, flags);
+       spin_lock(&vop->irq_lock);
 
        active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK);
        /* Clear all active interrupt sources */
        if (active_irqs)
                VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1);
 
-       spin_unlock_irqrestore(&vop->irq_lock, flags);
+       spin_unlock(&vop->irq_lock);
 
        /* This is expected for vop iommu irqs, since the irq is shared */
        if (!active_irqs)
@@ -1393,7 +1401,11 @@ static int vop_initial(struct vop *vop)
        usleep_range(10, 20);
        reset_control_deassert(ahb_rst);
 
-       memcpy(vop->regsbak, vop->regs, vop->len);
+       VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1);
+       VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0);
+
+       for (i = 0; i < vop->len; i += sizeof(u32))
+               vop->regsbak[i / 4] = readl_relaxed(vop->regs + i);
 
        VOP_REG_SET(vop, misc, global_regdone_en, 1);
        VOP_REG_SET(vop, common, dsp_blank, 0);
@@ -1473,15 +1485,21 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
 {
        struct vop *vop = to_vop(crtc);
        unsigned long jiffies_left;
+       int ret = 0;
 
        if (!crtc || !vop->is_enabled)
                return -ENODEV;
 
-       if (mstimeout <= 0)
-               return -EINVAL;
+       mutex_lock(&vop->vop_lock);
+       if (mstimeout <= 0) {
+               ret = -EINVAL;
+               goto out;
+       }
 
-       if (vop_line_flag_irq_is_enabled(vop))
-               return -EBUSY;
+       if (vop_line_flag_irq_is_enabled(vop)) {
+               ret = -EBUSY;
+               goto out;
+       }
 
        reinit_completion(&vop->line_flag_completion);
        vop_line_flag_irq_enable(vop);
@@ -1492,10 +1510,13 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
 
        if (jiffies_left == 0) {
                DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n");
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto out;
        }
 
-       return 0;
+out:
+       mutex_unlock(&vop->vop_lock);
+       return ret;
 }
 EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
 
@@ -1545,18 +1566,11 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
 
        spin_lock_init(&vop->reg_lock);
        spin_lock_init(&vop->irq_lock);
-
-       ret = devm_request_irq(dev, vop->irq, vop_isr,
-                              IRQF_SHARED, dev_name(dev), vop);
-       if (ret)
-               return ret;
-
-       /* IRQ is initially disabled; it gets enabled in power_on */
-       disable_irq(vop->irq);
+       mutex_init(&vop->vop_lock);
 
        ret = vop_create_crtc(vop);
        if (ret)
-               goto err_enable_irq;
+               return ret;
 
        pm_runtime_enable(&pdev->dev);
 
@@ -1567,13 +1581,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
                goto err_disable_pm_runtime;
        }
 
+       ret = devm_request_irq(dev, vop->irq, vop_isr,
+                              IRQF_SHARED, dev_name(dev), vop);
+       if (ret)
+               goto err_disable_pm_runtime;
+
+       /* IRQ is initially disabled; it gets enabled in power_on */
+       disable_irq(vop->irq);
+
        return 0;
 
 err_disable_pm_runtime:
        pm_runtime_disable(&pdev->dev);
        vop_destroy_crtc(vop);
-err_enable_irq:
-       enable_irq(vop->irq); /* To balance out the disable_irq above */
        return ret;
 }
 
index 092ade4ff6a56ca20be41e99fce44e274f6088c2..9bad54f3de386d7e517cc2ecbf67b784deb75270 100644 (file)
@@ -42,6 +42,56 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
        0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
 };
 
+/*
+ * These coefficients are taken from the A33 BSP from Allwinner.
+ *
+ * The formula is for each component, each coefficient being multiplied by
+ * 1024 and each constant being multiplied by 16:
+ * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
+ * R = 1.164 * Y + 1.596 * V - 222
+ * B = 1.164 * Y + 2.018 * U + 276
+ *
+ * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
+ * following the BT601 spec.
+ */
+static const u32 sunxi_bt601_yuv2rgb_coef[12] = {
+       0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
+       0x000004a7, 0x00000000, 0x00000662, 0x00003211,
+       0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
+};
+
+static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_YUV411:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YUV444:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+static inline bool sun4i_backend_format_is_yuv(uint32_t format)
+{
+       return sun4i_backend_format_is_planar_yuv(format) ||
+               sun4i_backend_format_is_packed_yuv422(format);
+}
+
 static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
 {
        int i;
@@ -166,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
        return 0;
 }
 
+static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
+                                          int layer, struct drm_plane *plane)
+{
+       struct drm_plane_state *state = plane->state;
+       struct drm_framebuffer *fb = state->fb;
+       uint32_t format = fb->format->format;
+       u32 val = SUN4I_BACKEND_IYUVCTL_EN;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
+               regmap_write(backend->engine.regs,
+                            SUN4I_BACKEND_YGCOEF_REG(i),
+                            sunxi_bt601_yuv2rgb_coef[i]);
+
+       /*
+        * We should do that only for a single plane, but the
+        * framebuffer's atomic_check has our back on this.
+        */
+       regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
+                          SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN,
+                          SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
+
+       /* TODO: Add support for the multi-planar YUV formats */
+       if (sun4i_backend_format_is_packed_yuv422(format))
+               val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422;
+       else
+               DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format);
+
+       /*
+        * Allwinner seems to list the pixel sequence from right to left, while
+        * DRM lists it from left to right.
+        */
+       switch (format) {
+       case DRM_FORMAT_YUYV:
+               val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY;
+               break;
+       case DRM_FORMAT_YVYU:
+               val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY;
+               break;
+       case DRM_FORMAT_UYVY:
+               val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU;
+               break;
+       case DRM_FORMAT_VYUY:
+               val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV;
+               break;
+       default:
+               DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n",
+                                format);
+       }
+
+       regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val);
+
+       return 0;
+}
+
 int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
                                       int layer, struct drm_plane *plane)
 {
@@ -175,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
        u32 val;
        int ret;
 
+       /* Clear the YUV mode */
+       regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
+                          SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
+
        if (plane->state->crtc)
                interlaced = plane->state->crtc->state->adjusted_mode.flags
                        & DRM_MODE_FLAG_INTERLACE;
@@ -186,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
        DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
                         interlaced ? "on" : "off");
 
+       if (sun4i_backend_format_is_yuv(fb->format->format))
+               return sun4i_backend_update_yuv_format(backend, layer, plane);
+
        ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val);
        if (ret) {
                DRM_DEBUG_DRIVER("Invalid format\n");
@@ -223,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
        return 0;
 }
 
+static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend,
+                                          struct drm_framebuffer *fb,
+                                          dma_addr_t paddr)
+{
+       /* TODO: Add support for the multi-planar YUV formats */
+       DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr);
+       regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr);
+
+       DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
+       regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0),
+                    fb->pitches[0] * 8);
+
+       return 0;
+}
+
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
                                      int layer, struct drm_plane *plane)
 {
@@ -248,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
         */
        paddr -= PHYS_OFFSET;
 
+       if (sun4i_backend_format_is_yuv(fb->format->format))
+               return sun4i_backend_update_yuv_buffer(backend, fb, paddr);
+
        /* Write the 32 lower bits of the address (in bits) */
        lo_paddr = paddr << 3;
        DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
@@ -330,6 +460,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
        unsigned int num_planes = 0;
        unsigned int num_alpha_planes = 0;
        unsigned int num_frontend_planes = 0;
+       unsigned int num_yuv_planes = 0;
        unsigned int current_pipe = 0;
        unsigned int i;
 
@@ -362,6 +493,11 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
                if (fb->format->has_alpha)
                        num_alpha_planes++;
 
+               if (sun4i_backend_format_is_yuv(fb->format->format)) {
+                       DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
+                       num_yuv_planes++;
+               }
+
                DRM_DEBUG_DRIVER("Plane zpos is %d\n",
                                 plane_state->normalized_zpos);
 
@@ -430,13 +566,20 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
                s_state->pipe = current_pipe;
        }
 
+       /* We can only have a single YUV plane at a time */
+       if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) {
+               DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n");
+               return -EINVAL;
+       }
+
        if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
                DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
                return -EINVAL;
        }
 
-       DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n",
-                        num_planes, num_alpha_planes, num_frontend_planes);
+       DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video, %u YUV\n",
+                        num_planes, num_alpha_planes, num_frontend_planes,
+                        num_yuv_planes);
 
        return 0;
 }
@@ -793,6 +936,9 @@ static const struct sun4i_backend_quirks sun7i_backend_quirks = {
 static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
 };
 
+static const struct sun4i_backend_quirks sun9i_backend_quirks = {
+};
+
 static const struct of_device_id sun4i_backend_of_table[] = {
        {
                .compatible = "allwinner,sun4i-a10-display-backend",
@@ -814,6 +960,10 @@ static const struct of_device_id sun4i_backend_of_table[] = {
                .compatible = "allwinner,sun8i-a33-display-backend",
                .data = &sun8i_a33_backend_quirks,
        },
+       {
+               .compatible = "allwinner,sun9i-a80-display-backend",
+               .data = &sun9i_backend_quirks,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
index 52e77591186acb4356f965a93bc060e8857c0f79..316f2179e9e186ea4969f7e7874cf5e6678c2922 100644 (file)
@@ -72,6 +72,7 @@
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)               ((x) << 15)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK      GENMASK(11, 10)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)                        ((x) << 10)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN            BIT(2)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN            BIT(1)
 
 #define SUN4I_BACKEND_ATTCTL_REG1(l)           (0x8a0 + (0x4 * (l)))
 #define SUN4I_BACKEND_SPREN_REG                        0x900
 #define SUN4I_BACKEND_SPRFMTCTL_REG            0x908
 #define SUN4I_BACKEND_SPRALPHACTL_REG          0x90c
+
 #define SUN4I_BACKEND_IYUVCTL_REG              0x920
+#define SUN4I_BACKEND_IYUVCTL_FBFMT_MASK               GENMASK(14, 12)
+#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV444              (4 << 12)
+#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422              (3 << 12)
+#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV444              (2 << 12)
+#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV222              (1 << 12)
+#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV111              (0 << 12)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_MASK                        GENMASK(9, 8)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_YVYU                                (3 << 8)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_VYUY                                (2 << 8)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_YUYV                                (1 << 8)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_UYVY                                (0 << 8)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_VUYA                                (1 << 8)
+#define SUN4I_BACKEND_IYUVCTL_FBPS_AYUV                                (0 << 8)
+#define SUN4I_BACKEND_IYUVCTL_EN                       BIT(0)
+
 #define SUN4I_BACKEND_IYUVADD_REG(c)           (0x930 + (0x4 * (c)))
 
 #define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c)     (0x940 + (0x4 * (c)))
 #define SUN4I_BACKEND_NUM_LAYERS               4
 #define SUN4I_BACKEND_NUM_ALPHA_LAYERS         1
 #define SUN4I_BACKEND_NUM_FRONTEND_LAYERS      1
+#define SUN4I_BACKEND_NUM_YUV_PLANES           1
 
 struct sun4i_backend {
        struct sunxi_engine     engine;
index a0f43b81c64cd5586db8b6f2c029f74de49fe8cc..7f0705ef9f4eff9b6d902135be17ac1218efc280 100644 (file)
@@ -176,7 +176,13 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node)
                of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
                of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") ||
                of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") ||
-               of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");
+               of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") ||
+               of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend");
+}
+
+static bool sun4i_drv_node_is_deu(struct device_node *node)
+{
+       return of_device_is_compatible(node, "allwinner,sun9i-a80-deu");
 }
 
 static bool sun4i_drv_node_is_supported_frontend(struct device_node *node)
@@ -257,7 +263,8 @@ static int sun4i_drv_add_endpoints(struct device *dev,
         * enabled frontend supported by the driver, we add it to our
         * component list.
         */
-       if (!sun4i_drv_node_is_frontend(node) ||
+       if (!(sun4i_drv_node_is_frontend(node) ||
+             sun4i_drv_node_is_deu(node)) ||
            (sun4i_drv_node_is_supported_frontend(node) &&
             of_device_is_available(node))) {
                /* Add current component */
@@ -361,6 +368,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
        { .compatible = "allwinner,sun8i-a83t-display-engine" },
        { .compatible = "allwinner,sun8i-h3-display-engine" },
        { .compatible = "allwinner,sun8i-v3s-display-engine" },
+       { .compatible = "allwinner,sun9i-a80-display-engine" },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
index 33ad377569ec5c084c9bc7529b1fe24fba936884..2949a3c912c113ec02f6e580abc0dd90352e6c24 100644 (file)
@@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = {
        DRM_FORMAT_RGBA4444,
        DRM_FORMAT_RGB888,
        DRM_FORMAT_RGB565,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
        DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
 };
 
 static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
index be3f14d7746deee1b0183c113dc653e4c7e3629d..bffff4c9fbf56f92dc8a3b566c33e266c729fb95 100644 (file)
@@ -94,9 +94,64 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder)
        }
 }
 
+static enum drm_mode_status sun4i_lvds_encoder_mode_valid(struct drm_encoder *crtc,
+                                                         const struct drm_display_mode *mode)
+{
+       struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(crtc);
+       struct sun4i_tcon *tcon = lvds->tcon;
+       u32 hsync = mode->hsync_end - mode->hsync_start;
+       u32 vsync = mode->vsync_end - mode->vsync_start;
+       unsigned long rate = mode->clock * 1000;
+       long rounded_rate;
+
+       DRM_DEBUG_DRIVER("Validating modes...\n");
+
+       if (hsync < 1)
+               return MODE_HSYNC_NARROW;
+
+       if (hsync > 0x3ff)
+               return MODE_HSYNC_WIDE;
+
+       if ((mode->hdisplay < 1) || (mode->htotal < 1))
+               return MODE_H_ILLEGAL;
+
+       if ((mode->hdisplay > 0x7ff) || (mode->htotal > 0xfff))
+               return MODE_BAD_HVALUE;
+
+       DRM_DEBUG_DRIVER("Horizontal parameters OK\n");
+
+       if (vsync < 1)
+               return MODE_VSYNC_NARROW;
+
+       if (vsync > 0x3ff)
+               return MODE_VSYNC_WIDE;
+
+       if ((mode->vdisplay < 1) || (mode->vtotal < 1))
+               return MODE_V_ILLEGAL;
+
+       if ((mode->vdisplay > 0x7ff) || (mode->vtotal > 0xfff))
+               return MODE_BAD_VVALUE;
+
+       DRM_DEBUG_DRIVER("Vertical parameters OK\n");
+
+       tcon->dclk_min_div = 7;
+       tcon->dclk_max_div = 7;
+       rounded_rate = clk_round_rate(tcon->dclk, rate);
+       if (rounded_rate < rate)
+               return MODE_CLOCK_LOW;
+
+       if (rounded_rate > rate)
+               return MODE_CLOCK_HIGH;
+
+       DRM_DEBUG_DRIVER("Clock rate OK\n");
+
+       return MODE_OK;
+}
+
 static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = {
        .disable        = sun4i_lvds_encoder_disable,
        .enable         = sun4i_lvds_encoder_enable,
+       .mode_valid     = sun4i_lvds_encoder_mode_valid,
 };
 
 static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = {
index 832f8f9bc47fd046baebde3af7c4d406b301a40c..a2a697a099e6b6a191aee43662d8ac39c5e1169e 100644 (file)
@@ -52,10 +52,10 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector)
        return drm_panel_get_modes(tcon->panel);
 }
 
-static int sun4i_rgb_mode_valid(struct drm_connector *connector,
-                               struct drm_display_mode *mode)
+static enum drm_mode_status sun4i_rgb_mode_valid(struct drm_encoder *crtc,
+                                                const struct drm_display_mode *mode)
 {
-       struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
+       struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(crtc);
        struct sun4i_tcon *tcon = rgb->tcon;
        u32 hsync = mode->hsync_end - mode->hsync_start;
        u32 vsync = mode->vsync_end - mode->vsync_start;
@@ -106,7 +106,6 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,
 
 static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
        .get_modes      = sun4i_rgb_get_modes,
-       .mode_valid     = sun4i_rgb_mode_valid,
 };
 
 static void
@@ -156,6 +155,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
 static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
        .disable        = sun4i_rgb_encoder_disable,
        .enable         = sun4i_rgb_encoder_enable,
+       .mode_valid     = sun4i_rgb_mode_valid,
 };
 
 static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder)
index 0d6c5ed44795c411574910153d45c7829d1d56e9..1a114e380f13ee8e13d970d18d57c8f4f930e093 100644 (file)
@@ -17,6 +17,7 @@
 #include <drm/drm_encoder.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_of.h>
+#include <drm/drm_panel.h>
 
 #include <uapi/drm/drm_mode.h>
 
@@ -343,6 +344,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
 static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
                                     const struct drm_display_mode *mode)
 {
+       struct drm_panel *panel = tcon->panel;
+       struct drm_connector *connector = panel->connector;
+       struct drm_display_info display_info = connector->display_info;
        unsigned int bp, hsync, vsync;
        u8 clk_delay;
        u32 val = 0;
@@ -400,6 +404,27 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
                val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
 
+       /*
+        * On A20 and similar SoCs, the only way to achieve Positive Edge
+        * (Rising Edge), is setting dclk clock phase to 2/3(240°).
+        * By default TCON works in Negative Edge(Falling Edge),
+        * this is why phase is set to 0 in that case.
+        * Unfortunately there's no way to logically invert dclk through
+        * IO_POL register.
+        * The only acceptable way to work, triple checked with scope,
+        * is using clock phase set to 0° for Negative Edge and set to 240°
+        * for Positive Edge.
+        * On A33 and similar SoCs there would be a 90° phase option,
+        * but it divides also dclk by 2.
+        * Following code is a way to avoid quirks all around TCON
+        * and DOTCLOCK drivers.
+        */
+       if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+               clk_set_phase(tcon->dclk, 240);
+
+       if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
+               clk_set_phase(tcon->dclk, 0);
+
        regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
                           SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
                           val);
@@ -850,6 +875,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
        struct sunxi_engine *engine;
        struct device_node *remote;
        struct sun4i_tcon *tcon;
+       struct reset_control *edp_rstc;
        bool has_lvds_rst, has_lvds_alt, can_lvds;
        int ret;
 
@@ -874,6 +900,20 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
                return PTR_ERR(tcon->lcd_rst);
        }
 
+       if (tcon->quirks->needs_edp_reset) {
+               edp_rstc = devm_reset_control_get_shared(dev, "edp");
+               if (IS_ERR(edp_rstc)) {
+                       dev_err(dev, "Couldn't get edp reset line\n");
+                       return PTR_ERR(edp_rstc);
+               }
+
+               ret = reset_control_deassert(edp_rstc);
+               if (ret) {
+                       dev_err(dev, "Couldn't deassert edp reset line\n");
+                       return ret;
+               }
+       }
+
        /* Make sure our TCON is reset */
        ret = reset_control_reset(tcon->lcd_rst);
        if (ret) {
@@ -1166,6 +1206,16 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
        .has_channel_0          = true,
 };
 
+static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {
+       .has_channel_0  = true,
+       .needs_edp_reset = true,
+};
+
+static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {
+       .has_channel_1  = true,
+       .needs_edp_reset = true,
+};
+
 /* sun4i_drv uses this list to check if a device node is a TCON */
 const struct of_device_id sun4i_tcon_of_table[] = {
        { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
@@ -1177,6 +1227,8 @@ const struct of_device_id sun4i_tcon_of_table[] = {
        { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
        { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
        { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
+       { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
+       { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
index 78d55e7cd2b3d286b6d16c19a94c28e55a50c91c..d3a945b7bb604330945cc4f07084b9d0dfc9dd34 100644 (file)
@@ -176,6 +176,7 @@ struct sun4i_tcon_quirks {
        bool    has_channel_1;  /* a33 does not have channel 1 */
        bool    has_lvds_alt;   /* Does the LVDS clock have a parent other than the TCON clock? */
        bool    needs_de_be_mux; /* sun6i needs mux to select backend */
+       bool    needs_edp_reset; /* a80 edp reset needed for tcon0 access */
 
        /* callback to handle tcon muxing options */
        int     (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
index 09bba853e2a4237cf876e8295a8a7a8314c247ef..b5e071a4904523386ceea0c8205dc3dad3ba6767 100644 (file)
@@ -101,6 +101,7 @@ static const struct of_device_id sun6i_drc_of_table[] = {
        { .compatible = "allwinner,sun6i-a31-drc" },
        { .compatible = "allwinner,sun6i-a31s-drc" },
        { .compatible = "allwinner,sun8i-a33-drc" },
+       { .compatible = "allwinner,sun9i-a80-drc" },
        { }
 };
 MODULE_DEVICE_TABLE(of, sun6i_drc_of_table);
index ce1e3b9e14c9ac2e676ad760f653fd6d7091f964..bf4667481935281526def8786619cd0a537c76f7 100644 (file)
@@ -643,9 +643,12 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
+       struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
        struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
        struct drm_plane *plane;
+       struct vc4_plane_state *vc4_plane_state;
        bool debug_dump_regs = false;
+       bool enable_bg_fill = false;
        u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
        u32 __iomem *dlist_next = dlist_start;
 
@@ -656,6 +659,20 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
 
        /* Copy all the active planes' dlist contents to the hardware dlist. */
        drm_atomic_crtc_for_each_plane(plane, crtc) {
+               /* Is this the first active plane? */
+               if (dlist_next == dlist_start) {
+                       /* We need to enable background fill when a plane
+                        * could be alpha blending from the background, i.e.
+                        * where no other plane is underneath. It suffices to
+                        * consider the first active plane here since we set
+                        * needs_bg_fill such that either the first plane
+                        * already needs it or all planes on top blend from
+                        * the first or a lower plane.
+                        */
+                       vc4_plane_state = to_vc4_plane_state(plane->state);
+                       enable_bg_fill = vc4_plane_state->needs_bg_fill;
+               }
+
                dlist_next += vc4_plane_write_dlist(plane, dlist_next);
        }
 
@@ -664,6 +681,14 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
 
        WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
 
+       if (enable_bg_fill)
+               /* This sets a black background color fill, as is the case
+                * with other DRM drivers.
+                */
+               HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
+                         HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) |
+                         SCALER_DISPBKGND_FILL);
+
        /* Only update DISPLIST if the CRTC was already running and is not
         * being disabled.
         * vc4_crtc_enable() takes care of updating the dlist just after
index fefa1664a9f5f6596616ebbedb80e5965b06388e..1b4cd1fabf56ead022b0885b3f3a1e7d17181453 100644 (file)
@@ -310,6 +310,66 @@ to_vc4_plane(struct drm_plane *plane)
        return (struct vc4_plane *)plane;
 }
 
+enum vc4_scaling_mode {
+       VC4_SCALING_NONE,
+       VC4_SCALING_TPZ,
+       VC4_SCALING_PPF,
+};
+
+struct vc4_plane_state {
+       struct drm_plane_state base;
+       /* System memory copy of the display list for this element, computed
+        * at atomic_check time.
+        */
+       u32 *dlist;
+       u32 dlist_size; /* Number of dwords allocated for the display list */
+       u32 dlist_count; /* Number of used dwords in the display list. */
+
+       /* Offset in the dlist to various words, for pageflip or
+        * cursor updates.
+        */
+       u32 pos0_offset;
+       u32 pos2_offset;
+       u32 ptr0_offset;
+
+       /* Offset where the plane's dlist was last stored in the
+        * hardware at vc4_crtc_atomic_flush() time.
+        */
+       u32 __iomem *hw_dlist;
+
+       /* Clipped coordinates of the plane on the display. */
+       int crtc_x, crtc_y, crtc_w, crtc_h;
+       /* Clipped area being scanned from in the FB. */
+       u32 src_x, src_y;
+
+       u32 src_w[2], src_h[2];
+
+       /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
+       enum vc4_scaling_mode x_scaling[2], y_scaling[2];
+       bool is_unity;
+       bool is_yuv;
+
+       /* Offset to start scanning out from the start of the plane's
+        * BO.
+        */
+       u32 offsets[3];
+
+       /* Our allocation in LBM for temporary storage during scaling. */
+       struct drm_mm_node lbm;
+
+       /* Set when the plane has per-pixel alpha content or does not cover
+        * the entire screen. This is a hint to the CRTC that it might need
+        * to enable background color fill.
+        */
+       bool needs_bg_fill;
+};
+
+static inline struct vc4_plane_state *
+to_vc4_plane_state(struct drm_plane_state *state)
+{
+       return (struct vc4_plane_state *)state;
+}
+
 enum vc4_encoder_type {
        VC4_ENCODER_TYPE_NONE,
        VC4_ENCODER_TYPE_HDMI,
index c4c7af11fec523d49b4075be4e6267605f4a6198..ce39390be389305bdd10a2641234785f465308f0 100644 (file)
 #include "vc4_drv.h"
 #include "vc4_regs.h"
 
-enum vc4_scaling_mode {
-       VC4_SCALING_NONE,
-       VC4_SCALING_TPZ,
-       VC4_SCALING_PPF,
-};
-
-struct vc4_plane_state {
-       struct drm_plane_state base;
-       /* System memory copy of the display list for this element, computed
-        * at atomic_check time.
-        */
-       u32 *dlist;
-       u32 dlist_size; /* Number of dwords allocated for the display list */
-       u32 dlist_count; /* Number of used dwords in the display list. */
-
-       /* Offset in the dlist to various words, for pageflip or
-        * cursor updates.
-        */
-       u32 pos0_offset;
-       u32 pos2_offset;
-       u32 ptr0_offset;
-
-       /* Offset where the plane's dlist was last stored in the
-        * hardware at vc4_crtc_atomic_flush() time.
-        */
-       u32 __iomem *hw_dlist;
-
-       /* Clipped coordinates of the plane on the display. */
-       int crtc_x, crtc_y, crtc_w, crtc_h;
-       /* Clipped area being scanned from in the FB. */
-       u32 src_x, src_y;
-
-       u32 src_w[2], src_h[2];
-
-       /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
-       enum vc4_scaling_mode x_scaling[2], y_scaling[2];
-       bool is_unity;
-       bool is_yuv;
-
-       /* Offset to start scanning out from the start of the plane's
-        * BO.
-        */
-       u32 offsets[3];
-
-       /* Our allocation in LBM for temporary storage during scaling. */
-       struct drm_mm_node lbm;
-};
-
-static inline struct vc4_plane_state *
-to_vc4_plane_state(struct drm_plane_state *state)
-{
-       return (struct vc4_plane_state *)state;
-}
-
 static const struct hvs_format {
        u32 drm; /* DRM_FORMAT_* */
        u32 hvs; /* HVS_FORMAT_* */
@@ -521,6 +467,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        u32 ctl0_offset = vc4_state->dlist_count;
        const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
        int num_planes = drm_format_num_planes(format->drm);
+       bool covers_screen;
        u32 scl0, scl1, pitch0;
        u32 lbm_size, tiling;
        unsigned long irqflags;
@@ -618,13 +565,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
                                              SCALER_POS1_SCL_HEIGHT));
        }
 
-       /* Position Word 2: Source Image Size, Alpha Mode */
+       /* Position Word 2: Source Image Size, Alpha */
        vc4_state->pos2_offset = vc4_state->dlist_count;
        vc4_dlist_write(vc4_state,
                        VC4_SET_FIELD(fb->format->has_alpha ?
                                      SCALER_POS2_ALPHA_MODE_PIPELINE :
                                      SCALER_POS2_ALPHA_MODE_FIXED,
                                      SCALER_POS2_ALPHA_MODE) |
+                       (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
                        VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
                        VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
 
@@ -700,6 +648,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
        vc4_state->dlist[ctl0_offset] |=
                VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
 
+       /* crtc_* are already clipped coordinates. */
+       covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
+                       vc4_state->crtc_w == state->crtc->mode.hdisplay &&
+                       vc4_state->crtc_h == state->crtc->mode.vdisplay;
+       /* Background fill might be necessary when the plane has per-pixel
+        * alpha content and blends from the background or does not cover
+        * the entire screen.
+        */
+       vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen;
+
        return 0;
 }
 
index b9749cb240638ddce98a656409c6b6ffb3e44582..a141496104a6594107e45288872026f98c989e32 100644 (file)
@@ -848,6 +848,7 @@ enum hvs_pixel_format {
 #define SCALER_POS2_ALPHA_MODE_FIXED           1
 #define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO   2
 #define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3
+#define SCALER_POS2_ALPHA_PREMULT              BIT(29)
 
 #define SCALER_POS2_HEIGHT_MASK                        VC4_MASK(27, 16)
 #define SCALER_POS2_HEIGHT_SHIFT               16
index 2db485abb186a292cd0c33773a07762e3808fb8b..eec76af49f04188bbe7cf3a7cfc39687e2895363 100644 (file)
@@ -753,7 +753,7 @@ validate_gl_shader_rec(struct drm_device *dev,
                28, /* cs */
        };
        uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets);
-       struct drm_gem_cma_object *bo[shader_reloc_count + 8];
+       struct drm_gem_cma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8];
        uint32_t nr_attributes, nr_relocs, packet_size;
        int i;
 
index d23a18aae476be3ab181a7a7bd3b8b52e3487efb..be7d7fb1b44b4508d37c9a34255b6fe920ab721f 100644 (file)
@@ -500,7 +500,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
        }
 
        if (cur_fb) {
-               drm_framebuffer_unreference(cur_fb);
+               drm_framebuffer_put(cur_fb);
                par->set_fb = NULL;
        }
 
index 67f844678ac87eabdb98c1c6612ad21eb07e17db..c5e8eae0dbe23c5f1f5966349075b4f242a1fc97 100644 (file)
@@ -316,7 +316,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 out_no_surface:
        ttm_read_unlock(&dev_priv->reservation_sem);
 out_no_ttm_lock:
-       drm_framebuffer_unreference(fb);
+       drm_framebuffer_put(fb);
 out_no_fb:
        drm_modeset_unlock_all(dev);
 out_no_copy:
@@ -393,7 +393,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 
        ttm_read_unlock(&dev_priv->reservation_sem);
 out_no_ttm_lock:
-       drm_framebuffer_unreference(fb);
+       drm_framebuffer_put(fb);
 out_no_fb:
        drm_modeset_unlock_all(dev);
 out_no_copy:
index 3cd153c6d271a5f451c3a6e6ea7893060e4441c5..fc4adf3d34e845c3c8463bf281d06b4a272cef30 100644 (file)
@@ -92,7 +92,8 @@
  * struct vga_switcheroo_client - registered client
  * @pdev: client pci device
  * @fb_info: framebuffer to which console is remapped on switching
- * @pwr_state: current power state
+ * @pwr_state: current power state if manual power control is used.
+ *     For driver power control, call vga_switcheroo_pwr_state().
  * @ops: client callbacks
  * @id: client identifier. Determining the id requires the handler,
  *     so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID
  * @list: client list
  *
  * Registered client. A client can be either a GPU or an audio device on a GPU.
- * For audio clients, the @fb_info, @active and @driver_power_control members
- * are bogus.
+ * For audio clients, the @fb_info and @active members are bogus.
  */
 struct vga_switcheroo_client {
        struct pci_dev *pdev;
@@ -331,8 +331,8 @@ EXPORT_SYMBOL(vga_switcheroo_register_client);
  * @ops: client callbacks
  * @id: client identifier
  *
- * Register audio client (audio device on a GPU). The power state of the
- * client is assumed to be ON. Beforehand, vga_switcheroo_client_probe_defer()
+ * Register audio client (audio device on a GPU). The client is assumed
+ * to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer()
  * shall be called to ensure that all prerequisites are met.
  *
  * Return: 0 on success, -ENOMEM on memory allocation error.
@@ -341,7 +341,7 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
                        const struct vga_switcheroo_client_ops *ops,
                        enum vga_switcheroo_client_id id)
 {
-       return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false);
+       return register_client(pdev, ops, id | ID_BIT_AUDIO, false, true);
 }
 EXPORT_SYMBOL(vga_switcheroo_register_audio_client);
 
@@ -406,6 +406,19 @@ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
 }
 EXPORT_SYMBOL(vga_switcheroo_client_probe_defer);
 
+static enum vga_switcheroo_state
+vga_switcheroo_pwr_state(struct vga_switcheroo_client *client)
+{
+       if (client->driver_power_control)
+               if (pm_runtime_enabled(&client->pdev->dev) &&
+                   pm_runtime_active(&client->pdev->dev))
+                       return VGA_SWITCHEROO_ON;
+               else
+                       return VGA_SWITCHEROO_OFF;
+       else
+               return client->pwr_state;
+}
+
 /**
  * vga_switcheroo_get_client_state() - obtain power state of a given client
  * @pdev: client pci device
@@ -425,7 +438,7 @@ enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev)
        if (!client)
                ret = VGA_SWITCHEROO_NOT_FOUND;
        else
-               ret = client->pwr_state;
+               ret = vga_switcheroo_pwr_state(client);
        mutex_unlock(&vgasr_mutex);
        return ret;
 }
@@ -598,7 +611,7 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
                           client_is_vga(client) ? "" : "-Audio",
                           client->active ? '+' : ' ',
                           client->driver_power_control ? "Dyn" : "",
-                          client->pwr_state ? "Pwr" : "Off",
+                          vga_switcheroo_pwr_state(client) ? "Pwr" : "Off",
                           pci_name(client->pdev));
                i++;
        }
@@ -641,10 +654,8 @@ static void set_audio_state(enum vga_switcheroo_client_id id,
        struct vga_switcheroo_client *client;
 
        client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
-       if (client && client->pwr_state != state) {
+       if (client)
                client->ops->set_gpu_state(client->pdev, state);
-               client->pwr_state = state;
-       }
 }
 
 /* stage one happens before delay */
@@ -656,7 +667,7 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
        if (!active)
                return 0;
 
-       if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
+       if (vga_switcheroo_pwr_state(new_client) == VGA_SWITCHEROO_OFF)
                vga_switchon(new_client);
 
        vga_set_default_device(new_client->pdev);
@@ -675,7 +686,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
 
        active->active = false;
 
-       set_audio_state(active->id, VGA_SWITCHEROO_OFF);
+       /* let HDA controller autosuspend if GPU uses driver power control */
+       if (!active->driver_power_control)
+               set_audio_state(active->id, VGA_SWITCHEROO_OFF);
 
        if (new_client->fb_info) {
                struct fb_event event;
@@ -695,10 +708,12 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
        if (new_client->ops->reprobe)
                new_client->ops->reprobe(new_client->pdev);
 
-       if (active->pwr_state == VGA_SWITCHEROO_ON)
+       if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
                vga_switchoff(active);
 
-       set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
+       /* let HDA controller autoresume if GPU uses driver power control */
+       if (!new_client->driver_power_control)
+               set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
 
        new_client->active = true;
        return 0;
@@ -939,11 +954,6 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
  * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel
  * command line disables it.
  *
- * When the driver decides to power up or down, it notifies vga_switcheroo
- * thereof so that it can (a) power the audio device on the GPU up or down,
- * and (b) update its internal power state representation for the device.
- * This is achieved by vga_switcheroo_set_dynamic_switch().
- *
  * After the GPU has been suspended, the handler needs to be called to cut
  * power to the GPU. Likewise it needs to reinstate power before the GPU
  * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(),
@@ -951,8 +961,9 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
  * calls to the handler.
  *
  * When the audio device resumes, the GPU needs to be woken. This is achieved
- * by vga_switcheroo_init_domain_pm_optimus_hdmi_audio(), which augments the
- * audio device's resume function.
+ * by a PCI quirk which calls device_link_add() to declare a dependency on the
+ * GPU. That way, the GPU is kept awake whenever and as long as the audio
+ * device is in use.
  *
  * On muxed machines, if the mux is initially switched to the discrete GPU,
  * the user ends up with a black screen when the GPU powers down after boot.
@@ -978,35 +989,6 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev,
        vgasr_priv.handler->power_state(client->id, state);
 }
 
-/**
- * vga_switcheroo_set_dynamic_switch() - helper for driver power control
- * @pdev: client pci device
- * @dynamic: new power state
- *
- * Helper for GPUs whose power state is controlled by the driver's runtime pm.
- * When the driver decides to power up or down, it notifies vga_switcheroo
- * thereof using this helper so that it can (a) power the audio device on
- * the GPU up or down, and (b) update its internal power state representation
- * for the device.
- */
-void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev,
-                                      enum vga_switcheroo_state dynamic)
-{
-       struct vga_switcheroo_client *client;
-
-       mutex_lock(&vgasr_mutex);
-       client = find_client_from_pci(&vgasr_priv.clients, pdev);
-       if (!client || !client->driver_power_control) {
-               mutex_unlock(&vgasr_mutex);
-               return;
-       }
-
-       client->pwr_state = dynamic;
-       set_audio_state(client->id, dynamic);
-       mutex_unlock(&vgasr_mutex);
-}
-EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch);
-
 /* switcheroo power domain */
 static int vga_switcheroo_runtime_suspend(struct device *dev)
 {
@@ -1022,6 +1004,7 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
                vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
                mutex_unlock(&vgasr_priv.mux_hw_lock);
        }
+       pci_bus_set_current_state(pdev->bus, PCI_D3cold);
        vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
        mutex_unlock(&vgasr_mutex);
        return 0;
@@ -1035,6 +1018,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
        mutex_lock(&vgasr_mutex);
        vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
        mutex_unlock(&vgasr_mutex);
+       pci_wakeup_bus(pdev->bus);
        ret = dev->bus->pm->runtime_resume(dev);
        if (ret)
                return ret;
@@ -1076,69 +1060,3 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev)
        dev_pm_domain_set(dev, NULL);
 }
 EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops);
-
-static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct vga_switcheroo_client *client;
-       struct device *video_dev = NULL;
-       int ret;
-
-       /* we need to check if we have to switch back on the video
-        * device so the audio device can come back
-        */
-       mutex_lock(&vgasr_mutex);
-       list_for_each_entry(client, &vgasr_priv.clients, list) {
-               if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) &&
-                   client_is_vga(client)) {
-                       video_dev = &client->pdev->dev;
-                       break;
-               }
-       }
-       mutex_unlock(&vgasr_mutex);
-
-       if (video_dev) {
-               ret = pm_runtime_get_sync(video_dev);
-               if (ret && ret != 1)
-                       return ret;
-       }
-       ret = dev->bus->pm->runtime_resume(dev);
-
-       /* put the reference for the gpu */
-       if (video_dev) {
-               pm_runtime_mark_last_busy(video_dev);
-               pm_runtime_put_autosuspend(video_dev);
-       }
-       return ret;
-}
-
-/**
- * vga_switcheroo_init_domain_pm_optimus_hdmi_audio() - helper for driver
- *     power control
- * @dev: audio client device
- * @domain: power domain
- *
- * Helper for GPUs whose power state is controlled by the driver's runtime pm.
- * When the audio device resumes, the GPU needs to be woken. This helper
- * augments the audio device's resume function to do that.
- *
- * Return: 0 on success, -EINVAL if no power management operations are
- * defined for this device.
- */
-int
-vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev,
-                                                struct dev_pm_domain *domain)
-{
-       /* copy over all the bus versions */
-       if (dev->bus && dev->bus->pm) {
-               domain->ops = *dev->bus->pm;
-               domain->ops.runtime_resume =
-                       vga_switcheroo_runtime_resume_hdmi_audio;
-
-               dev_pm_domain_set(dev, domain);
-               return 0;
-       }
-       dev_pm_domain_set(dev, NULL);
-       return -EINVAL;
-}
-EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio);
index 3bed6beda0514925be66bc6996dd91f9dabf1bb0..6a67cdbd0e6a345b1727cf2486cc817e5c5305af 100644 (file)
@@ -1224,11 +1224,14 @@ static int pci_pm_runtime_suspend(struct device *dev)
        int error;
 
        /*
-        * If pci_dev->driver is not set (unbound), the device should
-        * always remain in D0 regardless of the runtime PM status
+        * If pci_dev->driver is not set (unbound), we leave the device in D0,
+        * but it may go to D3cold when the bridge above it runtime suspends.
+        * Save its config space in case that happens.
         */
-       if (!pci_dev->driver)
+       if (!pci_dev->driver) {
+               pci_save_state(pci_dev);
                return 0;
+       }
 
        if (!pm || !pm->runtime_suspend)
                return -ENOSYS;
@@ -1276,16 +1279,18 @@ static int pci_pm_runtime_resume(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        /*
-        * If pci_dev->driver is not set (unbound), the device should
-        * always remain in D0 regardless of the runtime PM status
+        * Restoring config space is necessary even if the device is not bound
+        * to a driver because although we left it in D0, it may have gone to
+        * D3cold when the bridge above it runtime suspended.
         */
+       pci_restore_standard_config(pci_dev);
+
        if (!pci_dev->driver)
                return 0;
 
        if (!pm || !pm->runtime_resume)
                return -ENOSYS;
 
-       pci_restore_standard_config(pci_dev);
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
        pci_enable_wake(pci_dev, PCI_D0, false);
        pci_fixup_device(pci_fixup_resume, pci_dev);
index f6a4dd10d9b0da85a009a1cdd8b6498312573ac3..bd6f156dc3cfa9abc54a8aa0973fe6ffdcdd81fc 100644 (file)
@@ -800,7 +800,7 @@ static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
  * pci_wakeup_bus - Walk given bus and wake up devices on it
  * @bus: Top bus of the subtree to walk.
  */
-static void pci_wakeup_bus(struct pci_bus *bus)
+void pci_wakeup_bus(struct pci_bus *bus)
 {
        if (bus)
                pci_walk_bus(bus, pci_wakeup, NULL);
@@ -850,11 +850,11 @@ static int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
 }
 
 /**
- * __pci_bus_set_current_state - Walk given bus and set current state of devices
+ * pci_bus_set_current_state - Walk given bus and set current state of devices
  * @bus: Top bus of the subtree to walk.
  * @state: state to be set
  */
-static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
+void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
 {
        if (bus)
                pci_walk_bus(bus, __pci_dev_set_current_state, &state);
@@ -876,7 +876,7 @@ int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
        ret = pci_platform_power_transition(dev, state);
        /* Power off the bridge may power off the whole hierarchy */
        if (!ret && state == PCI_D3cold)
-               __pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
+               pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
        return ret;
 }
 EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
index fc734014206fb0845e9d6549e2b7b554f8845919..ec582d37c1898c8139f18ad67efde9d465601c11 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ktime.h>
 #include <linux/mm.h>
 #include <linux/platform_data/x86/apple.h>
+#include <linux/pm_runtime.h>
 #include <asm/dma.h>   /* isa_dma_bridge_buggy */
 #include "pci.h"
 
@@ -4832,3 +4833,41 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
                pdev->no_msi = 1;
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
+
+/*
+ * GPUs with integrated HDA controller for streaming audio to attached displays
+ * need a device link from the HDA controller (consumer) to the GPU (supplier)
+ * so that the GPU is powered up whenever the HDA controller is accessed.
+ * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
+ * The device link stays in place until shutdown (or removal of the PCI device
+ * if it's hotplugged).  Runtime PM is allowed by default on the HDA controller
+ * to prevent it from permanently keeping the GPU awake.
+ */
+static void quirk_gpu_hda(struct pci_dev *hda)
+{
+       struct pci_dev *gpu;
+
+       if (PCI_FUNC(hda->devfn) != 1)
+               return;
+
+       gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
+                                         hda->bus->number,
+                                         PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
+       if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
+               pci_dev_put(gpu);
+               return;
+       }
+
+       if (!device_link_add(&hda->dev, &gpu->dev,
+                            DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
+               pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
+
+       pm_runtime_allow(&hda->dev);
+       pci_dev_put(gpu);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+                             PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID,
+                             PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+                             PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
index 711fff9b6803d511c5f7795f5801bfbe1076a01b..e9a1116d2f8e602734450cea57ebd105f4c7d759 100644 (file)
@@ -41,7 +41,7 @@ struct analogix_dp_plat_data {
                         struct drm_connector *);
 };
 
-int analogix_dp_psr_supported(struct analogix_dp_device *dp);
+int analogix_dp_psr_enabled(struct analogix_dp_device *dp);
 int analogix_dp_enable_psr(struct analogix_dp_device *dp);
 int analogix_dp_disable_psr(struct analogix_dp_device *dp);
 
index b3b6d302ca8c0525b6f9873185e6684b938226fc..44f04233e3db6527c10097b5212c5d52408037b6 100644 (file)
@@ -38,6 +38,18 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
                                 int gamma_size);
 
+/**
+ * drm_color_lut_size - calculate the number of entries in the LUT
+ * @blob: blob containing the LUT
+ *
+ * Returns:
+ * The number of entries in the color LUT stored in @blob.
+ */
+static inline int drm_color_lut_size(const struct drm_property_blob *blob)
+{
+       return blob->length / sizeof(struct drm_color_lut);
+}
+
 enum drm_color_encoding {
        DRM_COLOR_YCBCR_BT601,
        DRM_COLOR_YCBCR_BT709,
index 4de97e94ef9dd980de0ae15030ca70f5fee54add..62903bae0221d37decc5d9c4017cf1453927693f 100644 (file)
 #define DP_PSR_SUPPORT                      0x070   /* XXX 1.2? */
 # define DP_PSR_IS_SUPPORTED                1
 # define DP_PSR2_IS_SUPPORTED              2       /* eDP 1.4 */
+# define DP_PSR2_WITH_Y_COORD_IS_SUPPORTED  3      /* eDP 1.4a */
 
 #define DP_PSR_CAPS                         0x071   /* XXX 1.2? */
 # define DP_PSR_NO_TRAIN_ON_EXIT            1
index 7ba3913f30b5708f1c4645c58b99a700a9fc119b..c34a3e8030e12c1cd2957c55780a11004edf967d 100644 (file)
@@ -120,30 +120,6 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 void drm_mode_object_get(struct drm_mode_object *obj);
 void drm_mode_object_put(struct drm_mode_object *obj);
 
-/**
- * drm_mode_object_reference - acquire a mode object reference
- * @obj: DRM mode object
- *
- * This is a compatibility alias for drm_mode_object_get() and should not be
- * used by new code.
- */
-static inline void drm_mode_object_reference(struct drm_mode_object *obj)
-{
-       drm_mode_object_get(obj);
-}
-
-/**
- * drm_mode_object_unreference - release a mode object reference
- * @obj: DRM mode object
- *
- * This is a compatibility alias for drm_mode_object_put() and should not be
- * used by new code.
- */
-static inline void drm_mode_object_unreference(struct drm_mode_object *obj)
-{
-       drm_mode_object_put(obj);
-}
-
 int drm_object_property_set_value(struct drm_mode_object *obj,
                                  struct drm_property *property,
                                  uint64_t val);
index 2a4a42e59a478284742d5d3669adb4ba7589abf8..e1a46e9991cca11a641b9a26ad64757502da38a3 100644 (file)
@@ -196,21 +196,22 @@ static inline struct drm_printer drm_debug_printer(const char *prefix)
 #define DRM_UT_STATE           0x40
 #define DRM_UT_LEASE           0x80
 
-__printf(6, 7)
+__printf(3, 4)
 void drm_dev_printk(const struct device *dev, const char *level,
-                   unsigned int category, const char *function_name,
-                   const char *prefix, const char *format, ...);
+                   const char *format, ...);
 __printf(3, 4)
-void drm_printk(const char *level, unsigned int category,
-               const char *format, ...);
+void drm_dev_dbg(const struct device *dev, unsigned int category,
+                const char *format, ...);
+
+__printf(2, 3)
+void drm_dbg(unsigned int category, const char *format, ...);
+__printf(1, 2)
+void drm_err(const char *format, ...);
 
 /* Macros to make printk easier */
 
 #define _DRM_PRINTK(once, level, fmt, ...)                             \
-       do {                                                            \
-               printk##once(KERN_##level "[" DRM_NAME "] " fmt,        \
-                            ##__VA_ARGS__);                            \
-       } while (0)
+       printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
 
 #define DRM_INFO(fmt, ...)                                             \
        _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
@@ -233,10 +234,9 @@ void drm_printk(const char *level, unsigned int category,
  * @fmt: printf() like format string.
  */
 #define DRM_DEV_ERROR(dev, fmt, ...)                                   \
-       drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\
-                      fmt, ##__VA_ARGS__)
+       drm_dev_printk(dev, KERN_ERR, "*ERROR* " fmt, ##__VA_ARGS__)
 #define DRM_ERROR(fmt, ...)                                            \
-       drm_printk(KERN_ERR, DRM_UT_NONE, fmt,  ##__VA_ARGS__)
+       drm_err(fmt, ##__VA_ARGS__)
 
 /**
  * Rate limited error output.  Like DRM_ERROR() but won't flood the log.
@@ -257,8 +257,7 @@ void drm_printk(const char *level, unsigned int category,
        DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_INFO(dev, fmt, ...)                                    \
-       drm_dev_printk(dev, KERN_INFO, DRM_UT_NONE, __func__, "", fmt,  \
-                      ##__VA_ARGS__)
+       drm_dev_printk(dev, KERN_INFO, fmt, ##__VA_ARGS__)
 
 #define DRM_DEV_INFO_ONCE(dev, fmt, ...)                               \
 ({                                                                     \
@@ -275,53 +274,46 @@ void drm_printk(const char *level, unsigned int category,
  * @dev: device pointer
  * @fmt: printf() like format string.
  */
-#define DRM_DEV_DEBUG(dev, fmt, args...)                               \
-       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \
-                      ##args)
+#define DRM_DEV_DEBUG(dev, fmt, ...)                                   \
+       drm_dev_dbg(dev, DRM_UT_CORE, fmt, ##__VA_ARGS__)
 #define DRM_DEBUG(fmt, ...)                                            \
-       drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__)
+       drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__)
 
-#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...)                                \
-       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "",    \
-                      fmt, ##args)
+#define DRM_DEV_DEBUG_DRIVER(dev, fmt, ...)                            \
+       drm_dev_dbg(dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
 #define DRM_DEBUG_DRIVER(fmt, ...)                                     \
-       drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
+       drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
 
-#define DRM_DEV_DEBUG_KMS(dev, fmt, args...)                           \
-       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt,  \
-                      ##args)
-#define DRM_DEBUG_KMS(fmt, ...)                                        \
-       drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__)
+#define DRM_DEV_DEBUG_KMS(dev, fmt, ...)                               \
+       drm_dev_dbg(dev, DRM_UT_KMS, fmt, ##__VA_ARGS__)
+#define DRM_DEBUG_KMS(fmt, ...)                                                \
+       drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__)
 
-#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...)                         \
-       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "",     \
-                      fmt, ##args)
+#define DRM_DEV_DEBUG_PRIME(dev, fmt, ...)                             \
+       drm_dev_dbg(dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
 #define DRM_DEBUG_PRIME(fmt, ...)                                      \
-       drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
+       drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__)
 
-#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...)                                \
-       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "",    \
-                      fmt, ##args)
+#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, ...)                            \
+       drm_dev_dbg(dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
 #define DRM_DEBUG_ATOMIC(fmt, ...)                                     \
-       drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
+       drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
 
-#define DRM_DEV_DEBUG_VBL(dev, fmt, args...)                           \
-       drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt,  \
-                      ##args)
-#define DRM_DEBUG_VBL(fmt, ...)                                        \
-       drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__)
+#define DRM_DEV_DEBUG_VBL(dev, fmt, ...)                               \
+       drm_dev_dbg(dev, DRM_UT_VBL, fmt, ##__VA_ARGS__)
+#define DRM_DEBUG_VBL(fmt, ...)                                                \
+       drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__)
 
 #define DRM_DEBUG_LEASE(fmt, ...)                                      \
-       drm_printk(KERN_DEBUG, DRM_UT_LEASE, fmt, ##__VA_ARGS__)
+       drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__)
 
-#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...)    \
+#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...)     \
 ({                                                                     \
        static DEFINE_RATELIMIT_STATE(_rs,                              \
                                      DEFAULT_RATELIMIT_INTERVAL,       \
                                      DEFAULT_RATELIMIT_BURST);         \
        if (__ratelimit(&_rs))                                          \
-               drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ ## level,       \
-                              __func__, "", fmt, ##args);              \
+               drm_dev_dbg(dev, category, fmt, ##__VA_ARGS__);         \
 })
 
 /**
@@ -330,21 +322,28 @@ void drm_printk(const char *level, unsigned int category,
  * @dev: device pointer
  * @fmt: printf() like format string.
  */
-#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, args...)                   \
-       DEV__DRM_DEFINE_DEBUG_RATELIMITED(dev, CORE, fmt, ##args)
-#define DRM_DEBUG_RATELIMITED(fmt, args...)                            \
-       DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##args)
-#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, args...)            \
-       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRIVER, fmt, ##args)
-#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, args...)                     \
-       DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##args)
-#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, args...)               \
-       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, KMS, fmt, ##args)
-#define DRM_DEBUG_KMS_RATELIMITED(fmt, args...)                                \
-       DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##args)
-#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, args...)             \
-       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, PRIME, fmt, ##args)
-#define DRM_DEBUG_PRIME_RATELIMITED(fmt, args...)                      \
-       DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##args)
+#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, ...)                       \
+       _DEV_DRM_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_CORE,             \
+                                         fmt, ##__VA_ARGS__)
+#define DRM_DEBUG_RATELIMITED(fmt, ...)                                        \
+       DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, ...)                        \
+       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_DRIVER,           \
+                                         fmt, ##__VA_ARGS__)
+#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, ...)                         \
+       DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, ...)                   \
+       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_KMS,              \
+                                         fmt, ##__VA_ARGS__)
+#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...)                            \
+       DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
+
+#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, ...)                 \
+       _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME,            \
+                                         fmt, ##__VA_ARGS__)
+#define DRM_DEBUG_PRIME_RATELIMITED(fmt, ...)                          \
+       DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
 
 #endif /* DRM_PRINT_H_ */
index 937757a8a5687a6453d4c36cbb208119c2ce0dad..d1423c7f3c73e4248aa5c845f4f3f5fbb119ebde 100644 (file)
@@ -209,7 +209,7 @@ struct drm_property_blob {
        struct list_head head_global;
        struct list_head head_file;
        size_t length;
-       unsigned char data[];
+       void *data;
 };
 
 struct drm_prop_enum_list {
index 024a1beda008c69d21bd65fe8d1a36cc92a6021a..ae42289662df9de4df880fc3db4b2038aa840220 100644 (file)
@@ -1147,6 +1147,8 @@ void pci_pme_wakeup_bus(struct pci_bus *bus);
 void pci_d3cold_enable(struct pci_dev *dev);
 void pci_d3cold_disable(struct pci_dev *dev);
 bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
+void pci_wakeup_bus(struct pci_bus *bus);
+void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
 
 /* PCI Virtual Channel */
 int pci_save_vc_state(struct pci_dev *dev);
index a6b30667a33147ed6f6cc9c648e013cfc3126189..a637a7d8ce5b9ec533ca95b2e509e9794022a903 100644 (file)
@@ -45,6 +45,7 @@
 #define PCI_CLASS_MULTIMEDIA_VIDEO     0x0400
 #define PCI_CLASS_MULTIMEDIA_AUDIO     0x0401
 #define PCI_CLASS_MULTIMEDIA_PHONE     0x0402
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
 #define PCI_CLASS_MULTIMEDIA_OTHER     0x0480
 
 #define PCI_BASE_CLASS_MEMORY          0x05
index 960bedbdec87b3e4586f487d57223dccc8b8a4fd..77f0f0af3a7105c2e6e400be65cb23da3d1a2019 100644 (file)
@@ -168,11 +168,8 @@ int vga_switcheroo_process_delayed_switch(void);
 bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev);
 enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev);
 
-void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic);
-
 int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain);
 void vga_switcheroo_fini_domain_pm_ops(struct device *dev);
-int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain);
 #else
 
 static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
@@ -192,11 +189,8 @@ static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
 static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; }
 static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
 
-static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}
-
 static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
 static inline void vga_switcheroo_fini_domain_pm_ops(struct device *dev) {}
-static inline int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
 
 #endif
 #endif /* _LINUX_VGA_SWITCHEROO_H_ */
index 68169e3749de164c140902413dc517e18c006c53..5b2ed12f58cecfaa4215404752c1288aa3afc1fa 100644 (file)
@@ -227,9 +227,6 @@ struct hdac_io_ops {
 #define HDA_UNSOL_QUEUE_SIZE   64
 #define HDA_MAX_CODECS         8       /* limit by controller side */
 
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
-
 /*
  * CORB/RIRB
  *
index 91fceb8f1fa28a65f5acea5b2a347cf6db4a8225..ceb71ea7f61c7428391f44ac989c14c808051a54 100644 (file)
@@ -16,12 +16,6 @@ expression object;
 @@
 
 (
-- drm_mode_object_reference(object)
-+ drm_mode_object_get(object)
-|
-- drm_mode_object_unreference(object)
-+ drm_mode_object_put(object)
-|
 - drm_connector_reference(object)
 + drm_connector_get(object)
 |
@@ -62,10 +56,6 @@ position p;
 @@
 
 (
-drm_mode_object_unreference@p(object)
-|
-drm_mode_object_reference@p(object)
-|
 drm_connector_unreference@p(object)
 |
 drm_connector_reference@p(object)
index c71dcacea807bf0e0d11aa147401acd12280686c..ec4e6b829ee279b9926ed6aa731ac67a7a7d03ca 100644 (file)
@@ -1227,6 +1227,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
        struct snd_card *card = pci_get_drvdata(pci);
        struct azx *chip = card->private_data;
        struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+       struct hda_codec *codec;
        bool disabled;
 
        wait_for_completion(&hda->probe_wait);
@@ -1251,8 +1252,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
                dev_info(chip->card->dev, "%s via vga_switcheroo\n",
                         disabled ? "Disabling" : "Enabling");
                if (disabled) {
-                       pm_runtime_put_sync_suspend(card->dev);
-                       azx_suspend(card->dev);
+                       list_for_each_codec(codec, &chip->bus) {
+                               pm_runtime_suspend(hda_codec_dev(codec));
+                               pm_runtime_disable(hda_codec_dev(codec));
+                       }
+                       pm_runtime_suspend(card->dev);
+                       pm_runtime_disable(card->dev);
                        /* when we get suspended by vga_switcheroo we end up in D3cold,
                         * however we have no ACPI handle, so pci/acpi can't put us there,
                         * put ourselves there */
@@ -1263,9 +1268,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
                                         "Cannot lock devices!\n");
                } else {
                        snd_hda_unlock_devices(&chip->bus);
-                       pm_runtime_get_noresume(card->dev);
                        chip->disabled = false;
-                       azx_resume(card->dev);
+                       pm_runtime_enable(card->dev);
+                       list_for_each_codec(codec, &chip->bus) {
+                               pm_runtime_enable(hda_codec_dev(codec));
+                               pm_runtime_resume(hda_codec_dev(codec));
+                       }
                }
        }
 }
@@ -1295,6 +1303,7 @@ static void init_vga_switcheroo(struct azx *chip)
                dev_info(chip->card->dev,
                         "Handle vga_switcheroo audio client\n");
                hda->use_vga_switcheroo = 1;
+               chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
                pci_dev_put(p);
        }
 }
@@ -1320,9 +1329,6 @@ static int register_vga_switcheroo(struct azx *chip)
                return err;
        hda->vga_switcheroo_registered = 1;
 
-       /* register as an optimus hdmi audio power domain */
-       vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev,
-                                                        &hda->hdmi_pm_domain);
        return 0;
 }
 #else
@@ -1351,10 +1357,8 @@ static int azx_free(struct azx *chip)
        if (use_vga_switcheroo(hda)) {
                if (chip->disabled && hda->probe_continued)
                        snd_hda_unlock_devices(&chip->bus);
-               if (hda->vga_switcheroo_registered) {
+               if (hda->vga_switcheroo_registered)
                        vga_switcheroo_unregister_client(chip->pci);
-                       vga_switcheroo_fini_domain_pm_ops(chip->card->dev);
-               }
        }
 
        if (bus->chip_init) {
@@ -2197,6 +2201,7 @@ static int azx_probe_continue(struct azx *chip)
        struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
        struct hdac_bus *bus = azx_bus(chip);
        struct pci_dev *pci = chip->pci;
+       struct hda_codec *codec;
        int dev = chip->dev_index;
        int err;
 
@@ -2278,8 +2283,17 @@ static int azx_probe_continue(struct azx *chip)
 
        chip->running = 1;
        azx_add_card_list(chip);
+
+       /*
+        * The discrete GPU cannot power down unless the HDA controller runtime
+        * suspends, so activate runtime PM on codecs even if power_save == 0.
+        */
+       if (use_vga_switcheroo(hda))
+               list_for_each_codec(codec, &chip->bus)
+                       codec->auto_runtime_pm = 1;
+
        snd_hda_set_power_save(&chip->bus, power_save * 1000);
-       if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
+       if (azx_has_pm_runtime(chip))
                pm_runtime_put_autosuspend(&pci->dev);
 
 out_free:
index ff0c4d617bc1dbba882b8e1c09d208a71be84bf3..e3a3d318d2e5f9fc57dbe9530a2470ab955b1765 100644 (file)
@@ -40,9 +40,6 @@ struct hda_intel {
        unsigned int vga_switcheroo_registered:1;
        unsigned int init_failed:1; /* delayed init failed */
 
-       /* secondary power domain for hdmi audio under vga device */
-       struct dev_pm_domain hdmi_pm_domain;
-
        bool need_i915_power:1; /* the hda controller needs i915 power */
 };