diff options
84 files changed, 1797 insertions, 680 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 3624363938dd..eda427ddca1b 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -46,9 +46,13 @@ properties: # AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel - auo,b116xw03 # AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel + - auo,b133han05 + # AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel - auo,b133htn01 # AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel - auo,b133xtn01 + # AU Optronics Corporation 14.0" FHD (1920x1080) color TFT-LCD panel + - auo,b140han06 # AU Optronics Corporation 7.0" FHD (800 x 480) TFT LCD panel - auo,g070vvn01 # AU Optronics Corporation 10.1" (1280x800) color TFT LCD panel @@ -208,8 +212,14 @@ properties: - logictechno,lt161010-2nhr # Logic Technologies LT170410-2WHC 10.1" 1280x800 IPS TFT Cap Touch Mod. - logictechno,lt170410-2whc + # Logic Technologies LTTD800x480 L2RT 7" 800x480 TFT Resistive Touch Module + - logictechno,lttd800480070-l2rt + # Logic Technologies LTTD800480070-L6WH-RT 7” 800x480 TFT Resistive Touch Module + - logictechno,lttd800480070-l6wh-rt # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel - mitsubishi,aa070mc01-ca1 + # Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod. + - multi-inno,mi1010ait-1cp # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel - nec,nl12880bc20-05 # NEC LCD Technologies,Ltd. WQVGA TFT LCD panel diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index 151be3bba06f..39792f051d2d 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -23,6 +23,7 @@ Required properties: Optional properties: - phys: from general PHY binding: the phandle for the PHY device. - phy-names: Should be "dphy" if phys references an external phy. +- #phy-cells: Defined when used as ISP phy, should be 0. - power-domains: a phandle to mipi dsi power domain node. - resets: list of phandle + reset specifier pairs, as described in [3]. - reset-names: string reset name, must be "apb". diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml new file mode 100644 index 000000000000..2ed2a7d0ca2f --- /dev/null +++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml @@ -0,0 +1,208 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/solomon,ssd1307fb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Solomon SSD1307 OLED Controller Framebuffer + +maintainers: + - Maxime Ripard <mripard@kernel.org> + +properties: + compatible: + enum: + - solomon,ssd1305fb-i2c + - solomon,ssd1306fb-i2c + - solomon,ssd1307fb-i2c + - solomon,ssd1309fb-i2c + + reg: + maxItems: 1 + + pwms: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + vbat-supply: + description: The supply for VBAT + + solomon,height: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 16 + description: + Height in pixel of the screen driven by the controller + + solomon,width: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 96 + description: + Width in pixel of the screen driven by the controller + + solomon,page-offset: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 1 + description: + Offset of pages (band of 8 pixels) that the screen is mapped to + + solomon,segment-no-remap: + type: boolean + description: + Display needs normal (non-inverted) data column to segment mapping + + solomon,col-offset: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + description: + Offset of columns (COL/SEG) that the screen is mapped to + + solomon,com-seq: + type: boolean + description: + Display uses sequential COM pin configuration + + solomon,com-lrremap: + type: boolean + description: + Display uses left-right COM pin remap + + solomon,com-invdir: + type: boolean + description: + Display uses inverted COM pin scan direction + + solomon,com-offset: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + description: + Number of the COM pin wired to the first display line + + solomon,prechargep1: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 2 + description: + Length of deselect period (phase 1) in clock cycles + + solomon,prechargep2: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 2 + description: + Length of precharge period (phase 2) in clock cycles. This needs to be + the higher, the higher the capacitance of the OLED's pixels is. + + solomon,dclk-div: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 16 + description: + Clock divisor. The default value is controller-dependent. + + solomon,dclk-frq: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + description: + Clock frequency, higher value means higher frequency. + The default value is controller-dependent. + + solomon,lookup-table: + $ref: /schemas/types.yaml#/definitions/uint8-array + maxItems: 4 + description: + 8 bit value array of current drive pulse widths for BANK0, and colors A, + B, and C. Each value in range of 31 to 63 for pulse widths of 32 to 64. + Color D is always width 64. + + solomon,area-color-enable: + type: boolean + description: + Display uses color mode + + solomon,low-power: + type: boolean + description: + Display runs in low power mode + +required: + - compatible + - reg + +allOf: + - if: + properties: + compatible: + contains: + const: solomon,ssd1305fb-i2c + then: + properties: + solomon,dclk-div: + default: 1 + solomon,dclk-frq: + default: 7 + + - if: + properties: + compatible: + contains: + const: solomon,ssd1306fb-i2c + then: + properties: + solomon,dclk-div: + default: 1 + solomon,dclk-frq: + default: 8 + + - if: + properties: + compatible: + contains: + const: solomon,ssd1307fb-i2c + then: + properties: + solomon,dclk-div: + default: 2 + solomon,dclk-frq: + default: 12 + required: + - pwms + + - if: + properties: + compatible: + contains: + const: solomon,ssd1309fb-i2c + then: + properties: + solomon,dclk-div: + default: 1 + solomon,dclk-frq: + default: 10 + +additionalProperties: false + +examples: + - | + i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7>; + }; + + ssd1306: oled@3d { + compatible = "solomon,ssd1306fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7>; + solomon,com-lrremap; + solomon,com-invdir; + solomon,com-offset = <32>; + solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>; + }; + }; diff --git a/Documentation/devicetree/bindings/display/ssd1307fb.txt b/Documentation/devicetree/bindings/display/ssd1307fb.txt deleted file mode 100644 index 2dcb6d12d137..000000000000 --- a/Documentation/devicetree/bindings/display/ssd1307fb.txt +++ /dev/null @@ -1,60 +0,0 @@ -* Solomon SSD1307 Framebuffer Driver - -Required properties: - - compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for - now is i2c, and the supported chips are ssd1305, ssd1306, ssd1307 and - ssd1309. - - reg: Should contain address of the controller on the I2C bus. Most likely - 0x3c or 0x3d - - pwm: Should contain the pwm to use according to the OF device tree PWM - specification [0]. Only required for the ssd1307. - - solomon,height: Height in pixel of the screen driven by the controller - - solomon,width: Width in pixel of the screen driven by the controller - - solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is - mapped to. - -Optional properties: - - reset-gpios: The GPIO used to reset the OLED display, if available. See - Documentation/devicetree/bindings/gpio/gpio.txt for details. - - vbat-supply: The supply for VBAT - - solomon,segment-no-remap: Display needs normal (non-inverted) data column - to segment mapping - - solomon,col-offset: Offset of columns (COL/SEG) that the screen is mapped to. - - solomon,com-seq: Display uses sequential COM pin configuration - - solomon,com-lrremap: Display uses left-right COM pin remap - - solomon,com-invdir: Display uses inverted COM pin scan direction - - solomon,com-offset: Number of the COM pin wired to the first display line - - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles. - - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles. - This needs to be the higher, the higher the capacitance - of the OLED's pixels is - - solomon,dclk-div: Clock divisor 1 to 16 - - solomon,dclk-frq: Clock frequency 0 to 15, higher value means higher - frequency - - solomon,lookup-table: 8 bit value array of current drive pulse widths for - BANK0, and colors A, B, and C. Each value in range - of 31 to 63 for pulse widths of 32 to 64. Color D - is always width 64. - - solomon,area-color-enable: Display uses color mode - - solomon,low-power. Display runs in low power mode - -[0]: Documentation/devicetree/bindings/pwm/pwm.txt - -Examples: -ssd1307: oled@3c { - compatible = "solomon,ssd1307fb-i2c"; - reg = <0x3c>; - pwms = <&pwm 4 3000>; - reset-gpios = <&gpio2 7>; -}; - -ssd1306: oled@3c { - compatible = "solomon,ssd1306fb-i2c"; - reg = <0x3c>; - pwms = <&pwm 4 3000>; - reset-gpios = <&gpio2 7>; - solomon,com-lrremap; - solomon,com-invdir; - solomon,com-offset = <32>; - solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>; -}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 07fb0d25fc15..3c6918dde429 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -936,6 +936,8 @@ patternProperties: description: Chengdu Kaixuan Information Technology Co., Ltd. "^qiaodian,.*": description: QiaoDian XianShi Corporation + "^qishenglong,.*": + description: Shenzhen QiShenglong Industrialist Co., Ltd. "^qnap,.*": description: QNAP Systems, Inc. "^radxa,.*": diff --git a/Documentation/driver-api/thermal/nouveau_thermal.rst b/Documentation/driver-api/thermal/nouveau_thermal.rst index 79ece266cf6d..aa10db6df309 100644 --- a/Documentation/driver-api/thermal/nouveau_thermal.rst +++ b/Documentation/driver-api/thermal/nouveau_thermal.rst @@ -90,7 +90,7 @@ Bug reports ----------- Thermal management on Nouveau is new and may not work on all cards. If you have -inquiries, please ping mupuf on IRC (#nouveau, freenode). +inquiries, please ping mupuf on IRC (#nouveau, OFTC). Bug reports should be filled on Freedesktop's bug tracker. Please follow https://nouveau.freedesktop.org/wiki/Bugs diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 87e5023e3f55..0cc21f6aaef5 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -463,6 +463,35 @@ KMS Properties This section of the documentation is primarily aimed at user-space developers. For the driver APIs, see the other sections. +Requirements +------------ + +KMS drivers might need to add extra properties to support new features. Each +new property introduced in a driver needs to meet a few requirements, in +addition to the one mentioned above: + +* It must be standardized, documenting: + + * The full, exact, name string; + * If the property is an enum, all the valid value name strings; + * What values are accepted, and what these values mean; + * What the property does and how it can be used; + * How the property might interact with other, existing properties. + +* It must provide a generic helper in the core code to register that + property on the object it attaches to. + +* Its content must be decoded by the core and provided in the object's + associated state structure. That includes anything drivers might want + to precompute, like struct drm_clip_rect for planes. + +* Its initial state must match the behavior prior to the property + introduction. This might be a fixed value matching what the hardware + does, or it may be inherited from the state the firmware left the + system in during boot. + +* An IGT test must be submitted where reasonable. + Property Types and Blob Property Support ---------------------------------------- @@ -508,8 +537,8 @@ Plane Composition Properties Damage Tracking Properties -------------------------- -.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c - :doc: overview +.. kernel-doc:: drivers/gpu/drm/drm_plane.c + :doc: damage tracking Color Management Properties --------------------------- diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 7e51dd40bf6e..199afb503ab1 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -37,6 +37,15 @@ Primary Nodes, DRM Master and Authentication .. kernel-doc:: include/drm/drm_auth.h :internal: + +.. _drm_leasing: + +DRM Display Resource Leasing +============================ + +.. kernel-doc:: drivers/gpu/drm/drm_lease.c + :doc: drm leasing + Open-Source Userspace Requirements ================================== diff --git a/MAINTAINERS b/MAINTAINERS index 2519793d31a1..dde565a88c87 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1690,7 +1690,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: https://asahilinux.org B: https://github.com/AsahiLinux/linux/issues -C: irc://chat.freenode.net/asahi-dev +C: irc://irc.oftc.net/asahi-dev T: git https://github.com/AsahiLinux/linux.git F: Documentation/devicetree/bindings/arm/apple.yaml F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml @@ -6080,7 +6080,7 @@ M: Daniel Vetter <daniel@ffwll.ch> L: dri-devel@lists.freedesktop.org S: Maintained B: https://gitlab.freedesktop.org/drm -C: irc://chat.freenode.net/dri-devel +C: irc://irc.oftc.net/dri-devel T: git git://anongit.freedesktop.org/drm/drm F: Documentation/devicetree/bindings/display/ F: Documentation/devicetree/bindings/gpu/ @@ -9264,7 +9264,7 @@ S: Supported W: https://01.org/linuxgraphics/ Q: http://patchwork.freedesktop.org/project/intel-gfx/ B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs -C: irc://chat.freenode.net/intel-gfx +C: irc://irc.oftc.net/intel-gfx T: git git://anongit.freedesktop.org/drm-intel F: Documentation/gpu/i915.rst F: drivers/gpu/drm/i915/ diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index aa19d5a40e31..59d718bde8c4 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -165,7 +165,7 @@ int adv7533_attach_dsi(struct adv7511 *adv) dsi->lanes = adv->num_dsi_lanes; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE; + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE; ret = mipi_dsi_attach(dsi); if (ret < 0) { diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index ef29197fed50..920824d8df2f 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1307,7 +1307,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_EOT_PACKET | + MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE; if (mipi_dsi_attach(dsi) < 0) { diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index b31281f76117..e6e331071a00 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -829,7 +829,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) tmp = DIV_ROUND_UP(dsi_cfg.htotal, nlanes) - DIV_ROUND_UP(dsi_cfg.hsa, nlanes); - if (!(output->dev->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + if (!(output->dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) tmp -= DIV_ROUND_UP(DSI_EOT_PKT_SIZE, nlanes); tx_byte_period = DIV_ROUND_DOWN_ULL((u64)NSEC_PER_SEC * 8, @@ -902,7 +902,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) tmp = readl(dsi->regs + MCTL_MAIN_DATA_CTL); tmp &= ~(IF_VID_SELECT_MASK | HOST_EOT_GEN | IF_VID_MODE); - if (!(output->dev->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + if (!(output->dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) tmp |= HOST_EOT_GEN; if (output->dev->mode_flags & MIPI_DSI_MODE_VIDEO) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 76c720b535fb..1b0c7eaf6c84 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -487,7 +487,7 @@ static int lt8912_attach_dsi(struct lt8912 *lt) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | - MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_NO_EOT_PACKET; ret = mipi_dsi_attach(dsi); if (ret < 0) { diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index d7986067eefe..ed8ac5059cd2 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -190,7 +190,7 @@ static u32 ps2bc(struct nwl_dsi *dsi, unsigned long long ps) u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); return DIV64_U64_ROUND_UP(ps * dsi->mode.clock * bpp, - dsi->lanes * 8 * NSEC_PER_SEC); + dsi->lanes * 8ULL * NSEC_PER_SEC); } /* diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 7900da1d4325..e44e18a0112a 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -246,6 +246,7 @@ struct dw_mipi_dsi { struct clk *pclk; + bool device_found; unsigned int lane_mbps; /* per lane */ u32 channel; u32 lanes; @@ -309,13 +310,37 @@ static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) return readl(dsi->base + reg); } +static int dw_mipi_dsi_panel_or_bridge(struct dw_mipi_dsi *dsi, + struct device_node *node) +{ + struct drm_bridge *bridge; + struct drm_panel *panel; + int ret; + + ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge); + if (ret) + return ret; + + if (panel) { + bridge = drm_panel_bridge_add_typed(panel, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + } + + dsi->panel_bridge = bridge; + + if (!dsi->panel_bridge) + return -EPROBE_DEFER; + + return 0; +} + static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct dw_mipi_dsi *dsi = host_to_dsi(host); const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; - struct drm_bridge *bridge; - struct drm_panel *panel; int ret; if (device->lanes > dsi->plat_data->max_data_lanes) { @@ -329,22 +354,14 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->format = device->format; dsi->mode_flags = device->mode_flags; - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, - &panel, &bridge); - if (ret) - return ret; + if (!dsi->device_found) { + ret = dw_mipi_dsi_panel_or_bridge(dsi, host->dev->of_node); + if (ret) + return ret; - if (panel) { - bridge = drm_panel_bridge_add_typed(panel, - DRM_MODE_CONNECTOR_DSI); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); + dsi->device_found = true; } - dsi->panel_bridge = bridge; - - drm_bridge_add(&dsi->bridge); - if (pdata->host_ops && pdata->host_ops->attach) { ret = pdata->host_ops->attach(pdata->priv_data, device); if (ret < 0) @@ -999,6 +1016,16 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge, /* Set the encoder type as caller does not know it */ bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI; + if (!dsi->device_found) { + int ret; + + ret = dw_mipi_dsi_panel_or_bridge(dsi, dsi->dev->of_node); + if (ret) + return ret; + + dsi->device_found = true; + } + /* Attach the panel-bridge to the dsi bridge */ return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge, flags); @@ -1181,6 +1208,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, #ifdef CONFIG_OF dsi->bridge.of_node = pdev->dev.of_node; #endif + drm_bridge_add(&dsi->bridge); return dsi; } diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index 2495ea46b091..a3db532bbdd1 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -825,7 +825,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) if (!(dsi_dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) val |= TC358768_DSI_CONTROL_HSCKMD; - if (dsi_dev->mode_flags & MIPI_DSI_MODE_EOT_PACKET) + if (dsi_dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET) val |= TC358768_DSI_CONTROL_EOTDIS; tc358768_write(priv, TC358768_DSI_CONFW, val); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index d820423fac32..c85dcfd69158 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -660,7 +660,7 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, return -ENOSPC; } - clips = drm_plane_get_damage_clips(new_plane_state); + clips = __drm_plane_get_damage_clips(new_plane_state); num_clips = drm_plane_get_damage_clips_count(new_plane_state); /* Make sure damage clips are valid and inside the fb. */ diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 3a64a6a79ade..5b1d92f5afea 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -63,8 +63,9 @@ static bool drm_is_current_master_locked(struct drm_file *fpriv) { - lockdep_assert_held_once(&fpriv->minor->dev->master_mutex); - + /* Either drm_device.master_mutex or drm_file.master_lookup_lock + * should be held here. + */ return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master; } @@ -82,9 +83,9 @@ bool drm_is_current_master(struct drm_file *fpriv) { bool ret; - mutex_lock(&fpriv->minor->dev->master_mutex); + spin_lock(&fpriv->master_lookup_lock); ret = drm_is_current_master_locked(fpriv); - mutex_unlock(&fpriv->minor->dev->master_mutex); + spin_unlock(&fpriv->master_lookup_lock); return ret; } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 1ca51addb589..edb772947cb4 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -262,6 +262,8 @@ int drm_plane_register_all(struct drm_device *dev); void drm_plane_unregister_all(struct drm_device *dev); int drm_plane_check_pixel_format(struct drm_plane *plane, u32 format, u64 modifier); +struct drm_mode_rect * +__drm_plane_get_damage_clips(const struct drm_plane_state *state); /* drm_bridge.c */ void drm_bridge_detach(struct drm_bridge *bridge); diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index 3a4126dc2520..245959dad7bb 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -34,44 +34,6 @@ #include <drm/drm_damage_helper.h> #include <drm/drm_device.h> -/** - * DOC: overview - * - * FB_DAMAGE_CLIPS is an optional plane property which provides a means to - * specify a list of damage rectangles on a plane in framebuffer coordinates of - * the framebuffer attached to the plane. In current context damage is the area - * of plane framebuffer that has changed since last plane update (also called - * page-flip), irrespective of whether currently attached framebuffer is same as - * framebuffer attached during last plane update or not. - * - * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers - * to optimize internally especially for virtual devices where each framebuffer - * change needs to be transmitted over network, usb, etc. - * - * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can - * ignore damage clips property and in that case driver will do a full plane - * update. In case damage clips are provided then it is guaranteed that the area - * inside damage clips will be updated to plane. For efficiency driver can do - * full update or can update more than specified in damage clips. Since driver - * is free to read more, user-space must always render the entire visible - * framebuffer. Otherwise there can be corruptions. Also, if a user-space - * provides damage clips which doesn't encompass the actual damage to - * framebuffer (since last plane update) can result in incorrect rendering. - * - * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an - * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates, - * damage clips are not in 16.16 fixed point. Similar to plane src in - * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are - * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped - * damage clips, it is strongly discouraged. - * - * Drivers that are interested in damage interface for plane should enable - * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips(). - * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and - * drm_atomic_helper_damage_iter_next() helper iterator function to get damage - * rectangles clipped to &drm_plane_state.src. - */ - static void convert_clip_rect_to_rect(const struct drm_clip_rect *src, struct drm_mode_rect *dest, uint32_t num_clips, uint32_t src_inc) @@ -88,22 +50,6 @@ static void convert_clip_rect_to_rect(const struct drm_clip_rect *src, } /** - * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property. - * @plane: Plane on which to enable damage clips property. - * - * This function lets driver to enable the damage clips property on a plane. - */ -void drm_plane_enable_fb_damage_clips(struct drm_plane *plane) -{ - struct drm_device *dev = plane->dev; - struct drm_mode_config *config = &dev->mode_config; - - drm_object_attach_property(&plane->base, config->prop_fb_damage_clips, - 0); -} -EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips); - -/** * drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check. * @state: The driver state object. * @plane_state: Plane state for which to verify damage. @@ -282,7 +228,7 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, if (!state || !state->crtc || !state->fb || !state->visible) return; - iter->clips = drm_helper_get_plane_damage_clips(state); + iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state); 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 */ diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index ad0795afc21c..86d13d6bc463 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2872,11 +2872,13 @@ static int process_single_tx_qlock(struct drm_dp_mst_topology_mgr *mgr, idx += tosend + 1; ret = drm_dp_send_sideband_msg(mgr, up, chunk, idx); - if (unlikely(ret) && drm_debug_enabled(DRM_UT_DP)) { - struct drm_printer p = drm_debug_printer(DBG_PREFIX); + if (ret) { + if (drm_debug_enabled(DRM_UT_DP)) { + struct drm_printer p = drm_debug_printer(DBG_PREFIX); - drm_printf(&p, "sideband msg failed to send\n"); - drm_dp_mst_dump_sideband_msg_tx(&p, txmsg); + drm_printf(&p, "sideband msg failed to send\n"); + drm_dp_mst_dump_sideband_msg_tx(&p, txmsg); + } return ret; } diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 4d01464b6f95..d3d09aba9833 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -404,6 +404,9 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w) struct drm_framebuffer *fb = list_first_entry(&arg->fbs, typeof(*fb), filp_head); + drm_dbg_kms(fb->dev, + "Removing [FB:%d] from all active usage due to RMFB ioctl\n", + fb->base.id); list_del_init(&fb->filp_head); drm_framebuffer_remove(fb); } @@ -981,6 +984,10 @@ retry: if (plane->state->fb != fb) continue; + drm_dbg_kms(dev, + "Disabling [PLANE:%d:%s] because [FB:%d] is removed\n", + plane->base.id, plane->name, fb->base.id); + plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { ret = PTR_ERR(plane_state); @@ -990,6 +997,11 @@ retry: if (disable_crtcs && plane_state->crtc->primary == plane) { struct drm_crtc_state *crtc_state; + drm_dbg_kms(dev, + "Disabling [CRTC:%d:%s] because [FB:%d] is removed\n", + plane_state->crtc->base.id, + plane_state->crtc->name, fb->base.id); + crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc); ret = drm_atomic_add_affected_connectors(state, plane_state->crtc); @@ -1052,6 +1064,10 @@ static void legacy_remove_fb(struct drm_framebuffer *fb) /* remove from any CRTC */ drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb == fb) { + drm_dbg_kms(dev, + "Disabling [CRTC:%d:%s] because [FB:%d] is removed\n", + crtc->base.id, crtc->name, fb->base.id); + /* should turn off the crtc */ if (drm_crtc_force_disable(crtc)) DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); @@ -1059,8 +1075,12 @@ static void legacy_remove_fb(struct drm_framebuffer *fb) } drm_for_each_plane(plane, dev) { - if (plane->fb == fb) + if (plane->fb == fb) { + drm_dbg_kms(dev, + "Disabling [PLANE:%d:%s] because [FB:%d] is removed\n", + plane->base.id, plane->name, fb->base.id); drm_plane_force_disable(plane); + } } drm_modeset_unlock_all(dev); } diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index e2c68822e05c..67bc9edc1d98 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -306,6 +306,95 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, } EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); +/** + * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access + * @fb: the framebuffer + * @dir: access mode + * + * Prepares a framebuffer's GEM buffer objects for CPU access. This function + * must be called before accessing the BO data within the kernel. For imported + * BOs, the function calls dma_buf_begin_cpu_access(). + * + * See drm_gem_fb_end_cpu_access() for signalling the end of CPU access. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) +{ + struct dma_buf_attachment *import_attach; + struct drm_gem_object *obj; + size_t i; + int ret, ret2; + + for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir); + if (ret) + goto err_dma_buf_end_cpu_access; + } + + return 0; + +err_dma_buf_end_cpu_access: + while (i) { + --i; + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret2 = dma_buf_end_cpu_access(import_attach->dmabuf, dir); + if (ret2) { + drm_err(fb->dev, + "dma_buf_end_cpu_access() failed during error handling: %d\n", + ret2); + } + } + + return ret; +} +EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); + +/** + * drm_gem_fb_end_cpu_access - signals end of CPU access to GEM buffer objects + * @fb: the framebuffer + * @dir: access mode + * + * Signals the end of CPU access to the given framebuffer's GEM buffer objects. This + * function must be paired with a corresponding call to drm_gem_fb_begin_cpu_access(). + * For imported BOs, the function calls dma_buf_end_cpu_access(). + * + * See also drm_gem_fb_begin_cpu_access(). + */ +void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) +{ + size_t i = ARRAY_SIZE(fb->obj); + struct dma_buf_attachment *import_attach; + struct drm_gem_object *obj; + int ret; + + while (i) { + --i; + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir); + if (ret) + drm_err(fb->dev, "dma_buf_end_cpu_access() failed: %d\n", ret); + } +} +EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); + static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd) { diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index 92eac73d9001..79be797e8689 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -15,6 +15,57 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" +/** + * DOC: drm leasing + * + * DRM leases provide information about whether a DRM master may control a DRM + * mode setting object. This enables the creation of multiple DRM masters that + * manage subsets of display resources. + * + * The original DRM master of a device 'owns' the available drm resources. It + * may create additional DRM masters and 'lease' resources which it controls + * to the new DRM master. This gives the new DRM master control over the + * leased resources until the owner revokes the lease, or the new DRM master + * is closed. Some helpful terminology: + * + * - An 'owner' is a &struct drm_master that is not leasing objects from + * another &struct drm_master, and hence 'owns' the objects. The owner can be + * identified as the &struct drm_master for which &drm_master.lessor is NULL. + * + * - A 'lessor' is a &struct drm_master which is leasing objects to one or more + * other &struct drm_master. Currently, lessees are not allowed to + * create sub-leases, hence the lessor is the same as the owner. + * + * - A 'lessee' is a &struct drm_master which is leasing objects from some + * other &struct drm_master. Each lessee only leases resources from a single + * lessor recorded in &drm_master.lessor, and holds the set of objects that + * it is leasing in &drm_master.leases. + * + * - A 'lease' is a contract between the lessor and lessee that identifies + * which resources may be controlled by the lessee. All of the resources + * that are leased must be owned by or leased to the lessor, and lessors are + * not permitted to lease the same object to multiple lessees. + * + * The set of objects any &struct drm_master 'controls' is limited to the set + * of objects it leases (for lessees) or all objects (for owners). + * + * Objects not controlled by a &struct drm_master cannot be modified through + * the various state manipulating ioctls, and any state reported back to user + * space will be edited to make them appear idle and/or unusable. For + * instance, connectors always report 'disconnected', while encoders + * report no possible crtcs or clones. + * + * Since each lessee may lease objects from a single lessor, display resource + * leases form a tree of &struct drm_master. As lessees are currently not + * allowed to create sub-leases, the tree depth is limited to 1. All of + * these get activated simultaneously when the top level device owner changes + * through the SETMASTER or DROPMASTER IOCTL, so &drm_device.master points to + * the owner at the top of the lease tree (i.e. the &struct drm_master for which + * &drm_master.lessor is NULL). The full list of lessees that are leasing + * objects from the owner can be searched via the owner's + * &drm_master.lessee_idr. + */ + #define drm_for_each_lessee(lessee, lessor) \ list_for_each_entry((lessee), &(lessor)->lessees, lessee_list) diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index 10b4e59384ae..71b646c4131f 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -7,7 +7,6 @@ #include <linux/debugfs.h> #include <linux/delay.h> -#include <linux/dma-buf.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/regulator/consumer.h> @@ -202,21 +201,17 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, { struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(gem); - struct dma_buf_attachment *import_attach = gem->import_attach; void *src = cma_obj->vaddr; - int ret = 0; + int ret; - if (import_attach) { - ret = dma_buf_begin_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); - if (ret) - return ret; - } + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return ret; switch (fb->format->format) { case DRM_FORMAT_RGB565: if (swap) - drm_fb_swab(dst, src, fb, clip, !import_attach); + drm_fb_swab(dst, src, fb, clip, !gem->import_attach); else drm_fb_memcpy(dst, src, fb, clip); break; @@ -229,9 +224,8 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, return -EINVAL; } - if (import_attach) - ret = dma_buf_end_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); + return ret; } EXPORT_SYMBOL(mipi_dbi_buf_copy); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index b373958ecb30..f5fe8255597c 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1397,6 +1397,110 @@ out: return ret; } +/** + * DOC: damage tracking + * + * FB_DAMAGE_CLIPS is an optional plane property which provides a means to + * specify a list of damage rectangles on a plane in framebuffer coordinates of + * the framebuffer attached to the plane. In current context damage is the area + * of plane framebuffer that has changed since last plane update (also called + * page-flip), irrespective of whether currently attached framebuffer is same as + * framebuffer attached during last plane update or not. + * + * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers + * to optimize internally especially for virtual devices where each framebuffer + * change needs to be transmitted over network, usb, etc. + * + * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can + * ignore damage clips property and in that case driver will do a full plane + * update. In case damage clips are provided then it is guaranteed that the area + * inside damage clips will be updated to plane. For efficiency driver can do + * full update or can update more than specified in damage clips. Since driver + * is free to read more, user-space must always render the entire visible + * framebuffer. Otherwise there can be corruptions. Also, if a user-space + * provides damage clips which doesn't encompass the actual damage to + * framebuffer (since last plane update) can result in incorrect rendering. + * + * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an + * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates, + * damage clips are not in 16.16 fixed point. Similar to plane src in + * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are + * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped + * damage clips, it is strongly discouraged. + * + * Drivers that are interested in damage interface for plane should enable + * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips(). + * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and + * drm_atomic_helper_damage_iter_next() helper iterator function to get damage + * rectangles clipped to &drm_plane_state.src. + */ + +/** + * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property. + * @plane: Plane on which to enable damage clips property. + * + * This function lets driver to enable the damage clips property on a plane. + */ +void drm_plane_enable_fb_damage_clips(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + drm_object_attach_property(&plane->base, config->prop_fb_damage_clips, + 0); +} +EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips); + +/** + * drm_plane_get_damage_clips_count - Returns damage clips count. + * @state: Plane state. + * + * Simple helper to get the number of &drm_mode_rect clips set by user-space + * during plane update. + * + * Return: Number of clips in plane fb_damage_clips blob property. + */ +unsigned int +drm_plane_get_damage_clips_count(const struct drm_plane_state *state) +{ + return (state && state->fb_damage_clips) ? + state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0; +} +EXPORT_SYMBOL(drm_plane_get_damage_clips_count); + +struct drm_mode_rect * +__drm_plane_get_damage_clips(const struct drm_plane_state *state) +{ + return (struct drm_mode_rect *)((state && state->fb_damage_clips) ? + state->fb_damage_clips->data : NULL); +} + +/** + * drm_plane_get_damage_clips - Returns damage clips. + * @state: Plane state. + * + * Note that this function returns uapi type &drm_mode_rect. Drivers might want + * to use the helper functions drm_atomic_helper_damage_iter_init() and + * drm_atomic_helper_damage_iter_next() or drm_atomic_helper_damage_merged() if + * the driver can only handle a single damage region at most. + * + * Return: Damage clips in plane fb_damage_clips blob property. + */ +struct drm_mode_rect * +drm_plane_get_damage_clips(const struct drm_plane_state *state) +{ + struct drm_device *dev = state->plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + /* check that drm_plane_enable_fb_damage_clips() was called */ + if (!drm_mode_obj_find_prop_id(&state->plane->base, + config->prop_fb_damage_clips->base.id)) + drm_warn_once(dev, "drm_plane_enable_fb_damage_clips() not called\n"); + + return __drm_plane_get_damage_clips(state); +} +EXPORT_SYMBOL(drm_plane_get_damage_clips); + struct drm_property * drm_create_scaling_filter_prop(struct drm_device *dev, unsigned int supported_filters) diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 2a54f86856af..178e18c28cab 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -549,7 +549,7 @@ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, * * FIXME: The underlying helper functions are named rather inconsistently. * - * Exporting buffers + * Importing buffers * ~~~~~~~~~~~~~~~~~ * * Importing dma-bufs using drm_gem_prime_import() relies on diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 1d777d8c1a83..e39fac889edc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -809,15 +809,15 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) reg |= DSIM_AUTO_MODE; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE) reg |= DSIM_HSE_MODE; - if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)) + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HFP)) reg |= DSIM_HFP_MODE; - if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)) + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HBP)) reg |= DSIM_HBP_MODE; - if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)) + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HSA)) reg |= DSIM_HSA_MODE; } - if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) reg |= DSIM_EOT_DISABLE; switch (dsi->format) { diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 8f56bf618ac2..4d7a26b68a2e 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -3,7 +3,6 @@ * Copyright 2020 Noralf Trønnes */ -#include <linux/dma-buf.h> #include <linux/lz4.h> #include <linux/usb.h> #include <linux/workqueue.h> @@ -15,6 +14,7 @@ #include <drm/drm_format_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_print.h> #include <drm/drm_rect.h> @@ -168,11 +168,9 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, vaddr = map.vaddr + fb->offsets[0]; - if (import_attach) { - ret = dma_buf_begin_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE); - if (ret) - goto vunmap; - } + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + goto vunmap; retry: if (compression) buf = gdrm->compress_buf; @@ -225,8 +223,7 @@ retry: } end_cpu_access: - if (import_attach) - dma_buf_end_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE); + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); vunmap: drm_gem_shmem_vunmap(fb->obj[0], &map); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index f73a8e0ea12e..610fc8e135f9 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -249,7 +249,6 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv) static int hibmc_unload(struct drm_device *dev) { - struct hibmc_drm_private *priv = to_hibmc_drm_private(dev); struct pci_dev *pdev = to_pci_dev(dev->dev); drm_atomic_helper_shutdown(dev); diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index f3644667e24f..180ebbccbeda 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -760,7 +760,7 @@ static void mcde_dsi_start(struct mcde_dsi *d) DSI_MCTL_MAIN_DATA_CTL_BTA_EN | DSI_MCTL_MAIN_DATA_CTL_READ_EN | DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN; - if (!(d->mdsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + if (!(d->mdsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) val |= DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN; writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index ae403c67cbd9..93b40c245f00 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -404,7 +404,7 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi) if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) tmp_reg |= HSTX_CKLP_EN; - if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) tmp_reg |= DIS_EOT; writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL); @@ -481,7 +481,7 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) timing->da_hs_zero + timing->da_hs_exit + 3; delta = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? 18 : 12; - delta += dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET ? 2 : 0; + delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 2 : 0; horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp; horizontal_front_back_byte = horizontal_frontporch_byte + horizontal_backporch_byte; diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index ed504fe5074f..b466a4af7c3e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -849,11 +849,11 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, if (flags & MIPI_DSI_MODE_VIDEO) { if (flags & MIPI_DSI_MODE_VIDEO_HSE) data |= DSI_VID_CFG0_PULSE_MODE_HSA_HE; - if (flags & MIPI_DSI_MODE_VIDEO_HFP) + if (flags & MIPI_DSI_MODE_VIDEO_NO_HFP) data |= DSI_VID_CFG0_HFP_POWER_STOP; - if (flags & MIPI_DSI_MODE_VIDEO_HBP) + if (flags & MIPI_DSI_MODE_VIDEO_NO_HBP) data |= DSI_VID_CFG0_HBP_POWER_STOP; - if (flags & MIPI_DSI_MODE_VIDEO_HSA) + if (flags & MIPI_DSI_MODE_VIDEO_NO_HSA) data |= DSI_VID_CFG0_HSA_POWER_STOP; /* Always set low power stop mode for BLLP * to let command engine send packets @@ -908,7 +908,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, DSI_T_CLK_PRE_EXTEND_INC_BY_2_BYTECLK); data = 0; - if (!(flags & MIPI_DSI_MODE_EOT_PACKET)) + if (!(flags & MIPI_DSI_MODE_NO_EOT_PACKET)) data |= DSI_EOT_PACKET_CTRL_TX_EOT_APPEND; dsi_write(msm_host, REG_DSI_EOT_PACKET_CTRL, data); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 6da93551e2e5..c277d3f61a5e 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -51,6 +51,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { .hs_wdth_mask = 0xff, .hs_wdth_shift = 24, .has_overlay = false, + .has_ctrl2 = false, }, [MXSFB_V4] = { .transfer_count = LCDC_V4_TRANSFER_COUNT, @@ -59,6 +60,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { .hs_wdth_mask = 0x3fff, .hs_wdth_shift = 18, .has_overlay = false, + .has_ctrl2 = true, }, [MXSFB_V6] = { .transfer_count = LCDC_V4_TRANSFER_COUNT, @@ -67,6 +69,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { .hs_wdth_mask = 0x3fff, .hs_wdth_shift = 18, .has_overlay = true, + .has_ctrl2 = true, }, }; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index 399d23e91ed1..7c720e226fdf 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -22,6 +22,7 @@ struct mxsfb_devdata { unsigned int hs_wdth_mask; unsigned int hs_wdth_shift; bool has_overlay; + bool has_ctrl2; }; struct mxsfb_drm_private { diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c index 8797c671d0d5..89dd618d78f3 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_kms.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c @@ -47,16 +47,13 @@ static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) * Setup the MXSFB registers for decoding the pixels out of the framebuffer and * outputting them on the bus. */ -static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb) +static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb, + const u32 bus_format) { struct drm_device *drm = mxsfb->drm; const u32 format = mxsfb->crtc.primary->state->fb->format->format; - u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; u32 ctrl, ctrl1; - if (mxsfb->connector->display_info.num_bus_formats) - bus_format = mxsfb->connector->display_info.bus_formats[0]; - DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", bus_format); @@ -107,6 +104,14 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) clk_prepare_enable(mxsfb->clk_disp_axi); clk_prepare_enable(mxsfb->clk); + /* Increase number of outstanding requests on all supported IPs */ + if (mxsfb->devdata->has_ctrl2) { + reg = readl(mxsfb->base + LCDC_V4_CTRL2); + reg &= ~CTRL2_SET_OUTSTANDING_REQS_MASK; + reg |= CTRL2_SET_OUTSTANDING_REQS_16; + writel(reg, mxsfb->base + LCDC_V4_CTRL2); + } + /* If it was disabled, re-enable the mode again */ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); @@ -115,6 +120,35 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) reg |= VDCTRL4_SYNC_SIGNALS_ON; writel(reg, mxsfb->base + LCDC_VDCTRL4); + /* + * Enable recovery on underflow. + * + * There is some sort of corner case behavior of the controller, + * which could rarely be triggered at least on i.MX6SX connected + * to 800x480 DPI panel and i.MX8MM connected to DPI->DSI->LVDS + * bridged 1920x1080 panel (and likely on other setups too), where + * the image on the panel shifts to the right and wraps around. + * This happens either when the controller is enabled on boot or + * even later during run time. The condition does not correct + * itself automatically, i.e. the display image remains shifted. + * + * It seems this problem is known and is due to sporadic underflows + * of the LCDIF FIFO. While the LCDIF IP does have underflow/overflow + * IRQs, neither of the IRQs trigger and neither IRQ status bit is + * asserted when this condition occurs. + * + * All known revisions of the LCDIF IP have CTRL1 RECOVER_ON_UNDERFLOW + * bit, which is described in the reference manual since i.MX23 as + * " + * Set this bit to enable the LCDIF block to recover in the next + * field/frame if there was an underflow in the current field/frame. + * " + * Enable this bit to mitigate the sporadic underflows. + */ + reg = readl(mxsfb->base + LCDC_CTRL1); + reg |= CTRL1_RECOVER_ON_UNDERFLOW; + writel(reg, mxsfb->base + LCDC_CTRL1); + writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET); } @@ -185,7 +219,8 @@ static dma_addr_t mxsfb_get_fb_paddr(struct drm_plane *plane) return gem->paddr; } -static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) +static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb, + const u32 bus_format) { struct drm_device *drm = mxsfb->crtc.dev; struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode; @@ -206,11 +241,14 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) /* Clear the FIFOs */ writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); + readl(mxsfb->base + LCDC_CTRL1); + writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_CLR); + readl(mxsfb->base + LCDC_CTRL1); if (mxsfb->devdata->has_overlay) writel(0, mxsfb->base + LCDC_AS_CTRL); - mxsfb_set_formats(mxsfb); + mxsfb_set_formats(mxsfb, bus_format); clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); @@ -308,7 +346,9 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); + struct drm_bridge_state *bridge_state; struct drm_device *drm = mxsfb->drm; + u32 bus_format = 0; dma_addr_t paddr; pm_runtime_get_sync(drm->dev); @@ -316,7 +356,23 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, drm_crtc_vblank_on(crtc); - mxsfb_crtc_mode_set_nofb(mxsfb); + /* If there is a bridge attached to the LCDIF, use its bus format */ + if (mxsfb->bridge) { + bridge_state = + drm_atomic_get_new_bridge_state(state, + mxsfb->bridge); + bus_format = bridge_state->input_bus_cfg.format; + } + + /* If there is no bridge, use bus format from connector */ + if (!bus_format && mxsfb->connector->display_info.num_bus_formats) + bus_format = mxsfb->connector->display_info.bus_formats[0]; + + /* If all else fails, default to RGB888_1X24 */ + if (!bus_format) + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + mxsfb_crtc_mode_set_nofb(mxsfb, bus_format); /* Write cur_buf as well to avoid an initial corrupt frame */ paddr = mxsfb_get_fb_paddr(crtc->primary); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h index 55d28a27f912..694fea13e893 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h @@ -15,6 +15,7 @@ #define LCDC_CTRL 0x00 #define LCDC_CTRL1 0x10 #define LCDC_V3_TRANSFER_COUNT 0x20 +#define LCDC_V4_CTRL2 0x20 #define LCDC_V4_TRANSFER_COUNT 0x30 #define LCDC_V4_CUR_BUF 0x40 #define LCDC_V4_NEXT_BUF 0x50 @@ -54,12 +55,20 @@ #define CTRL_DF24 BIT(1) #define CTRL_RUN BIT(0) +#define CTRL1_RECOVER_ON_UNDERFLOW BIT(24) #define CTRL1_FIFO_CLEAR BIT(21) #define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) #define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) #define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13) #define CTRL1_CUR_FRAME_DONE_IRQ BIT(9) +#define CTRL2_SET_OUTSTANDING_REQS_1 0 +#define CTRL2_SET_OUTSTANDING_REQS_2 (0x1 << 21) +#define CTRL2_SET_OUTSTANDING_REQS_4 (0x2 << 21) +#define CTRL2_SET_OUTSTANDING_REQS_8 (0x3 << 21) +#define CTRL2_SET_OUTSTANDING_REQS_16 (0x4 << 21) +#define CTRL2_SET_OUTSTANDING_REQS_MASK (0x7 << 21) + #define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) #define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) #define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c index e95bc9f60b3f..44674ebedf59 100644 --- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c +++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c @@ -302,7 +302,7 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_EOT_PACKET | + MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; drm_panel_init(&ctx->panel, dev, &tm5p5_nt35596_panel_funcs, diff --git a/drivers/gpu/drm/panel/panel-dsi-cm.c b/drivers/gpu/drm/panel/panel-dsi-cm.c index 5fbfb71ca3d9..da4a69067e18 100644 --- a/drivers/gpu/drm/panel/panel-dsi-cm.c +++ b/drivers/gpu/drm/panel/panel-dsi-cm.c @@ -574,7 +574,7 @@ static int dsicm_probe(struct mipi_dsi_device *dsi) dsi->lanes = 2; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS | - MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_NO_EOT_PACKET; dsi->hs_rate = ddata->panel_data->max_hs_rate; dsi->lp_rate = ddata->panel_data->max_lp_rate; diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index 4787f0833264..80227617a4d6 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -273,7 +273,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) dsi->lanes = 1; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_CLOCK_NON_CONTINUOUS; drm_panel_init(&ctx->panel, &dsi->dev, &kd35t133_funcs, diff --git a/drivers/gpu/drm/panel/panel-khadas-ts050.c b/drivers/gpu/drm/panel/panel-khadas-ts050.c index 8f6ac1a40c31..a3ec4cbdbf7a 100644 --- a/drivers/gpu/drm/panel/panel-khadas-ts050.c +++ b/drivers/gpu/drm/panel/panel-khadas-ts050.c @@ -809,7 +809,7 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050), GFP_KERNEL); diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index ed0d5f959037..a5a414920430 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -593,7 +593,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c index 3c00e4f8f803..21e48923836d 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -442,7 +442,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; drm_panel_init(&ctx->panel, &dsi->dev, <k500hd1829_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c index 45b975dee587..198493a6eb6a 100644 --- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c +++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c @@ -184,7 +184,7 @@ static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_NO_EOT_PACKET; osd101t2587 = devm_kzalloc(&dsi->dev, sizeof(*osd101t2587), GFP_KERNEL); if (!osd101t2587) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index b962c817fb30..ccc8ed6fe3ae 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -446,7 +446,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) dsi->lanes = 1; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_EOT_PACKET; + dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET; ctx->supplies[0].supply = "vdd3"; ctx->supplies[1].supply = "vci"; diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index 527371120266..9b3599d6d2de 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -990,8 +990,8 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST - | MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP - | MIPI_DSI_MODE_VIDEO_HSA | MIPI_DSI_MODE_EOT_PACKET + | MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP + | MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT; ret = s6e8aa0_parse_dt(ctx); diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index 16dbf0f353ed..b937e24dac8e 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -282,7 +282,7 @@ static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_CLOCK_NON_CONTINUOUS | - MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_NO_EOT_PACKET; sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL); if (!sharp_nt) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 9b286bd4444f..dff3dedd734b 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1122,6 +1122,36 @@ static const struct panel_desc auo_b133xtn01 = { }, }; +static const struct drm_display_mode auo_b133han05_mode = { + .clock = 142600, + .hdisplay = 1920, + .hsync_start = 1920 + 58, + .hsync_end = 1920 + 58 + 42, + .htotal = 1920 + 58 + 42 + 60, + .vdisplay = 1080, + .vsync_start = 1080 + 3, + .vsync_end = 1080 + 3 + 5, + .vtotal = 1080 + 3 + 5 + 54, +}; + +static const struct panel_desc auo_b133han05 = { + .modes = &auo_b133han05_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 293, + .height = 165, + }, + .delay = { + .prepare = 100, + .enable = 20, + .unprepare = 50, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + static const struct drm_display_mode auo_b133htn01_mode = { .clock = 150660, .hdisplay = 1920, @@ -1149,6 +1179,36 @@ static const struct panel_desc auo_b133htn01 = { }, }; +static const struct drm_display_mode auo_b140han06_mode = { + .clock = 141000, + .hdisplay = 1920, + .hsync_start = 1920 + 16, + .hsync_end = 1920 + 16 + 16, + .htotal = 1920 + 16 + 16 + 152, + .vdisplay = 1080, + .vsync_start = 1080 + 3, + .vsync_end = 1080 + 3 + 14, + .vtotal = 1080 + 3 + 14 + 19, +}; + +static const struct panel_desc auo_b140han06 = { + .modes = &auo_b140han06_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 309, + .height = 174, + }, + .delay = { + .prepare = 100, + .enable = 20, + .unprepare = 50, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB, + .connector_type = DRM_MODE_CONNECTOR_eDP, +}; + static const struct display_timing auo_g070vvn01_timings = { .pixelclock = { 33300000, 34209000, 45000000 }, .hactive = { 800, 800, 800 }, @@ -4364,9 +4424,15 @@ static const struct of_device_id platform_of_match[] = { .compatible = "auo,b116xw03", .data = &auo_b116xw03, }, { + .compatible = "auo,b133han05", + .data = &auo_b133han05, + }, { .compatible = "auo,b133htn01", .data = &auo_b133htn01, }, { + .compatible = "auo,b140han06", + .data = &auo_b140han06, + }, { .compatible = "auo,b133xtn01", .data = &auo_b133xtn01, }, { @@ -5006,7 +5072,7 @@ static const struct panel_desc_dsi osd101t2045_53ts = { }, .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_EOT_PACKET, + MIPI_DSI_MODE_NO_EOT_PACKET, .format = MIPI_DSI_FMT_RGB888, .lanes = 4, }; diff --git a/drivers/gpu/drm/panel/panel-sony-acx424akp.c b/drivers/gpu/drm/panel/panel-sony-acx424akp.c index 95659a4d15e9..9536d56a94a5 100644 --- a/drivers/gpu/drm/panel/panel-sony-acx424akp.c +++ b/drivers/gpu/drm/panel/panel-sony-acx424akp.c @@ -40,7 +40,6 @@ struct acx424akp { struct drm_panel panel; struct device *dev; - struct backlight_device *bl; struct regulator *supply; struct gpio_desc *reset_gpio; bool video_mode; @@ -102,6 +101,18 @@ static int acx424akp_set_brightness(struct backlight_device *bl) u8 par; int ret; + if (backlight_is_blank(bl)) { + /* Disable backlight */ + par = 0x00; + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, + &par, 1); + if (ret) { + dev_err(acx->dev, "failed to disable display backlight (%d)\n", ret); + return ret; + } + return 0; + } + /* Calculate the PWM duty cycle in n/256's */ pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1); pwm_div = max(1, @@ -172,6 +183,12 @@ static const struct backlight_ops acx424akp_bl_ops = { .update_status = acx424akp_set_brightness, }; +static const struct backlight_properties acx424akp_bl_props = { + .type = BACKLIGHT_RAW, + .brightness = 512, + .max_brightness = 1023, +}; + static int acx424akp_read_id(struct acx424akp *acx) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); @@ -310,8 +327,6 @@ static int acx424akp_prepare(struct drm_panel *panel) } } - acx->bl->props.power = FB_BLANK_NORMAL; - return 0; err_power_off: @@ -323,18 +338,8 @@ static int acx424akp_unprepare(struct drm_panel *panel) { struct acx424akp *acx = panel_to_acx424akp(panel); struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev); - u8 par; int ret; - /* Disable backlight */ - par = 0x00; - ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, - &par, 1); - if (ret) { - dev_err(acx->dev, "failed to disable display backlight (%d)\n", ret); - return ret; - } - ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) { dev_err(acx->dev, "failed to turn display off (%d)\n", ret); @@ -350,36 +355,10 @@ static int acx424akp_unprepare(struct drm_panel *panel) msleep(85); acx424akp_power_off(acx); - acx->bl->props.power = FB_BLANK_POWERDOWN; - - return 0; -} - -static int acx424akp_enable(struct drm_panel *panel) -{ - struct acx424akp *acx = panel_to_acx424akp(panel); - - /* - * The backlight is on as long as the display is on - * so no use to call backlight_enable() here. - */ - acx->bl->props.power = FB_BLANK_UNBLANK; return 0; } -static int acx424akp_disable(struct drm_panel *panel) -{ - struct acx424akp *acx = panel_to_acx424akp(panel); - - /* - * The backlight is on as long as the display is on - * so no use to call backlight_disable() here. - */ - acx->bl->props.power = FB_BLANK_NORMAL; - - return 0; -} static int acx424akp_get_modes(struct drm_panel *panel, struct drm_connector *connector) @@ -409,10 +388,8 @@ static int acx424akp_get_modes(struct drm_panel *panel, } static const struct drm_panel_funcs acx424akp_drm_funcs = { - .disable = acx424akp_disable, .unprepare = acx424akp_unprepare, .prepare = acx424akp_prepare, - .enable = acx424akp_enable, .get_modes = acx424akp_get_modes, }; @@ -458,25 +435,18 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) /* This asserts RESET by default */ acx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(acx->reset_gpio)) { - ret = PTR_ERR(acx->reset_gpio); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to request GPIO (%d)\n", ret); - return ret; - } + if (IS_ERR(acx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(acx->reset_gpio), + "failed to request GPIO\n"); drm_panel_init(&acx->panel, dev, &acx424akp_drm_funcs, DRM_MODE_CONNECTOR_DSI); - acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, - &acx424akp_bl_ops, NULL); - if (IS_ERR(acx->bl)) { - dev_err(dev, "failed to register backlight device\n"); - return PTR_ERR(acx->bl); - } - acx->bl->props.max_brightness = 1023; - acx->bl->props.brightness = 512; - acx->bl->props.power = FB_BLANK_POWERDOWN; + acx->panel.backlight = devm_backlight_device_register(dev, "acx424akp", dev, acx, + &acx424akp_bl_ops, &acx424akp_bl_props); + if (IS_ERR(acx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(acx->panel.backlight), + "failed to register backlight device\n"); drm_panel_add(&acx->panel); diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c index 55172d63a922..d17aae8b71d7 100644 --- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c +++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c @@ -311,7 +311,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs, DRM_MODE_CONNECTOR_DSI); diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 3644652f726f..194af7f607a6 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -106,7 +106,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) if (ret) { /* Continue if the optional regulator is missing */ if (ret != -ENODEV) { - DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); return ret; } } diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index cb25c0e8fc9b..558f1b58bd69 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -10,6 +10,8 @@ config DRM_ROCKCHIP select DRM_DW_HDMI if ROCKCHIP_DW_HDMI select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI select DRM_RGB if ROCKCHIP_RGB + select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI + select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC help Choose this option if you have a Rockchip soc chipset. diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index ec7729d18cb8..a2262bee5aa4 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -14,6 +14,7 @@ #include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/pm_runtime.h> +#include <linux/phy/phy.h> #include <linux/regmap.h> #include <video/mipi_display.h> @@ -125,7 +126,9 @@ #define BANDGAP_AND_BIAS_CONTROL 0x20 #define TERMINATION_RESISTER_CONTROL 0x21 #define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22 +#define HS_RX_CONTROL_OF_LANE_CLK 0x34 #define HS_RX_CONTROL_OF_LANE_0 0x44 +#define HS_RX_CONTROL_OF_LANE_1 0x54 #define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60 #define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61 #define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62 @@ -137,6 +140,9 @@ #define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72 #define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73 #define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74 +#define HS_RX_DATA_LANE_THS_SETTLE_CONTROL 0x75 +#define HS_RX_CONTROL_OF_LANE_2 0x84 +#define HS_RX_CONTROL_OF_LANE_3 0x94 #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) #define DW_MIPI_NEEDS_GRF_CLK BIT(1) @@ -171,12 +177,20 @@ #define RK3399_TXRX_MASTERSLAVEZ BIT(7) #define RK3399_TXRX_ENABLECLK BIT(6) #define RK3399_TXRX_BASEDIR BIT(5) +#define RK3399_TXRX_SRC_SEL_ISP0 BIT(4) +#define RK3399_TXRX_TURNREQUEST GENMASK(3, 0) #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) #define to_dsi(nm) container_of(nm, struct dw_mipi_dsi_rockchip, nm) enum { + DW_DSI_USAGE_IDLE, + DW_DSI_USAGE_DSI, + DW_DSI_USAGE_PHY, +}; + +enum { BANDGAP_97_07, BANDGAP_98_05, BANDGAP_99_02, @@ -213,6 +227,10 @@ struct rockchip_dw_dsi_chip_data { u32 lanecfg2_grf_reg; u32 lanecfg2; + int (*dphy_rx_init)(struct phy *phy); + int (*dphy_rx_power_on)(struct phy *phy); + int (*dphy_rx_power_off)(struct phy *phy); + unsigned int flags; unsigned int max_data_lanes; }; @@ -223,6 +241,7 @@ struct dw_mipi_dsi_rockchip { void __iomem *base; struct regmap *grf_regmap; + struct clk *pclk; struct clk *pllref_clk; struct clk *grf_clk; struct clk *phy_cfg_clk; @@ -235,6 +254,12 @@ struct dw_mipi_dsi_rockchip { struct phy *phy; union phy_configure_opts phy_opts; + /* being a phy for other mipi hosts */ + unsigned int usage_mode; + struct mutex usage_mutex; + struct phy *dphy; + struct phy_configure_opts_mipi_dphy dphy_config; + unsigned int lane_mbps; /* per lane */ u16 input_div; u16 feedback_div; @@ -978,6 +1003,17 @@ static int dw_mipi_dsi_rockchip_host_attach(void *priv_data, struct device *second; int ret; + mutex_lock(&dsi->usage_mutex); + + if (dsi->usage_mode != DW_DSI_USAGE_IDLE) { + DRM_DEV_ERROR(dsi->dev, "dsi controller already in use\n"); + mutex_unlock(&dsi->usage_mutex); + return -EBUSY; + } + + dsi->usage_mode = DW_DSI_USAGE_DSI; + mutex_unlock(&dsi->usage_mutex); + ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops); if (ret) { DRM_DEV_ERROR(dsi->dev, "Failed to register component: %d\n", @@ -1013,6 +1049,10 @@ static int dw_mipi_dsi_rockchip_host_detach(void *priv_data, component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops); + mutex_lock(&dsi->usage_mutex); + dsi->usage_mode = DW_DSI_USAGE_IDLE; + mutex_unlock(&dsi->usage_mutex); + return 0; } @@ -1021,11 +1061,227 @@ static const struct dw_mipi_dsi_host_ops dw_mipi_dsi_rockchip_host_ops = { .detach = dw_mipi_dsi_rockchip_host_detach, }; +static int dw_mipi_dsi_rockchip_dphy_bind(struct device *dev, + struct device *master, + void *data) +{ + /* + * Nothing to do when used as a dphy. + * Just make the rest of Rockchip-DRM happy + * by being here. + */ + + return 0; +} + +static void dw_mipi_dsi_rockchip_dphy_unbind(struct device *dev, + struct device *master, + void *data) +{ + /* Nothing to do when used as a dphy. */ +} + +static const struct component_ops dw_mipi_dsi_rockchip_dphy_ops = { + .bind = dw_mipi_dsi_rockchip_dphy_bind, + .unbind = dw_mipi_dsi_rockchip_dphy_unbind, +}; + +static int dw_mipi_dsi_dphy_init(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + int ret; + + mutex_lock(&dsi->usage_mutex); + + if (dsi->usage_mode != DW_DSI_USAGE_IDLE) { + DRM_DEV_ERROR(dsi->dev, "dsi controller already in use\n"); + mutex_unlock(&dsi->usage_mutex); + return -EBUSY; + } + + dsi->usage_mode = DW_DSI_USAGE_PHY; + mutex_unlock(&dsi->usage_mutex); + + ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_dphy_ops); + if (ret < 0) + goto err_graph; + + if (dsi->cdata->dphy_rx_init) { + ret = clk_prepare_enable(dsi->pclk); + if (ret < 0) + goto err_init; + + ret = clk_prepare_enable(dsi->grf_clk); + if (ret) { + clk_disable_unprepare(dsi->pclk); + goto err_init; + } + + ret = dsi->cdata->dphy_rx_init(phy); + clk_disable_unprepare(dsi->grf_clk); + clk_disable_unprepare(dsi->pclk); + if (ret < 0) + goto err_init; + } + + return 0; + +err_init: + component_del(dsi->dev, &dw_mipi_dsi_rockchip_dphy_ops); +err_graph: + mutex_lock(&dsi->usage_mutex); + dsi->usage_mode = DW_DSI_USAGE_IDLE; + mutex_unlock(&dsi->usage_mutex); + + return ret; +} + +static int dw_mipi_dsi_dphy_exit(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + + component_del(dsi->dev, &dw_mipi_dsi_rockchip_dphy_ops); + + mutex_lock(&dsi->usage_mutex); + dsi->usage_mode = DW_DSI_USAGE_IDLE; + mutex_unlock(&dsi->usage_mutex); + + return 0; +} + +static int dw_mipi_dsi_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy; + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + int ret; + + ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); + if (ret) + return ret; + + dsi->dphy_config = *config; + dsi->lane_mbps = div_u64(config->hs_clk_rate, 1000 * 1000 * 1); + + return 0; +} + +static int dw_mipi_dsi_dphy_power_on(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + int i, ret; + + DRM_DEV_DEBUG(dsi->dev, "lanes %d - data_rate_mbps %u\n", + dsi->dphy_config.lanes, dsi->lane_mbps); + + i = max_mbps_to_parameter(dsi->lane_mbps); + if (i < 0) { + DRM_DEV_ERROR(dsi->dev, "failed to get parameter for %dmbps clock\n", + dsi->lane_mbps); + return i; + } + + ret = pm_runtime_get_sync(dsi->dev); + if (ret < 0) { + DRM_DEV_ERROR(dsi->dev, "failed to enable device: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(dsi->pclk); + if (ret) { + DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk: %d\n", ret); + goto err_pclk; + } + + ret = clk_prepare_enable(dsi->grf_clk); + if (ret) { + DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret); + goto err_grf_clk; + } + + ret = clk_prepare_enable(dsi->phy_cfg_clk); + if (ret) { + DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk: %d\n", ret); + goto err_phy_cfg_clk; + } + + /* do soc-variant specific init */ + if (dsi->cdata->dphy_rx_power_on) { + ret = dsi->cdata->dphy_rx_power_on(phy); + if (ret < 0) { + DRM_DEV_ERROR(dsi->dev, "hardware-specific phy bringup failed: %d\n", ret); + goto err_pwr_on; + } + } + + /* + * Configure hsfreqrange according to frequency values + * Set clock lane and hsfreqrange by lane0(test code 0x44) + */ + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_CLK, 0); + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0, + HSFREQRANGE_SEL(dppa_map[i].hsfreqrange)); + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_1, 0); + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_2, 0); + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_3, 0); + + /* Normal operation */ + dw_mipi_dsi_phy_write(dsi, 0x0, 0); + + clk_disable_unprepare(dsi->phy_cfg_clk); + clk_disable_unprepare(dsi->grf_clk); + + return ret; + +err_pwr_on: + clk_disable_unprepare(dsi->phy_cfg_clk); +err_phy_cfg_clk: + clk_disable_unprepare(dsi->grf_clk); +err_grf_clk: + clk_disable_unprepare(dsi->pclk); +err_pclk: + pm_runtime_put(dsi->dev); + return ret; +} + +static int dw_mipi_dsi_dphy_power_off(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(dsi->grf_clk); + if (ret) { + DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret); + return ret; + } + + if (dsi->cdata->dphy_rx_power_off) { + ret = dsi->cdata->dphy_rx_power_off(phy); + if (ret < 0) + DRM_DEV_ERROR(dsi->dev, "hardware-specific phy shutdown failed: %d\n", ret); + } + + clk_disable_unprepare(dsi->grf_clk); + clk_disable_unprepare(dsi->pclk); + + pm_runtime_put(dsi->dev); + + return ret; +} + +static const struct phy_ops dw_mipi_dsi_dphy_ops = { + .configure = dw_mipi_dsi_dphy_configure, + .power_on = dw_mipi_dsi_dphy_power_on, + .power_off = dw_mipi_dsi_dphy_power_off, + .init = dw_mipi_dsi_dphy_init, + .exit = dw_mipi_dsi_dphy_exit, +}; + static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct dw_mipi_dsi_rockchip *dsi; + struct phy_provider *phy_provider; struct resource *res; const struct rockchip_dw_dsi_chip_data *cdata = of_device_get_match_data(dev); @@ -1065,6 +1321,13 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev) return ret; } + dsi->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dsi->pclk)) { + ret = PTR_ERR(dsi->pclk); + DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret); + return ret; + } + dsi->pllref_clk = devm_clk_get(dev, "ref"); if (IS_ERR(dsi->pllref_clk)) { if (dsi->phy) { @@ -1115,6 +1378,19 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev) dsi->pdata.priv_data = dsi; platform_set_drvdata(pdev, dsi); + mutex_init(&dsi->usage_mutex); + + dsi->dphy = devm_phy_create(dev, NULL, &dw_mipi_dsi_dphy_ops); + if (IS_ERR(dsi->dphy)) { + DRM_DEV_ERROR(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(dsi->dphy); + } + + phy_set_drvdata(dsi->dphy, dsi); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata); if (IS_ERR(dsi->dmd)) { ret = PTR_ERR(dsi->dmd); @@ -1178,6 +1454,75 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = { { /* sentinel */ } }; +static int rk3399_dphy_tx1rx1_init(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + + /* + * Set TX1RX1 source to isp1. + * Assume ISP0 is supplied by the RX0 dphy. + */ + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, + HIWORD_UPDATE(0, RK3399_TXRX_SRC_SEL_ISP0)); + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, + HIWORD_UPDATE(0, RK3399_TXRX_MASTERSLAVEZ)); + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, + HIWORD_UPDATE(0, RK3399_TXRX_BASEDIR)); + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, + HIWORD_UPDATE(0, RK3399_DSI1_ENABLE)); + + return 0; +} + +static int rk3399_dphy_tx1rx1_power_on(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + + /* tester reset pulse */ + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_TESTCLR); + usleep_range(100, 150); + + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, + HIWORD_UPDATE(0, RK3399_TXRX_MASTERSLAVEZ)); + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, + HIWORD_UPDATE(RK3399_TXRX_BASEDIR, RK3399_TXRX_BASEDIR)); + + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, + HIWORD_UPDATE(0, RK3399_DSI1_FORCERXMODE)); + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, + HIWORD_UPDATE(0, RK3399_DSI1_FORCETXSTOPMODE)); + + /* Disable lane turn around, which is ignored in receive mode */ + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON24, + HIWORD_UPDATE(0, RK3399_TXRX_TURNREQUEST)); + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, + HIWORD_UPDATE(RK3399_DSI1_TURNDISABLE, + RK3399_DSI1_TURNDISABLE)); + usleep_range(100, 150); + + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR); + usleep_range(100, 150); + + /* Enable dphy lanes */ + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, + HIWORD_UPDATE(GENMASK(dsi->dphy_config.lanes - 1, 0), + RK3399_DSI1_ENABLE)); + + usleep_range(100, 150); + + return 0; +} + +static int rk3399_dphy_tx1rx1_power_off(struct phy *phy) +{ + struct dw_mipi_dsi_rockchip *dsi = phy_get_drvdata(phy); + + regmap_write(dsi->grf_regmap, RK3399_GRF_SOC_CON23, + HIWORD_UPDATE(0, RK3399_DSI1_ENABLE)); + + return 0; +} + static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { { .reg = 0xff960000, @@ -1220,6 +1565,10 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, .max_data_lanes = 4, + + .dphy_rx_init = rk3399_dphy_tx1rx1_init, + .dphy_rx_power_on = rk3399_dphy_tx1rx1_power_on, + .dphy_rx_power_off = rk3399_dphy_tx1rx1_power_off, }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 0a02b7092c04..7db01904d18d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -18,7 +18,6 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_gem_cma_helper.h> -#include <drm/drm_irq.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -130,7 +129,6 @@ DEFINE_DRM_GEM_CMA_FOPS(shmob_drm_fops); static const struct drm_driver shmob_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET, - .irq_handler = shmob_drm_irq, DRM_GEM_CMA_DRIVER_OPS, .fops = &shmob_drm_fops, .name = "shmob-drm", @@ -183,7 +181,7 @@ static int shmob_drm_remove(struct platform_device *pdev) drm_dev_unregister(ddev); drm_kms_helper_poll_fini(ddev); - drm_irq_uninstall(ddev); + free_irq(sdev->irq, ddev); drm_dev_put(ddev); return 0; @@ -258,7 +256,13 @@ static int shmob_drm_probe(struct platform_device *pdev) goto err_modeset_cleanup; } - ret = drm_irq_install(ddev, platform_get_irq(pdev, 0)); + ret = platform_get_irq(pdev, 0); + if (ret < 0) + goto err_modeset_cleanup; + sdev->irq = ret; + + ret = request_irq(sdev->irq, shmob_drm_irq, 0, ddev->driver->name, + ddev); if (ret < 0) { dev_err(&pdev->dev, "failed to install IRQ handler\n"); goto err_modeset_cleanup; @@ -275,7 +279,7 @@ static int shmob_drm_probe(struct platform_device *pdev) return 0; err_irq_uninstall: - drm_irq_uninstall(ddev); + free_irq(sdev->irq, ddev); err_modeset_cleanup: drm_kms_helper_poll_fini(ddev); err_free_drm_dev: diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/shmobile/shmob_drm_drv.h index 80dc4b1020aa..4964ddd5ab74 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.h +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.h @@ -29,6 +29,7 @@ struct shmob_drm_device { u32 lddckr; u32 ldmt1r; + unsigned int irq; spinlock_t irq_lock; /* Protects hardware LDINTR register */ struct drm_device *ddev; diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index a233c86d428b..cf7287fccd72 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -3,7 +3,6 @@ * Copyright 2019 Hans de Goede <hdegoede@redhat.com> */ -#include <linux/dma-buf.h> #include <linux/module.h> #include <linux/usb.h> @@ -268,13 +267,10 @@ static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320) y2 = gm12u320->fb_update.rect.y2; vaddr = gm12u320->fb_update.src_map.vaddr; /* TODO: Use mapping abstraction properly */ - if (fb->obj[0]->import_attach) { - ret = dma_buf_begin_cpu_access( - fb->obj[0]->import_attach->dmabuf, DMA_FROM_DEVICE); - if (ret) { - GM12U320_ERR("dma_buf_begin_cpu_access err: %d\n", ret); - goto put_fb; - } + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) { + GM12U320_ERR("drm_gem_fb_begin_cpu_access err: %d\n", ret); + goto put_fb; } src = vaddr + y1 * fb->pitches[0] + x1 * 4; @@ -311,12 +307,7 @@ static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320) src += fb->pitches[0]; } - if (fb->obj[0]->import_attach) { - ret = dma_buf_end_cpu_access(fb->obj[0]->import_attach->dmabuf, - DMA_FROM_DEVICE); - if (ret) - GM12U320_ERR("dma_buf_end_cpu_access err: %d\n", ret); - } + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); put_fb: drm_framebuffer_put(fb); gm12u320->fb_update.fb = NULL; diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 007d9d59f01c..4d07b21a16e6 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -14,7 +14,6 @@ */ #include <linux/delay.h> -#include <linux/dma-buf.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/property.h> @@ -532,7 +531,6 @@ static void repaper_gray8_to_mono_reversed(u8 *buf, u32 width, u32 height) static int repaper_fb_dirty(struct drm_framebuffer *fb) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; struct repaper_epd *epd = drm_to_epd(fb->dev); struct drm_rect clip; int idx, ret = 0; @@ -558,21 +556,13 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb) goto out_exit; } - if (import_attach) { - ret = dma_buf_begin_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); - if (ret) - goto out_free; - } + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + goto out_free; drm_fb_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip); - if (import_attach) { - ret = dma_buf_end_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); - if (ret) - goto out_free; - } + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); repaper_gray8_to_mono_reversed(buf, fb->width, fb->height); diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c index 1be55bed609a..ad0faa8723c2 100644 --- a/drivers/gpu/drm/tiny/st7586.c +++ b/drivers/gpu/drm/tiny/st7586.c @@ -6,7 +6,6 @@ */ #include <linux/delay.h> -#include <linux/dma-buf.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/property.h> @@ -21,6 +20,7 @@ #include <drm/drm_format_helper.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_rect.h> @@ -92,24 +92,18 @@ static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb, struct drm_rect *clip) { struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; void *src = cma_obj->vaddr; int ret = 0; - if (import_attach) { - ret = dma_buf_begin_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); - if (ret) - return ret; - } + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return ret; st7586_xrgb8888_to_gray332(dst, src, fb, clip); - if (import_attach) - ret = dma_buf_end_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); - return ret; + return 0; } static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 8d98bf69d075..8a6b94b1511b 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -6,11 +6,8 @@ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> - */ -#include <linux/dma-buf.h> - #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_damage_helper.h> @@ -271,9 +268,8 @@ static int udl_handle_damage(struct drm_framebuffer *fb, const struct dma_buf_ma int x, int y, int width, int height) { struct drm_device *dev = fb->dev; - struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach; void *vaddr = map->vaddr; /* TODO: Use mapping abstraction properly */ - int i, ret, tmp_ret; + int i, ret; char *cmd; struct urb *urb; struct drm_rect clip; @@ -290,17 +286,14 @@ static int udl_handle_damage(struct drm_framebuffer *fb, const struct dma_buf_ma else if ((clip.x2 > fb->width) || (clip.y2 > fb->height)) return -EINVAL; - if (import_attach) { - ret = dma_buf_begin_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); - if (ret) - return ret; - } + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return ret; urb = udl_get_urb(dev); if (!urb) { ret = -ENOMEM; - goto out_dma_buf_end_cpu_access; + goto out_drm_gem_fb_end_cpu_access; } cmd = urb->transfer_buffer; @@ -313,7 +306,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, const struct dma_buf_ma &cmd, byte_offset, dev_byte_offset, byte_width); if (ret) - goto out_dma_buf_end_cpu_access; + goto out_drm_gem_fb_end_cpu_access; } if (cmd > (char *)urb->transfer_buffer) { @@ -329,14 +322,8 @@ static int udl_handle_damage(struct drm_framebuffer *fb, const struct dma_buf_ma ret = 0; -out_dma_buf_end_cpu_access: - if (import_attach) { - tmp_ret = dma_buf_end_cpu_access(import_attach->dmabuf, - DMA_FROM_DEVICE); - if (tmp_ret && !ret) - ret = tmp_ret; /* only update ret if not set yet */ - } - +out_drm_gem_fb_end_cpu_access: + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); return ret; } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b20530cf6a23..b7dc32a0c9bb 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1184,12 +1184,13 @@ static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) } /* HDMI audio codec callbacks */ -static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi) +static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, + unsigned int samplerate) { u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock); unsigned long n, m; - rational_best_approximation(hsm_clock, vc4_hdmi->audio.samplerate, + rational_best_approximation(hsm_clock, samplerate, VC4_HD_MAI_SMP_N_MASK >> VC4_HD_MAI_SMP_N_SHIFT, (VC4_HD_MAI_SMP_M_MASK >> @@ -1201,12 +1202,11 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi) VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); } -static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi) +static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) { struct drm_connector *connector = &vc4_hdmi->connector; struct drm_crtc *crtc = connector->state->crtc; const struct drm_display_mode *mode = &crtc->state->adjusted_mode; - u32 samplerate = vc4_hdmi->audio.samplerate; u32 n, cts; u64 tmp; @@ -1340,27 +1340,25 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + unsigned int sample_rate = params->sample_rate; + unsigned int channels = params->channels; u32 audio_packet_config, channel_mask; u32 channel_map; u32 mai_audio_format; u32 mai_sample_rate; dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, - params->sample_rate, params->sample_width, - params->channels); - - vc4_hdmi->audio.channels = params->channels; - vc4_hdmi->audio.samplerate = params->sample_rate; + sample_rate, params->sample_width, channels); HDMI_WRITE(HDMI_MAI_CTL, - VC4_SET_FIELD(params->channels, VC4_HD_MAI_CTL_CHNUM) | + VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) | VC4_HD_MAI_CTL_WHOLSMP | VC4_HD_MAI_CTL_CHALIGN | VC4_HD_MAI_CTL_ENABLE); - vc4_hdmi_audio_set_mai_clock(vc4_hdmi); + vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); - mai_sample_rate = sample_rate_to_mai_fmt(vc4_hdmi->audio.samplerate); + mai_sample_rate = sample_rate_to_mai_fmt(sample_rate); if (params->iec.status[0] & IEC958_AES0_NONAUDIO && params->channels == 8) mai_audio_format = VC4_HDMI_MAI_FORMAT_HBR; @@ -1378,7 +1376,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS | VC4_SET_FIELD(0x8, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); - channel_mask = GENMASK(vc4_hdmi->audio.channels - 1, 0); + channel_mask = GENMASK(channels - 1, 0); audio_packet_config |= VC4_SET_FIELD(channel_mask, VC4_HDMI_AUDIO_PACKET_CEA_MASK); @@ -1397,7 +1395,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask); HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map); HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); - vc4_hdmi_set_n_cts(vc4_hdmi); + vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate); memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); vc4_hdmi_set_audio_infoframe(encoder); @@ -1413,18 +1411,6 @@ static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = { { "TX", NULL, "Playback" }, }; -static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = { - .name = "vc4-hdmi-codec-dai-component", - .dapm_widgets = vc4_hdmi_audio_widgets, - .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets), - .dapm_routes = vc4_hdmi_audio_routes, - .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes), - .idle_bias_on = 1, - .use_pmdown_time = 1, - .endianness = 1, - .non_legacy_dai_naming = 1, -}; - static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { .name = "vc4-hdmi-cpu-dai-component", }; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index b6697b695f71..33e9f665ab8e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -111,8 +111,6 @@ struct vc4_hdmi_audio { struct snd_soc_dai_link_component cpu; struct snd_soc_dai_link_component codec; struct snd_soc_dai_link_component platform; - int samplerate; - int channels; struct snd_dmaengine_dai_dma_data dma_data; struct hdmi_audio_infoframe infoframe; bool streaming; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c index 30a837b5baa6..67db472d3493 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c @@ -140,7 +140,8 @@ struct vmw_fifo_state *vmw_fifo_create(struct vmw_private *dev_priv) min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN); fifo->capabilities = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CAPABILITIES); - DRM_INFO("Fifo max 0x%08x min 0x%08x cap 0x%08x\n", + drm_info(&dev_priv->drm, + "Fifo max 0x%08x min 0x%08x cap 0x%08x\n", (unsigned int) max, (unsigned int) min, (unsigned int) fifo->capabilities); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 9656d4a2abff..81b84570da0a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -1272,7 +1272,8 @@ int vmw_cmdbuf_set_pool_size(struct vmw_cmdbuf_man *man, size_t size) * submissions to be able to free up space. */ man->default_size = VMW_CMDBUF_INLINE_SIZE; - DRM_INFO("Using command buffers with %s pool.\n", + drm_info(&dev_priv->drm, + "Using command buffers with %s pool.\n", (man->using_mob) ? "MOB" : "DMA"); return 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 40864ce19ae1..ab9a1750e1df 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -160,109 +160,101 @@ struct drm_vmw_mksstat_remove_arg) /* - * The core DRM version of this macro doesn't account for - * DRM_COMMAND_BASE. - */ - -#define VMW_IOCTL_DEF(ioctl, func, flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func} - -/* * Ioctl definitions. */ static const struct drm_ioctl_desc vmw_ioctls[] = { - VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, - vmw_kms_cursor_bypass_ioctl, - DRM_MASTER), - - VMW_IOCTL_DEF(VMW_CONTROL_STREAM, vmw_overlay_ioctl, - DRM_MASTER), - VMW_IOCTL_DEF(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, - DRM_MASTER), - VMW_IOCTL_DEF(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, - DRM_MASTER), - - VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_SIGNALED, - vmw_fence_obj_signaled_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, - DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GET_PARAM, vmw_getparam_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CURSOR_BYPASS, + vmw_kms_cursor_bypass_ioctl, + DRM_MASTER), + + DRM_IOCTL_DEF_DRV(VMW_CONTROL_STREAM, vmw_overlay_ioctl, + DRM_MASTER), + DRM_IOCTL_DEF_DRV(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, + DRM_MASTER), + DRM_IOCTL_DEF_DRV(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, + DRM_MASTER), + + DRM_IOCTL_DEF_DRV(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_REF_SURFACE, vmw_surface_reference_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_EXECBUF, vmw_execbuf_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_SIGNALED, + vmw_fence_obj_signaled_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_FENCE_EVENT, vmw_fence_event_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, + DRM_RENDER_ALLOW), /* these allow direct access to the framebuffers mark as master only */ - VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, - DRM_MASTER | DRM_AUTH), - VMW_IOCTL_DEF(VMW_PRESENT_READBACK, - vmw_present_readback_ioctl, - DRM_MASTER | DRM_AUTH), + DRM_IOCTL_DEF_DRV(VMW_PRESENT, vmw_present_ioctl, + DRM_MASTER | DRM_AUTH), + DRM_IOCTL_DEF_DRV(VMW_PRESENT_READBACK, + vmw_present_readback_ioctl, + DRM_MASTER | DRM_AUTH), /* * The permissions of the below ioctl are overridden in * vmw_generic_ioctl(). We require either * DRM_MASTER or capable(CAP_SYS_ADMIN). */ - VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, - vmw_kms_update_layout_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CREATE_SHADER, - vmw_shader_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_SHADER, - vmw_shader_destroy_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, - vmw_gb_surface_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, - vmw_gb_surface_reference_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_SYNCCPU, - vmw_user_bo_synccpu_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, - vmw_extended_context_define_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, - vmw_gb_surface_define_ext_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, - vmw_gb_surface_reference_ext_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MSG, - vmw_msg_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MKSSTAT_RESET, - vmw_mksstat_reset_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MKSSTAT_ADD, - vmw_mksstat_add_ioctl, - DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_MKSSTAT_REMOVE, - vmw_mksstat_remove_ioctl, - DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UPDATE_LAYOUT, + vmw_kms_update_layout_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CREATE_SHADER, + vmw_shader_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_UNREF_SHADER, + vmw_shader_destroy_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_CREATE, + vmw_gb_surface_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_REF, + vmw_gb_surface_reference_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_SYNCCPU, + vmw_user_bo_synccpu_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_CREATE_EXTENDED_CONTEXT, + vmw_extended_context_define_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_CREATE_EXT, + vmw_gb_surface_define_ext_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_GB_SURFACE_REF_EXT, + vmw_gb_surface_reference_ext_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MSG, + vmw_msg_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_RESET, + vmw_mksstat_reset_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_ADD, + vmw_mksstat_add_ioctl, + DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(VMW_MKSSTAT_REMOVE, + vmw_mksstat_remove_ioctl, + DRM_RENDER_ALLOW), }; static const struct pci_device_id vmw_pci_id_list[] = { @@ -294,62 +286,92 @@ MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); -static void vmw_print_capabilities2(uint32_t capabilities2) +struct bitmap_name { + uint32 value; + const char *name; +}; + +static const struct bitmap_name cap1_names[] = { + { SVGA_CAP_RECT_COPY, "rect copy" }, + { SVGA_CAP_CURSOR, "cursor" }, + { SVGA_CAP_CURSOR_BYPASS, "cursor bypass" }, + { SVGA_CAP_CURSOR_BYPASS_2, "cursor bypass 2" }, + { SVGA_CAP_8BIT_EMULATION, "8bit emulation" }, + { SVGA_CAP_ALPHA_CURSOR, "alpha cursor" }, + { SVGA_CAP_3D, "3D" }, + { SVGA_CAP_EXTENDED_FIFO, "extended fifo" }, + { SVGA_CAP_MULTIMON, "multimon" }, + { SVGA_CAP_PITCHLOCK, "pitchlock" }, + { SVGA_CAP_IRQMASK, "irq mask" }, + { SVGA_CAP_DISPLAY_TOPOLOGY, "display topology" }, + { SVGA_CAP_GMR, "gmr" }, + { SVGA_CAP_TRACES, "traces" }, + { SVGA_CAP_GMR2, "gmr2" }, + { SVGA_CAP_SCREEN_OBJECT_2, "screen object 2" }, + { SVGA_CAP_COMMAND_BUFFERS, "command buffers" }, + { SVGA_CAP_CMD_BUFFERS_2, "command buffers 2" }, + { SVGA_CAP_GBOBJECTS, "gbobject" }, + { SVGA_CAP_DX, "dx" }, + { SVGA_CAP_HP_CMD_QUEUE, "hp cmd queue" }, + { SVGA_CAP_NO_BB_RESTRICTION, "no bb restriction" }, + { SVGA_CAP_CAP2_REGISTER, "cap2 register" }, +}; + + +static const struct bitmap_name cap2_names[] = { + { SVGA_CAP2_GROW_OTABLE, "grow otable" }, + { SVGA_CAP2_INTRA_SURFACE_COPY, "intra surface copy" }, + { SVGA_CAP2_DX2, "dx2" }, + { SVGA_CAP2_GB_MEMSIZE_2, "gb memsize 2" }, + { SVGA_CAP2_SCREENDMA_REG, "screendma reg" }, + { SVGA_CAP2_OTABLE_PTDEPTH_2, "otable ptdepth2" }, + { SVGA_CAP2_NON_MS_TO_MS_STRETCHBLT, "non ms to ms stretchblt" }, + { SVGA_CAP2_CURSOR_MOB, "cursor mob" }, + { SVGA_CAP2_MSHINT, "mshint" }, + { SVGA_CAP2_CB_MAX_SIZE_4MB, "cb max size 4mb" }, + { SVGA_CAP2_DX3, "dx3" }, + { SVGA_CAP2_FRAME_TYPE, "frame type" }, + { SVGA_CAP2_COTABLE_COPY, "cotable copy" }, + { SVGA_CAP2_TRACE_FULL_FB, "trace full fb" }, + { SVGA_CAP2_EXTRA_REGS, "extra regs" }, + { SVGA_CAP2_LO_STAGING, "lo staging" }, +}; + +static void vmw_print_bitmap(struct drm_device *drm, + const char *prefix, uint32_t bitmap, + const struct bitmap_name *bnames, + uint32_t num_names) { - DRM_INFO("Capabilities2:\n"); - if (capabilities2 & SVGA_CAP2_GROW_OTABLE) - DRM_INFO(" Grow oTable.\n"); - if (capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY) - DRM_INFO(" IntraSurface copy.\n"); - if (capabilities2 & SVGA_CAP2_DX3) - DRM_INFO(" DX3.\n"); + char buf[512]; + uint32_t i; + uint32_t offset = 0; + for (i = 0; i < num_names; ++i) { + if ((bitmap & bnames[i].value) != 0) { + offset += snprintf(buf + offset, + ARRAY_SIZE(buf) - offset, + "%s, ", bnames[i].name); + bitmap &= ~bnames[i].value; + } + } + + drm_info(drm, "%s: %s\n", prefix, buf); + if (bitmap != 0) + drm_dbg(drm, "%s: unknown enums: %x\n", prefix, bitmap); } -static void vmw_print_capabilities(uint32_t capabilities) + +static void vmw_print_sm_type(struct vmw_private *dev_priv) { - DRM_INFO("Capabilities:\n"); - if (capabilities & SVGA_CAP_RECT_COPY) - DRM_INFO(" Rect copy.\n"); - if (capabilities & SVGA_CAP_CURSOR) - DRM_INFO(" Cursor.\n"); - if (capabilities & SVGA_CAP_CURSOR_BYPASS) - DRM_INFO(" Cursor bypass.\n"); - if (capabilities & SVGA_CAP_CURSOR_BYPASS_2) - DRM_INFO(" Cursor bypass 2.\n"); - if (capabilities & SVGA_CAP_8BIT_EMULATION) - DRM_INFO(" 8bit emulation.\n"); - if (capabilities & SVGA_CAP_ALPHA_CURSOR) - DRM_INFO(" Alpha cursor.\n"); - if (capabilities & SVGA_CAP_3D) - DRM_INFO(" 3D.\n"); - if (capabilities & SVGA_CAP_EXTENDED_FIFO) - DRM_INFO(" Extended Fifo.\n"); - if (capabilities & SVGA_CAP_MULTIMON) - DRM_INFO(" Multimon.\n"); - if (capabilities & SVGA_CAP_PITCHLOCK) - DRM_INFO(" Pitchlock.\n"); - if (capabilities & SVGA_CAP_IRQMASK) - DRM_INFO(" Irq mask.\n"); - if (capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) - DRM_INFO(" Display Topology.\n"); - if (capabilities & SVGA_CAP_GMR) - DRM_INFO(" GMR.\n"); - if (capabilities & SVGA_CAP_TRACES) - DRM_INFO(" Traces.\n"); - if (capabilities & SVGA_CAP_GMR2) - DRM_INFO(" GMR2.\n"); - if (capabilities & SVGA_CAP_SCREEN_OBJECT_2) - DRM_INFO(" Screen Object 2.\n"); - if (capabilities & SVGA_CAP_COMMAND_BUFFERS) - DRM_INFO(" Command Buffers.\n"); - if (capabilities & SVGA_CAP_CMD_BUFFERS_2) - DRM_INFO(" Command Buffers 2.\n"); - if (capabilities & SVGA_CAP_GBOBJECTS) - DRM_INFO(" Guest Backed Resources.\n"); - if (capabilities & SVGA_CAP_DX) - DRM_INFO(" DX Features.\n"); - if (capabilities & SVGA_CAP_HP_CMD_QUEUE) - DRM_INFO(" HP Command Queue.\n"); + static const char *names[] = { + [VMW_SM_LEGACY] = "Legacy", + [VMW_SM_4] = "SM4", + [VMW_SM_4_1] = "SM4_1", + [VMW_SM_5] = "SM_5", + [VMW_SM_MAX] = "Invalid" + }; + BUILD_BUG_ON(ARRAY_SIZE(names) != (VMW_SM_MAX + 1)); + drm_info(&dev_priv->drm, "Available shader model: %s.\n", + names[dev_priv->sm_type]); } /** @@ -416,10 +438,6 @@ static int vmw_device_init(struct vmw_private *dev_priv) { bool uses_fb_traces = false; - DRM_INFO("width %d\n", vmw_read(dev_priv, SVGA_REG_WIDTH)); - DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT)); - DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL)); - dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); @@ -658,7 +676,8 @@ static int vmw_dma_select_mode(struct vmw_private *dev_priv) else dev_priv->map_mode = vmw_dma_map_populate; - DRM_INFO("DMA map mode: %s\n", names[dev_priv->map_mode]); + drm_info(&dev_priv->drm, + "DMA map mode: %s\n", names[dev_priv->map_mode]); return 0; } @@ -677,7 +696,8 @@ static int vmw_dma_masks(struct vmw_private *dev_priv) ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)); if (sizeof(unsigned long) == 4 || vmw_restrict_dma_mask) { - DRM_INFO("Restricting DMA addresses to 44 bits.\n"); + drm_info(&dev_priv->drm, + "Restricting DMA addresses to 44 bits.\n"); return dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(44)); } @@ -729,13 +749,15 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, dev->vram_start = pci_resource_start(pdev, 2); dev->vram_size = pci_resource_len(pdev, 2); - DRM_INFO("Register MMIO at 0x%pa size is %llu kiB\n", + drm_info(&dev->drm, + "Register MMIO at 0x%pa size is %llu kiB\n", &rmmio_start, (uint64_t)rmmio_size / 1024); dev->rmmio = devm_ioremap(dev->drm.dev, rmmio_start, rmmio_size); if (!dev->rmmio) { - DRM_ERROR("Failed mapping registers mmio memory.\n"); + drm_err(&dev->drm, + "Failed mapping registers mmio memory.\n"); pci_release_regions(pdev); return -ENOMEM; } @@ -746,7 +768,8 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, fifo_start = pci_resource_start(pdev, 2); fifo_size = pci_resource_len(pdev, 2); - DRM_INFO("FIFO at %pa size is %llu kiB\n", + drm_info(&dev->drm, + "FIFO at %pa size is %llu kiB\n", &fifo_start, (uint64_t)fifo_size / 1024); dev->fifo_mem = devm_memremap(dev->drm.dev, fifo_start, @@ -754,7 +777,8 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, MEMREMAP_WB); if (IS_ERR(dev->fifo_mem)) { - DRM_ERROR("Failed mapping FIFO memory.\n"); + drm_err(&dev->drm, + "Failed mapping FIFO memory.\n"); pci_release_regions(pdev); return PTR_ERR(dev->fifo_mem); } @@ -769,7 +793,8 @@ static int vmw_setup_pci_resources(struct vmw_private *dev, * size will be equal to or bigger than the size reported by * SVGA_REG_VRAM_SIZE. */ - DRM_INFO("VRAM at %pa size is %llu kiB\n", + drm_info(&dev->drm, + "VRAM at %pa size is %llu kiB\n", &dev->vram_start, (uint64_t)dev->vram_size / 1024); return 0; @@ -783,12 +808,14 @@ static int vmw_detect_version(struct vmw_private *dev) SVGA_ID_3 : SVGA_ID_2); svga_id = vmw_read(dev, SVGA_REG_ID); if (svga_id != SVGA_ID_2 && svga_id != SVGA_ID_3) { - DRM_ERROR("Unsupported SVGA ID 0x%x on chipset 0x%x\n", - svga_id, dev->pci_id); + drm_err(&dev->drm, + "Unsupported SVGA ID 0x%x on chipset 0x%x\n", + svga_id, dev->pci_id); return -ENOSYS; } BUG_ON(vmw_is_svga_v3(dev) && (svga_id != SVGA_ID_3)); - DRM_INFO("Running on SVGA version %d.\n", (svga_id & 0xff)); + drm_info(&dev->drm, + "Running on SVGA version %d.\n", (svga_id & 0xff)); return 0; } @@ -842,10 +869,12 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { - DRM_INFO("Restricting capabilities since DMA not available.\n"); + drm_info(&dev_priv->drm, + "Restricting capabilities since DMA not available.\n"); refuse_dma = true; if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) - DRM_INFO("Disabling 3D acceleration.\n"); + drm_info(&dev_priv->drm, + "Disabling 3D acceleration.\n"); } dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE); @@ -913,12 +942,23 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->texture_max_height = 8192; dev_priv->max_primary_mem = dev_priv->vram_size; } - - vmw_print_capabilities(dev_priv->capabilities); + drm_info(&dev_priv->drm, + "Legacy memory limits: VRAM = %llu kB, FIFO = %llu kB, surface = %u kB\n", + (u64)dev_priv->vram_size / 1024, + (u64)dev_priv->fifo_mem_size / 1024, + dev_priv->memory_size / 1024); + + drm_info(&dev_priv->drm, + "MOB limits: max mob size = %u kB, max mob pages = %u\n", + dev_priv->max_mob_size / 1024, dev_priv->max_mob_pages); + + vmw_print_bitmap(&dev_priv->drm, "Capabilities", + dev_priv->capabilities, + cap1_names, ARRAY_SIZE(cap1_names)); if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) - vmw_print_capabilities2(dev_priv->capabilities2); - DRM_INFO("Supports command queues = %d\n", - vmw_cmd_supported((dev_priv))); + vmw_print_bitmap(&dev_priv->drm, "Capabilities2", + dev_priv->capabilities2, + cap2_names, ARRAY_SIZE(cap2_names)); ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) @@ -927,14 +967,15 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dma_set_max_seg_size(dev_priv->drm.dev, U32_MAX); if (dev_priv->capabilities & SVGA_CAP_GMR2) { - DRM_INFO("Max GMR ids is %u\n", + drm_info(&dev_priv->drm, + "Max GMR ids is %u\n", (unsigned)dev_priv->max_gmr_ids); - DRM_INFO("Max number of GMR pages is %u\n", + drm_info(&dev_priv->drm, + "Max number of GMR pages is %u\n", (unsigned)dev_priv->max_gmr_pages); - DRM_INFO("Max dedicated hypervisor surface memory is %u kiB\n", - (unsigned)dev_priv->memory_size / 1024); } - DRM_INFO("Maximum display memory size is %llu kiB\n", + drm_info(&dev_priv->drm, + "Maximum display memory size is %llu kiB\n", (uint64_t)dev_priv->max_primary_mem / 1024); /* Need mmio memory to check for fifo pitchlock cap. */ @@ -950,7 +991,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) &vmw_prime_dmabuf_ops); if (unlikely(dev_priv->tdev == NULL)) { - DRM_ERROR("Unable to initialize TTM object management.\n"); + drm_err(&dev_priv->drm, + "Unable to initialize TTM object management.\n"); ret = -ENOMEM; goto out_err0; } @@ -958,7 +1000,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { ret = vmw_irq_install(&dev_priv->drm, pdev->irq); if (ret != 0) { - DRM_ERROR("Failed installing irq: %d\n", ret); + drm_err(&dev_priv->drm, + "Failed installing irq: %d\n", ret); goto out_no_irq; } } @@ -979,7 +1022,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->map_mode == vmw_dma_alloc_coherent, false); if (unlikely(ret != 0)) { - DRM_ERROR("Failed initializing TTM buffer object driver.\n"); + drm_err(&dev_priv->drm, + "Failed initializing TTM buffer object driver.\n"); goto out_no_bdev; } @@ -990,13 +1034,15 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) ret = vmw_vram_manager_init(dev_priv); if (unlikely(ret != 0)) { - DRM_ERROR("Failed initializing memory manager for VRAM.\n"); + drm_err(&dev_priv->drm, + "Failed initializing memory manager for VRAM.\n"); goto out_no_vram; } ret = vmw_devcaps_create(dev_priv); if (unlikely(ret != 0)) { - DRM_ERROR("Failed initializing device caps.\n"); + drm_err(&dev_priv->drm, + "Failed initializing device caps.\n"); goto out_no_vram; } @@ -1010,7 +1056,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || refuse_dma || vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) { - DRM_INFO("No GMR memory available. " + drm_info(&dev_priv->drm, + "No GMR memory available. " "Graphics memory resources are very limited.\n"); dev_priv->has_gmr = false; } @@ -1019,7 +1066,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->has_mob = true; if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) { - DRM_INFO("No MOB memory available. " + drm_info(&dev_priv->drm, + "No MOB memory available. " "3D will be disabled.\n"); dev_priv->has_mob = false; } @@ -1053,14 +1101,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) if (ret) goto out_no_fifo; - if (dev_priv->sm_type == VMW_SM_5) - DRM_INFO("SM5 support available.\n"); - if (dev_priv->sm_type == VMW_SM_4_1) - DRM_INFO("SM4_1 support available.\n"); - if (dev_priv->sm_type == VMW_SM_4) - DRM_INFO("SM4 support available.\n"); - DRM_INFO("Running without reservation semaphore\n"); - + vmw_print_sm_type(dev_priv); vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 356f82c26f59..63437270cbca 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -54,10 +54,10 @@ #define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20210218" +#define VMWGFX_DRIVER_DATE "20210722" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 18 -#define VMWGFX_DRIVER_PATCHLEVEL 1 +#define VMWGFX_DRIVER_MINOR 19 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 #define VMWGFX_MAX_VALIDATIONS 2048 @@ -367,7 +367,8 @@ enum vmw_display_unit_type { vmw_du_invalid = 0, vmw_du_legacy, vmw_du_screen_object, - vmw_du_screen_target + vmw_du_screen_target, + vmw_du_max }; struct vmw_validation_context; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index 28ceb749a733..b2c4af331c9d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -71,8 +71,40 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, if (gman->max_gmr_pages > 0) { gman->used_gmr_pages += (*res)->num_pages; - if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) - goto nospace; + /* + * Because the graphics memory is a soft limit we can try to + * expand it instead of letting the userspace apps crash. + * We're just going to have a sane limit (half of RAM) + * on the number of MOB's that we create and will try to keep + * the system running until we reach that. + */ + if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) { + const unsigned long max_graphics_pages = totalram_pages() / 2; + uint32_t new_max_pages = 0; + + DRM_WARN("vmwgfx: mob memory overflow. Consider increasing guest RAM and graphicsMemory.\n"); + vmw_host_printf("vmwgfx, warning: mob memory overflow. Consider increasing guest RAM and graphicsMemory.\n"); + + if (gman->max_gmr_pages > (max_graphics_pages / 2)) { + DRM_WARN("vmwgfx: guest requires more than half of RAM for graphics.\n"); + new_max_pages = max_graphics_pages; + } else + new_max_pages = gman->max_gmr_pages * 2; + if (new_max_pages > gman->max_gmr_pages && new_max_pages >= gman->used_gmr_pages) { + DRM_WARN("vmwgfx: increasing guest mob limits to %u kB.\n", + ((new_max_pages) << (PAGE_SHIFT - 10))); + + gman->max_gmr_pages = new_max_pages; + } else { + char buf[256]; + snprintf(buf, sizeof(buf), + "vmwgfx, error: guest graphics is out of memory (mob limit at: %ukB).\n", + ((gman->max_gmr_pages) << (PAGE_SHIFT - 10))); + vmw_host_printf(buf); + DRM_WARN("%s", buf); + goto nospace; + } + } } (*res)->start = id; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 2ddf4932d62c..338c6e2613ea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1793,6 +1793,13 @@ int vmw_kms_init(struct vmw_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; int ret; + static const char *display_unit_names[] = { + "Invalid", + "Legacy", + "Screen Object", + "Screen Target", + "Invalid (max)" + }; drm_mode_config_init(dev); dev->mode_config.funcs = &vmw_kms_funcs; @@ -1810,6 +1817,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) if (ret) /* Fallback */ ret = vmw_kms_ldu_init_display(dev_priv); } + BUILD_BUG_ON(ARRAY_SIZE(display_unit_names) != (vmw_du_max + 1)); + drm_info(&dev_priv->drm, "%s display unit initialized\n", + display_unit_names[dev_priv->active_display_unit]); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index d85c7eab9469..fb58a71c458f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -493,8 +493,7 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) struct drm_device *dev = &dev_priv->drm; int i, ret; - if (dev_priv->ldu_priv) { - DRM_INFO("ldu system already on\n"); + if (unlikely(dev_priv->ldu_priv)) { return -EINVAL; } @@ -527,8 +526,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) drm_mode_config_reset(dev); - DRM_INFO("Legacy Display Unit initialized\n"); - return 0; err_free: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 145430d14219..bd157fb21b45 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -954,8 +954,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) int i, ret; if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { - DRM_INFO("Not using screen objects," - " missing cap SCREEN_OBJECT_2\n"); return -ENOSYS; } @@ -972,8 +970,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) drm_mode_config_reset(dev); - DRM_INFO("Screen Objects Display Unit initialized\n"); - return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 365ed93dd3e8..d85310b2608d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1889,14 +1889,13 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) ret = vmw_stdu_init(dev_priv, i); if (unlikely(ret != 0)) { - DRM_ERROR("Failed to initialize STDU %d", i); + drm_err(&dev_priv->drm, + "Failed to initialize STDU %d", i); return ret; } } drm_mode_config_reset(dev); - DRM_INFO("Screen Target Display device initialized\n"); - return 0; } diff --git a/drivers/video/fbdev/asiliantfb.c b/drivers/video/fbdev/asiliantfb.c index 3e006da47752..84c56f525889 100644 --- a/drivers/video/fbdev/asiliantfb.c +++ b/drivers/video/fbdev/asiliantfb.c @@ -227,6 +227,9 @@ static int asiliantfb_check_var(struct fb_var_screeninfo *var, { unsigned long Ftarget, ratio, remainder; + if (!var->pixclock) + return -EINVAL; + ratio = 1000000 / var->pixclock; remainder = 1000000 % var->pixclock; Ftarget = 1000000 * ratio + (1000000 * remainder) / var->pixclock; diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c index ba33b4dce0df..2398b3d48fed 100644 --- a/drivers/video/fbdev/ep93xx-fb.c +++ b/drivers/video/fbdev/ep93xx-fb.c @@ -548,7 +548,7 @@ static int ep93xxfb_probe(struct platform_device *pdev) } ep93xxfb_set_par(info); - clk_enable(fbi->clk); + clk_prepare_enable(fbi->clk); err = register_framebuffer(info); if (err) @@ -577,7 +577,7 @@ static int ep93xxfb_remove(struct platform_device *pdev) struct ep93xx_fbi *fbi = info->par; unregister_framebuffer(info); - clk_disable(fbi->clk); + clk_disable_unprepare(fbi->clk); ep93xxfb_dealloc_videomem(info); fb_dealloc_cmap(&info->cmap); diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index 4b8c7c16b1df..25801e8e3f74 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -399,6 +399,9 @@ static int kyrofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct kyrofb_info *par = info->par; + if (!var->pixclock) + return -EINVAL; + if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32) { printk(KERN_WARNING "kyrofb: depth not supported: %u\n", var->bits_per_pixel); return -EINVAL; diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index 55554b0433cb..84d5e23ad7d3 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -1084,6 +1084,9 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) int mode_valid = 0; NVTRACE_ENTER(); + if (!var->pixclock) + return -EINVAL; + switch (var->bits_per_pixel) { case 1 ... 8: var->red.offset = var->green.offset = var->blue.offset = 0; diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index eda448b7a0c9..1e2f71c2f8a8 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -82,6 +82,11 @@ struct ssd1307fb_par { struct regulator *vbat_reg; u32 vcomh; u32 width; + /* Cached address ranges */ + u8 col_start; + u8 col_end; + u8 page_start; + u8 page_end; }; struct ssd1307fb_array { @@ -152,17 +157,72 @@ static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) return ret; } -static void ssd1307fb_update_display(struct ssd1307fb_par *par) +static int ssd1307fb_set_col_range(struct ssd1307fb_par *par, u8 col_start, + u8 cols) +{ + u8 col_end = col_start + cols - 1; + int ret; + + if (col_start == par->col_start && col_end == par->col_end) + return 0; + + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, col_start); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, col_end); + if (ret < 0) + return ret; + + par->col_start = col_start; + par->col_end = col_end; + return 0; +} + +static int ssd1307fb_set_page_range(struct ssd1307fb_par *par, u8 page_start, + u8 pages) +{ + u8 page_end = page_start + pages - 1; + int ret; + + if (page_start == par->page_start && page_end == par->page_end) + return 0; + + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, page_start); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, page_end); + if (ret < 0) + return ret; + + par->page_start = page_start; + par->page_end = page_end; + return 0; +} + +static int ssd1307fb_update_rect(struct ssd1307fb_par *par, unsigned int x, + unsigned int y, unsigned int width, + unsigned int height) { struct ssd1307fb_array *array; u8 *vmem = par->info->screen_buffer; unsigned int line_length = par->info->fix.line_length; - unsigned int pages = DIV_ROUND_UP(par->height, 8); - int i, j, k; + unsigned int pages = DIV_ROUND_UP(y % 8 + height, 8); + u32 array_idx = 0; + int ret, i, j, k; - array = ssd1307fb_alloc_array(par->width * pages, SSD1307FB_DATA); + array = ssd1307fb_alloc_array(width * pages, SSD1307FB_DATA); if (!array) - return; + return -ENOMEM; /* * The screen is divided in pages, each having a height of 8 @@ -193,27 +253,44 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par) * (5) A4 B4 C4 D4 E4 F4 G4 H4 */ - for (i = 0; i < pages; i++) { - for (j = 0; j < par->width; j++) { - int m = 8; - u32 array_idx = i * par->width + j; - array->data[array_idx] = 0; - /* Last page may be partial */ - if (i + 1 == pages && par->height % 8) - m = par->height % 8; + ret = ssd1307fb_set_col_range(par, par->col_offset + x, width); + if (ret < 0) + goto out_free; + + ret = ssd1307fb_set_page_range(par, par->page_offset + y / 8, pages); + if (ret < 0) + goto out_free; + + for (i = y / 8; i < y / 8 + pages; i++) { + int m = 8; + + /* Last page may be partial */ + if (8 * (i + 1) > par->height) + m = par->height % 8; + for (j = x; j < x + width; j++) { + u8 data = 0; + for (k = 0; k < m; k++) { u8 byte = vmem[(8 * i + k) * line_length + j / 8]; u8 bit = (byte >> (j % 8)) & 1; - array->data[array_idx] |= bit << k; + data |= bit << k; } + array->data[array_idx++] = data; } } - ssd1307fb_write_array(par->client, array, par->width * pages); + ret = ssd1307fb_write_array(par->client, array, width * pages); + +out_free: kfree(array); + return ret; } +static int ssd1307fb_update_display(struct ssd1307fb_par *par) +{ + return ssd1307fb_update_rect(par, 0, 0, par->width, par->height); +} static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) @@ -222,6 +299,7 @@ static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf, unsigned long total_size; unsigned long p = *ppos; void *dst; + int ret; total_size = info->fix.smem_len; @@ -239,7 +317,9 @@ static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf, if (copy_from_user(dst, buf, count)) return -EFAULT; - ssd1307fb_update_display(par); + ret = ssd1307fb_update_display(par); + if (ret < 0) + return ret; *ppos += count; @@ -260,21 +340,24 @@ static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *r { struct ssd1307fb_par *par = info->par; sys_fillrect(info, rect); - ssd1307fb_update_display(par); + ssd1307fb_update_rect(par, rect->dx, rect->dy, rect->width, + rect->height); } static void ssd1307fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct ssd1307fb_par *par = info->par; sys_copyarea(info, area); - ssd1307fb_update_display(par); + ssd1307fb_update_rect(par, area->dx, area->dy, area->width, + area->height); } static void ssd1307fb_imageblit(struct fb_info *info, const struct fb_image *image) { struct ssd1307fb_par *par = info->par; sys_imageblit(info, image); - ssd1307fb_update_display(par); + ssd1307fb_update_rect(par, image->dx, image->dy, image->width, + image->height); } static const struct fb_ops ssd1307fb_ops = { @@ -454,37 +537,11 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) if (ret < 0) return ret; - /* Set column range */ - ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE); - if (ret < 0) - return ret; - - ret = ssd1307fb_write_cmd(par->client, par->col_offset); - if (ret < 0) - return ret; - - ret = ssd1307fb_write_cmd(par->client, par->col_offset + par->width - 1); - if (ret < 0) - return ret; - - /* Set page range */ - ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE); - if (ret < 0) - return ret; - - ret = ssd1307fb_write_cmd(par->client, par->page_offset); - if (ret < 0) - return ret; - - ret = ssd1307fb_write_cmd(par->client, - par->page_offset + - DIV_ROUND_UP(par->height, 8) - 1); + /* Clear the screen */ + ret = ssd1307fb_update_display(par); if (ret < 0) return ret; - /* Clear the screen */ - ssd1307fb_update_display(par); - /* Turn on the display */ ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); if (ret < 0) diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h index f99d3417f304..ba248ca8866f 100644 --- a/include/drm/drm_auth.h +++ b/include/drm/drm_auth.h @@ -58,12 +58,6 @@ struct drm_lock_data { * @refcount: Refcount for this master object. * @dev: Link back to the DRM device * @driver_priv: Pointer to driver-private information. - * @lessor: Lease holder - * @lessee_id: id for lessees. Owners always have id 0 - * @lessee_list: other lessees of the same master - * @lessees: drm_masters leasing from this one - * @leases: Objects leased to this drm_master. - * @lessee_idr: All lessees under this owner (only used where lessor == NULL) * * Note that master structures are only relevant for the legacy/primary device * nodes, hence there can only be one per device, not one per drm_minor. @@ -88,17 +82,68 @@ struct drm_master { struct idr magic_map; void *driver_priv; - /* Tree of display resource leases, each of which is a drm_master struct - * All of these get activated simultaneously, so drm_device master points - * at the top of the tree (for which lessor is NULL). Protected by - * &drm_device.mode_config.idr_mutex. + /** + * @lessor: + * + * Lease grantor, only set if this &struct drm_master represents a + * lessee holding a lease of objects from @lessor. Full owners of the + * device have this set to NULL. + * + * The lessor does not change once it's set in drm_lease_create(), and + * each lessee holds a reference to its lessor that it releases upon + * being destroyed in drm_lease_destroy(). + * + * See also the :ref:`section on display resource leasing + * <drm_leasing>`. */ - struct drm_master *lessor; + + /** + * @lessee_id: + * + * ID for lessees. Owners (i.e. @lessor is NULL) always have ID 0. + * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex. + */ int lessee_id; + + /** + * @lessee_list: + * + * List entry of lessees of @lessor, where they are linked to @lessees. + * Not used for owners. Protected by &drm_device.mode_config's + * &drm_mode_config.idr_mutex. + */ struct list_head lessee_list; + + /** + * @lessees: + * + * List of drm_masters leasing from this one. Protected by + * &drm_device.mode_config's &drm_mode_config.idr_mutex. + * + * This list is empty if no leases have been granted, or if all lessees + * have been destroyed. Since lessors are referenced by all their + * lessees, this master cannot be destroyed unless the list is empty. + */ struct list_head lessees; + + /** + * @leases: + * + * Objects leased to this drm_master. Protected by + * &drm_device.mode_config's &drm_mode_config.idr_mutex. + * + * Objects are leased all together in drm_lease_create(), and are + * removed all together when the lease is revoked. + */ struct idr leases; + + /** + * @lessee_idr: + * + * All lessees under this owner (only used where @lessor is NULL). + * Protected by &drm_device.mode_config's &drm_mode_config.idr_mutex. + */ struct idr lessee_idr; /* private: */ #if IS_ENABLED(CONFIG_DRM_LEGACY) diff --git a/include/drm/drm_damage_helper.h b/include/drm/drm_damage_helper.h index 40c34a5bf149..effda42cce31 100644 --- a/include/drm/drm_damage_helper.h +++ b/include/drm/drm_damage_helper.h @@ -64,7 +64,6 @@ struct drm_atomic_helper_damage_iter { bool full_update; }; -void drm_plane_enable_fb_damage_clips(struct drm_plane *plane); void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state, struct drm_plane_state *plane_state); int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, @@ -82,21 +81,4 @@ bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state, struct drm_plane_state *state, struct drm_rect *rect); -/** - * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect. - * @state: Plane state. - * - * Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect - * can be obtained by simply typecasting &drm_mode_rect. This is because both - * are signed 32 and during drm_atomic_check_only() it is verified that damage - * clips are inside fb. - * - * Return: Clips in plane fb_damage_clips blob property. - */ -static inline struct drm_rect * -drm_helper_get_plane_damage_clips(const struct drm_plane_state *state) -{ - return (struct drm_rect *)drm_plane_get_damage_clips(state); -} - #endif diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 6bdffc7aa124..5705722f0855 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -1,6 +1,9 @@ #ifndef __DRM_GEM_FB_HELPER_H__ #define __DRM_GEM_FB_HELPER_H__ +#include <linux/dma-buf.h> +#include <linux/dma-buf-map.h> + struct drm_afbc_framebuffer; struct drm_device; struct drm_fb_helper_surface_size; @@ -34,6 +37,9 @@ struct drm_framebuffer * drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); +int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); +void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); + #define drm_is_afbc(modifier) \ (((modifier) & AFBC_VENDOR_AND_TYPE_MASK) == DRM_FORMAT_MOD_ARM_AFBC(0)) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 849d3029e303..af7ba8071eb0 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -124,15 +124,15 @@ struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node); /* enable hsync-end packets in vsync-pulse and v-porch area */ #define MIPI_DSI_MODE_VIDEO_HSE BIT(4) /* disable hfront-porch area */ -#define MIPI_DSI_MODE_VIDEO_HFP BIT(5) +#define MIPI_DSI_MODE_VIDEO_NO_HFP BIT(5) /* disable hback-porch area */ -#define MIPI_DSI_MODE_VIDEO_HBP BIT(6) +#define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6) /* disable hsync-active area */ -#define MIPI_DSI_MODE_VIDEO_HSA BIT(7) +#define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7) /* flush display FIFO on vsync pulse */ #define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) /* disable EoT packets in HS mode */ -#define MIPI_DSI_MODE_EOT_PACKET BIT(9) +#define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9) /* device supports non-continuous clock behavior (DSI spec 5.6.1) */ #define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) /* transmit data in low power */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 1294610e84f4..fed97e35626f 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -186,6 +186,9 @@ struct drm_plane_state { * since last plane update) as an array of &drm_mode_rect in framebuffer * coodinates of the attached framebuffer. Note that unlike plane src, * damage clips are not in 16.16 fixed point. + * + * See drm_plane_get_damage_clips() and + * drm_plane_get_damage_clips_count() for accessing these. */ struct drm_property_blob *fb_damage_clips; @@ -894,38 +897,12 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, bool drm_any_plane_has_format(struct drm_device *dev, u32 format, u64 modifier); -/** - * drm_plane_get_damage_clips_count - Returns damage clips count. - * @state: Plane state. - * - * Simple helper to get the number of &drm_mode_rect clips set by user-space - * during plane update. - * - * Return: Number of clips in plane fb_damage_clips blob property. - */ -static inline unsigned int -drm_plane_get_damage_clips_count(const struct drm_plane_state *state) -{ - return (state && state->fb_damage_clips) ? - state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0; -} -/** - * drm_plane_get_damage_clips - Returns damage clips. - * @state: Plane state. - * - * Note that this function returns uapi type &drm_mode_rect. Drivers might - * instead be interested in internal &drm_rect which can be obtained by calling - * drm_helper_get_plane_damage_clips(). - * - * Return: Damage clips in plane fb_damage_clips blob property. - */ -static inline struct drm_mode_rect * -drm_plane_get_damage_clips(const struct drm_plane_state *state) -{ - return (struct drm_mode_rect *)((state && state->fb_damage_clips) ? - state->fb_damage_clips->data : NULL); -} +void drm_plane_enable_fb_damage_clips(struct drm_plane *plane); +unsigned int +drm_plane_get_damage_clips_count(const struct drm_plane_state *state); +struct drm_mode_rect * +drm_plane_get_damage_clips(const struct drm_plane_state *state); int drm_plane_create_scaling_filter_property(struct drm_plane *plane, unsigned int supported_filters); diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index bbf5c1fdd7b0..65bc9710a470 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -31,7 +31,6 @@ /** * struct drm_property_enum - symbolic values for enumerations - * @value: numeric property value for this enum entry * @head: list of enum values, linked to &drm_property.enum_list * @name: symbolic name for the enum * @@ -39,6 +38,14 @@ * decoding for each value. This is used for example for the rotation property. */ struct drm_property_enum { + /** + * @value: numeric property value for this enum entry + * + * If the property has the type &DRM_MODE_PROP_BITMASK, @value stores a + * bitshift, not a bitmask. In other words, the enum entry is enabled + * if the bit number @value is set in the property's value. This enum + * entry has the bitmask ``1 << value``. + */ uint64_t value; struct list_head head; char name[DRM_PROP_NAME_LEN]; diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h index 39f2deee709c..6f6e19bd4dac 100644 --- a/include/drm/drm_rect.h +++ b/include/drm/drm_rect.h @@ -39,6 +39,9 @@ * @x2: horizontal ending coordinate (exclusive) * @y1: vertical starting coordinate (inclusive) * @y2: vertical ending coordinate (exclusive) + * + * Note that this must match the layout of struct drm_mode_rect or the damage + * helpers like drm_atomic_helper_damage_iter_init() break. */ struct drm_rect { int x1, y1, x2, y2; diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index e1f49dd241f7..3b810b53ba8b 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1050,6 +1050,16 @@ extern "C" { #define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) +/** + * DRM_IOCTL_MODE_RMFB - Remove a framebuffer. + * + * This removes a framebuffer previously added via ADDFB/ADDFB2. The IOCTL + * argument is a framebuffer object ID. + * + * Warning: removing a framebuffer currently in-use on an enabled plane will + * disable that plane. The CRTC the plane is linked to may also be disabled + * (depending on driver capabilities). + */ #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) #define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index f7156322aba5..9f4bb4a6f358 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -900,9 +900,9 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) /* * The top 4 bits (out of the 56 bits alloted for specifying vendor specific - * modifiers) denote the category for modifiers. Currently we have only two - * categories of modifiers ie AFBC and MISC. We can have a maximum of sixteen - * different categories. + * modifiers) denote the category for modifiers. Currently we have three + * categories of modifiers ie AFBC, MISC and AFRC. We can have a maximum of + * sixteen different categories. */ #define DRM_FORMAT_MOD_ARM_CODE(__type, __val) \ fourcc_mod_code(ARM, ((__u64)(__type) << 52) | ((__val) & 0x000fffffffffffffULL)) @@ -1018,6 +1018,109 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) #define AFBC_FORMAT_MOD_USM (1ULL << 12) /* + * Arm Fixed-Rate Compression (AFRC) modifiers + * + * AFRC is a proprietary fixed rate image compression protocol and format, + * designed to provide guaranteed bandwidth and memory footprint + * reductions in graphics and media use-cases. + * + * AFRC buffers consist of one or more planes, with the same components + * and meaning as an uncompressed buffer using the same pixel format. + * + * Within each plane, the pixel/luma/chroma values are grouped into + * "coding unit" blocks which are individually compressed to a + * fixed size (in bytes). All coding units within a given plane of a buffer + * store the same number of values, and have the same compressed size. + * + * The coding unit size is configurable, allowing different rates of compression. + * + * The start of each AFRC buffer plane must be aligned to an alignment granule which + * depends on the coding unit size. + * + * Coding Unit Size Plane Alignment + * ---------------- --------------- + * 16 bytes 1024 bytes + * 24 bytes 512 bytes + * 32 bytes 2048 bytes + * + * Coding units are grouped into paging tiles. AFRC buffer dimensions must be aligned + * to a multiple of the paging tile dimensions. + * The dimensions of each paging tile depend on whether the buffer is optimised for + * scanline (SCAN layout) or rotated (ROT layout) access. + * + * Layout Paging Tile Width Paging Tile Height + * ------ ----------------- ------------------ + * SCAN 16 coding units 4 coding units + * ROT 8 coding units 8 coding units + * + * The dimensions of each coding unit depend on the number of components + * in the compressed plane and whether the buffer is optimised for + * scanline (SCAN layout) or rotated (ROT layout) access. + * + * Number of Components in Plane Layout Coding Unit Width Coding Unit Height + * ----------------------------- --------- ----------------- ------------------ + * 1 SCAN 16 samples 4 samples + * Example: 16x4 luma samples in a 'Y' plane + * 16x4 chroma 'V' values, in the 'V' plane of a fully-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 1 ROT 8 samples 8 samples + * Example: 8x8 luma samples in a 'Y' plane + * 8x8 chroma 'V' values, in the 'V' plane of a fully-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 2 DONT CARE 8 samples 4 samples + * Example: 8x4 chroma pairs in the 'UV' plane of a semi-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 3 DONT CARE 4 samples 4 samples + * Example: 4x4 pixels in an RGB buffer without alpha + * ----------------------------- --------- ----------------- ------------------ + * 4 DONT CARE 4 samples 4 samples + * Example: 4x4 pixels in an RGB buffer with alpha + */ + +#define DRM_FORMAT_MOD_ARM_TYPE_AFRC 0x02 + +#define DRM_FORMAT_MOD_ARM_AFRC(__afrc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFRC, __afrc_mode) + +/* + * AFRC coding unit size modifier. + * + * Indicates the number of bytes used to store each compressed coding unit for + * one or more planes in an AFRC encoded buffer. The coding unit size for chrominance + * is the same for both Cb and Cr, which may be stored in separate planes. + * + * AFRC_FORMAT_MOD_CU_SIZE_P0 indicates the number of bytes used to store + * each compressed coding unit in the first plane of the buffer. For RGBA buffers + * this is the only plane, while for semi-planar and fully-planar YUV buffers, + * this corresponds to the luma plane. + * + * AFRC_FORMAT_MOD_CU_SIZE_P12 indicates the number of bytes used to store + * each compressed coding unit in the second and third planes in the buffer. + * For semi-planar and fully-planar YUV buffers, this corresponds to the chroma plane(s). + * + * For single-plane buffers, AFRC_FORMAT_MOD_CU_SIZE_P0 must be specified + * and AFRC_FORMAT_MOD_CU_SIZE_P12 must be zero. + * For semi-planar and fully-planar buffers, both AFRC_FORMAT_MOD_CU_SIZE_P0 and + * AFRC_FORMAT_MOD_CU_SIZE_P12 must be specified. + */ +#define AFRC_FORMAT_MOD_CU_SIZE_MASK 0xf +#define AFRC_FORMAT_MOD_CU_SIZE_16 (1ULL) +#define AFRC_FORMAT_MOD_CU_SIZE_24 (2ULL) +#define AFRC_FORMAT_MOD_CU_SIZE_32 (3ULL) + +#define AFRC_FORMAT_MOD_CU_SIZE_P0(__afrc_cu_size) (__afrc_cu_size) +#define AFRC_FORMAT_MOD_CU_SIZE_P12(__afrc_cu_size) ((__afrc_cu_size) << 4) + +/* + * AFRC scanline memory layout. + * + * Indicates if the buffer uses the scanline-optimised layout + * for an AFRC encoded buffer, otherwise, it uses the rotation-optimised layout. + * The memory layout is the same for all planes. + */ +#define AFRC_FORMAT_MOD_LAYOUT_SCAN (1ULL << 8) + +/* * Arm 16x16 Block U-Interleaved modifier * * This is used by Arm Mali Utgard and Midgard GPUs. It divides the image |