Merge drm/drm-next into drm-misc-next
authorMaxime Ripard <maxime@cerno.tech>
Wed, 14 Sep 2022 11:22:18 +0000 (12:22 +0100)
committerMaxime Ripard <maxime@cerno.tech>
Wed, 14 Sep 2022 11:22:18 +0000 (12:22 +0100)
We need 6.0-rc1 to merge the backlight rework PR.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
46 files changed:
Documentation/devicetree/bindings/display/bridge/chrontel,ch7033.yaml
Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
drivers/gpu/drm/amd/pm/powerplay/inc/hardwaremanager.h
drivers/gpu/drm/bridge/ite-it6505.c
drivers/gpu/drm/bridge/ti-sn65dsi86.c
drivers/gpu/drm/display/drm_scdc_helper.c
drivers/gpu/drm/drm_aperture.c
drivers/gpu/drm/drm_damage_helper.c
drivers/gpu/drm/drm_format_helper.c
drivers/gpu/drm/drm_mipi_dbi.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/omapdrm/dss/dispc.c
drivers/gpu/drm/omapdrm/dss/dss.c
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
drivers/gpu/drm/panel/panel-ilitek-ili9341.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/tests/drm_damage_helper_test.c
drivers/gpu/drm/tests/drm_format_test.c
drivers/gpu/drm/tidss/tidss_kms.c
drivers/gpu/drm/tiny/hx8357d.c
drivers/gpu/drm/tiny/ili9163.c
drivers/gpu/drm/tiny/ili9341.c
drivers/gpu/drm/tiny/ili9486.c
drivers/gpu/drm/tiny/mi0283qt.c
drivers/gpu/drm/tiny/panel-mipi-dbi.c
drivers/gpu/drm/tiny/repaper.c
drivers/gpu/drm/tiny/simpledrm.c
drivers/gpu/drm/tiny/st7735r.c
drivers/gpu/drm/udl/udl_drv.c
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/udl/udl_modeset.c
drivers/gpu/drm/udl/udl_transfer.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.h
drivers/gpu/drm/vkms/vkms_plane.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
include/drm/drm_format_helper.h
include/drm/drm_mipi_dbi.h
include/drm/drm_modes.h
include/drm/drm_probe_helper.h

index 984b90893583bcfbbc416ce0c914b89f50eeaed9..bb6289c7d375e79928edcc1f8d649f9849754919 100644 (file)
@@ -14,19 +14,6 @@ properties:
   compatible:
     const: chrontel,ch7033
 
-  chrontel,byteswap:
-    $ref: /schemas/types.yaml#/definitions/uint8
-    enum:
-      - 0  # BYTE_SWAP_RGB
-      - 1  # BYTE_SWAP_RBG
-      - 2  # BYTE_SWAP_GRB
-      - 3  # BYTE_SWAP_GBR
-      - 4  # BYTE_SWAP_BRG
-      - 5  # BYTE_SWAP_BGR
-    description: |
-      Set the byteswap value of the bridge. This is optional and if not
-      set value of BYTE_SWAP_BGR is used.
-
   reg:
     maxItems: 1
     description: I2C address of the device
index 39792f051d2dde108777f670760217d676cbd61d..9a223df8530c04286a6c12dd4339b022c8384479 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
        "rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi"
        "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi"
        "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi"
+       "rockchip,rk3568-mipi-dsi", "snps,dw-mipi-dsi"
 - reg: Represent the physical address range of the controller.
 - interrupts: Represent the controller's interrupt to the CPU(s).
 - clocks, clock-names: Phandles to the controller's pll reference
index 6e0be602770579542e2db1fd3f11492287bee76a..01a7d66864f227c524edd251d87fbdd8216c3d52 100644 (file)
@@ -401,8 +401,6 @@ extern int phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
 extern int phm_setup_asic(struct pp_hwmgr *hwmgr);
 extern int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr);
 extern int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr);
-extern bool phm_is_hw_access_blocked(struct pp_hwmgr *hwmgr);
-extern int phm_block_hw_access(struct pp_hwmgr *hwmgr, bool block);
 extern int phm_set_power_state(struct pp_hwmgr *hwmgr,
                    const struct pp_hw_power_state *pcurrent_state,
                 const struct pp_hw_power_state *pnew_power_state);
index 2bb957cffd9424d110d68ed4334e66e0274cc9bf..2767b70fa2cb874efa50ca5073f171c1dd705f7d 100644 (file)
@@ -563,7 +563,7 @@ static void it6505_debug_print(struct it6505 *it6505, unsigned int reg,
        struct device *dev = &it6505->client->dev;
        int val;
 
-       if (likely(!(__drm_debug & DRM_UT_DRIVER)))
+       if (!drm_debug_enabled(DRM_UT_DRIVER))
                return;
 
        val = it6505_read(it6505, reg);
index 3c3561942eb661e807cc59013d63bf91b7f28443..6e053e2af229916c21ae15c7e215948fcd326694 100644 (file)
@@ -29,7 +29,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge_connector.h>
-#include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
@@ -69,7 +68,6 @@
 #define  BPP_18_RGB                            BIT(0)
 #define SN_HPD_DISABLE_REG                     0x5C
 #define  HPD_DISABLE                           BIT(0)
-#define  HPD_DEBOUNCED_STATE                   BIT(4)
 #define SN_GPIO_IO_REG                         0x5E
 #define  SN_GPIO_INPUT_SHIFT                   4
 #define  SN_GPIO_OUTPUT_SHIFT                  0
@@ -1160,33 +1158,10 @@ static void ti_sn_bridge_atomic_post_disable(struct drm_bridge *bridge,
        pm_runtime_put_sync(pdata->dev);
 }
 
-static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge)
-{
-       struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
-       int val = 0;
-
-       pm_runtime_get_sync(pdata->dev);
-       regmap_read(pdata->regmap, SN_HPD_DISABLE_REG, &val);
-       pm_runtime_put_autosuspend(pdata->dev);
-
-       return val & HPD_DEBOUNCED_STATE ? connector_status_connected
-                                        : connector_status_disconnected;
-}
-
-static struct edid *ti_sn_bridge_get_edid(struct drm_bridge *bridge,
-                                         struct drm_connector *connector)
-{
-       struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
-
-       return drm_get_edid(connector, &pdata->aux.ddc);
-}
-
 static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
        .attach = ti_sn_bridge_attach,
        .detach = ti_sn_bridge_detach,
        .mode_valid = ti_sn_bridge_mode_valid,
-       .get_edid = ti_sn_bridge_get_edid,
-       .detect = ti_sn_bridge_detect,
        .atomic_pre_enable = ti_sn_bridge_atomic_pre_enable,
        .atomic_enable = ti_sn_bridge_atomic_enable,
        .atomic_disable = ti_sn_bridge_atomic_disable,
@@ -1282,9 +1257,6 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
        pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort
                           ? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP;
 
-       if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort)
-               pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
-
        drm_bridge_add(&pdata->bridge);
 
        ret = ti_sn_attach_host(pdata);
index 81881e81ceae09c76a093d022545aa76373f8052..c3ad4ab2b45696d70642f3dfc10fe8ffd1f8c3b5 100644 (file)
  * HDMI 2.0 specification. It is a point-to-point protocol that allows the
  * HDMI source and HDMI sink to exchange data. The same I2C interface that
  * is used to access EDID serves as the transport mechanism for SCDC.
+ *
+ * Note: The SCDC status is going to be lost when the display is
+ * disconnected. This can happen physically when the user disconnects
+ * the cable, but also when a display is switched on (such as waking up
+ * a TV).
+ *
+ * This is further complicated by the fact that, upon a disconnection /
+ * reconnection, KMS won't change the mode on its own. This means that
+ * one can't just rely on setting the SCDC status on enable, but also
+ * has to track the connector status changes using interrupts and
+ * restore the SCDC status. The typical solution for this is to trigger an
+ * empty modeset in drm_connector_helper_funcs.detect_ctx(), like what vc4 does
+ * in vc4_hdmi_reset_link().
  */
 
 #define SCDC_I2C_SLAVE_ADDRESS 0x54
index fdb7d5c17ba155f89f1f5ad8b639265e6899206f..3b8fdeeafd53a7696796f6737d84231cc413603a 100644 (file)
@@ -74,7 +74,7 @@
  * given framebuffer memory. Ownership of the framebuffer memory is achieved
  * by calling devm_aperture_acquire_from_firmware(). On success, the driver
  * is the owner of the framebuffer range. The function fails if the
- * framebuffer is already by another driver. See below for an example.
+ * framebuffer is already owned by another driver. See below for an example.
  *
  * .. code-block:: c
  *
  *
  * The generic driver is now subject to forced removal by other drivers. This
  * only works for platform drivers that support hot unplug.
- * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al
+ * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al.
  * for the registered framebuffer range, the aperture helpers call
  * platform_device_unregister() and the generic driver unloads itself. It
  * may not access the device's registers, framebuffer memory, ROM, etc
@@ -164,7 +164,7 @@ EXPORT_SYMBOL(devm_aperture_acquire_from_firmware);
  * @primary: also kick vga16fb if present
  * @req_driver: requesting DRM driver
  *
- * This function removes graphics device drivers which use memory range described by
+ * This function removes graphics device drivers which use the memory range described by
  * @base and @size.
  *
  * Returns:
@@ -182,8 +182,8 @@ EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers);
  * @pdev: PCI device
  * @req_driver: requesting DRM driver
  *
- * This function removes graphics device drivers using memory range configured
- * for any of @pdev's memory bars. The function assumes that PCI device with
+ * This function removes graphics device drivers using the memory range configured
+ * for any of @pdev's memory bars. The function assumes that PCI device with
  * shadowed ROM drives a primary display and so kicks out vga16fb.
  *
  * Returns:
index 937b699ac2a8f601c08e66308bcc12e69bb55d28..d8b2955e88fd0a606c37e74ed454f4a27874a26d 100644 (file)
@@ -224,6 +224,7 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
                                   const struct drm_plane_state *old_state,
                                   const struct drm_plane_state *state)
 {
+       struct drm_rect src;
        memset(iter, 0, sizeof(*iter));
 
        if (!state || !state->crtc || !state->fb || !state->visible)
@@ -233,10 +234,12 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
        iter->num_clips = drm_plane_get_damage_clips_count(state);
 
        /* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
-       iter->plane_src.x1 = state->src.x1 >> 16;
-       iter->plane_src.y1 = state->src.y1 >> 16;
-       iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
-       iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
+       src = drm_plane_state_src(state);
+
+       iter->plane_src.x1 = src.x1 >> 16;
+       iter->plane_src.y1 = src.y1 >> 16;
+       iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF);
+       iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF);
 
        if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
                iter->clips = NULL;
index 56642816fdff0d998cf6ff814a099dad0a064e3a..4afc4ac27342f06351a4d1395552e6c2c5c5a1a8 100644 (file)
@@ -793,3 +793,111 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
        kfree(src32);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
+
+static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
+{
+       const uint32_t *fourccs_end = fourccs + nfourccs;
+
+       while (fourccs < fourccs_end) {
+               if (*fourccs == fourcc)
+                       return true;
+               ++fourccs;
+       }
+       return false;
+}
+
+/**
+ * drm_fb_build_fourcc_list - Filters a list of supported color formats against
+ *                            the device's native formats
+ * @dev: DRM device
+ * @native_fourccs: 4CC codes of natively supported color formats
+ * @native_nfourccs: The number of entries in @native_fourccs
+ * @driver_fourccs: 4CC codes of all driver-supported color formats
+ * @driver_nfourccs: The number of entries in @driver_fourccs
+ * @fourccs_out: Returns 4CC codes of supported color formats
+ * @nfourccs_out: The number of available entries in @fourccs_out
+ *
+ * This function create a list of supported color format from natively
+ * supported formats and the emulated formats.
+ * At a minimum, most userspace programs expect at least support for
+ * XRGB8888 on the primary plane. Devices that have to emulate the
+ * format, and possibly others, can use drm_fb_build_fourcc_list() to
+ * create a list of supported color formats. The returned list can
+ * be handed over to drm_universal_plane_init() et al. Native formats
+ * will go before emulated formats. Other heuristics might be applied
+ * to optimize the order. Formats near the beginning of the list are
+ * usually preferred over formats near the end of the list.
+ *
+ * Returns:
+ * The number of color-formats 4CC codes returned in @fourccs_out.
+ */
+size_t drm_fb_build_fourcc_list(struct drm_device *dev,
+                               const u32 *native_fourccs, size_t native_nfourccs,
+                               const u32 *driver_fourccs, size_t driver_nfourccs,
+                               u32 *fourccs_out, size_t nfourccs_out)
+{
+       u32 *fourccs = fourccs_out;
+       const u32 *fourccs_end = fourccs_out + nfourccs_out;
+       bool found_native = false;
+       size_t i;
+
+       /*
+        * The device's native formats go first.
+        */
+
+       for (i = 0; i < native_nfourccs; ++i) {
+               u32 fourcc = native_fourccs[i];
+
+               if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
+                       continue; /* skip duplicate entries */
+               } else if (fourccs == fourccs_end) {
+                       drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);
+                       continue; /* end of available output buffer */
+               }
+
+               drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
+
+               if (!found_native)
+                       found_native = is_listed_fourcc(driver_fourccs, driver_nfourccs, fourcc);
+               *fourccs = fourcc;
+               ++fourccs;
+       }
+
+       /*
+        * The plane's atomic_update helper converts the framebuffer's color format
+        * to a native format when copying to device memory.
+        *
+        * If there is not a single format supported by both, device and
+        * driver, the native formats are likely not supported by the conversion
+        * helpers. Therefore *only* support the native formats and add a
+        * conversion helper ASAP.
+        */
+       if (!found_native) {
+               drm_warn(dev, "Format conversion helpers required to add extra formats.\n");
+               goto out;
+       }
+
+       /*
+        * The extra formats, emulated by the driver, go second.
+        */
+
+       for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) {
+               u32 fourcc = driver_fourccs[i];
+
+               if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
+                       continue; /* skip duplicate and native entries */
+               } else if (fourccs == fourccs_end) {
+                       drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
+                       continue; /* end of available output buffer */
+               }
+
+               drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
+
+               *fourccs = fourcc;
+               ++fourccs;
+       }
+
+out:
+       return fourccs - fourccs_out;
+}
+EXPORT_SYMBOL(drm_fb_build_fourcc_list);
index 84abc3920b5730c67143decb6fc1c1a5e29f44e0..a6ac565808765cf3fb330fc7fa3f724c0e55e646 100644 (file)
@@ -309,6 +309,24 @@ err_drm_dev_exit:
        drm_dev_exit(idx);
 }
 
+/**
+ * mipi_dbi_pipe_mode_valid - MIPI DBI mode-valid helper
+ * @pipe: Simple display pipe
+ * @mode: The mode to test
+ *
+ * This function validates a given display mode against the MIPI DBI's hardware
+ * display. Drivers can use this as their &drm_simple_display_pipe_funcs->mode_valid
+ * callback.
+ */
+enum drm_mode_status mipi_dbi_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+                                             const struct drm_display_mode *mode)
+{
+       struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
+
+       return drm_crtc_helper_mode_valid_fixed(&pipe->crtc, mode, &dbidev->mode);
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_mode_valid);
+
 /**
  * mipi_dbi_pipe_update - Display pipe update helper
  * @pipe: Simple display pipe
@@ -415,26 +433,8 @@ EXPORT_SYMBOL(mipi_dbi_pipe_disable);
 static int mipi_dbi_connector_get_modes(struct drm_connector *connector)
 {
        struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(connector->dev);
-       struct drm_display_mode *mode;
-
-       mode = drm_mode_duplicate(connector->dev, &dbidev->mode);
-       if (!mode) {
-               DRM_ERROR("Failed to duplicate mode\n");
-               return 0;
-       }
-
-       if (mode->name[0] == '\0')
-               drm_mode_set_name(mode);
-
-       mode->type |= DRM_MODE_TYPE_PREFERRED;
-       drm_mode_probed_add(connector, mode);
-
-       if (mode->width_mm) {
-               connector->display_info.width_mm = mode->width_mm;
-               connector->display_info.height_mm = mode->height_mm;
-       }
 
-       return 1;
+       return drm_connector_helper_get_modes_fixed(connector, &dbidev->mode);
 }
 
 static const struct drm_connector_helper_funcs mipi_dbi_connector_hfuncs = {
index bb427c5a4f1f3173924a02cf5e156365119f145d..69b0b2b9cc1c52b5299f8d758b9a970be8212b21 100644 (file)
@@ -1014,6 +1014,30 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_helper_hpd_irq_event);
 
+/**
+ * drm_crtc_helper_mode_valid_fixed - Validates a display mode
+ * @crtc: the crtc
+ * @mode: the mode to validate
+ * @fixed_mode: the display hardware's mode
+ *
+ * Returns:
+ * MODE_OK on success, or another mode-status code otherwise.
+ */
+enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,
+                                                     const struct drm_display_mode *mode,
+                                                     const struct drm_display_mode *fixed_mode)
+{
+       if (mode->hdisplay != fixed_mode->hdisplay && mode->vdisplay != fixed_mode->vdisplay)
+               return MODE_ONE_SIZE;
+       else if (mode->hdisplay != fixed_mode->hdisplay)
+               return MODE_ONE_WIDTH;
+       else if (mode->vdisplay != fixed_mode->vdisplay)
+               return MODE_ONE_HEIGHT;
+
+       return MODE_OK;
+}
+EXPORT_SYMBOL(drm_crtc_helper_mode_valid_fixed);
+
 /**
  * drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID
  *                                           property from the connector's
@@ -1050,6 +1074,46 @@ int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc);
 
+/**
+ * drm_connector_helper_get_modes_fixed - Duplicates a display mode for a connector
+ * @connector: the connector
+ * @fixed_mode: the display hardware's mode
+ *
+ * This function duplicates a display modes for a connector. Drivers for hardware
+ * that only supports a single fixed mode can use this function in their connector's
+ * get_modes helper.
+ *
+ * Returns:
+ * The number of created modes.
+ */
+int drm_connector_helper_get_modes_fixed(struct drm_connector *connector,
+                                        const struct drm_display_mode *fixed_mode)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(dev, fixed_mode);
+       if (!mode) {
+               drm_err(dev, "Failed to duplicate mode " DRM_MODE_FMT "\n",
+                       DRM_MODE_ARG(fixed_mode));
+               return 0;
+       }
+
+       if (mode->name[0] == '\0')
+               drm_mode_set_name(mode);
+
+       mode->type |= DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(connector, mode);
+
+       if (mode->width_mm)
+               connector->display_info.width_mm = mode->width_mm;
+       if (mode->height_mm)
+               connector->display_info.height_mm = mode->height_mm;
+
+       return 1;
+}
+EXPORT_SYMBOL(drm_connector_helper_get_modes_fixed);
+
 /**
  * drm_connector_helper_get_modes - Read EDID and update connector.
  * @connector: The connector
index 8ccba116821b54d0e76aff66882749a3e9f4f898..8a1111fe714b5a40afa4fa0ab27d074f38bcbb3a 100644 (file)
@@ -197,8 +197,6 @@ extern void psb_intel_lvds_set_brightness(struct drm_device *dev, int level);
 extern void oaktrail_lvds_init(struct drm_device *dev,
                           struct psb_intel_mode_device *mode_dev);
 extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev);
-extern void oaktrail_dsi_init(struct drm_device *dev,
-                          struct psb_intel_mode_device *mode_dev);
 struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev);
 extern void mid_dsi_init(struct drm_device *dev,
                    struct psb_intel_mode_device *mode_dev, int dsi_num);
@@ -219,9 +217,6 @@ extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev,
                                                 int pipe);
 extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev,
                                             int sdvoB);
-extern int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector);
-extern void psb_intel_sdvo_set_hotplug(struct drm_connector *connector,
-                                  int enable);
 extern int intelfb_probe(struct drm_device *dev);
 extern int intelfb_remove(struct drm_device *dev,
                          struct drm_framebuffer *fb);
index c4de142cc85bf343626a183b8dc2aeb572ae28da..0ee344ebcd1cd14d9b33b723710262d7c1a281a6 100644 (file)
@@ -2451,7 +2451,7 @@ static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc,
 
        *decim_x = DIV_ROUND_UP(width, in_width_max);
 
-       *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
+       *decim_x = max(*decim_x, decim_x_min);
        if (*decim_x > *x_predecim)
                return -EINVAL;
 
index 0399f3390a0ad6299bbf407b96bb83535ca790e8..c4febb8619103721c3aad7787f7aa79bece2a751 100644 (file)
@@ -1176,6 +1176,7 @@ static void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports)
                default:
                        break;
                }
+               of_node_put(port);
        }
 }
 
@@ -1208,11 +1209,13 @@ static int dss_init_ports(struct dss_device *dss)
                default:
                        break;
                }
+               of_node_put(port);
        }
 
        return 0;
 
 error:
+       of_node_put(port);
        __dss_uninit_ports(dss, i);
        return r;
 }
index ac869acf80eac5afdd5468781d5ddce010d1449c..61a27dd7392eaf49887c0fb063b7db9b025ac4b3 100644 (file)
@@ -813,10 +813,8 @@ static int omap_dmm_probe(struct platform_device *dev)
        }
 
        omap_dmm->irq = platform_get_irq(dev, 0);
-       if (omap_dmm->irq < 0) {
-               dev_err(&dev->dev, "failed to get IRQ resource\n");
+       if (omap_dmm->irq < 0)
                goto fail;
-       }
 
        omap_dmm->dev = &dev->dev;
 
index 7da09e34385d3d73231fdcc570cb3ce95b4f12cb..39dc40cf681f015abaea9158348c2c839b990605 100644 (file)
@@ -576,6 +576,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs ili9341_dbi_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = ili9341_dbi_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index 8be4799a98eff701e4f378423b66e1055c31db9a..638f861af80fa1866bf20454e0f630f8e9e1ae24 100644 (file)
@@ -34,8 +34,6 @@
 #include "r600_reg_safe.h"
 
 static int r600_nomm;
-extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size);
-
 
 struct r600_cs_track {
        /* configuration we mirror so that we use same code btw kms/ums */
index 08f83bf2c33073ff37bfbe2290b2604bc0a5d2a7..166c18d62f6d7dd66139e109da0cdd274cceb4ef 100644 (file)
@@ -116,7 +116,6 @@ extern int radeon_use_pflipirq;
 extern int radeon_bapm;
 extern int radeon_backlight;
 extern int radeon_auxch;
-extern int radeon_mst;
 extern int radeon_uvd;
 extern int radeon_vce;
 extern int radeon_si_support;
@@ -2950,8 +2949,6 @@ struct radeon_hdmi_acr {
 
 };
 
-extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock);
-
 extern u32 r6xx_remap_render_backend(struct radeon_device *rdev,
                                     u32 tiling_pipe_num,
                                     u32 max_rb_num,
index 6a6a7320422628f4ca27a07457a6dce53d464c79..9f5be416454faa380a4cec1033e6cc368011ca4a 100644 (file)
@@ -874,7 +874,6 @@ extern struct radeon_encoder_tv_dac *
 radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder);
 extern struct radeon_encoder_lvds *
 radeon_combios_get_lvds_info(struct radeon_encoder *encoder);
-extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder);
 extern struct radeon_encoder_tv_dac *
 radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder);
 extern struct radeon_encoder_primary_dac *
index 110e83aad9bb440b5d4b81479839b5982a9fd843..bf6948125b8415082b9698ebf44ecedca2496b2a 100644 (file)
 #define RK3399_TXRX_SRC_SEL_ISP0       BIT(4)
 #define RK3399_TXRX_TURNREQUEST                GENMASK(3, 0)
 
+#define RK3568_GRF_VO_CON2             0x0368
+#define RK3568_DSI0_SKEWCALHS          (0x1f << 11)
+#define RK3568_DSI0_FORCETXSTOPMODE    (0xf << 4)
+#define RK3568_DSI0_TURNDISABLE                BIT(2)
+#define RK3568_DSI0_FORCERXMODE                BIT(0)
+
+/*
+ * Note these registers do not appear in the datasheet, they are
+ * however present in the BSP driver which is where these values
+ * come from. Name GRF_VO_CON3 is assumed.
+ */
+#define RK3568_GRF_VO_CON3             0x36c
+#define RK3568_DSI1_SKEWCALHS          (0x1f << 11)
+#define RK3568_DSI1_FORCETXSTOPMODE    (0xf << 4)
+#define RK3568_DSI1_TURNDISABLE                BIT(2)
+#define RK3568_DSI1_FORCERXMODE                BIT(0)
+
 #define HIWORD_UPDATE(val, mask)       (val | (mask) << 16)
 
 enum {
@@ -735,8 +752,9 @@ static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi)
 static void dw_mipi_dsi_rockchip_set_lcdsel(struct dw_mipi_dsi_rockchip *dsi,
                                            int mux)
 {
-       regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
-               mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+       if (dsi->cdata->lcdsel_grf_reg < 0)
+               regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+                       mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
 }
 
 static int
@@ -963,6 +981,8 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
                DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
                goto out_pll_clk;
        }
+       rockchip_drm_encoder_set_crtc_endpoint_id(&dsi->encoder,
+                                                 dev->of_node, 0, 0);
 
        ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder.encoder);
        if (ret) {
@@ -1612,6 +1632,30 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
        { /* sentinel */ }
 };
 
+static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
+       {
+               .reg = 0xfe060000,
+               .lcdsel_grf_reg = -1,
+               .lanecfg1_grf_reg = RK3568_GRF_VO_CON2,
+               .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI0_SKEWCALHS |
+                                         RK3568_DSI0_FORCETXSTOPMODE |
+                                         RK3568_DSI0_TURNDISABLE |
+                                         RK3568_DSI0_FORCERXMODE),
+               .max_data_lanes = 4,
+       },
+       {
+               .reg = 0xfe070000,
+               .lcdsel_grf_reg = -1,
+               .lanecfg1_grf_reg = RK3568_GRF_VO_CON3,
+               .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI1_SKEWCALHS |
+                                         RK3568_DSI1_FORCETXSTOPMODE |
+                                         RK3568_DSI1_TURNDISABLE |
+                                         RK3568_DSI1_FORCERXMODE),
+               .max_data_lanes = 4,
+       },
+       { /* sentinel */ }
+};
+
 static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
        {
         .compatible = "rockchip,px30-mipi-dsi",
@@ -1622,6 +1666,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
        }, {
         .compatible = "rockchip,rk3399-mipi-dsi",
         .data = &rk3399_chip_data,
+       }, {
+        .compatible = "rockchip,rk3568-mipi-dsi",
+        .data = &rk3568_chip_data,
        },
        { /* sentinel */ }
 };
index bdd48f87d098e4d1b8d249bb7221f0cbe5d46bf2..fab710910997701c7eeb16e5f7b4fce0ce17b432 100644 (file)
@@ -1188,7 +1188,7 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
         *
         * Key points:
         *
-        * - DRM works in in kHz.
+        * - DRM works in kHz.
         * - Clock framework works in Hz.
         * - Rockchip's clock driver picks the clock rate that is the
         *   same _OR LOWER_ than the one requested.
index bf250bd08d7e180be69db252d3575b0d133680da..c608ae06f0e31f0beedf2560222e89194ad67594 100644 (file)
@@ -59,6 +59,11 @@ static int drm_damage_helper_init(struct kunit *test)
 static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
                          int y2)
 {
+       state->src_x = x1;
+       state->src_y = y1;
+       state->src_w = x2 - x1;
+       state->src_h = y2 - y1;
+
        state->src.x1 = x1;
        state->src.y1 = y1;
        state->src.x2 = x2;
index afb4bca72187971e748173279413ba3a5ed7e412..1936d2d59908707f680a7d8dbec1df3fff56ce2a 100644 (file)
 
 #include <drm/drm_fourcc.h>
 
-static void igt_check_drm_format_block_width(struct kunit *test)
+static void drm_format_block_width_invalid(struct kunit *test)
 {
        const struct drm_format_info *info = NULL;
 
-       /* Test invalid arguments */
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1));
-
-       /* Test 1 plane format */
-       info = drm_format_info(DRM_FORMAT_XRGB4444);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1));
-
-       /* Test 2 planes format */
-       info = drm_format_info(DRM_FORMAT_NV12);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0));
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 2));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1));
-
-       /* Test 3 planes format */
-       info = drm_format_info(DRM_FORMAT_YUV422);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0));
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 1));
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 2));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 3));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1));
-
-       /* Test a tiled format */
-       info = drm_format_info(DRM_FORMAT_X0L0);
-       KUNIT_EXPECT_TRUE(test, info);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+}
+
+static void drm_format_block_width_one_plane(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_two_plane(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_three_plane(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 3), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_tiled(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
        KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 2);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1));
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
 }
 
-static void igt_check_drm_format_block_height(struct kunit *test)
+static void drm_format_block_height_invalid(struct kunit *test)
 {
        const struct drm_format_info *info = NULL;
 
-       /* Test invalid arguments */
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1));
-
-       /* Test 1 plane format */
-       info = drm_format_info(DRM_FORMAT_XRGB4444);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1));
-
-       /* Test 2 planes format */
-       info = drm_format_info(DRM_FORMAT_NV12);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0));
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 2));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1));
-
-       /* Test 3 planes format */
-       info = drm_format_info(DRM_FORMAT_YUV422);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0));
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 1));
-       KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 2));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 3));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1));
-
-       /* Test a tiled format */
-       info = drm_format_info(DRM_FORMAT_X0L0);
-       KUNIT_EXPECT_TRUE(test, info);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+}
+
+static void drm_format_block_height_one_plane(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+}
+
+static void drm_format_block_height_two_plane(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_three_plane(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 1);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 3), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_tiled(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
        KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 2);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1));
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
 }
 
-static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test)
+static void drm_format_min_pitch_invalid(struct kunit *test)
 {
        const struct drm_format_info *info = NULL;
 
-       /* Test invalid arguments */
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+}
+
+static void drm_format_min_pitch_one_plane_8bpp(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB332);
 
-       /* Test 1 plane 8 bits per pixel format */
-       info = drm_format_info(DRM_FORMAT_RGB332);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
@@ -118,13 +151,17 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test)
                        (uint64_t)UINT_MAX);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
                        (uint64_t)(UINT_MAX - 1));
+}
+
+static void drm_format_min_pitch_one_plane_16bpp(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
 
-       /* Test 1 plane 16 bits per pixel format */
-       info = drm_format_info(DRM_FORMAT_XRGB4444);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4);
@@ -137,13 +174,17 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test)
                        (uint64_t)UINT_MAX * 2);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
                        (uint64_t)(UINT_MAX - 1) * 2);
+}
+
+static void drm_format_min_pitch_one_plane_24bpp(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB888);
 
-       /* Test 1 plane 24 bits per pixel format */
-       info = drm_format_info(DRM_FORMAT_RGB888);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 3);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 6);
@@ -154,15 +195,19 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test)
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2013);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
                        (uint64_t)UINT_MAX * 3);
-       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
                        (uint64_t)(UINT_MAX - 1) * 3);
+}
 
-       /* Test 1 plane 32 bits per pixel format */
-       info = drm_format_info(DRM_FORMAT_ABGR8888);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
+static void drm_format_min_pitch_one_plane_32bpp(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_ABGR8888);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
+
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 4);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 8);
@@ -173,21 +218,20 @@ static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test)
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2684);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
                        (uint64_t)UINT_MAX * 4);
-       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
                        (uint64_t)(UINT_MAX - 1) * 4);
 }
 
-static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test)
+static void drm_format_min_pitch_two_plane(struct kunit *test)
 {
-       const struct drm_format_info *info = NULL;
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
 
-       /* Test 2 planes format */
-       info = drm_format_info(DRM_FORMAT_NV12);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 2, 0));
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2);
@@ -211,15 +255,19 @@ static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test)
                        (uint64_t)(UINT_MAX - 1));
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) /  2),
                        (uint64_t)(UINT_MAX - 1));
+}
+
+static void drm_format_min_pitch_three_plane_8bpp(struct kunit *test)
+{
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
 
-       /* Test 3 planes 8 bits per pixel format */
-       info = drm_format_info(DRM_FORMAT_YUV422);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 2, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 3, 0));
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 3, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 1);
@@ -256,16 +304,15 @@ static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test)
                        (uint64_t)(UINT_MAX - 1) / 2);
 }
 
-static void igt_check_drm_format_min_pitch_for_tiled_format(struct kunit *test)
+static void drm_format_min_pitch_tiled(struct kunit *test)
 {
-       const struct drm_format_info *info = NULL;
+       const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L2);
+
+       KUNIT_ASSERT_NOT_NULL(test, info);
 
-       /* Test tiled format */
-       info = drm_format_info(DRM_FORMAT_X0L2);
-       KUNIT_EXPECT_TRUE(test, info);
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0));
-       KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0));
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+       KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
 
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2);
        KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4);
@@ -281,12 +328,25 @@ static void igt_check_drm_format_min_pitch_for_tiled_format(struct kunit *test)
 }
 
 static struct kunit_case drm_format_tests[] = {
-       KUNIT_CASE(igt_check_drm_format_block_width),
-       KUNIT_CASE(igt_check_drm_format_block_height),
-       KUNIT_CASE(igt_check_drm_format_min_pitch_for_single_plane),
-       KUNIT_CASE(igt_check_drm_format_min_pitch_for_multi_planar),
-       KUNIT_CASE(igt_check_drm_format_min_pitch_for_tiled_format),
-       { }
+       KUNIT_CASE(drm_format_block_width_invalid),
+       KUNIT_CASE(drm_format_block_width_one_plane),
+       KUNIT_CASE(drm_format_block_width_two_plane),
+       KUNIT_CASE(drm_format_block_width_three_plane),
+       KUNIT_CASE(drm_format_block_width_tiled),
+       KUNIT_CASE(drm_format_block_height_invalid),
+       KUNIT_CASE(drm_format_block_height_one_plane),
+       KUNIT_CASE(drm_format_block_height_two_plane),
+       KUNIT_CASE(drm_format_block_height_three_plane),
+       KUNIT_CASE(drm_format_block_height_tiled),
+       KUNIT_CASE(drm_format_min_pitch_invalid),
+       KUNIT_CASE(drm_format_min_pitch_one_plane_8bpp),
+       KUNIT_CASE(drm_format_min_pitch_one_plane_16bpp),
+       KUNIT_CASE(drm_format_min_pitch_one_plane_24bpp),
+       KUNIT_CASE(drm_format_min_pitch_one_plane_32bpp),
+       KUNIT_CASE(drm_format_min_pitch_two_plane),
+       KUNIT_CASE(drm_format_min_pitch_three_plane_8bpp),
+       KUNIT_CASE(drm_format_min_pitch_tiled),
+       {}
 };
 
 static struct kunit_suite drm_format_test_suite = {
index b61db8f279e94bafa17a4c87f484980f7585be7b..afb2879980c6c8c252ddbc8e2b0c5c340448174d 100644 (file)
@@ -70,7 +70,7 @@ static int tidss_atomic_check(struct drm_device *ddev,
         * changes. This is needed for updating the plane positions in
         * tidss_crtc_position_planes() which is called from
         * crtc_atomic_enable() and crtc_atomic_flush(). We have an
-        * extra flag to to mark x,y-position changes and together
+        * extra flag to mark x,y-position changes and together
         * with zpos_changed the condition recognizes all the above
         * cases.
         */
index 57f229a785bf8abba4ec6eb277d6bfbc83c78856..48c24aa8c28a11fcfebb79b7ceff40f976ebb0bc 100644 (file)
@@ -181,6 +181,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = yx240qv29_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index 86439e50e304f7ffde79a9763cdd2db8ee3e1b04..9a1a5943bee013b0129a4473526e62bdd91c2585 100644 (file)
@@ -100,6 +100,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs ili9163_pipe_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = yx240qv29_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index b8826a0b086bfee98f19fbd73b94540b44de5b31..69b265e78096b063fff318971a3ae38f50d976e2 100644 (file)
@@ -137,6 +137,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = yx240qv29_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index a5b433a8e0d8abec911e3294bc090f7404d099d2..c80028bb1d1102211abfbfdbcb8457e2f3efed70 100644 (file)
@@ -150,6 +150,7 @@ static void waveshare_enable(struct drm_simple_display_pipe *pipe,
 }
 
 static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = waveshare_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index 27f1bd4da2f4e800673a156f2827bb90fe193cde..bc522fb3d94d127ffe77b33760f650a4425e5050 100644 (file)
@@ -141,6 +141,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = mi0283qt_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index a76fefa8adbc8701a2344bdd69eab26f39c8cdbd..955a61d628e7c1f8381993c23e0e83365a297d92 100644 (file)
@@ -212,6 +212,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = {
+       .mode_valid = mipi_dbi_pipe_mode_valid,
        .enable = panel_mipi_dbi_enable,
        .disable = mipi_dbi_pipe_disable,
        .update = mipi_dbi_pipe_update,
index c4c1be3ac0b86a8401c860fe891f8ff87c7fedd0..e62f4d16b2c6bffd9320fee8e55433a70fd48ca0 100644 (file)
@@ -621,6 +621,15 @@ static void power_off(struct repaper_epd *epd)
        gpiod_set_value_cansleep(epd->discharge, 0);
 }
 
+static enum drm_mode_status repaper_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+                                                   const struct drm_display_mode *mode)
+{
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct repaper_epd *epd = drm_to_epd(crtc->dev);
+
+       return drm_crtc_helper_mode_valid_fixed(crtc, mode, epd->mode);
+}
+
 static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe,
                                struct drm_crtc_state *crtc_state,
                                struct drm_plane_state *plane_state)
@@ -831,6 +840,7 @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe,
 }
 
 static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = {
+       .mode_valid = repaper_pipe_mode_valid,
        .enable = repaper_pipe_enable,
        .disable = repaper_pipe_disable,
        .update = repaper_pipe_update,
@@ -839,22 +849,8 @@ static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = {
 static int repaper_connector_get_modes(struct drm_connector *connector)
 {
        struct repaper_epd *epd = drm_to_epd(connector->dev);
-       struct drm_display_mode *mode;
-
-       mode = drm_mode_duplicate(connector->dev, epd->mode);
-       if (!mode) {
-               DRM_ERROR("Failed to duplicate mode\n");
-               return 0;
-       }
-
-       drm_mode_set_name(mode);
-       mode->type |= DRM_MODE_TYPE_PREFERRED;
-       drm_mode_probed_add(connector, mode);
-
-       connector->display_info.width_mm = mode->width_mm;
-       connector->display_info.height_mm = mode->height_mm;
 
-       return 1;
+       return drm_connector_helper_get_modes_fixed(connector, epd->mode);
 }
 
 static const struct drm_connector_helper_funcs repaper_connector_hfuncs = {
index a81f91814595ba145522f0669c2a701fa4671a41..777ccd250871749744d1dc80e339e10c19c8232c 100644 (file)
 #define DRIVER_MAJOR   1
 #define DRIVER_MINOR   0
 
-/*
- * Assume a monitor resolution of 96 dpi to
- * get a somewhat reasonable screen size.
- */
-#define RES_MM(d)      \
-       (((d) * 254ul) / (96ul * 10ul))
-
-#define SIMPLEDRM_MODE(hd, vd) \
-       DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd))
-
 /*
  * Helpers for simplefb
  */
@@ -570,15 +560,7 @@ static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *cr
 {
        struct simpledrm_device *sdev = simpledrm_device_of_dev(crtc->dev);
 
-       if (mode->hdisplay != sdev->mode.hdisplay &&
-           mode->vdisplay != sdev->mode.vdisplay)
-               return MODE_ONE_SIZE;
-       else if (mode->hdisplay != sdev->mode.hdisplay)
-               return MODE_ONE_WIDTH;
-       else if (mode->vdisplay != sdev->mode.vdisplay)
-               return MODE_ONE_HEIGHT;
-
-       return MODE_OK;
+       return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode);
 }
 
 static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc,
@@ -620,24 +602,8 @@ static const struct drm_encoder_funcs simpledrm_encoder_funcs = {
 static int simpledrm_connector_helper_get_modes(struct drm_connector *connector)
 {
        struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev);
-       struct drm_display_mode *mode;
-
-       mode = drm_mode_duplicate(connector->dev, &sdev->mode);
-       if (!mode)
-               return 0;
-
-       if (mode->name[0] == '\0')
-               drm_mode_set_name(mode);
-
-       mode->type |= DRM_MODE_TYPE_PREFERRED;
-       drm_mode_probed_add(connector, mode);
 
-       if (mode->width_mm)
-               connector->display_info.width_mm = mode->width_mm;
-       if (mode->height_mm)
-               connector->display_info.height_mm = mode->height_mm;
-
-       return 1;
+       return drm_connector_helper_get_modes_fixed(connector, &sdev->mode);
 }
 
 static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = {
@@ -665,51 +631,17 @@ static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = {
 static struct drm_display_mode simpledrm_mode(unsigned int width,
                                              unsigned int height)
 {
-       struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) };
-
-       mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */;
-       drm_mode_set_name(&mode);
-
-       return mode;
-}
-
-static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev,
-                                               size_t *nformats_out)
-{
-       struct drm_device *dev = &sdev->dev;
-       size_t i;
-
-       if (sdev->nformats)
-               goto out; /* don't rebuild list on recurring calls */
-
-       /* native format goes first */
-       sdev->formats[0] = sdev->format->format;
-       sdev->nformats = 1;
-
-       /* default formats go second */
-       for (i = 0; i < ARRAY_SIZE(simpledrm_primary_plane_formats); ++i) {
-               if (simpledrm_primary_plane_formats[i] == sdev->format->format)
-                       continue; /* native format already went first */
-               sdev->formats[sdev->nformats] = simpledrm_primary_plane_formats[i];
-               sdev->nformats++;
-       }
-
        /*
-        * TODO: The simpledrm driver converts framebuffers to the native
-        * format when copying them to device memory. If there are more
-        * formats listed than supported by the driver, the native format
-        * is not supported by the conversion helpers. Therefore *only*
-        * support the native format and add a conversion helper ASAP.
+        * Assume a monitor resolution of 96 dpi to
+        * get a somewhat reasonable screen size.
         */
-       if (drm_WARN_ONCE(dev, i != sdev->nformats,
-                         "format conversion helpers required for %p4cc",
-                         &sdev->format->format)) {
-               sdev->nformats = 1;
-       }
+       const struct drm_display_mode mode = {
+               DRM_MODE_INIT(60, width, height,
+                             DRM_MODE_RES_MM(width, 96ul),
+                             DRM_MODE_RES_MM(height, 96ul))
+       };
 
-out:
-       *nformats_out = sdev->nformats;
-       return sdev->formats;
+       return mode;
 }
 
 static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
@@ -728,7 +660,6 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
        struct drm_encoder *encoder;
        struct drm_connector *connector;
        unsigned long max_width, max_height;
-       const uint32_t *formats;
        size_t nformats;
        int ret;
 
@@ -840,11 +771,14 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 
        /* Primary plane */
 
-       formats = simpledrm_device_formats(sdev, &nformats);
+       nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
+                                           simpledrm_primary_plane_formats,
+                                           ARRAY_SIZE(simpledrm_primary_plane_formats),
+                                           sdev->formats, ARRAY_SIZE(sdev->formats));
 
        primary_plane = &sdev->primary_plane;
        ret = drm_universal_plane_init(dev, primary_plane, 0, &simpledrm_primary_plane_funcs,
-                                      formats, nformats,
+                                      sdev->formats, nformats,
                                       simpledrm_primary_plane_format_modifiers,
                                       DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret)
index d2042a0f02dd358b357fb63ba26d39f7289de5b7..c36ba08acda1896376a56c79efbfed3ecd8fd7ce 100644 (file)
@@ -133,6 +133,7 @@ out_exit:
 }
 
 static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = {
+       .mode_valid     = mipi_dbi_pipe_mode_valid,
        .enable         = st7735r_pipe_enable,
        .disable        = mipi_dbi_pipe_disable,
        .update         = mipi_dbi_pipe_update,
index 5703277c6f5276197f1d5a4c5d8d6ae76723456b..91effdcefb6d5b2adcf5f11b4f1f048c0ddc7f77 100644 (file)
@@ -21,8 +21,14 @@ static int udl_usb_suspend(struct usb_interface *interface,
                           pm_message_t message)
 {
        struct drm_device *dev = usb_get_intfdata(interface);
+       int ret;
 
-       return drm_mode_config_helper_suspend(dev);
+       ret = drm_mode_config_helper_suspend(dev);
+       if (ret)
+               return ret;
+
+       udl_sync_pending_urbs(dev);
+       return 0;
 }
 
 static int udl_usb_resume(struct usb_interface *interface)
@@ -32,6 +38,16 @@ static int udl_usb_resume(struct usb_interface *interface)
        return drm_mode_config_helper_resume(dev);
 }
 
+static int udl_usb_reset_resume(struct usb_interface *interface)
+{
+       struct drm_device *dev = usb_get_intfdata(interface);
+       struct udl_device *udl = to_udl(dev);
+
+       udl_select_std_channel(udl);
+
+       return drm_mode_config_helper_resume(dev);
+}
+
 /*
  * FIXME: Dma-buf sharing requires DMA support by the importing device.
  *        This function is a workaround to make USB devices work as well.
@@ -140,6 +156,7 @@ static struct usb_driver udl_driver = {
        .disconnect = udl_usb_disconnect,
        .suspend = udl_usb_suspend,
        .resume = udl_usb_resume,
+       .reset_resume = udl_usb_reset_resume,
        .id_table = id_table,
 };
 module_usb_driver(udl_driver);
index 28aaf75d71cf09ffadbcace9acc7506cff3b0793..b4cc7cc568c743ad78f3c6eb51e93f0e23268793 100644 (file)
@@ -39,7 +39,6 @@ struct urb_node {
 
 struct urb_list {
        struct list_head list;
-       struct list_head in_flight;
        spinlock_t lock;
        wait_queue_head_t sleep;
        int available;
@@ -75,17 +74,10 @@ static inline struct usb_device *udl_to_usb_device(struct udl_device *udl)
 int udl_modeset_init(struct drm_device *dev);
 struct drm_connector *udl_connector_init(struct drm_device *dev);
 
-struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout);
-
-#define GET_URB_TIMEOUT        HZ
-static inline struct urb *udl_get_urb(struct drm_device *dev)
-{
-       return udl_get_urb_timeout(dev, GET_URB_TIMEOUT);
-}
+struct urb *udl_get_urb(struct drm_device *dev);
 
 int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);
-int udl_sync_pending_urbs(struct drm_device *dev);
-void udl_kill_pending_urbs(struct drm_device *dev);
+void udl_sync_pending_urbs(struct drm_device *dev);
 void udl_urb_completion(struct urb *urb);
 
 int udl_init(struct udl_device *udl);
@@ -95,6 +87,7 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
                     u32 byte_offset, u32 device_byte_offset, u32 byte_width);
 
 int udl_drop_usb(struct drm_device *dev);
+int udl_select_std_channel(struct udl_device *udl);
 
 #define CMD_WRITE_RAW8   "\xAF\x60" /**< 8 bit raw write command. */
 #define CMD_WRITE_RL8    "\xAF\x61" /**< 8 bit run length command. */
index fdafbf8f3c3cb083b1cd03029d1089ce21bc267c..061cb88c08a210781d9589fec2e350d7871ac0a1 100644 (file)
 #define NR_USB_REQUEST_CHANNEL 0x12
 
 #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
-#define WRITES_IN_FLIGHT (4)
+#define WRITES_IN_FLIGHT (20)
 #define MAX_VENDOR_DESCRIPTOR_SIZE 256
 
+static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout);
+
 static int udl_parse_vendor_descriptor(struct udl_device *udl)
 {
        struct usb_device *udev = udl_to_usb_device(udl);
@@ -92,7 +94,7 @@ success:
 /*
  * Need to ensure a channel is selected before submitting URBs
  */
-static int udl_select_std_channel(struct udl_device *udl)
+int udl_select_std_channel(struct udl_device *udl)
 {
        static const u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7,
                                         0x1C, 0x88, 0x5E, 0x15,
@@ -126,6 +128,7 @@ void udl_urb_completion(struct urb *urb)
        if (urb->status) {
                if (!(urb->status == -ENOENT ||
                    urb->status == -ECONNRESET ||
+                   urb->status == -EPROTO ||
                    urb->status == -ESHUTDOWN)) {
                        DRM_ERROR("%s - nonzero write bulk status received: %d\n",
                                __func__, urb->status);
@@ -135,7 +138,7 @@ void udl_urb_completion(struct urb *urb)
        urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */
 
        spin_lock_irqsave(&udl->urbs.lock, flags);
-       list_move(&unode->entry, &udl->urbs.list);
+       list_add_tail(&unode->entry, &udl->urbs.list);
        udl->urbs.available++;
        spin_unlock_irqrestore(&udl->urbs.lock, flags);
 
@@ -145,15 +148,17 @@ void udl_urb_completion(struct urb *urb)
 static void udl_free_urb_list(struct drm_device *dev)
 {
        struct udl_device *udl = to_udl(dev);
-       int count = udl->urbs.count;
        struct urb_node *unode;
        struct urb *urb;
 
        DRM_DEBUG("Waiting for completes and freeing all render urbs\n");
 
        /* keep waiting and freeing, until we've got 'em all */
-       while (count--) {
-               urb = udl_get_urb_timeout(dev, MAX_SCHEDULE_TIMEOUT);
+       while (udl->urbs.count) {
+               spin_lock_irq(&udl->urbs.lock);
+               urb = udl_get_urb_locked(udl, MAX_SCHEDULE_TIMEOUT);
+               udl->urbs.count--;
+               spin_unlock_irq(&udl->urbs.lock);
                if (WARN_ON(!urb))
                        break;
                unode = urb->context;
@@ -163,7 +168,8 @@ static void udl_free_urb_list(struct drm_device *dev)
                usb_free_urb(urb);
                kfree(unode);
        }
-       udl->urbs.count = 0;
+
+       wake_up_all(&udl->urbs.sleep);
 }
 
 static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
@@ -176,16 +182,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
        struct usb_device *udev = udl_to_usb_device(udl);
 
        spin_lock_init(&udl->urbs.lock);
-
-retry:
-       udl->urbs.size = size;
        INIT_LIST_HEAD(&udl->urbs.list);
-       INIT_LIST_HEAD(&udl->urbs.in_flight);
-
        init_waitqueue_head(&udl->urbs.sleep);
        udl->urbs.count = 0;
        udl->urbs.available = 0;
 
+retry:
+       udl->urbs.size = size;
+
        while (udl->urbs.count * size < wanted_size) {
                unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
                if (!unode)
@@ -228,43 +232,56 @@ retry:
        return udl->urbs.count;
 }
 
-struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout)
+static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout)
 {
-       struct udl_device *udl = to_udl(dev);
-       struct urb_node *unode = NULL;
+       struct urb_node *unode;
 
-       if (!udl->urbs.count)
-               return NULL;
+       assert_spin_locked(&udl->urbs.lock);
 
        /* Wait for an in-flight buffer to complete and get re-queued */
-       spin_lock_irq(&udl->urbs.lock);
        if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
+                                        !udl->urbs.count ||
                                         !list_empty(&udl->urbs.list),
                                         udl->urbs.lock, timeout)) {
                DRM_INFO("wait for urb interrupted: available: %d\n",
                         udl->urbs.available);
-               goto unlock;
+               return NULL;
        }
 
+       if (!udl->urbs.count)
+               return NULL;
+
        unode = list_first_entry(&udl->urbs.list, struct urb_node, entry);
-       list_move(&unode->entry, &udl->urbs.in_flight);
+       list_del_init(&unode->entry);
        udl->urbs.available--;
 
-unlock:
-       spin_unlock_irq(&udl->urbs.lock);
        return unode ? unode->urb : NULL;
 }
 
+#define GET_URB_TIMEOUT        HZ
+struct urb *udl_get_urb(struct drm_device *dev)
+{
+       struct udl_device *udl = to_udl(dev);
+       struct urb *urb;
+
+       spin_lock_irq(&udl->urbs.lock);
+       urb = udl_get_urb_locked(udl, GET_URB_TIMEOUT);
+       spin_unlock_irq(&udl->urbs.lock);
+       return urb;
+}
+
 int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
 {
        struct udl_device *udl = to_udl(dev);
        int ret;
 
-       if (WARN_ON(len > udl->urbs.size))
-               return -EINVAL;
-
+       if (WARN_ON(len > udl->urbs.size)) {
+               ret = -EINVAL;
+               goto error;
+       }
        urb->transfer_buffer_length = len; /* set to actual payload len */
        ret = usb_submit_urb(urb, GFP_ATOMIC);
+ error:
        if (ret) {
                udl_urb_completion(urb); /* because no one else will */
                DRM_ERROR("usb_submit_urb error %x\n", ret);
@@ -273,36 +290,17 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
 }
 
 /* wait until all pending URBs have been processed */
-int udl_sync_pending_urbs(struct drm_device *dev)
+void udl_sync_pending_urbs(struct drm_device *dev)
 {
        struct udl_device *udl = to_udl(dev);
-       int ret = 0;
 
        spin_lock_irq(&udl->urbs.lock);
        /* 2 seconds as a sane timeout */
        if (!wait_event_lock_irq_timeout(udl->urbs.sleep,
-                                        list_empty(&udl->urbs.in_flight),
+                                        udl->urbs.available == udl->urbs.count,
                                         udl->urbs.lock,
                                         msecs_to_jiffies(2000)))
-               ret = -ETIMEDOUT;
-       spin_unlock_irq(&udl->urbs.lock);
-       return ret;
-}
-
-/* kill pending URBs */
-void udl_kill_pending_urbs(struct drm_device *dev)
-{
-       struct udl_device *udl = to_udl(dev);
-       struct urb_node *unode;
-
-       spin_lock_irq(&udl->urbs.lock);
-       while (!list_empty(&udl->urbs.in_flight)) {
-               unode = list_first_entry(&udl->urbs.in_flight,
-                                        struct urb_node, entry);
-               spin_unlock_irq(&udl->urbs.lock);
-               usb_kill_urb(unode->urb);
-               spin_lock_irq(&udl->urbs.lock);
-       }
+               drm_err(dev, "Timeout for syncing pending URBs\n");
        spin_unlock_irq(&udl->urbs.lock);
 }
 
@@ -354,7 +352,6 @@ int udl_drop_usb(struct drm_device *dev)
 {
        struct udl_device *udl = to_udl(dev);
 
-       udl_kill_pending_urbs(dev);
        udl_free_urb_list(dev);
        put_device(udl->dmadev);
        udl->dmadev = NULL;
index 169110d8fc2e193b235d8b4cc2ee5c4849d49ca0..ec6876f449f31d45c8724df6ff6473d5c2690c58 100644 (file)
@@ -242,38 +242,15 @@ static long udl_log_cpp(unsigned int cpp)
        return __ffs(cpp);
 }
 
-static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y,
-                                  int width, int height)
-{
-       int x1, x2;
-
-       if (WARN_ON_ONCE(x < 0) ||
-           WARN_ON_ONCE(y < 0) ||
-           WARN_ON_ONCE(width < 0) ||
-           WARN_ON_ONCE(height < 0))
-               return -EINVAL;
-
-       x1 = ALIGN_DOWN(x, sizeof(unsigned long));
-       x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1;
-
-       clip->x1 = x1;
-       clip->y1 = y;
-       clip->x2 = x2;
-       clip->y2 = y + height;
-
-       return 0;
-}
-
 static int udl_handle_damage(struct drm_framebuffer *fb,
                             const struct iosys_map *map,
-                            int x, int y, int width, int height)
+                            const struct drm_rect *clip)
 {
        struct drm_device *dev = fb->dev;
        void *vaddr = map->vaddr; /* TODO: Use mapping abstraction properly */
        int i, ret;
        char *cmd;
        struct urb *urb;
-       struct drm_rect clip;
        int log_bpp;
 
        ret = udl_log_cpp(fb->format->cpp[0]);
@@ -281,12 +258,6 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
                return ret;
        log_bpp = ret;
 
-       ret = udl_aligned_damage_clip(&clip, x, y, width, height);
-       if (ret)
-               return ret;
-       else if ((clip.x2 > fb->width) || (clip.y2 > fb->height))
-               return -EINVAL;
-
        ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
        if (ret)
                return ret;
@@ -298,11 +269,11 @@ static int udl_handle_damage(struct drm_framebuffer *fb,
        }
        cmd = urb->transfer_buffer;
 
-       for (i = clip.y1; i < clip.y2; i++) {
+       for (i = clip->y1; i < clip->y2; i++) {
                const int line_offset = fb->pitches[0] * i;
-               const int byte_offset = line_offset + (clip.x1 << log_bpp);
-               const int dev_byte_offset = (fb->width * i + clip.x1) << log_bpp;
-               const int byte_width = (clip.x2 - clip.x1) << log_bpp;
+               const int byte_offset = line_offset + (clip->x1 << log_bpp);
+               const int dev_byte_offset = (fb->width * i + clip->x1) << log_bpp;
+               const int byte_width = drm_rect_width(clip) << log_bpp;
                ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr,
                                       &cmd, byte_offset, dev_byte_offset,
                                       byte_width);
@@ -355,6 +326,7 @@ udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
        struct udl_device *udl = to_udl(dev);
        struct drm_display_mode *mode = &crtc_state->mode;
        struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+       struct drm_rect clip = DRM_RECT_INIT(0, 0, fb->width, fb->height);
        char *buf;
        char *wrptr;
        int color_depth = UDL_COLOR_DEPTH_16BPP;
@@ -380,10 +352,7 @@ udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 
        udl->mode_buf_len = wrptr - buf;
 
-       udl_handle_damage(fb, &shadow_plane_state->data[0], 0, 0, fb->width, fb->height);
-
-       if (!crtc_state->mode_changed)
-               return;
+       udl_handle_damage(fb, &shadow_plane_state->data[0], &clip);
 
        /* enable display */
        udl_crtc_write_mode_to_hw(crtc);
@@ -397,8 +366,6 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
        struct urb *urb;
        char *buf;
 
-       udl_kill_pending_urbs(dev);
-
        urb = udl_get_urb(dev);
        if (!urb)
                return;
@@ -410,8 +377,6 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
        buf = udl_dummy_render(buf);
 
        udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer);
-
-       udl_sync_pending_urbs(dev);
 }
 
 static void
@@ -427,8 +392,7 @@ udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
                return;
 
        if (drm_atomic_helper_damage_merged(old_plane_state, state, &rect))
-               udl_handle_damage(fb, &shadow_plane_state->data[0], rect.x1, rect.y1,
-                                 rect.x2 - rect.x1, rect.y2 - rect.y1);
+               udl_handle_damage(fb, &shadow_plane_state->data[0], &rect);
 }
 
 static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = {
@@ -483,6 +447,7 @@ int udl_modeset_init(struct drm_device *dev)
                                           format_count, NULL, connector);
        if (ret)
                return ret;
+       drm_plane_enable_fb_damage_clips(&udl->display_pipe.plane);
 
        drm_mode_config_reset(dev);
 
index 176ef2a6a73138b793add72ed3490500f73a437c..b57844632dbd74ce69c3fe79d46d63c38c952cfc 100644 (file)
 #define MIN_RAW_PIX_BYTES      2
 #define MIN_RAW_CMD_BYTES      (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
 
-/*
- * Trims identical data from front and back of line
- * Sets new front buffer address and width
- * And returns byte count of identical pixels
- * Assumes CPU natural alignment (unsigned long)
- * for back and front buffer ptrs and width
- */
-#if 0
-static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
-{
-       int j, k;
-       const unsigned long *back = (const unsigned long *) bback;
-       const unsigned long *front = (const unsigned long *) *bfront;
-       const int width = *width_bytes / sizeof(unsigned long);
-       int identical = width;
-       int start = width;
-       int end = width;
-
-       for (j = 0; j < width; j++) {
-               if (back[j] != front[j]) {
-                       start = j;
-                       break;
-               }
-       }
-
-       for (k = width - 1; k > j; k--) {
-               if (back[k] != front[k]) {
-                       end = k+1;
-                       break;
-               }
-       }
-
-       identical = start + (width - end);
-       *bfront = (u8 *) &front[start];
-       *width_bytes = (end - start) * sizeof(unsigned long);
-
-       return identical * sizeof(unsigned long);
-}
-#endif
-
 static inline u16 pixel32_to_be16(const uint32_t pixel)
 {
        return (((pixel >> 3) & 0x001f) |
@@ -220,8 +180,11 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
        u8 *cmd = *urb_buf_ptr;
        u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
 
-       if (WARN_ON(!(log_bpp == 1 || log_bpp == 2)))
+       if (WARN_ON(!(log_bpp == 1 || log_bpp == 2))) {
+               /* need to finish URB at error from this function */
+               udl_urb_completion(urb);
                return -EINVAL;
+       }
 
        line_start = (u8 *) (front + byte_offset);
        next_pixel = line_start;
index 25299fbc083b1f46e3c76b93b2838402bb225da1..64f9feabf43ef92c63ad7f8c4e164650e452d7e4 100644 (file)
@@ -124,6 +124,23 @@ static unsigned long long
 vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
                                    unsigned int bpc, enum vc4_hdmi_output_format fmt);
 
+static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder)
+{
+       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+       struct drm_display_info *display = &vc4_hdmi->connector.display_info;
+
+       lockdep_assert_held(&vc4_hdmi->mutex);
+
+       if (!display->is_hdmi)
+               return false;
+
+       if (!display->hdmi.scdc.supported ||
+           !display->hdmi.scdc.scrambling.supported)
+               return false;
+
+       return true;
+}
+
 static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
                                           unsigned int bpc,
                                           enum vc4_hdmi_output_format fmt)
@@ -271,47 +288,172 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
 static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
 #endif
 
-static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder);
+static int reset_pipe(struct drm_crtc *crtc,
+                       struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_atomic_state *state;
+       struct drm_crtc_state *crtc_state;
+       int ret;
+
+       state = drm_atomic_state_alloc(crtc->dev);
+       if (!state)
+               return -ENOMEM;
 
-static enum drm_connector_status
-vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
+       state->acquire_ctx = ctx;
+
+       crtc_state = drm_atomic_get_crtc_state(state, crtc);
+       if (IS_ERR(crtc_state)) {
+               ret = PTR_ERR(crtc_state);
+               goto out;
+       }
+
+       crtc_state->connectors_changed = true;
+
+       ret = drm_atomic_commit(state);
+out:
+       drm_atomic_state_put(state);
+
+       return ret;
+}
+
+static int vc4_hdmi_reset_link(struct drm_connector *connector,
+                              struct drm_modeset_acquire_ctx *ctx)
 {
+       struct drm_device *drm = connector->dev;
        struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
-       bool connected = false;
+       struct drm_encoder *encoder = &vc4_hdmi->encoder.base;
+       struct drm_connector_state *conn_state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       bool scrambling_needed;
+       u8 config;
+       int ret;
 
-       mutex_lock(&vc4_hdmi->mutex);
+       if (!connector)
+               return 0;
+
+       ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
+       if (ret)
+               return ret;
+
+       conn_state = connector->state;
+       crtc = conn_state->crtc;
+       if (!crtc)
+               return 0;
+
+       ret = drm_modeset_lock(&crtc->mutex, ctx);
+       if (ret)
+               return ret;
+
+       crtc_state = crtc->state;
+       if (!crtc_state->active)
+               return 0;
+
+       if (!vc4_hdmi_supports_scrambling(encoder))
+               return 0;
+
+       scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
+                                                          vc4_hdmi->output_bpc,
+                                                          vc4_hdmi->output_format);
+       if (!scrambling_needed)
+               return 0;
+
+       if (conn_state->commit &&
+           !try_wait_for_completion(&conn_state->commit->hw_done))
+               return 0;
+
+       ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+       if (ret < 0) {
+               drm_err(drm, "Failed to read TMDS config: %d\n", ret);
+               return 0;
+       }
+
+       if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed)
+               return 0;
+
+       /*
+        * HDMI 2.0 says that one should not send scrambled data
+        * prior to configuring the sink scrambling, and that
+        * TMDS clock/data transmission should be suspended when
+        * changing the TMDS clock rate in the sink. So let's
+        * just do a full modeset here, even though some sinks
+        * would be perfectly happy if were to just reconfigure
+        * the SCDC settings on the fly.
+        */
+       return reset_pipe(crtc, ctx);
+}
+
+static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
+                                   struct drm_modeset_acquire_ctx *ctx,
+                                   enum drm_connector_status status)
+{
+       struct drm_connector *connector = &vc4_hdmi->connector;
+       struct edid *edid;
+
+       /*
+        * NOTE: This function should really be called with
+        * vc4_hdmi->mutex held, but doing so results in reentrancy
+        * issues since cec_s_phys_addr_from_edid might call
+        * .adap_enable, which leads to that funtion being called with
+        * our mutex held.
+        *
+        * A similar situation occurs with
+        * drm_atomic_helper_connector_hdmi_reset_link() that will call
+        * into our KMS hooks if the scrambling was enabled.
+        *
+        * Concurrency isn't an issue at the moment since we don't share
+        * any state with any of the other frameworks so we can ignore
+        * the lock for now.
+        */
+
+       if (status == connector_status_disconnected) {
+               cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
+               return;
+       }
+
+       edid = drm_get_edid(connector, vc4_hdmi->ddc);
+       if (!edid)
+               return;
+
+       cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
+       kfree(edid);
+
+       vc4_hdmi_reset_link(connector, ctx);
+}
+
+static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
+                                        struct drm_modeset_acquire_ctx *ctx,
+                                        bool force)
+{
+       struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+       enum drm_connector_status status = connector_status_disconnected;
+
+       /*
+        * NOTE: This function should really take vc4_hdmi->mutex, but
+        * doing so results in reentrancy issues since
+        * vc4_hdmi_handle_hotplug() can call into other functions that
+        * would take the mutex while it's held here.
+        *
+        * Concurrency isn't an issue at the moment since we don't share
+        * any state with any of the other frameworks so we can ignore
+        * the lock for now.
+        */
 
        WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
 
        if (vc4_hdmi->hpd_gpio) {
                if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
-                       connected = true;
+                       status = connector_status_connected;
        } else {
                if (vc4_hdmi->variant->hp_detect &&
                    vc4_hdmi->variant->hp_detect(vc4_hdmi))
-                       connected = true;
-       }
-
-       if (connected) {
-               if (connector->status != connector_status_connected) {
-                       struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc);
-
-                       if (edid) {
-                               cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
-                               kfree(edid);
-                       }
-               }
-
-               vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base);
-               pm_runtime_put(&vc4_hdmi->pdev->dev);
-               mutex_unlock(&vc4_hdmi->mutex);
-               return connector_status_connected;
+                       status = connector_status_connected;
        }
 
-       cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
+       vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
        pm_runtime_put(&vc4_hdmi->pdev->dev);
-       mutex_unlock(&vc4_hdmi->mutex);
-       return connector_status_disconnected;
+
+       return status;
 }
 
 static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -320,14 +462,21 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
        int ret = 0;
        struct edid *edid;
 
-       mutex_lock(&vc4_hdmi->mutex);
+       /*
+        * NOTE: This function should really take vc4_hdmi->mutex, but
+        * doing so results in reentrancy issues since
+        * cec_s_phys_addr_from_edid might call .adap_enable, which
+        * leads to that funtion being called with our mutex held.
+        *
+        * Concurrency isn't an issue at the moment since we don't share
+        * any state with any of the other frameworks so we can ignore
+        * the lock for now.
+        */
 
        edid = drm_get_edid(connector, vc4_hdmi->ddc);
        cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
-       if (!edid) {
-               ret = -ENODEV;
-               goto out;
-       }
+       if (!edid)
+               return -ENODEV;
 
        drm_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
@@ -335,7 +484,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
 
        if (vc4_hdmi->disable_4kp60) {
                struct drm_device *drm = connector->dev;
-               struct drm_display_mode *mode;
+               const struct drm_display_mode *mode;
 
                list_for_each_entry(mode, &connector->probed_modes, head) {
                        if (vc4_hdmi_mode_needs_scrambling(mode, 8, VC4_HDMI_OUTPUT_RGB)) {
@@ -345,9 +494,6 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
                }
        }
 
-out:
-       mutex_unlock(&vc4_hdmi->mutex);
-
        return ret;
 }
 
@@ -419,7 +565,6 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
-       .detect = vc4_hdmi_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .reset = vc4_hdmi_connector_reset,
        .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state,
@@ -427,6 +572,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
 };
 
 static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
+       .detect_ctx = vc4_hdmi_connector_detect_ctx,
        .get_modes = vc4_hdmi_connector_get_modes,
        .atomic_check = vc4_hdmi_connector_atomic_check,
 };
@@ -708,37 +854,19 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
        vc4_hdmi_set_hdr_infoframe(encoder);
 }
 
-static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
-                                        struct drm_display_mode *mode)
-{
-       struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
-       struct drm_display_info *display = &vc4_hdmi->connector.display_info;
-
-       lockdep_assert_held(&vc4_hdmi->mutex);
-
-       if (!display->is_hdmi)
-               return false;
-
-       if (!display->hdmi.scdc.supported ||
-           !display->hdmi.scdc.scrambling.supported)
-               return false;
-
-       return true;
-}
-
 #define SCRAMBLING_POLLING_DELAY_MS    1000
 
 static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
 {
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        struct drm_device *drm = vc4_hdmi->connector.dev;
-       struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+       const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
        unsigned long flags;
        int idx;
 
        lockdep_assert_held(&vc4_hdmi->mutex);
 
-       if (!vc4_hdmi_supports_scrambling(encoder, mode))
+       if (!vc4_hdmi_supports_scrambling(encoder))
                return;
 
        if (!vc4_hdmi_mode_needs_scrambling(mode,
@@ -1077,7 +1205,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
 
 static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
                                 struct drm_connector_state *state,
-                                struct drm_display_mode *mode)
+                                const struct drm_display_mode *mode)
 {
        struct drm_device *drm = vc4_hdmi->connector.dev;
        bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
@@ -1141,7 +1269,7 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
 
 static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
                                 struct drm_connector_state *state,
-                                struct drm_display_mode *mode)
+                                const struct drm_display_mode *mode)
 {
        struct drm_device *drm = vc4_hdmi->connector.dev;
        const struct vc4_hdmi_connector_state *vc4_state =
@@ -1303,7 +1431,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
                drm_atomic_get_new_connector_state(state, connector);
        struct vc4_hdmi_connector_state *vc4_conn_state =
                conn_state_to_vc4_hdmi_conn_state(conn_state);
-       struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+       const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
        unsigned long tmds_char_rate = vc4_conn_state->tmds_char_rate;
        unsigned long bvb_rate, hsm_rate;
        unsigned long flags;
@@ -1416,7 +1544,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        struct drm_device *drm = vc4_hdmi->connector.dev;
        struct drm_connector *connector = &vc4_hdmi->connector;
-       struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+       const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
        struct drm_connector_state *conn_state =
                drm_atomic_get_new_connector_state(state, connector);
        unsigned long flags;
@@ -1445,7 +1573,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
 {
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
        struct drm_device *drm = vc4_hdmi->connector.dev;
-       struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+       const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
        struct drm_display_info *display = &vc4_hdmi->connector.display_info;
        bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
        bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
@@ -2668,17 +2796,6 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
        int ret;
        int idx;
 
-       /*
-        * NOTE: This function should really take vc4_hdmi->mutex, but doing so
-        * results in a reentrancy since cec_s_phys_addr_from_edid() called in
-        * .detect or .get_modes might call .adap_enable, which leads to this
-        * function being called with that mutex held.
-        *
-        * Concurrency is not an issue for the moment since we don't share any
-        * state with KMS, so we can ignore the lock for now, but we need to
-        * keep it in mind if we were to change that assumption.
-        */
-
        if (!drm_dev_enter(drm, &idx))
                /*
                 * We can't return an error code, because the CEC
@@ -2693,6 +2810,8 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
                return ret;
        }
 
+       mutex_lock(&vc4_hdmi->mutex);
+
        spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
 
        val = HDMI_READ(HDMI_CEC_CNTRL_5);
@@ -2727,6 +2846,7 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
 
        spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
 
+       mutex_unlock(&vc4_hdmi->mutex);
        drm_dev_exit(idx);
 
        return 0;
@@ -2747,16 +2867,7 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
                 */
                return 0;
 
-       /*
-        * NOTE: This function should really take vc4_hdmi->mutex, but doing so
-        * results in a reentrancy since cec_s_phys_addr_from_edid() called in
-        * .detect or .get_modes might call .adap_enable, which leads to this
-        * function being called with that mutex held.
-        *
-        * Concurrency is not an issue for the moment since we don't share any
-        * state with KMS, so we can ignore the lock for now, but we need to
-        * keep it in mind if we were to change that assumption.
-        */
+       mutex_lock(&vc4_hdmi->mutex);
 
        spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
 
@@ -2768,6 +2879,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
 
        spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
 
+       mutex_unlock(&vc4_hdmi->mutex);
+
        pm_runtime_put(&vc4_hdmi->pdev->dev);
 
        drm_dev_exit(idx);
@@ -2790,17 +2903,6 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
        unsigned long flags;
        int idx;
 
-       /*
-        * NOTE: This function should really take vc4_hdmi->mutex, but doing so
-        * results in a reentrancy since cec_s_phys_addr_from_edid() called in
-        * .detect or .get_modes might call .adap_enable, which leads to this
-        * function being called with that mutex held.
-        *
-        * Concurrency is not an issue for the moment since we don't share any
-        * state with KMS, so we can ignore the lock for now, but we need to
-        * keep it in mind if we were to change that assumption.
-        */
-
        if (!drm_dev_enter(drm, &idx))
                /*
                 * We can't return an error code, because the CEC
@@ -2809,11 +2911,13 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
                 */
                return 0;
 
+       mutex_lock(&vc4_hdmi->mutex);
        spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
        HDMI_WRITE(HDMI_CEC_CNTRL_1,
                   (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
                   (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
        spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
+       mutex_unlock(&vc4_hdmi->mutex);
 
        drm_dev_exit(idx);
 
@@ -2830,17 +2934,6 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
        unsigned int i;
        int idx;
 
-       /*
-        * NOTE: This function should really take vc4_hdmi->mutex, but doing so
-        * results in a reentrancy since cec_s_phys_addr_from_edid() called in
-        * .detect or .get_modes might call .adap_enable, which leads to this
-        * function being called with that mutex held.
-        *
-        * Concurrency is not an issue for the moment since we don't share any
-        * state with KMS, so we can ignore the lock for now, but we need to
-        * keep it in mind if we were to change that assumption.
-        */
-
        if (!drm_dev_enter(dev, &idx))
                return -ENODEV;
 
@@ -2850,6 +2943,8 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
                return -ENOMEM;
        }
 
+       mutex_lock(&vc4_hdmi->mutex);
+
        spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
 
        for (i = 0; i < msg->len; i += 4)
@@ -2869,7 +2964,7 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
        HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
 
        spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
-
+       mutex_unlock(&vc4_hdmi->mutex);
        drm_dev_exit(idx);
 
        return 0;
index 99b0bc1297be8c6d5e1d40c940f87e0de5116010..db823efb256399146a0a66b4dd5b9bdfba31e98c 100644 (file)
@@ -72,7 +72,7 @@ struct vc4_hdmi_variant {
        /* Callback to configure the video timings in the HDMI block */
        void (*set_timings)(struct vc4_hdmi *vc4_hdmi,
                            struct drm_connector_state *state,
-                           struct drm_display_mode *mode);
+                           const struct drm_display_mode *mode);
 
        /* Callback to initialize the PHY according to the connector state */
        void (*phy_init)(struct vc4_hdmi *vc4_hdmi,
@@ -195,15 +195,7 @@ struct vc4_hdmi {
 
        /**
         * @mutex: Mutex protecting the driver access across multiple
-        * frameworks (KMS, ALSA).
-        *
-        * NOTE: While supported, CEC has been left out since
-        * cec_s_phys_addr_from_edid() might call .adap_enable and lead to a
-        * reentrancy issue between .get_modes (or .detect) and .adap_enable.
-        * Since we don't share any state between the CEC hooks and KMS', it's
-        * not a big deal. The only trouble might come from updating the CEC
-        * clock divider which might be affected by a modeset, but CEC should
-        * be resilient to that.
+        * frameworks (KMS, ALSA, CEC).
         */
        struct mutex mutex;
 
index f4319066adcc9c340f4bac51323e935d8389bdf2..c3a845220e10c4d8d9a37b08e6722e6bfb514da2 100644 (file)
@@ -105,11 +105,12 @@ static void vkms_plane_atomic_update(struct drm_plane *plane,
        struct drm_shadow_plane_state *shadow_plane_state;
        struct drm_framebuffer *fb = new_state->fb;
        struct vkms_frame_info *frame_info;
-       u32 fmt = fb->format->format;
+       u32 fmt;
 
        if (!new_state->crtc || !fb)
                return;
 
+       fmt = fb->format->format;
        vkms_plane_state = to_vkms_plane_state(new_state);
        shadow_plane_state = &vkms_plane_state->base;
 
index be19aa6e1f13fa08e839a7845b4adc151a23d99d..09e2d738aa8767439aca76f75cacd2a6afa9d24e 100644 (file)
@@ -877,7 +877,6 @@ static inline void vmw_user_resource_noref_release(void)
 /**
  * Buffer object helper functions - vmwgfx_bo.c
  */
-extern bool vmw_bo_is_vmw_bo(struct ttm_buffer_object *bo);
 extern int vmw_bo_pin_in_placement(struct vmw_private *vmw_priv,
                                   struct vmw_buffer_object *bo,
                                   struct ttm_placement *placement,
index caa18119433576419e1123c8e91fd23249109c85..eb5c98cf82b8f8f0db19090b2ed08589767174f0 100644 (file)
@@ -6,11 +6,15 @@
 #ifndef __LINUX_DRM_FORMAT_HELPER_H
 #define __LINUX_DRM_FORMAT_HELPER_H
 
-struct iosys_map;
+#include <linux/types.h>
+
+struct drm_device;
 struct drm_format_info;
 struct drm_framebuffer;
 struct drm_rect;
 
+struct iosys_map;
+
 unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
                                const struct drm_rect *clip);
 
@@ -44,4 +48,9 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
                             const struct iosys_map *src, const struct drm_framebuffer *fb,
                             const struct drm_rect *clip);
 
+size_t drm_fb_build_fourcc_list(struct drm_device *dev,
+                               const u32 *native_fourccs, size_t native_nfourccs,
+                               const u32 *extra_fourccs, size_t extra_nfourccs,
+                               u32 *fourccs_out, size_t nfourccs_out);
+
 #endif /* __LINUX_DRM_FORMAT_HELPER_H */
index dad2f187b64b1c0ad6aec6e72fb5baa6292d7188..14eaecb1825c172806909c0d3527f3b817772d2a 100644 (file)
@@ -155,6 +155,8 @@ int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev,
 int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev,
                      const struct drm_simple_display_pipe_funcs *funcs,
                      const struct drm_display_mode *mode, unsigned int rotation);
+enum drm_mode_status mipi_dbi_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
+                                             const struct drm_display_mode *mode);
 void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
                          struct drm_plane_state *old_state);
 void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev,
index a80ae9639e969087f35dbfe5700bf4de0209a646..b0c680e6f6707a59870ce43339baff2929403b8d 100644 (file)
@@ -138,6 +138,35 @@ enum drm_mode_status {
        .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
        .vscan = (vs), .flags = (f)
 
+/**
+ * DRM_MODE_RES_MM - Calculates the display size from resolution and DPI
+ * @res: The resolution in pixel
+ * @dpi: The number of dots per inch
+ */
+#define DRM_MODE_RES_MM(res, dpi)      \
+       (((res) * 254ul) / ((dpi) * 10ul))
+
+#define __DRM_MODE_INIT(pix, hd, vd, hd_mm, vd_mm) \
+       .type = DRM_MODE_TYPE_DRIVER, .clock = (pix), \
+       .hdisplay = (hd), .hsync_start = (hd), .hsync_end = (hd), \
+       .htotal = (hd), .vdisplay = (vd), .vsync_start = (vd), \
+       .vsync_end = (vd), .vtotal = (vd), .width_mm = (hd_mm), \
+       .height_mm = (vd_mm)
+
+/**
+ * DRM_MODE_INIT - Initialize display mode
+ * @hz: Vertical refresh rate in Hertz
+ * @hd: Horizontal resolution, width
+ * @vd: Vertical resolution, height
+ * @hd_mm: Display width in millimeters
+ * @vd_mm: Display height in millimeters
+ *
+ * This macro initializes a &drm_display_mode that contains information about
+ * refresh rate, resolution and physical size.
+ */
+#define DRM_MODE_INIT(hz, hd, vd, hd_mm, vd_mm) \
+       __DRM_MODE_INIT((hd) * (vd) * (hz) / 1000 /* kHz */, hd, vd, hd_mm, vd_mm)
+
 /**
  * DRM_SIMPLE_MODE - Simple display mode
  * @hd: Horizontal resolution, width
@@ -149,11 +178,7 @@ enum drm_mode_status {
  * resolution and physical size.
  */
 #define DRM_SIMPLE_MODE(hd, vd, hd_mm, vd_mm) \
-       .type = DRM_MODE_TYPE_DRIVER, .clock = 1 /* pass validation */, \
-       .hdisplay = (hd), .hsync_start = (hd), .hsync_end = (hd), \
-       .htotal = (hd), .vdisplay = (vd), .vsync_start = (vd), \
-       .vsync_end = (vd), .vtotal = (vd), .width_mm = (hd_mm), \
-       .height_mm = (vd_mm)
+       __DRM_MODE_INIT(1 /* pass validation */, hd, vd, hd_mm, vd_mm)
 
 #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */
 #define CRTC_STEREO_DOUBLE     (1 << 1) /* adjust timings for stereo modes */
index 8075e02aa865464b0d552496ee8aa8316e19bec9..5880daa146240f9606f61419bd5839b30bb2d09e 100644 (file)
@@ -3,9 +3,10 @@
 #ifndef __DRM_PROBE_HELPER_H__
 #define __DRM_PROBE_HELPER_H__
 
-#include <linux/types.h>
+#include <drm/drm_modes.h>
 
 struct drm_connector;
+struct drm_crtc;
 struct drm_device;
 struct drm_modeset_acquire_ctx;
 
@@ -26,7 +27,13 @@ void drm_kms_helper_poll_disable(struct drm_device *dev);
 void drm_kms_helper_poll_enable(struct drm_device *dev);
 bool drm_kms_helper_is_poll_worker(void);
 
+enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,
+                                                     const struct drm_display_mode *mode,
+                                                     const struct drm_display_mode *fixed_mode);
+
 int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector);
+int drm_connector_helper_get_modes_fixed(struct drm_connector *connector,
+                                        const struct drm_display_mode *fixed_mode);
 int drm_connector_helper_get_modes(struct drm_connector *connector);
 
 #endif