diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml index 0521261b04a9..ae894d996d21 100644 --- a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml @@ -49,6 +49,9 @@ properties: description: | OF device-tree gpio specification for RSTX pin(active low system reset) + interrupts: + maxItems: 1 + toshiba,hpd-pin: $ref: /schemas/types.yaml#/definitions/uint32 enum: diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index c5d1df680858..e7ab6224b52e 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -18,6 +18,7 @@ properties: - enum: - bananapi,lhr050h41 - feixin,k101-im2byl02 + - tdo,tl050hdv35 - wanchanglong,w552946aba - const: ilitek,ili9881c diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml index 929fe046d1e7..9f1016551e0b 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml @@ -40,6 +40,12 @@ properties: items: - enum: - auo,b101ew05 + # Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel + - chunghwa,claa070wp03xg + # HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel + - hannstar,hsd101pww2 + # Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel + - hydis,hv070wx2-1e0 - tbs,a711-panel - const: panel-lvds diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 1d4936fc5182..25b4589d4a58 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -103,8 +103,6 @@ properties: - cdtech,s070wv95-ct16 # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel - chefree,ch101olhlwh-002 - # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel - - chunghwa,claa070wp03xg # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel - chunghwa,claa101wa01a # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel @@ -168,8 +166,6 @@ properties: - hannstar,hsd070pww1 # HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel - hannstar,hsd100pxn1 - # HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel - - hannstar,hsd101pww2 # Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel - hit,tx23d38vm0caa # InfoVision Optoelectronics M133NWF4 R0 13.3" FHD (1920x1080) TFT LCD panel @@ -196,6 +192,8 @@ properties: - innolux,n116bge # InnoLux 13.3" FHD (1920x1080) eDP TFT LCD panel - innolux,n125hce-gn1 + # InnoLux 15.6" FHD (1920x1080) TFT LCD panel + - innolux,g156hce-l01 # InnoLux 15.6" WXGA TFT LCD panel - innolux,n156bge-l21 # Innolux P120ZDG-BF1 12.02 inch eDP 2K display panel diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml index fa6556363cca..905c064cd106 100644 --- a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml +++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml @@ -15,7 +15,10 @@ allOf: properties: compatible: - const: sitronix,st7789v + enum: + - edt,et028013dma + - inanbo,t28cp45tn89-v17 + - sitronix,st7789v reg: true reset-gpios: true @@ -26,6 +29,10 @@ properties: spi-cpha: true spi-cpol: true + spi-rx-bus-width: + minimum: 0 + maximum: 1 + dc-gpios: maxItems: 1 description: DCX pin, Display data/command selection pin in parallel interface @@ -33,7 +40,6 @@ properties: required: - compatible - reg - - reset-gpios - power-supply unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/display/panel/startek,kd070fhfid015.yaml b/Documentation/devicetree/bindings/display/panel/startek,kd070fhfid015.yaml new file mode 100644 index 000000000000..d817f998cddc --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/startek,kd070fhfid015.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/startek,kd070fhfid015.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Startek Electronic Technology Co. kd070fhfid015 7 inch TFT LCD panel + +maintainers: + - Alexandre Mergnat + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: startek,kd070fhfid015 + + enable-gpios: true + + iovcc-supply: + description: Reference to the regulator powering the panel IO pins. + + reg: + maxItems: 1 + description: DSI virtual channel + + reset-gpios: true + + port: true + + power-supply: true + +additionalProperties: false + +required: + - compatible + - enable-gpios + - iovcc-supply + - reg + - reset-gpios + - port + - power-supply + +examples: + - | + #include + + dsi0 { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "startek,kd070fhfid015"; + reg = <0>; + enable-gpios = <&pio 67 GPIO_ACTIVE_HIGH>; + reset-gpios = <&pio 20 GPIO_ACTIVE_HIGH>; + iovcc-supply = <&mt6357_vsim1_reg>; + power-supply = <&vsys_lcm_reg>; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml index 05e6f2df604c..3e2d216c6432 100644 --- a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml +++ b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml @@ -13,6 +13,9 @@ description: Supports the Elan eKTH6915 touchscreen controller. This touchscreen controller uses the i2c-hid protocol with a reset GPIO. +allOf: + - $ref: /schemas/input/touchscreen/touchscreen.yaml# + properties: compatible: items: @@ -24,6 +27,8 @@ properties: interrupts: maxItems: 1 + panel: true + reset-gpios: description: Reset GPIO; not all touchscreens using eKTH6915 hook this up. diff --git a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml index 1edad1da1196..358cb8275bf1 100644 --- a/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml +++ b/Documentation/devicetree/bindings/input/goodix,gt7375p.yaml @@ -14,6 +14,9 @@ description: This touchscreen uses the i2c-hid protocol but has some non-standard power sequencing required. +allOf: + - $ref: /schemas/input/touchscreen/touchscreen.yaml# + properties: compatible: oneOf: @@ -30,6 +33,8 @@ properties: interrupts: maxItems: 1 + panel: true + reset-gpios: true diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.yaml b/Documentation/devicetree/bindings/input/hid-over-i2c.yaml index 7156b08f7645..138caad96a29 100644 --- a/Documentation/devicetree/bindings/input/hid-over-i2c.yaml +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.yaml @@ -44,6 +44,8 @@ properties: description: HID descriptor address $ref: /schemas/types.yaml#/definitions/uint32 + panel: true + post-power-on-delay-ms: description: Time required by the device after enabling its regulators or powering it on, before it is ready for communication. diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml index 895592da9626..431c13335c40 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml @@ -10,6 +10,13 @@ maintainers: - Dmitry Torokhov properties: + panel: + description: If this touchscreen is integrally connected to a panel, this + is a reference to that panel. The presence of this reference indicates + that the touchscreen should be power sequenced together with the panel + and that they may share power and/or reset signals. + $ref: /schemas/types.yaml#/definitions/phandle + touchscreen-min-x: description: minimum x coordinate reported $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index af60bf1a6664..1e2e51401dc5 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -617,6 +617,8 @@ patternProperties: description: Imagination Technologies Ltd. "^imi,.*": description: Integrated Micro-Electronics Inc. + "^inanbo,.*": + description: Shenzhen INANBO Electronic Technology Co., Ltd. "^incircuit,.*": description: In-Circuit GmbH "^indiedroid,.*": diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 3d5dc9dc1bfe..513197359aba 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -517,6 +517,8 @@ DRM Cache Handling and Fast WC memcpy() .. kernel-doc:: drivers/gpu/drm/drm_cache.c :export: +.. _drm_sync_objects: + DRM Sync Objects =========================== diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index d0f9f87ea515..139980487ccf 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -49,14 +49,18 @@ converted over. Modern compositors like Wayland or Surfaceflinger on Android really want an atomic modeset interface, so this is all about the bright future. -There is a conversion guide for atomic and all you need is a GPU for a -non-converted driver (again virtual HW drivers for KVM are still all -suitable). +There is a conversion guide for atomic [1]_ and all you need is a GPU for a +non-converted driver. The "Atomic mode setting design overview" series [2]_ +[3]_ at LWN.net can also be helpful. As part of this drivers also need to convert to universal plane (which means exposing primary & cursor as proper plane objects). But that's much easier to do by directly using the new atomic helper driver callbacks. + .. [1] https://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html + .. [2] https://lwn.net/Articles/653071/ + .. [3] https://lwn.net/Articles/653466/ + Contact: Daniel Vetter, respective driver maintainers Level: Advanced @@ -456,6 +460,31 @@ Contact: Thomas Zimmermann Level: Starter +Clean up checks for already prepared/enabled in panels +------------------------------------------------------ + +In a whole pile of panel drivers, we have code to make the +prepare/unprepare/enable/disable callbacks behave as no-ops if they've already +been called. To get some idea of the duplicated code, try:: + + git grep 'if.*>prepared' -- drivers/gpu/drm/panel + git grep 'if.*>enabled' -- drivers/gpu/drm/panel + +In the patch ("drm/panel: Check for already prepared/enabled in drm_panel") +we've moved this check to the core. Now we can most definitely remove the +check from the individual panels and save a pile of code. + +In adition to removing the check from the individual panels, it is believed +that even the core shouldn't need this check and that should be considered +an error if other code ever relies on this check. The check in the core +currently prints a warning whenever something is relying on this check with +dev_warn(). After a little while, we likely want to promote this to a +WARN(1) to help encourage folks not to rely on this behavior. + +Contact: Douglas Anderson + +Level: Starter/Intermediate + Core refactorings ================= @@ -753,16 +782,16 @@ existing hardware. The new driver's call-back functions are filled from existing fbdev code. More complex fbdev drivers can be refactored step-by-step into a DRM -driver with the help of the DRM fbconv helpers. [1] These helpers provide +driver with the help of the DRM fbconv helpers [4]_. These helpers provide the transition layer between the DRM core infrastructure and the fbdev driver interface. Create a new DRM driver on top of the fbconv helpers, copy over the fbdev driver, and hook it up to the DRM code. Examples for -several fbdev drivers are available at [1] and a tutorial of this process -available at [2]. The result is a primitive DRM driver that can run X11 -and Weston. +several fbdev drivers are available in Thomas Zimmermann's fbconv tree +[4]_, as well as a tutorial of this process [5]_. The result is a primitive +DRM driver that can run X11 and Weston. - - [1] https://gitlab.freedesktop.org/tzimmermann/linux/tree/fbconv - - [2] https://gitlab.freedesktop.org/tzimmermann/linux/blob/fbconv/drivers/gpu/drm/drm_fbconv_helper.c + .. [4] https://gitlab.freedesktop.org/tzimmermann/linux/tree/fbconv + .. [5] https://gitlab.freedesktop.org/tzimmermann/linux/blob/fbconv/drivers/gpu/drm/drm_fbconv_helper.c Contact: Thomas Zimmermann diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index e9a1cb779b30..a90b64b325b4 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -1292,7 +1292,6 @@ static void update_profiling_data(struct drm_file *file_priv, static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv, bool is_partial) { - struct qaic_partial_execute_entry *pexec; struct qaic_execute *args = data; struct qaic_execute_entry *exec; struct dma_bridge_chan *dbc; @@ -1312,7 +1311,7 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr received_ts = ktime_get_ns(); - size = is_partial ? sizeof(*pexec) : sizeof(*exec); + size = is_partial ? sizeof(struct qaic_partial_execute_entry) : sizeof(*exec); n = (unsigned long)size * args->hdr.count; if (args->hdr.count == 0 || n / args->hdr.count != size) return -EINVAL; @@ -1320,7 +1319,6 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr user_data = u64_to_user_ptr(args->data); exec = kcalloc(args->hdr.count, size, GFP_KERNEL); - pexec = (struct qaic_partial_execute_entry *)exec; if (!exec) return -ENOMEM; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 0d499669d653..b51c6a141dfa 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -11,7 +11,7 @@ menuconfig DRM select DRM_PANEL_ORIENTATION_QUIRKS select DRM_KMS_HELPER if DRM_FBDEV_EMULATION select FB_CORE if DRM_FBDEV_EMULATION - select FB_SYS_HELPERS_DEFERRED if DRM_FBDEV_EMULATION + select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION select HDMI select I2C select DMA_SHARED_BUFFER @@ -224,7 +224,7 @@ config DRM_TTM_HELPER config DRM_GEM_DMA_HELPER tristate depends on DRM - select FB_DMA_HELPERS if DRM_FBDEV_EMULATION + select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION help Choose this if you need the GEM DMA helper functions diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index 5afade25e217..e5597d7c9ae1 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -3,7 +3,7 @@ config DRM_ARMADA tristate "DRM support for Marvell Armada SoCs" depends on DRM && HAVE_CLK && ARM && MMU select DRM_KMS_HELPER - select FB_IO_HELPERS if DRM_FBDEV_EMULATION + select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION help Support the "LCD" controllers found on the Marvell Armada 510 devices. There are two controllers on the device, each controller diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index e40a95e51785..d223176912b6 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -34,7 +34,7 @@ static void armada_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops armada_fb_ops = { .owner = THIS_MODULE, - FB_DEFAULT_IO_OPS, + FB_DEFAULT_IOMEM_OPS, DRM_FB_HELPER_DEFAULT_OPS, .fb_destroy = armada_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index f21eb8fb76d8..3b9bd8ecda13 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -4,6 +4,8 @@ * Rewritten from the dovefb driver, and Armada510 manuals. */ +#include + #include #include #include @@ -445,8 +447,8 @@ static int armada_overlay_get_property(struct drm_plane *plane, drm_to_overlay_state(state)->colorkey_ug, drm_to_overlay_state(state)->colorkey_vb, 0); } else if (property == priv->colorkey_mode_prop) { - *val = (drm_to_overlay_state(state)->colorkey_mode & - CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK); + *val = FIELD_GET(CFG_CKMODE_MASK, + drm_to_overlay_state(state)->colorkey_mode); } else if (property == priv->brightness_prop) { *val = drm_to_overlay_state(state)->brightness + 256; } else if (property == priv->contrast_prop) { diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c index 6dc1a09504e1..fdd9a493aa9c 100644 --- a/drivers/gpu/drm/ast/ast_dp.c +++ b/drivers/gpu/drm/ast/ast_dp.c @@ -7,6 +7,17 @@ #include #include "ast_drv.h" +bool ast_astdp_is_connected(struct ast_device *ast) +{ + if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING)) + return false; + if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)) + return false; + if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS)) + return false; + return true; +} + int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) { struct ast_device *ast = to_ast_device(dev); diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index a5d285850ffb..f10d53b0c94f 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -272,11 +272,9 @@ static bool ast_launch_m68k(struct drm_device *dev) return true; } -bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) +bool ast_dp501_is_connected(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); - u32 i, boot_address, offset, data; - u32 *pEDIDidx; + u32 boot_address, offset, data; if (ast->config_mode == ast_use_p2a) { boot_address = get_fw_base(ast); @@ -292,14 +290,6 @@ bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) data = ast_mindwm(ast, boot_address + offset); if (!(data & AST_DP501_PNP_CONNECTED)) return false; - - /* Read EDID */ - offset = AST_DP501_EDID_DATA; - for (i = 0; i < 128; i += 4) { - data = ast_mindwm(ast, boot_address + offset + i); - pEDIDidx = (u32 *)(ediddata + i); - *pEDIDidx = data; - } } else { if (!ast->dp501_fw_buf) return false; @@ -319,7 +309,30 @@ bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) data = readl(ast->dp501_fw_buf + offset); if (!(data & AST_DP501_PNP_CONNECTED)) return false; + } + return true; +} +bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) +{ + struct ast_device *ast = to_ast_device(dev); + u32 i, boot_address, offset, data; + u32 *pEDIDidx; + + if (!ast_dp501_is_connected(ast)) + return false; + + if (ast->config_mode == ast_use_p2a) { + boot_address = get_fw_base(ast); + + /* Read EDID */ + offset = AST_DP501_EDID_DATA; + for (i = 0; i < 128; i += 4) { + data = ast_mindwm(ast, boot_address + offset + i); + pEDIDidx = (u32 *)(ediddata + i); + *pEDIDidx = data; + } + } else { /* Read EDID */ offset = AST_DP501_EDID_DATA; for (i = 0; i < 128; i += 4) { diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 3f6e0c984523..848a9f1403e8 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -214,6 +214,10 @@ struct ast_device { struct drm_encoder encoder; struct drm_connector connector; } astdp; + struct { + struct drm_encoder encoder; + struct drm_connector connector; + } bmc; } output; bool support_wide_screen; @@ -510,6 +514,7 @@ void ast_patch_ahb_2500(struct ast_device *ast); /* ast dp501 */ void ast_set_dp501_video_output(struct drm_device *dev, u8 mode); bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); +bool ast_dp501_is_connected(struct ast_device *ast); bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); u8 ast_get_dp501_max_clk(struct drm_device *dev); void ast_init_3rdtx(struct drm_device *dev); @@ -518,6 +523,7 @@ void ast_init_3rdtx(struct drm_device *dev); struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev); /* aspeed DP */ +bool ast_astdp_is_connected(struct ast_device *ast); int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata); void ast_dp_launch(struct drm_device *dev); void ast_dp_power_on_off(struct drm_device *dev, bool no); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index f711d592da52..32f04ec6c386 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1582,8 +1582,20 @@ err_drm_connector_update_edid_property: return 0; } +static int ast_dp501_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct ast_device *ast = to_ast_device(connector->dev); + + if (ast_dp501_is_connected(ast)) + return connector_status_connected; + return connector_status_disconnected; +} + static const struct drm_connector_helper_funcs ast_dp501_connector_helper_funcs = { .get_modes = ast_dp501_connector_helper_get_modes, + .detect_ctx = ast_dp501_connector_helper_detect_ctx, }; static const struct drm_connector_funcs ast_dp501_connector_funcs = { @@ -1608,7 +1620,7 @@ static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; return 0; } @@ -1680,8 +1692,20 @@ err_drm_connector_update_edid_property: return 0; } +static int ast_astdp_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct ast_device *ast = to_ast_device(connector->dev); + + if (ast_astdp_is_connected(ast)) + return connector_status_connected; + return connector_status_disconnected; +} + static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = { .get_modes = ast_astdp_connector_helper_get_modes, + .detect_ctx = ast_astdp_connector_helper_detect_ctx, }; static const struct drm_connector_funcs ast_astdp_connector_funcs = { @@ -1706,7 +1730,7 @@ static int ast_astdp_connector_init(struct drm_device *dev, struct drm_connector connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; return 0; } @@ -1735,6 +1759,60 @@ static int ast_astdp_output_init(struct ast_device *ast) return 0; } +/* + * BMC virtual Connector + */ + +static const struct drm_encoder_funcs ast_bmc_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector) +{ + return drm_add_modes_noedid(connector, 4096, 4096); +} + +static const struct drm_connector_helper_funcs ast_bmc_connector_helper_funcs = { + .get_modes = ast_bmc_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs ast_bmc_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_bmc_output_init(struct ast_device *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.bmc.encoder; + struct drm_connector *connector = &ast->output.bmc.connector; + int ret; + + ret = drm_encoder_init(dev, encoder, + &ast_bmc_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, "ast_bmc"); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + if (ret) + return ret; + + drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; + + return 0; +} + /* * Mode config */ @@ -1842,8 +1920,13 @@ int ast_mode_config_init(struct ast_device *ast) if (ret) return ret; } + ret = ast_bmc_output_init(ast); + if (ret) + return ret; drm_mode_config_reset(dev); + drm_kms_helper_poll_init(dev); + return 0; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index 72ab2ab77081..c9e35731e6a1 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -813,7 +813,7 @@ MODULE_DEVICE_TABLE(of, anx6345_match_table); static struct i2c_driver anx6345_driver = { .driver = { .name = "anx6345", - .of_match_table = of_match_ptr(anx6345_match_table), + .of_match_table = anx6345_match_table, }, .probe = anx6345_i2c_probe, .remove = anx6345_i2c_remove, diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 06a3e3243e19..800555aef97f 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -1373,7 +1373,6 @@ static const struct i2c_device_id anx78xx_id[] = { }; MODULE_DEVICE_TABLE(i2c, anx78xx_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id anx78xx_match_table[] = { { .compatible = "analogix,anx7808", .data = anx7808_i2c_addresses }, { .compatible = "analogix,anx7812", .data = anx781x_i2c_addresses }, @@ -1382,12 +1381,11 @@ static const struct of_device_id anx78xx_match_table[] = { { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, anx78xx_match_table); -#endif static struct i2c_driver anx78xx_driver = { .driver = { .name = "anx7814", - .of_match_table = of_match_ptr(anx78xx_match_table), + .of_match_table = anx78xx_match_table, }, .probe = anx78xx_i2c_probe, .remove = anx78xx_i2c_remove, diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 0ff51f945fb0..6af565ac307a 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -2655,7 +2655,7 @@ MODULE_DEVICE_TABLE(of, mhdp_ids); static struct platform_driver mhdp_driver = { .driver = { .name = "cdns-mhdp8546", - .of_match_table = of_match_ptr(mhdp_ids), + .of_match_table = mhdp_ids, }, .probe = cdns_mhdp_probe, .remove = cdns_mhdp_remove, diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index a854eb84e399..483c28c7fc99 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -607,7 +607,7 @@ static struct i2c_driver ch7033_driver = { .remove = ch7033_remove, .driver = { .name = "ch7033", - .of_match_table = of_match_ptr(ch7033_dt_ids), + .of_match_table = ch7033_dt_ids, }, .id_table = ch7033_ids, }; diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 79b09ccd1353..599164e3877d 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2376,7 +2376,7 @@ MODULE_DEVICE_TABLE(i2c, sii8620_id); static struct i2c_driver sii8620_driver = { .driver = { .name = "sii8620", - .of_match_table = of_match_ptr(sii8620_dt_match), + .of_match_table = sii8620_dt_match, }, .probe = sii8620_probe, .remove = sii8620_remove, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c index 9389ce526eb1..be21c11de1f2 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c @@ -62,6 +62,10 @@ struct dw_hdmi_cec { bool rx_done; struct cec_notifier *notify; int irq; + + u8 regs_polarity; + u8 regs_mask; + u8 regs_mute_stat0; }; static void dw_hdmi_write(struct dw_hdmi_cec *cec, u8 val, int offset) @@ -304,11 +308,44 @@ static void dw_hdmi_cec_remove(struct platform_device *pdev) cec_unregister_adapter(cec->adap); } +static int __maybe_unused dw_hdmi_cec_resume(struct device *dev) +{ + struct dw_hdmi_cec *cec = dev_get_drvdata(dev); + + /* Restore logical address */ + dw_hdmi_write(cec, cec->addresses & 255, HDMI_CEC_ADDR_L); + dw_hdmi_write(cec, cec->addresses >> 8, HDMI_CEC_ADDR_H); + + /* Restore interrupt status/mask registers */ + dw_hdmi_write(cec, cec->regs_polarity, HDMI_CEC_POLARITY); + dw_hdmi_write(cec, cec->regs_mask, HDMI_CEC_MASK); + dw_hdmi_write(cec, cec->regs_mute_stat0, HDMI_IH_MUTE_CEC_STAT0); + + return 0; +} + +static int __maybe_unused dw_hdmi_cec_suspend(struct device *dev) +{ + struct dw_hdmi_cec *cec = dev_get_drvdata(dev); + + /* store interrupt status/mask registers */ + cec->regs_polarity = dw_hdmi_read(cec, HDMI_CEC_POLARITY); + cec->regs_mask = dw_hdmi_read(cec, HDMI_CEC_MASK); + cec->regs_mute_stat0 = dw_hdmi_read(cec, HDMI_IH_MUTE_CEC_STAT0); + + return 0; +} + +static const struct dev_pm_ops dw_hdmi_cec_pm = { + SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_cec_suspend, dw_hdmi_cec_resume) +}; + static struct platform_driver dw_hdmi_cec_driver = { .probe = dw_hdmi_cec_probe, .remove_new = dw_hdmi_cec_remove, .driver = { .name = "dw-hdmi-cec", + .pm = &dw_hdmi_cec_pm, }, }; module_platform_driver(dw_hdmi_cec_driver); diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 22b07260a78e..28848a8eb42e 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -448,7 +448,7 @@ MODULE_DEVICE_TABLE(i2c, tfp410_i2c_ids); static struct i2c_driver tfp410_i2c_driver = { .driver = { .name = "tfp410", - .of_match_table = of_match_ptr(tfp410_match), + .of_match_table = tfp410_match, }, .id_table = tfp410_i2c_ids, .probe = tfp410_i2c_probe, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 41b8066f61ff..292e38eb6218 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3332,7 +3332,7 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_all); * that also takes a snapshot of the modeset state to be restored on resume. * * This is just a convenience wrapper around drm_atomic_helper_disable_all(), - * and it is the atomic version of drm_crtc_force_disable_all(). + * and it is the atomic version of drm_helper_force_disable_all(). */ void drm_atomic_helper_shutdown(struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c3d69af02e79..39e68e45bb12 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -27,8 +27,10 @@ #include #include +#include #include #include +#include #include #include @@ -1345,6 +1347,50 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) EXPORT_SYMBOL(of_drm_find_bridge); #endif +#ifdef CONFIG_DEBUG_FS +static int drm_bridge_chains_info(struct seq_file *m, void *data) +{ + struct drm_debugfs_entry *entry = m->private; + struct drm_device *dev = entry->dev; + struct drm_printer p = drm_seq_file_printer(m); + struct drm_mode_config *config = &dev->mode_config; + struct drm_encoder *encoder; + unsigned int bridge_idx = 0; + + list_for_each_entry(encoder, &config->encoder_list, head) { + struct drm_bridge *bridge; + + drm_printf(&p, "encoder[%u]\n", encoder->base.id); + + drm_for_each_bridge_in_chain(encoder, bridge) { + drm_printf(&p, "\tbridge[%u] type: %u, ops: %#x", + bridge_idx, bridge->type, bridge->ops); + +#ifdef CONFIG_OF + if (bridge->of_node) + drm_printf(&p, ", OF: %pOFfc", bridge->of_node); +#endif + + drm_printf(&p, "\n"); + + bridge_idx++; + } + } + + return 0; +} + +static const struct drm_debugfs_info drm_bridge_debugfs_list[] = { + { "bridge_chains", drm_bridge_chains_info, 0 }, +}; + +void drm_bridge_debugfs_init(struct drm_minor *minor) +{ + drm_debugfs_add_files(minor->dev, drm_bridge_debugfs_list, + ARRAY_SIZE(drm_bridge_debugfs_list)); +} +#endif + MODULE_AUTHOR("Ajay Kumar "); MODULE_DESCRIPTION("DRM bridge infrastructure"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index fc6f16e14f36..1da93d5a1f61 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -318,6 +318,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, struct i2c_adapter *ddc = NULL; struct drm_bridge *bridge, *panel_bridge = NULL; int connector_type; + int ret; bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL); if (!bridge_connector) @@ -368,8 +369,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, return ERR_PTR(-EINVAL); } - drm_connector_init_with_ddc(drm, connector, &drm_bridge_connector_funcs, - connector_type, ddc); + ret = drm_connector_init_with_ddc(drm, connector, + &drm_bridge_connector_funcs, + connector_type, ddc); + if (ret) { + kfree(bridge_connector); + return ERR_PTR(ret); + } + drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs); if (bridge_connector->bridge_hpd) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index a3a488205009..2de43ff3ce0a 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -274,6 +275,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, if (drm_drv_uses_atomic_modeset(dev)) { drm_atomic_debugfs_init(minor); + drm_bridge_debugfs_init(minor); } if (drm_core_check_feature(dev, DRIVER_MODESET)) { diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c index 6db168f94290..6c9427bb4053 100644 --- a/drivers/gpu/drm/drm_fbdev_dma.c +++ b/drivers/gpu/drm/drm_fbdev_dma.c @@ -62,9 +62,9 @@ static const struct fb_ops drm_fbdev_dma_fb_ops = { .owner = THIS_MODULE, .fb_open = drm_fbdev_dma_fb_open, .fb_release = drm_fbdev_dma_fb_release, - __FB_DEFAULT_DMA_OPS_RDWR, + __FB_DEFAULT_DMAMEM_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - __FB_DEFAULT_DMA_OPS_DRAW, + __FB_DEFAULT_DMAMEM_OPS_DRAW, .fb_mmap = drm_fbdev_dma_fb_mmap, .fb_destroy = drm_fbdev_dma_fb_destroy, }; diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c index a0ea042b1526..d647d89764cb 100644 --- a/drivers/gpu/drm/drm_fbdev_generic.c +++ b/drivers/gpu/drm/drm_fbdev_generic.c @@ -34,9 +34,9 @@ static int drm_fbdev_generic_fb_release(struct fb_info *info, int user) return 0; } -FB_GEN_DEFAULT_DEFERRED_SYS_OPS(drm_fbdev_generic, - drm_fb_helper_damage_range, - drm_fb_helper_damage_area); +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(drm_fbdev_generic, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area); static void drm_fbdev_generic_fb_destroy(struct fb_info *info) { diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index b8a615a138cd..3bdb6ba37ff4 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -168,8 +168,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev, if (drm_drv_uses_atomic_modeset(dev) && !drm_any_plane_has_format(dev, mode_cmd->pixel_format, mode_cmd->modifier[0])) { - drm_dbg(dev, "Unsupported pixel format %p4cc / modifier 0x%llx\n", - &mode_cmd->pixel_format, mode_cmd->modifier[0]); + drm_dbg_kms(dev, "Unsupported pixel format %p4cc / modifier 0x%llx\n", + &mode_cmd->pixel_format, mode_cmd->modifier[0]); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index c871d9f096b8..e90f0bf895b3 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -1140,10 +1140,13 @@ static int mipi_dbi_typec3_command_read(struct mipi_dbi *dbi, u8 *cmd, return -ENOMEM; tr[1].rx_buf = buf; + + spi_bus_lock(spi->controller); gpiod_set_value_cansleep(dbi->dc, 0); spi_message_init_with_transfers(&m, tr, ARRAY_SIZE(tr)); - ret = spi_sync(spi, &m); + ret = spi_sync_locked(spi, &m); + spi_bus_unlock(spi->controller); if (ret) goto err_free; @@ -1177,19 +1180,24 @@ static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd, MIPI_DBI_DEBUG_COMMAND(*cmd, par, num); + spi_bus_lock(spi->controller); gpiod_set_value_cansleep(dbi->dc, 0); speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1); ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, cmd, 1); + spi_bus_unlock(spi->controller); if (ret || !num) return ret; if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !dbi->swap_bytes) bpw = 16; + spi_bus_lock(spi->controller); gpiod_set_value_cansleep(dbi->dc, 1); speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num); + ret = mipi_dbi_spi_transfer(spi, speed_hz, bpw, par, num); + spi_bus_unlock(spi->controller); - return mipi_dbi_spi_transfer(spi, speed_hz, bpw, par, num); + return ret; } /** @@ -1271,7 +1279,8 @@ EXPORT_SYMBOL(mipi_dbi_spi_init); * @len: Buffer length * * This SPI transfer helper breaks up the transfer of @buf into chunks which - * the SPI controller driver can handle. + * the SPI controller driver can handle. The SPI bus must be locked when + * calling this. * * Returns: * Zero on success, negative error code on failure. @@ -1305,7 +1314,7 @@ int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz, buf += chunk; len -= chunk; - ret = spi_sync(spi, &m); + ret = spi_sync_locked(spi, &m); if (ret) return ret; } diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index f634371c717a..e814020bbcd3 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -58,6 +58,8 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev, const struct drm_panel_funcs *funcs, int connector_type) { INIT_LIST_HEAD(&panel->list); + INIT_LIST_HEAD(&panel->followers); + mutex_init(&panel->follower_lock); panel->dev = dev; panel->funcs = funcs; panel->connector_type = connector_type; @@ -105,13 +107,38 @@ EXPORT_SYMBOL(drm_panel_remove); */ int drm_panel_prepare(struct drm_panel *panel) { + struct drm_panel_follower *follower; + int ret; + if (!panel) return -EINVAL; - if (panel->funcs && panel->funcs->prepare) - return panel->funcs->prepare(panel); + if (panel->prepared) { + dev_warn(panel->dev, "Skipping prepare of already prepared panel\n"); + return 0; + } - return 0; + mutex_lock(&panel->follower_lock); + + if (panel->funcs && panel->funcs->prepare) { + ret = panel->funcs->prepare(panel); + if (ret < 0) + goto exit; + } + panel->prepared = true; + + list_for_each_entry(follower, &panel->followers, list) { + ret = follower->funcs->panel_prepared(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_prepared, ret); + } + + ret = 0; +exit: + mutex_unlock(&panel->follower_lock); + + return ret; } EXPORT_SYMBOL(drm_panel_prepare); @@ -128,13 +155,38 @@ EXPORT_SYMBOL(drm_panel_prepare); */ int drm_panel_unprepare(struct drm_panel *panel) { + struct drm_panel_follower *follower; + int ret; + if (!panel) return -EINVAL; - if (panel->funcs && panel->funcs->unprepare) - return panel->funcs->unprepare(panel); + if (!panel->prepared) { + dev_warn(panel->dev, "Skipping unprepare of already unprepared panel\n"); + return 0; + } - return 0; + mutex_lock(&panel->follower_lock); + + list_for_each_entry(follower, &panel->followers, list) { + ret = follower->funcs->panel_unpreparing(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_unpreparing, ret); + } + + if (panel->funcs && panel->funcs->unprepare) { + ret = panel->funcs->unprepare(panel); + if (ret < 0) + goto exit; + } + panel->prepared = false; + + ret = 0; +exit: + mutex_unlock(&panel->follower_lock); + + return ret; } EXPORT_SYMBOL(drm_panel_unprepare); @@ -155,11 +207,17 @@ int drm_panel_enable(struct drm_panel *panel) if (!panel) return -EINVAL; + if (panel->enabled) { + dev_warn(panel->dev, "Skipping enable of already enabled panel\n"); + return 0; + } + if (panel->funcs && panel->funcs->enable) { ret = panel->funcs->enable(panel); if (ret < 0) return ret; } + panel->enabled = true; ret = backlight_enable(panel->backlight); if (ret < 0) @@ -187,13 +245,22 @@ int drm_panel_disable(struct drm_panel *panel) if (!panel) return -EINVAL; + if (!panel->enabled) { + dev_warn(panel->dev, "Skipping disable of already disabled panel\n"); + return 0; + } + ret = backlight_disable(panel->backlight); if (ret < 0) DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n", ret); - if (panel->funcs && panel->funcs->disable) - return panel->funcs->disable(panel); + if (panel->funcs && panel->funcs->disable) { + ret = panel->funcs->disable(panel); + if (ret < 0) + return ret; + } + panel->enabled = false; return 0; } @@ -305,6 +372,141 @@ int of_drm_get_panel_orientation(const struct device_node *np, EXPORT_SYMBOL(of_drm_get_panel_orientation); #endif +/** + * drm_is_panel_follower() - Check if the device is a panel follower + * @dev: The 'struct device' to check + * + * This checks to see if a device needs to be power sequenced together with + * a panel using the panel follower API. + * At the moment panels can only be followed on device tree enabled systems. + * The "panel" property of the follower points to the panel to be followed. + * + * Return: true if we should be power sequenced with a panel; false otherwise. + */ +bool drm_is_panel_follower(struct device *dev) +{ + /* + * The "panel" property is actually a phandle, but for simplicity we + * don't bother trying to parse it here. We just need to know if the + * property is there. + */ + return of_property_read_bool(dev->of_node, "panel"); +} +EXPORT_SYMBOL(drm_is_panel_follower); + +/** + * drm_panel_add_follower() - Register something to follow panel state. + * @follower_dev: The 'struct device' for the follower. + * @follower: The panel follower descriptor for the follower. + * + * A panel follower is called right after preparing the panel and right before + * unpreparing the panel. It's primary intention is to power on an associated + * touchscreen, though it could be used for any similar devices. Multiple + * devices are allowed the follow the same panel. + * + * If a follower is added to a panel that's already been turned on, the + * follower's prepare callback is called right away. + * + * At the moment panels can only be followed on device tree enabled systems. + * The "panel" property of the follower points to the panel to be followed. + * + * Return: 0 or an error code. Note that -ENODEV means that we detected that + * follower_dev is not actually following a panel. The caller may + * choose to ignore this return value if following a panel is optional. + */ +int drm_panel_add_follower(struct device *follower_dev, + struct drm_panel_follower *follower) +{ + struct device_node *panel_np; + struct drm_panel *panel; + int ret; + + panel_np = of_parse_phandle(follower_dev->of_node, "panel", 0); + if (!panel_np) + return -ENODEV; + + panel = of_drm_find_panel(panel_np); + of_node_put(panel_np); + if (IS_ERR(panel)) + return PTR_ERR(panel); + + get_device(panel->dev); + follower->panel = panel; + + mutex_lock(&panel->follower_lock); + + list_add_tail(&follower->list, &panel->followers); + if (panel->prepared) { + ret = follower->funcs->panel_prepared(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_prepared, ret); + } + + mutex_unlock(&panel->follower_lock); + + return 0; +} +EXPORT_SYMBOL(drm_panel_add_follower); + +/** + * drm_panel_remove_follower() - Reverse drm_panel_add_follower(). + * @follower: The panel follower descriptor for the follower. + * + * Undo drm_panel_add_follower(). This includes calling the follower's + * unprepare function if we're removed from a panel that's currently prepared. + * + * Return: 0 or an error code. + */ +void drm_panel_remove_follower(struct drm_panel_follower *follower) +{ + struct drm_panel *panel = follower->panel; + int ret; + + mutex_lock(&panel->follower_lock); + + if (panel->prepared) { + ret = follower->funcs->panel_unpreparing(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_unpreparing, ret); + } + list_del_init(&follower->list); + + mutex_unlock(&panel->follower_lock); + + put_device(panel->dev); +} +EXPORT_SYMBOL(drm_panel_remove_follower); + +static void drm_panel_remove_follower_void(void *follower) +{ + drm_panel_remove_follower(follower); +} + +/** + * devm_drm_panel_add_follower() - devm version of drm_panel_add_follower() + * @follower_dev: The 'struct device' for the follower. + * @follower: The panel follower descriptor for the follower. + * + * Handles calling drm_panel_remove_follower() using devm on the follower_dev. + * + * Return: 0 or an error code. + */ +int devm_drm_panel_add_follower(struct device *follower_dev, + struct drm_panel_follower *follower) +{ + int ret; + + ret = drm_panel_add_follower(follower_dev, follower); + if (ret) + return ret; + + return devm_add_action_or_reset(follower_dev, + drm_panel_remove_follower_void, follower); +} +EXPORT_SYMBOL(devm_drm_panel_add_follower); + #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) /** * drm_panel_of_backlight - use backlight device node for backlight diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index c91e454eba09..5e95089676ff 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -40,8 +40,8 @@ /** * DOC: overview * - * This helper library has two parts. The first part has support to implement - * primary plane support on top of the normal CRTC configuration interface. + * This helper library contains helpers to implement primary plane support on + * top of the normal CRTC configuration interface. * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary * plane together with the CRTC state this does not allow userspace to disable * the primary plane itself. The default primary plane only expose XRBG8888 and @@ -51,14 +51,6 @@ * planes, and newly merged drivers must not rely upon these transitional * helpers. * - * The second part also implements transitional helpers which allow drivers to - * gradually switch to the atomic helper infrastructure for plane updates. Once - * that switch is complete drivers shouldn't use these any longer, instead using - * the proper legacy implementations for update and disable plane hooks provided - * by the atomic helpers. - * - * Again drivers are strongly urged to switch to the new interfaces. - * * The plane helpers share the function table structures with other helpers, * specifically also the atomic helpers. See &struct drm_plane_helper_funcs for * the details. diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 661b42ad4873..733b109a5095 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -7,7 +7,7 @@ config DRM_EXYNOS select DRM_DISPLAY_HELPER if DRM_EXYNOS_DP select DRM_KMS_HELPER select VIDEOMODE_HELPERS - select FB_DMA_HELPERS if DRM_FBDEV_EMULATION + select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION select SND_SOC_HDMI_CODEC if SND_SOC help Choose this option if you have a Samsung SoC Exynos chipset. diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 4ccb385aff52..a379c8ca435a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -49,9 +49,9 @@ static void exynos_drm_fb_destroy(struct fb_info *info) static const struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, - __FB_DEFAULT_DMA_OPS_RDWR, + __FB_DEFAULT_DMAMEM_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, - __FB_DEFAULT_DMA_OPS_DRAW, + __FB_DEFAULT_DMAMEM_OPS_DRAW, .fb_mmap = exynos_drm_fb_mmap, .fb_destroy = exynos_drm_fb_destroy, }; diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index cd3d92725ed4..efb4a2dd2f80 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -3,7 +3,7 @@ config DRM_GMA500 tristate "Intel GMA500/600/3600/3650 KMS Framebuffer" depends on DRM && PCI && X86 && MMU select DRM_KMS_HELPER - select FB_IO_HELPERS if DRM_FBDEV_EMULATION + select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION select I2C select I2C_ALGOBIT # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c index be8f5fbd5260..98b44974d42d 100644 --- a/drivers/gpu/drm/gma500/fbdev.c +++ b/drivers/gpu/drm/gma500/fbdev.c @@ -135,10 +135,10 @@ static void psb_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops psb_fbdev_fb_ops = { .owner = THIS_MODULE, - __FB_DEFAULT_IO_OPS_RDWR, + __FB_DEFAULT_IOMEM_OPS_RDWR, DRM_FB_HELPER_DEFAULT_OPS, .fb_setcolreg = psb_fbdev_fb_setcolreg, - __FB_DEFAULT_IO_OPS_DRAW, + __FB_DEFAULT_IOMEM_OPS_DRAW, .fb_mmap = psb_fbdev_fb_mmap, .fb_destroy = psb_fbdev_fb_destroy, }; diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 01b5a8272a27..ce397a8797f7 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -17,7 +17,7 @@ config DRM_I915 select DRM_KMS_HELPER select DRM_PANEL select DRM_MIPI_DSI - select FB_IO_HELPERS if DRM_FBDEV_EMULATION + select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION select RELAY select I2C select I2C_ALGOBIT diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 1cc0ddc6a310..f1439827bc80 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -85,9 +85,9 @@ static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev) intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU); } -FB_GEN_DEFAULT_DEFERRED_IO_OPS(intel_fbdev, - drm_fb_helper_damage_range, - drm_fb_helper_damage_area) +FB_GEN_DEFAULT_DEFERRED_IOMEM_OPS(intel_fbdev, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area) static int intel_fbdev_set_par(struct fb_info *info) { diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index 4a33ad2d122b..d4b918fb11ce 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -186,7 +186,7 @@ i915_gem_object_wait(struct drm_i915_gem_object *obj, static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) { /* nsecs_to_jiffies64() does not guard against overflow */ - if (NSEC_PER_SEC % HZ && + if ((NSEC_PER_SEC % HZ) != 0 && div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ) return MAX_JIFFY_OFFSET; diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 894068bb37b6..32323bb801a1 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1220,7 +1220,7 @@ emit_semaphore_wait(struct i915_request *to, /* * If this or its dependents are waiting on an external fence * that may fail catastrophically, then we want to avoid using - * sempahores as they bypass the fence signaling metadata, and we + * semaphores as they bypass the fence signaling metadata, and we * lose the fence->error propagation. */ if (from->sched.flags & I915_SCHED_HAS_EXTERNAL_CHAIN) diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c index 4f2291610139..c68b0d93ae9e 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-drv.c +++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c @@ -66,6 +66,7 @@ static int dcss_drv_platform_probe(struct platform_device *pdev) mdrv->kms = dcss_kms_attach(mdrv->dcss); if (IS_ERR(mdrv->kms)) { err = PTR_ERR(mdrv->kms); + dev_err_probe(dev, err, "Failed to initialize KMS\n"); goto dcss_shutoff; } diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index 80142d9a4a55..dade8b59feae 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -618,6 +618,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, width = ipu_src_rect_width(new_state); else width = drm_rect_width(&new_state->src) >> 16; + height = drm_rect_height(&new_state->src) >> 16; eba = drm_plane_state_to_eba(new_state, 0); @@ -628,9 +629,9 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, if (ipu_state->use_pre) { axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, width, - drm_rect_height(&new_state->src) >> 16, - fb->pitches[0], fb->format->format, - fb->modifier, &eba); + height, fb->pitches[0], + fb->format->format, fb->modifier, + &eba); } if (!old_state->fb || @@ -684,7 +685,6 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_dmfc_config_wait4eot(ipu_plane->dmfc, width); - height = drm_rect_height(&new_state->src) >> 16; info = drm_format_info(fb->format->format); ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], &burstsize, &num_bursts); @@ -747,8 +747,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16); ipu_cpmem_zero(ipu_plane->alpha_ch); - ipu_cpmem_set_resolution(ipu_plane->alpha_ch, width, - drm_rect_height(&new_state->src) >> 16); + ipu_cpmem_set_resolution(ipu_plane->alpha_ch, width, height); ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8); ipu_cpmem_set_high_priority(ipu_plane->alpha_ch); ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1); diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index a78662bd6273..6309a857ca31 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -21,7 +21,7 @@ config DRM_MSM select DRM_BRIDGE select DRM_PANEL_BRIDGE select DRM_SCHED - select FB_SYS_HELPERS if DRM_FBDEV_EMULATION + select FB_SYSMEM_HELPERS if DRM_FBDEV_EMULATION select SHMEM select TMPFS select QCOM_SCM diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index bf1e17dc4550..030bedac632d 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -25,9 +25,9 @@ module_param(fbdev, bool, 0600); * fbdev funcs, to implement legacy fbdev interface on top of drm driver */ -FB_GEN_DEFAULT_DEFERRED_SYS_OPS(msm_fbdev, - drm_fb_helper_damage_range, - drm_fb_helper_damage_area) +FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(msm_fbdev, + drm_fb_helper_damage_range, + drm_fb_helper_damage_area) static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 40c8ea43c42f..b8ac66b4a2c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -26,6 +26,8 @@ #include "head.h" #include "ior.h" +#include + #include #include #include @@ -634,6 +636,50 @@ nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp) return outp->dp.rates != 0; } +/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps() + * converted to work inside nvkm. This is a temporary holdover until we start + * passing the drm_dp_aux device through NVKM + */ +static int +nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp) +{ + struct nvkm_i2c_aux *aux = outp->dp.aux; + u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; + int ret; + + ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE); + if (ret < 0) + return ret; + + /* + * Prior to DP1.3 the bit represented by + * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved. + * If it is set DP_DPCD_REV at 0000h could be at a value less than + * the true capability of the panel. The only way to check is to + * then compare 0000h and 2200h. + */ + if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)) + return 0; + + ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext)); + if (ret < 0) + return ret; + + if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { + OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n", + outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]); + return 0; + } + + if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext))) + return 0; + + memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)); + + return 0; +} + void nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) { @@ -689,7 +735,7 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr) memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr)); } - if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, sizeof(outp->dp.dpcd))) { + if (!nvkm_dp_read_dpcd_caps(outp)) { const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 }; const u8 *rate; int rate_max; diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index d3c4877e465c..b715301ec79f 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -4,7 +4,7 @@ config DRM_OMAP depends on DRM && OF depends on ARCH_OMAP2PLUS select DRM_KMS_HELPER - select FB_DMA_HELPERS if DRM_FBDEV_EMULATION + select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION select VIDEOMODE_HELPERS select HDMI default n diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 5b33c789e17a..6b08b137af1a 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -106,13 +106,13 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) static const struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, - __FB_DEFAULT_DMA_OPS_RDWR, + __FB_DEFAULT_DMAMEM_OPS_RDWR, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_setcmap = drm_fb_helper_setcmap, .fb_blank = drm_fb_helper_blank, .fb_pan_display = omap_fbdev_pan_display, - __FB_DEFAULT_DMA_OPS_DRAW, + __FB_DEFAULT_DMAMEM_OPS_DRAW, .fb_ioctl = drm_fb_helper_ioctl, .fb_mmap = omap_fbdev_fb_mmap, .fb_destroy = omap_fbdev_fb_destroy, diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 05f9e800e448..869e535faefa 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -734,6 +734,17 @@ config DRM_PANEL_SONY_TULIP_TRULY_NT35521 NT35521 1280x720 video mode panel as found on Sony Xperia M4 Aqua phone. +config DRM_PANEL_STARTEK_KD070FHFID015 + tristate "STARTEK KD070FHFID015 panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for STARTEK KD070FHFID015 DSI panel + based on RENESAS-R69429 controller. The pannel is a 7-inch TFT LCD display + with a resolution of 1024 x 600 pixels. It provides a MIPI DSI interface to + the host, a built-in LED backlight and touch controller. + config DRM_PANEL_TDO_TL070WSH30 tristate "TDO TL070WSH30 DSI panel" depends on OF @@ -799,6 +810,8 @@ config DRM_PANEL_VISIONOX_R66451 depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER help Say Y here if you want to enable support for Visionox R66451 1080x2340 AMOLED DSI panel. diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 499e38244253..433e93d57949 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o +obj-$(CONFIG_DRM_PANEL_STARTEK_KD070FHFID015) += panel-startek-kd070fhfid015.o obj-$(CONFIG_DRM_PANEL_TDO_TL070WSH30) += panel-tdo-tl070wsh30.o obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index df7e3cff004c..feb665df35a1 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1890,6 +1890,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x854a, &delay_200_500_p2e100, "M133NW4J"), diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 72dbb8184280..7838947a1bf3 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -455,6 +455,174 @@ static const struct ili9881c_instr k101_im2byl02_init[] = { ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ }; +static const struct ili9881c_instr tl050hdv35_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0a), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x01), + ILI9881C_COMMAND_INSTR(0x0a, 0x00), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x01), + ILI9881C_COMMAND_INSTR(0x0d, 0x00), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x1d), + ILI9881C_COMMAND_INSTR(0x10, 0x1d), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0x40), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x02), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3C), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x40), + ILI9881C_COMMAND_INSTR(0x3b, 0x40), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x55, 0xab), + ILI9881C_COMMAND_INSTR(0x5a, 0x89), + ILI9881C_COMMAND_INSTR(0x5b, 0xab), + ILI9881C_COMMAND_INSTR(0x5c, 0xcd), + ILI9881C_COMMAND_INSTR(0x5d, 0xef), + ILI9881C_COMMAND_INSTR(0x5e, 0x11), + ILI9881C_COMMAND_INSTR(0x5f, 0x01), + ILI9881C_COMMAND_INSTR(0x60, 0x00), + ILI9881C_COMMAND_INSTR(0x61, 0x15), + ILI9881C_COMMAND_INSTR(0x62, 0x14), + ILI9881C_COMMAND_INSTR(0x63, 0x0e), + ILI9881C_COMMAND_INSTR(0x64, 0x0f), + ILI9881C_COMMAND_INSTR(0x65, 0x0c), + ILI9881C_COMMAND_INSTR(0x66, 0x0d), + ILI9881C_COMMAND_INSTR(0x67, 0x06), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x07), + ILI9881C_COMMAND_INSTR(0x6a, 0x02), + ILI9881C_COMMAND_INSTR(0x6b, 0x02), + ILI9881C_COMMAND_INSTR(0x6c, 0x02), + ILI9881C_COMMAND_INSTR(0x6d, 0x02), + ILI9881C_COMMAND_INSTR(0x6e, 0x02), + ILI9881C_COMMAND_INSTR(0x6f, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x01), + ILI9881C_COMMAND_INSTR(0x76, 0x00), + ILI9881C_COMMAND_INSTR(0x77, 0x14), + ILI9881C_COMMAND_INSTR(0x78, 0x15), + ILI9881C_COMMAND_INSTR(0x79, 0x0e), + ILI9881C_COMMAND_INSTR(0x7a, 0x0f), + ILI9881C_COMMAND_INSTR(0x7b, 0x0c), + ILI9881C_COMMAND_INSTR(0x7c, 0x0d), + ILI9881C_COMMAND_INSTR(0x7d, 0x06), + ILI9881C_COMMAND_INSTR(0x7e, 0x02), + ILI9881C_COMMAND_INSTR(0x7f, 0x07), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x38, 0x01), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x6c, 0x15), + ILI9881C_COMMAND_INSTR(0x6e, 0x2b), + ILI9881C_COMMAND_INSTR(0x6f, 0x33), + ILI9881C_COMMAND_INSTR(0x8d, 0x18), + ILI9881C_COMMAND_INSTR(0x87, 0xba), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xb2, 0xd1), + ILI9881C_COMMAND_INSTR(0xb5, 0x06), + ILI9881C_COMMAND_INSTR(0x3a, 0x24), + ILI9881C_COMMAND_INSTR(0x35, 0x1f), + ILI9881C_COMMAND_INSTR(0x33, 0x14), + ILI9881C_COMMAND_INSTR(0x3b, 0x98), + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0a), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x33), + ILI9881C_COMMAND_INSTR(0x53, 0xa2), + ILI9881C_COMMAND_INSTR(0x55, 0x92), + ILI9881C_COMMAND_INSTR(0x50, 0x96), + ILI9881C_COMMAND_INSTR(0x51, 0x96), + ILI9881C_COMMAND_INSTR(0x60, 0x22), + ILI9881C_COMMAND_INSTR(0x61, 0x00), + ILI9881C_COMMAND_INSTR(0x62, 0x19), + ILI9881C_COMMAND_INSTR(0x63, 0x00), + ILI9881C_COMMAND_INSTR(0xa0, 0x08), + ILI9881C_COMMAND_INSTR(0xa1, 0x11), + ILI9881C_COMMAND_INSTR(0xa2, 0x19), + ILI9881C_COMMAND_INSTR(0xa3, 0x0d), + ILI9881C_COMMAND_INSTR(0xa4, 0x0d), + ILI9881C_COMMAND_INSTR(0xa5, 0x1e), + ILI9881C_COMMAND_INSTR(0xa6, 0x14), + ILI9881C_COMMAND_INSTR(0xa7, 0x17), + ILI9881C_COMMAND_INSTR(0xa8, 0x4f), + ILI9881C_COMMAND_INSTR(0xa9, 0x1a), + ILI9881C_COMMAND_INSTR(0xaa, 0x27), + ILI9881C_COMMAND_INSTR(0xab, 0x49), + ILI9881C_COMMAND_INSTR(0xac, 0x1a), + ILI9881C_COMMAND_INSTR(0xad, 0x18), + ILI9881C_COMMAND_INSTR(0xae, 0x4c), + ILI9881C_COMMAND_INSTR(0xaf, 0x22), + ILI9881C_COMMAND_INSTR(0xb0, 0x27), + ILI9881C_COMMAND_INSTR(0xb1, 0x4b), + ILI9881C_COMMAND_INSTR(0xb2, 0x60), + ILI9881C_COMMAND_INSTR(0xb3, 0x39), + ILI9881C_COMMAND_INSTR(0xc0, 0x08), + ILI9881C_COMMAND_INSTR(0xc1, 0x11), + ILI9881C_COMMAND_INSTR(0xc2, 0x19), + ILI9881C_COMMAND_INSTR(0xc3, 0x0d), + ILI9881C_COMMAND_INSTR(0xc4, 0x0d), + ILI9881C_COMMAND_INSTR(0xc5, 0x1e), + ILI9881C_COMMAND_INSTR(0xc6, 0x14), + ILI9881C_COMMAND_INSTR(0xc7, 0x17), + ILI9881C_COMMAND_INSTR(0xc8, 0x4f), + ILI9881C_COMMAND_INSTR(0xc9, 0x1a), + ILI9881C_COMMAND_INSTR(0xca, 0x27), + ILI9881C_COMMAND_INSTR(0xcb, 0x49), + ILI9881C_COMMAND_INSTR(0xcc, 0x1a), + ILI9881C_COMMAND_INSTR(0xcd, 0x18), + ILI9881C_COMMAND_INSTR(0xce, 0x4c), + ILI9881C_COMMAND_INSTR(0xcf, 0x33), + ILI9881C_COMMAND_INSTR(0xd0, 0x27), + ILI9881C_COMMAND_INSTR(0xd1, 0x4b), + ILI9881C_COMMAND_INSTR(0xd2, 0x60), + ILI9881C_COMMAND_INSTR(0xd3, 0x39), + ILI9881C_SWITCH_PAGE_INSTR(0), + ILI9881C_COMMAND_INSTR(0x36, 0x03), +}; + static const struct ili9881c_instr w552946ab_init[] = { ILI9881C_SWITCH_PAGE_INSTR(3), ILI9881C_COMMAND_INSTR(0x01, 0x00), @@ -812,6 +980,23 @@ static const struct drm_display_mode k101_im2byl02_default_mode = { .height_mm = 217, }; +static const struct drm_display_mode tl050hdv35_default_mode = { + .clock = 59400, + + .hdisplay = 720, + .hsync_start = 720 + 18, + .hsync_end = 720 + 18 + 3, + .htotal = 720 + 18 + 3 + 20, + + .vdisplay = 1280, + .vsync_start = 1280 + 26, + .vsync_end = 1280 + 26 + 6, + .vtotal = 1280 + 26 + 6 + 28, + + .width_mm = 62, + .height_mm = 110, +}; + static const struct drm_display_mode w552946aba_default_mode = { .clock = 64000, @@ -944,6 +1129,14 @@ static const struct ili9881c_desc k101_im2byl02_desc = { .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, }; +static const struct ili9881c_desc tl050hdv35_desc = { + .init = tl050hdv35_init, + .init_length = ARRAY_SIZE(tl050hdv35_init), + .mode = &tl050hdv35_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, +}; + static const struct ili9881c_desc w552946aba_desc = { .init = w552946ab_init, .init_length = ARRAY_SIZE(w552946ab_init), @@ -955,6 +1148,7 @@ static const struct ili9881c_desc w552946aba_desc = { static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, + { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, { } }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 4badda6570d5..72cef64441a6 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1185,7 +1185,9 @@ static const struct panel_desc auo_t215hvn01 = { .delay = { .disable = 5, .unprepare = 1000, - } + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, }; static const struct drm_display_mode avic_tm070ddh03_mode = { @@ -2374,6 +2376,37 @@ static const struct panel_desc innolux_g121x1_l03 = { }, }; +static const struct display_timing innolux_g156hce_l01_timings = { + .pixelclock = { 120000000, 144000000, 150000000 }, + .hactive = { 1920, 1920, 1920 }, + .hfront_porch = { 80, 90, 100 }, + .hback_porch = { 80, 90, 100 }, + .hsync_len = { 20, 30, 30 }, + .vactive = { 1080, 1080, 1080 }, + .vfront_porch = { 3, 10, 20 }, + .vback_porch = { 3, 10, 20 }, + .vsync_len = { 4, 10, 10 }, +}; + +static const struct panel_desc innolux_g156hce_l01 = { + .timings = &innolux_g156hce_l01_timings, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 344, + .height = 194, + }, + .delay = { + .prepare = 1, /* T1+T2 */ + .enable = 450, /* T5 */ + .disable = 200, /* T6 */ + .unprepare = 10, /* T3+T7 */ + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode innolux_n156bge_l21_mode = { .clock = 69300, .hdisplay = 1366, @@ -3205,6 +3238,7 @@ static const struct drm_display_mode powertip_ph800480t013_idf02_mode = { static const struct panel_desc powertip_ph800480t013_idf02 = { .modes = &powertip_ph800480t013_idf02_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 152, .height = 91, @@ -4239,6 +4273,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "innolux,g121x1-l03", .data = &innolux_g121x1_l03, + }, { + .compatible = "innolux,g156hce-l01", + .data = &innolux_g156hce_l01, }, { .compatible = "innolux,n156bge-l21", .data = &innolux_n156bge_l21, @@ -4455,13 +4492,13 @@ MODULE_DEVICE_TABLE(of, platform_of_match); static int panel_simple_platform_probe(struct platform_device *pdev) { - const struct of_device_id *id; + const struct panel_desc *desc; - id = of_match_node(platform_of_match, pdev->dev.of_node); - if (!id) + desc = of_device_get_match_data(&pdev->dev); + if (!desc) return -ENODEV; - return panel_simple_probe(&pdev->dev, id->data); + return panel_simple_probe(&pdev->dev, desc); } static void panel_simple_platform_remove(struct platform_device *pdev) @@ -4732,15 +4769,12 @@ MODULE_DEVICE_TABLE(of, dsi_of_match); static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) { const struct panel_desc_dsi *desc; - const struct of_device_id *id; int err; - id = of_match_node(dsi_of_match, dsi->dev.of_node); - if (!id) + desc = of_device_get_match_data(&dsi->dev); + if (!desc) return -ENODEV; - desc = id->data; - err = panel_simple_probe(&dsi->dev, &desc->desc); if (err < 0) return err; diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index bbc4569cbcdc..dc010d87a9ef 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -10,14 +10,12 @@ #include #include