drm-misc-next for 5.15:

UAPI Changes:
 
 Cross-subsystem Changes:
 
 Core Changes:
 
 Driver Changes:
   - Conversions to dev_err_probe() helper
   - rockchip: Various build improvements, Use
     DRM_BRIDGE_ATTACH_NO_CONNECTOR for LVDS and RGB
   - panel: New panel-edp driver
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCYUwwfAAKCRDj7w1vZxhR
 xaiVAP0VRNLapEFzXiSKz4BC3lK1bxMW9EA41fw6QqOgc1W7dgD7BDc07sSR4i1h
 1eAAYyuygCFH9JPaDmjTB4uH+X+QKgw=
 =wh6l
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2021-09-23' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 5.15:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:

Driver Changes:
  - Conversions to dev_err_probe() helper
  - rockchip: Various build improvements, Use
    DRM_BRIDGE_ATTACH_NO_CONNECTOR for LVDS and RGB
  - panel: New panel-edp driver

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20210923074522.zaja7mzxeimxf6g3@gilmour
This commit is contained in:
Dave Airlie 2021-09-24 13:48:48 +10:00
commit f602a96e02
45 changed files with 2522 additions and 1281 deletions

View File

@ -0,0 +1,188 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/panel-edp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Probeable (via DP AUX / EDID) eDP Panels with simple poweron sequences
maintainers:
- Douglas Anderson <dianders@chromium.org>
description: |
This binding file can be used to indicate that an eDP panel is connected
to a Embedded DisplayPort AUX bus (see display/dp-aux-bus.yaml) without
actually specifying exactly what panel is connected. This is useful for
the case that more than one different panel could be connected to the
board, either for second-sourcing purposes or to support multiple SKUs
with different LCDs that hook up to a common board.
As per above, a requirement for using this binding is that the panel is
represented under the DP AUX bus. This means that we can use any
information provided by the DP AUX bus (including the EDID) to identify
the panel. We can use this to identify display size, resolution, and
timings among other things.
One piece of information about eDP panels that is typically _not_
provided anywhere on the DP AUX bus is the power sequencing timings.
This is the reason why, historically, we've always had to explicitly
list eDP panels. We solve that here with two tricks. The "worst case"
power on timings for any panels expected to be connected to a board are
specified in these bindings. Once we've powered on, it's expected that
the operating system will lookup the panel in a table (based on EDID
information) to figure out other power sequencing timings.
eDP panels in general can have somewhat arbitrary power sequencing
requirements. However, even though it's arbitrary in general, the
vast majority of panel datasheets have a power sequence diagram that
looks the exactly the same as every other panel. Each panel datasheet
cares about different timings in this diagram but the fact that the
diagram is so similar means we can come up with a single driver to
handle it.
These diagrams all look roughly like this, sometimes labeled with
slightly different numbers / lines but all pretty much the same
sequence. This is because much of this diagram comes straight from
the eDP Standard.
__________________________________________________
Vdd ___/: :\____ /
_/ : : \_____/
:<T1>:<T2>: :<--T10-->:<T11>:<T12>:
: +-----------------------+---------+---------+
eDP -----------+ Black video | Src vid | Blk vid +
Display : +-----------------------+---------+---------+
: _______________________:_________:_________:
HPD :<T3>| : : |
___________| : : |_____________
: : : :
Sink +-----------------------:---------:---------+
AUX CH -----------+ AUX Ch operational : : +-------------
+-----------------------:---------:---------+
: : : :
:<T4>: :<T7>: : :
Src main +------+------+--------------+---------+
lnk data----------------+LnkTrn| Idle |Valid vid data| Idle/off+-------------
+------+------+--------------+---------+
: <T5> :<-T6->:<-T8->: :
:__:<T9>:
LED_EN | |
_____________________________________| |____________________________
: :
__________:__:_
PWM | : : |
__________________________| : : |__________________________
: : : :
_____________:__________:__:_:______
Bklight ____/: : : : : :\____
power _______/ :<---T13---->: : : :<T16>: \______________
(Vbl) :<T17>:<---------T14--------->: :<-T15->:<T18>:
The above looks fairly complex but, as per above, each panel only cares
about a subset of those timings.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
const: edp-panel
hpd-reliable-delay-ms:
description:
A fixed amount of time that must be waited after powering on the
panel's power-supply before the HPD signal is a reliable way to know
when the AUX channel is ready. This is useful for panels that glitch
the HPD at the start of power-on. This value is not needed if HPD is
always reliable for all panels that might be connected.
hpd-absent-delay-ms:
description:
The panel specifies that HPD will be asserted this many milliseconds
from power on (timing T3 in the diagram above). If we have no way to
measure HPD then a fixed delay of this many milliseconds can be used.
This can also be used as a timeout when waiting for HPD. Does not
include the hpd-reliable-delay, so if hpd-reliable-delay was 80 ms
and hpd-absent-delay was 200 ms then we'd do a fixed 80 ms delay and
then we know HPD would assert in the next 120 ms. This value is not
needed if HPD hooked up, either through a GPIO in the panel node or
hooked up directly to the eDP controller.
backlight: true
enable-gpios: true
port: true
power-supply: true
no-hpd: true
hpd-gpios: true
additionalProperties: false
required:
- compatible
- power-supply
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
bridge@2d {
compatible = "ti,sn65dsi86";
reg = <0x2d>;
interrupt-parent = <&tlmm>;
interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>;
vpll-supply = <&src_pp1800_s4a>;
vccio-supply = <&src_pp1800_s4a>;
vcca-supply = <&src_pp1200_l2a>;
vcc-supply = <&src_pp1200_l2a>;
clocks = <&rpmhcc RPMH_LN_BB_CLK2>;
clock-names = "refclk";
no-hpd;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&dsi0_out>;
};
};
port@1 {
reg = <1>;
sn65dsi86_out: endpoint {
remote-endpoint = <&panel_in_edp>;
};
};
};
aux-bus {
panel {
compatible = "edp-panel";
power-supply = <&pp3300_dx_edp>;
backlight = <&backlight>;
hpd-gpios = <&sn65dsi86_bridge 2 GPIO_ACTIVE_HIGH>;
hpd-reliable-delay-ms = <15>;
port {
panel_in_edp: endpoint {
remote-endpoint = <&sn65dsi86_out>;
};
};
};
};
};
};

View File

@ -6022,7 +6022,7 @@ DRM DRIVER FOR SAMSUNG S6D27A1 PANELS
M: Markuss Broks <markuss.broks@gmail.com> M: Markuss Broks <markuss.broks@gmail.com>
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/display/panel/samsung,s6d27a1.yaml F: Documentation/devicetree/bindings/display/panel/samsung,s6d27a1.yaml
F: driver/gpu/drm/panel/panel-samsung-s6d27a1.c F: drivers/gpu/drm/panel/panel-samsung-s6d27a1.c
DRM DRIVER FOR SITRONIX ST7703 PANELS DRM DRIVER FOR SITRONIX ST7703 PANELS
M: Guido Günther <agx@sigxcpu.org> M: Guido Günther <agx@sigxcpu.org>
@ -6431,6 +6431,14 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/ttm/ F: drivers/gpu/drm/ttm/
F: include/drm/ttm/ F: include/drm/ttm/
DRM GPU SCHEDULER
M: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/scheduler/
F: include/drm/gpu_scheduler.h
DSBR100 USB FM RADIO DRIVER DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com> M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org

View File

@ -144,6 +144,7 @@ CONFIG_VIDEO_MT9V032=m
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_ATMEL_HLCDC=y CONFIG_DRM_ATMEL_HLCDC=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_FB_ATMEL=y CONFIG_FB_ATMEL=y
CONFIG_BACKLIGHT_ATMEL_LCDC=y CONFIG_BACKLIGHT_ATMEL_LCDC=y
CONFIG_BACKLIGHT_PWM=y CONFIG_BACKLIGHT_PWM=y

View File

@ -227,6 +227,7 @@ CONFIG_DRM_EXYNOS_DPI=y
CONFIG_DRM_EXYNOS_DSI=y CONFIG_DRM_EXYNOS_DSI=y
CONFIG_DRM_EXYNOS_HDMI=y CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_PANEL_SAMSUNG_LD9040=y CONFIG_DRM_PANEL_SAMSUNG_LD9040=y
CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=y CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=y
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y

View File

@ -281,6 +281,7 @@ CONFIG_DRM=y
CONFIG_DRM_MSM=y CONFIG_DRM_MSM=y
CONFIG_DRM_PANEL_LVDS=y CONFIG_DRM_PANEL_LVDS=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_PANEL_SEIKO_43WVF1G=y CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
CONFIG_DRM_TI_TFP410=y CONFIG_DRM_TI_TFP410=y
CONFIG_DRM_DW_HDMI_AHB_AUDIO=m CONFIG_DRM_DW_HDMI_AHB_AUDIO=m

View File

@ -108,6 +108,7 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_PL111=y CONFIG_DRM_PL111=y
CONFIG_FB_MODE_HELPERS=y CONFIG_FB_MODE_HELPERS=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y

View File

@ -194,6 +194,7 @@ CONFIG_VIDEO_ATMEL_ISI=m
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_ATMEL_HLCDC=m CONFIG_DRM_ATMEL_HLCDC=m
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_ASPEED_GFX=m CONFIG_DRM_ASPEED_GFX=m
CONFIG_FB_IMX=y CONFIG_FB_IMX=y
CONFIG_FB_ATMEL=y CONFIG_FB_ATMEL=y

View File

@ -704,6 +704,7 @@ CONFIG_DRM_TEGRA=y
CONFIG_DRM_STM=m CONFIG_DRM_STM=m
CONFIG_DRM_STM_DSI=m CONFIG_DRM_STM_DSI=m
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_PANEL_SAMSUNG_LD9040=m CONFIG_DRM_PANEL_SAMSUNG_LD9040=m
CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
CONFIG_DRM_PANEL_RAYDIUM_RM68200=m CONFIG_DRM_PANEL_RAYDIUM_RM68200=m

View File

@ -511,6 +511,7 @@ CONFIG_OMAP2_DSS_DSI=y
CONFIG_DRM_TILCDC=m CONFIG_DRM_TILCDC=m
CONFIG_DRM_PANEL_DSI_CM=m CONFIG_DRM_PANEL_DSI_CM=m
CONFIG_DRM_PANEL_SIMPLE=m CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_PANEL_EDP=m
CONFIG_DRM_PANEL_LG_LB035Q02=m CONFIG_DRM_PANEL_LG_LB035Q02=m
CONFIG_DRM_PANEL_NEC_NL8048HL11=m CONFIG_DRM_PANEL_NEC_NL8048HL11=m
CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m

View File

@ -158,6 +158,7 @@ CONFIG_MEDIA_SUPPORT=y
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_MSM=m CONFIG_DRM_MSM=m
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_ANALOGIX_ANX78XX=m CONFIG_DRM_ANALOGIX_ANX78XX=m
CONFIG_FB=y CONFIG_FB=y
CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y

View File

@ -61,6 +61,7 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_DISPLAY_CONNECTOR=y CONFIG_DRM_DISPLAY_CONNECTOR=y
CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_SIMPLE_BRIDGE=y
CONFIG_DRM_PL111=y CONFIG_DRM_PL111=y

View File

@ -160,6 +160,7 @@ CONFIG_VIDEO_MT9V032=m
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_ATMEL_HLCDC=y CONFIG_DRM_ATMEL_HLCDC=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_CLASS_DEVICE=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_PWM=y CONFIG_BACKLIGHT_PWM=y

View File

@ -129,6 +129,7 @@ CONFIG_VIDEO_ML86V7667=y
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_RCAR_DU=y CONFIG_DRM_RCAR_DU=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_DISPLAY_CONNECTOR=y CONFIG_DRM_DISPLAY_CONNECTOR=y
CONFIG_DRM_LVDS_CODEC=y CONFIG_DRM_LVDS_CODEC=y
CONFIG_DRM_SII902X=y CONFIG_DRM_SII902X=y

View File

@ -108,6 +108,7 @@ CONFIG_DRM_SUN4I_HDMI_CEC=y
CONFIG_DRM_SUN8I_DW_HDMI=y CONFIG_DRM_SUN8I_DW_HDMI=y
CONFIG_DRM_PANEL_LVDS=y CONFIG_DRM_PANEL_LVDS=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_SIMPLE_BRIDGE=y
CONFIG_DRM_LIMA=y CONFIG_DRM_LIMA=y
CONFIG_FB_SIMPLE=y CONFIG_FB_SIMPLE=y

View File

@ -199,6 +199,7 @@ CONFIG_DRM_TEGRA=y
CONFIG_DRM_TEGRA_STAGING=y CONFIG_DRM_TEGRA_STAGING=y
CONFIG_DRM_PANEL_LVDS=y CONFIG_DRM_PANEL_LVDS=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_LVDS_CODEC=y CONFIG_DRM_LVDS_CODEC=y
CONFIG_FB=y CONFIG_FB=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y

View File

@ -57,6 +57,7 @@ CONFIG_GPIO_PL061=y
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_PANEL_ARM_VERSATILE=y CONFIG_DRM_PANEL_ARM_VERSATILE=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_DISPLAY_CONNECTOR=y CONFIG_DRM_DISPLAY_CONNECTOR=y
CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_SIMPLE_BRIDGE=y
CONFIG_DRM_PL111=y CONFIG_DRM_PL111=y

View File

@ -77,6 +77,7 @@ CONFIG_SENSORS_VEXPRESS=y
CONFIG_REGULATOR_VEXPRESS=y CONFIG_REGULATOR_VEXPRESS=y
CONFIG_DRM=y CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_EDP=y
CONFIG_DRM_SII902X=y CONFIG_DRM_SII902X=y
CONFIG_DRM_PL111=y CONFIG_DRM_PL111=y
CONFIG_FB=y CONFIG_FB=y

View File

@ -697,6 +697,7 @@ CONFIG_DRM_MSM=m
CONFIG_DRM_TEGRA=m CONFIG_DRM_TEGRA=m
CONFIG_DRM_PANEL_LVDS=m CONFIG_DRM_PANEL_LVDS=m
CONFIG_DRM_PANEL_SIMPLE=m CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_PANEL_EDP=m
CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m
CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m
CONFIG_DRM_PANEL_RAYDIUM_RM67191=m CONFIG_DRM_PANEL_RAYDIUM_RM67191=m

View File

@ -918,11 +918,23 @@ static int it66121_probe(struct i2c_client *client,
return -EINVAL; return -EINVAL;
ep = of_graph_get_remote_node(dev->of_node, 1, -1); ep = of_graph_get_remote_node(dev->of_node, 1, -1);
if (!ep) if (!ep) {
return -EPROBE_DEFER; dev_err(ctx->dev, "The endpoint is unconnected\n");
return -EINVAL;
}
if (!of_device_is_available(ep)) {
of_node_put(ep);
dev_err(ctx->dev, "The remote device is disabled\n");
return -ENODEV;
}
ctx->next_bridge = of_drm_find_bridge(ep); ctx->next_bridge = of_drm_find_bridge(ep);
of_node_put(ep); of_node_put(ep);
if (!ctx->next_bridge) {
dev_dbg(ctx->dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
}
if (!ctx->next_bridge) if (!ctx->next_bridge)
return -EPROBE_DEFER; return -EPROBE_DEFER;

View File

@ -9,6 +9,7 @@
#include <drm/drm_connector.h> #include <drm/drm_connector.h>
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include <drm/drm_print.h> #include <drm/drm_print.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
@ -332,3 +333,39 @@ struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
return &panel_bridge->connector; return &panel_bridge->connector;
} }
EXPORT_SYMBOL(drm_panel_bridge_connector); EXPORT_SYMBOL(drm_panel_bridge_connector);
#ifdef CONFIG_OF
/**
* devm_drm_of_get_bridge - Return next bridge in the chain
* @dev: device to tie the bridge lifetime to
* @np: device tree node containing encoder output ports
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
*
* Given a DT node's port and endpoint number, finds the connected node
* and returns the associated bridge if any, or creates and returns a
* drm panel bridge instance if a panel is connected.
*
* Returns a pointer to the bridge if successful, or an error pointer
* otherwise.
*/
struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
struct device_node *np,
u32 port, u32 endpoint)
{
struct drm_bridge *bridge;
struct drm_panel *panel;
int ret;
ret = drm_of_find_panel_or_bridge(np, port, endpoint,
&panel, &bridge);
if (ret)
return ERR_PTR(ret);
if (panel)
bridge = devm_drm_panel_bridge_add(dev, panel);
return bridge;
}
EXPORT_SYMBOL(devm_drm_of_get_bridge);
#endif

View File

@ -1232,40 +1232,6 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)
return NULL; return NULL;
} }
EXPORT_SYMBOL(of_drm_find_bridge); EXPORT_SYMBOL(of_drm_find_bridge);
/**
* devm_drm_of_get_bridge - Return next bridge in the chain
* @dev: device to tie the bridge lifetime to
* @np: device tree node containing encoder output ports
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
*
* Given a DT node's port and endpoint number, finds the connected node
* and returns the associated bridge if any, or creates and returns a
* drm panel bridge instance if a panel is connected.
*
* Returns a pointer to the bridge if successful, or an error pointer
* otherwise.
*/
struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
struct device_node *np,
u32 port, u32 endpoint)
{
struct drm_bridge *bridge;
struct drm_panel *panel;
int ret;
ret = drm_of_find_panel_or_bridge(np, port, endpoint,
&panel, &bridge);
if (ret)
return ERR_PTR(ret);
if (panel)
bridge = devm_drm_panel_bridge_add(dev, panel);
return bridge;
}
EXPORT_SYMBOL(devm_drm_of_get_bridge);
#endif #endif
MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>"); MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");

View File

@ -1620,7 +1620,7 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties);
* connectors. * connectors.
* *
* Atomic drivers should use drm_connector_attach_scaling_mode_property() * Atomic drivers should use drm_connector_attach_scaling_mode_property()
* instead to correctly assign &drm_connector_state.picture_aspect_ratio * instead to correctly assign &drm_connector_state.scaling_mode
* in the atomic state. * in the atomic state.
*/ */
int drm_mode_create_scaling_mode_property(struct drm_device *dev) int drm_mode_create_scaling_mode_property(struct drm_device *dev)
@ -1740,7 +1740,7 @@ EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property);
* @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*). * @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*).
* *
* This is used to add support for scaling mode to atomic drivers. * This is used to add support for scaling mode to atomic drivers.
* The scaling mode will be set to &drm_connector_state.picture_aspect_ratio * The scaling mode will be set to &drm_connector_state.scaling_mode
* and can be used from &drm_connector_helper_funcs->atomic_check for validation. * and can be used from &drm_connector_helper_funcs->atomic_check for validation.
* *
* This is the atomic version of drm_mode_create_scaling_mode_property(). * This is the atomic version of drm_mode_create_scaling_mode_property().

View File

@ -100,122 +100,127 @@ struct detailed_mode_closure {
#define LEVEL_GTF2 2 #define LEVEL_GTF2 2
#define LEVEL_CVT 3 #define LEVEL_CVT 3
#define EDID_QUIRK(vend, product_id, _quirks) \
{ \
.panel_id = drm_edid_encode_panel_id(vend, product_id), \
.quirks = _quirks \
}
static const struct edid_quirk { static const struct edid_quirk {
char vendor[4]; u32 panel_id;
int product_id;
u32 quirks; u32 quirks;
} edid_quirk_list[] = { } edid_quirk_list[] = {
/* Acer AL1706 */ /* Acer AL1706 */
{ "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("ACR", 44358, EDID_QUIRK_PREFER_LARGE_60),
/* Acer F51 */ /* Acer F51 */
{ "API", 0x7602, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("API", 0x7602, EDID_QUIRK_PREFER_LARGE_60),
/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
{ "AEO", 0, EDID_QUIRK_FORCE_6BPC }, EDID_QUIRK("AEO", 0, EDID_QUIRK_FORCE_6BPC),
/* BOE model on HP Pavilion 15-n233sl reports 8 bpc, but is a 6 bpc panel */ /* BOE model on HP Pavilion 15-n233sl reports 8 bpc, but is a 6 bpc panel */
{ "BOE", 0x78b, EDID_QUIRK_FORCE_6BPC }, EDID_QUIRK("BOE", 0x78b, EDID_QUIRK_FORCE_6BPC),
/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
{ "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, EDID_QUIRK("CPT", 0x17df, EDID_QUIRK_FORCE_6BPC),
/* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */ /* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */
{ "SDC", 0x3652, EDID_QUIRK_FORCE_6BPC }, EDID_QUIRK("SDC", 0x3652, EDID_QUIRK_FORCE_6BPC),
/* BOE model 0x0771 reports 8 bpc, but is a 6 bpc panel */ /* BOE model 0x0771 reports 8 bpc, but is a 6 bpc panel */
{ "BOE", 0x0771, EDID_QUIRK_FORCE_6BPC }, EDID_QUIRK("BOE", 0x0771, EDID_QUIRK_FORCE_6BPC),
/* Belinea 10 15 55 */ /* Belinea 10 15 55 */
{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("MAX", 1516, EDID_QUIRK_PREFER_LARGE_60),
{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60),
/* Envision Peripherals, Inc. EN-7100e */ /* Envision Peripherals, Inc. EN-7100e */
{ "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH }, EDID_QUIRK("EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH),
/* Envision EN2028 */ /* Envision EN2028 */
{ "EPI", 8232, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("EPI", 8232, EDID_QUIRK_PREFER_LARGE_60),
/* Funai Electronics PM36B */ /* Funai Electronics PM36B */
{ "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 | EDID_QUIRK("FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
EDID_QUIRK_DETAILED_IN_CM }, EDID_QUIRK_DETAILED_IN_CM),
/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */ /* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */
{ "LGD", 764, EDID_QUIRK_FORCE_10BPC }, EDID_QUIRK("LGD", 764, EDID_QUIRK_FORCE_10BPC),
/* LG Philips LCD LP154W01-A5 */ /* LG Philips LCD LP154W01-A5 */
{ "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, EDID_QUIRK("LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE),
{ "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, EDID_QUIRK("LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE),
/* Samsung SyncMaster 205BW. Note: irony */ /* Samsung SyncMaster 205BW. Note: irony */
{ "SAM", 541, EDID_QUIRK_DETAILED_SYNC_PP }, EDID_QUIRK("SAM", 541, EDID_QUIRK_DETAILED_SYNC_PP),
/* Samsung SyncMaster 22[5-6]BW */ /* Samsung SyncMaster 22[5-6]BW */
{ "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("SAM", 596, EDID_QUIRK_PREFER_LARGE_60),
{ "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, EDID_QUIRK("SAM", 638, EDID_QUIRK_PREFER_LARGE_60),
/* Sony PVM-2541A does up to 12 bpc, but only reports max 8 bpc */ /* Sony PVM-2541A does up to 12 bpc, but only reports max 8 bpc */
{ "SNY", 0x2541, EDID_QUIRK_FORCE_12BPC }, EDID_QUIRK("SNY", 0x2541, EDID_QUIRK_FORCE_12BPC),
/* ViewSonic VA2026w */ /* ViewSonic VA2026w */
{ "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING }, EDID_QUIRK("VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING),
/* Medion MD 30217 PG */ /* Medion MD 30217 PG */
{ "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 }, EDID_QUIRK("MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75),
/* Lenovo G50 */ /* Lenovo G50 */
{ "SDC", 18514, EDID_QUIRK_FORCE_6BPC }, EDID_QUIRK("SDC", 18514, EDID_QUIRK_FORCE_6BPC),
/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */ /* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
{ "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC }, EDID_QUIRK("SEC", 0xd033, EDID_QUIRK_FORCE_8BPC),
/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/ /* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
{ "ETR", 13896, EDID_QUIRK_FORCE_8BPC }, EDID_QUIRK("ETR", 13896, EDID_QUIRK_FORCE_8BPC),
/* Valve Index Headset */ /* Valve Index Headset */
{ "VLV", 0x91a8, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91a8, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b0, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b0, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b1, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b1, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b2, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b2, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b3, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b3, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b4, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b4, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b5, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b5, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b6, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b6, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b7, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b7, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b8, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b8, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91b9, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91b9, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91ba, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91ba, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91bb, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91bb, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91bc, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91bc, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91bd, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91bd, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91be, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91be, EDID_QUIRK_NON_DESKTOP),
{ "VLV", 0x91bf, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("VLV", 0x91bf, EDID_QUIRK_NON_DESKTOP),
/* HTC Vive and Vive Pro VR Headsets */ /* HTC Vive and Vive Pro VR Headsets */
{ "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP),
{ "HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP),
/* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */ /* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */
{ "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("OVR", 0x0001, EDID_QUIRK_NON_DESKTOP),
{ "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("OVR", 0x0003, EDID_QUIRK_NON_DESKTOP),
{ "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("OVR", 0x0004, EDID_QUIRK_NON_DESKTOP),
{ "OVR", 0x0012, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("OVR", 0x0012, EDID_QUIRK_NON_DESKTOP),
/* Windows Mixed Reality Headsets */ /* Windows Mixed Reality Headsets */
{ "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP),
{ "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("HPN", 0x3515, EDID_QUIRK_NON_DESKTOP),
{ "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("LEN", 0x0408, EDID_QUIRK_NON_DESKTOP),
{ "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("LEN", 0xb800, EDID_QUIRK_NON_DESKTOP),
{ "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP),
{ "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP),
{ "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("SEC", 0x144a, EDID_QUIRK_NON_DESKTOP),
{ "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("AUS", 0xc102, EDID_QUIRK_NON_DESKTOP),
/* Sony PlayStation VR Headset */ /* Sony PlayStation VR Headset */
{ "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("SNY", 0x0704, EDID_QUIRK_NON_DESKTOP),
/* Sensics VR Headsets */ /* Sensics VR Headsets */
{ "SEN", 0x1019, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("SEN", 0x1019, EDID_QUIRK_NON_DESKTOP),
/* OSVR HDK and HDK2 VR Headsets */ /* OSVR HDK and HDK2 VR Headsets */
{ "SVR", 0x1019, EDID_QUIRK_NON_DESKTOP }, EDID_QUIRK("SVR", 0x1019, EDID_QUIRK_NON_DESKTOP),
}; };
/* /*
@ -1905,6 +1910,44 @@ int drm_add_override_edid_modes(struct drm_connector *connector)
} }
EXPORT_SYMBOL(drm_add_override_edid_modes); EXPORT_SYMBOL(drm_add_override_edid_modes);
static struct edid *drm_do_get_edid_base_block(
int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
size_t len),
void *data, bool *edid_corrupt, int *null_edid_counter)
{
int i;
void *edid;
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (edid == NULL)
return NULL;
/* base block fetch */
for (i = 0; i < 4; i++) {
if (get_edid_block(data, edid, 0, EDID_LENGTH))
goto out;
if (drm_edid_block_valid(edid, 0, false, edid_corrupt))
break;
if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
if (null_edid_counter)
(*null_edid_counter)++;
goto carp;
}
}
if (i == 4)
goto carp;
return edid;
carp:
kfree(edid);
return ERR_PTR(-EINVAL);
out:
kfree(edid);
return NULL;
}
/** /**
* drm_do_get_edid - get EDID data using a custom EDID block read function * drm_do_get_edid - get EDID data using a custom EDID block read function
* @connector: connector we're probing * @connector: connector we're probing
@ -1938,25 +1981,16 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
if (override) if (override)
return override; return override;
if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) edid = (u8 *)drm_do_get_edid_base_block(get_edid_block, data,
&connector->edid_corrupt,
&connector->null_edid_counter);
if (IS_ERR_OR_NULL(edid)) {
if (IS_ERR(edid))
connector_bad_edid(connector, edid, 1);
return NULL; return NULL;
/* base block fetch */
for (i = 0; i < 4; i++) {
if (get_edid_block(data, edid, 0, EDID_LENGTH))
goto out;
if (drm_edid_block_valid(edid, 0, false,
&connector->edid_corrupt))
break;
if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
connector->null_edid_counter++;
goto carp;
}
} }
if (i == 4)
goto carp;
/* if there's no extensions, we're done */ /* if there's no extensions or no connector, we're done */
valid_extensions = edid[0x7e]; valid_extensions = edid[0x7e];
if (valid_extensions == 0) if (valid_extensions == 0)
return (struct edid *)edid; return (struct edid *)edid;
@ -2010,8 +2044,6 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
return (struct edid *)edid; return (struct edid *)edid;
carp:
connector_bad_edid(connector, edid, 1);
out: out:
kfree(edid); kfree(edid);
return NULL; return NULL;
@ -2060,6 +2092,72 @@ struct edid *drm_get_edid(struct drm_connector *connector,
} }
EXPORT_SYMBOL(drm_get_edid); EXPORT_SYMBOL(drm_get_edid);
static u32 edid_extract_panel_id(const struct edid *edid)
{
/*
* We represent the ID as a 32-bit number so it can easily be compared
* with "==".
*
* NOTE that we deal with endianness differently for the top half
* of this ID than for the bottom half. The bottom half (the product
* id) gets decoded as little endian by the EDID_PRODUCT_ID because
* that's how everyone seems to interpret it. The top half (the mfg_id)
* gets stored as big endian because that makes
* drm_edid_encode_panel_id() and drm_edid_decode_panel_id() easier
* to write (it's easier to extract the ASCII). It doesn't really
* matter, though, as long as the number here is unique.
*/
return (u32)edid->mfg_id[0] << 24 |
(u32)edid->mfg_id[1] << 16 |
(u32)EDID_PRODUCT_ID(edid);
}
/**
* drm_edid_get_panel_id - Get a panel's ID through DDC
* @adapter: I2C adapter to use for DDC
*
* This function reads the first block of the EDID of a panel and (assuming
* that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
* (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
* supposed to be different for each different modem of panel.
*
* This function is intended to be used during early probing on devices where
* more than one panel might be present. Because of its intended use it must
* assume that the EDID of the panel is correct, at least as far as the ID
* is concerned (in other words, we don't process any overrides here).
*
* NOTE: it's expected that this function and drm_do_get_edid() will both
* be read the EDID, but there is no caching between them. Since we're only
* reading the first block, hopefully this extra overhead won't be too big.
*
* Return: A 32-bit ID that should be different for each make/model of panel.
* See the functions drm_edid_encode_panel_id() and
* drm_edid_decode_panel_id() for some details on the structure of this
* ID.
*/
u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
{
struct edid *edid;
u32 panel_id;
edid = drm_do_get_edid_base_block(drm_do_probe_ddc_edid, adapter,
NULL, NULL);
/*
* There are no manufacturer IDs of 0, so if there is a problem reading
* the EDID then we'll just return 0.
*/
if (IS_ERR_OR_NULL(edid))
return 0;
panel_id = edid_extract_panel_id(edid);
kfree(edid);
return panel_id;
}
EXPORT_SYMBOL(drm_edid_get_panel_id);
/** /**
* drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
* @connector: connector we're probing * @connector: connector we're probing
@ -2103,25 +2201,6 @@ EXPORT_SYMBOL(drm_edid_duplicate);
/*** EDID parsing ***/ /*** EDID parsing ***/
/**
* edid_vendor - match a string against EDID's obfuscated vendor field
* @edid: EDID to match
* @vendor: vendor string
*
* Returns true if @vendor is in @edid, false otherwise
*/
static bool edid_vendor(const struct edid *edid, const char *vendor)
{
char edid_vendor[3];
edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@';
edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) |
((edid->mfg_id[1] & 0xe0) >> 5)) + '@';
edid_vendor[2] = (edid->mfg_id[1] & 0x1f) + '@';
return !strncmp(edid_vendor, vendor, 3);
}
/** /**
* edid_get_quirks - return quirk flags for a given EDID * edid_get_quirks - return quirk flags for a given EDID
* @edid: EDID to process * @edid: EDID to process
@ -2130,14 +2209,13 @@ static bool edid_vendor(const struct edid *edid, const char *vendor)
*/ */
static u32 edid_get_quirks(const struct edid *edid) static u32 edid_get_quirks(const struct edid *edid)
{ {
u32 panel_id = edid_extract_panel_id(edid);
const struct edid_quirk *quirk; const struct edid_quirk *quirk;
int i; int i;
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) { for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
quirk = &edid_quirk_list[i]; quirk = &edid_quirk_list[i];
if (quirk->panel_id == panel_id)
if (edid_vendor(edid, quirk->vendor) &&
(EDID_PRODUCT_ID(edid) == quirk->product_id))
return quirk->quirks; return quirk->quirks;
} }

View File

@ -77,14 +77,26 @@ config DRM_PANEL_LVDS
backlight handling if the panel is attached to a backlight controller. backlight handling if the panel is attached to a backlight controller.
config DRM_PANEL_SIMPLE config DRM_PANEL_SIMPLE
tristate "support for simple panels" tristate "support for simple panels (other than eDP ones)"
depends on OF
depends on BACKLIGHT_CLASS_DEVICE
depends on PM
select VIDEOMODE_HELPERS
help
DRM panel driver for dumb non-eDP panels that need at most a regulator
and a GPIO to be powered up. Optionally a backlight can be attached so
that it can be automatically turned off when the panel goes into a
low power state.
config DRM_PANEL_EDP
tristate "support for simple Embedded DisplayPort panels"
depends on OF depends on OF
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on PM depends on PM
select VIDEOMODE_HELPERS select VIDEOMODE_HELPERS
select DRM_DP_AUX_BUS select DRM_DP_AUX_BUS
help help
DRM panel driver for dumb panels that need at most a regulator and DRM panel driver for dumb eDP panels that need at most a regulator and
a GPIO to be powered up. Optionally a backlight can be attached so a GPIO to be powered up. Optionally a backlight can be attached so
that it can be automatically turned off when the panel goes into a that it can be automatically turned off when the panel goes into a
low power state. low power state.

View File

@ -7,6 +7,7 @@ obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o
obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o
obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
obj-$(CONFIG_DRM_PANEL_EDP) += panel-edp.o
obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -398,8 +398,7 @@ void panfrost_device_reset(struct panfrost_device *pfdev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
int panfrost_device_resume(struct device *dev) int panfrost_device_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct panfrost_device *pfdev = dev_get_drvdata(dev);
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
panfrost_device_reset(pfdev); panfrost_device_reset(pfdev);
panfrost_devfreq_resume(pfdev); panfrost_devfreq_resume(pfdev);
@ -409,8 +408,7 @@ int panfrost_device_resume(struct device *dev)
int panfrost_device_suspend(struct device *dev) int panfrost_device_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct panfrost_device *pfdev = dev_get_drvdata(dev);
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
if (!panfrost_job_is_idle(pfdev)) if (!panfrost_job_is_idle(pfdev))
return -EBUSY; return -EBUSY;

View File

@ -638,8 +638,8 @@ static const struct panfrost_compatible amlogic_data = {
.vendor_quirk = panfrost_gpu_amlogic_quirk, .vendor_quirk = panfrost_gpu_amlogic_quirk,
}; };
const char * const mediatek_mt8183_supplies[] = { "mali", "sram" }; static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" }; static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
static const struct panfrost_compatible mediatek_mt8183_data = { static const struct panfrost_compatible mediatek_mt8183_data = {
.num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies), .num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
.supply_names = mediatek_mt8183_supplies, .supply_names = mediatek_mt8183_supplies,

View File

@ -58,17 +58,33 @@ static int write_cmd(struct panfrost_device *pfdev, u32 as_nr, u32 cmd)
} }
static void lock_region(struct panfrost_device *pfdev, u32 as_nr, static void lock_region(struct panfrost_device *pfdev, u32 as_nr,
u64 iova, u64 size) u64 region_start, u64 size)
{ {
u8 region_width; u8 region_width;
u64 region = iova & PAGE_MASK; u64 region;
u64 region_end = region_start + size;
/* The size is encoded as ceil(log2) minus(1), which may be calculated if (!size)
* with fls. The size must be clamped to hardware bounds. return;
/*
* The locked region is a naturally aligned power of 2 block encoded as
* log2 minus(1).
* Calculate the desired start/end and look for the highest bit which
* differs. The smallest naturally aligned block must include this bit
* change, the desired region starts with this bit (and subsequent bits)
* zeroed and ends with the bit (and subsequent bits) set to one.
*/ */
size = max_t(u64, size, AS_LOCK_REGION_MIN_SIZE); region_width = max(fls64(region_start ^ (region_end - 1)),
region_width = fls64(size - 1) - 1; const_ilog2(AS_LOCK_REGION_MIN_SIZE)) - 1;
region |= region_width;
/*
* Mask off the low bits of region_start (which would be ignored by
* the hardware anyway)
*/
region_start &= GENMASK_ULL(63, region_width);
region = region_width | region_start;
/* Lock the region that needs to be updated */ /* Lock the region that needs to be updated */
mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), lower_32_bits(region)); mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), lower_32_bits(region));

View File

@ -467,6 +467,6 @@ struct platform_driver rockchip_dp_driver = {
.driver = { .driver = {
.name = "rockchip-dp", .name = "rockchip-dp",
.pm = &rockchip_dp_pm_ops, .pm = &rockchip_dp_pm_ops,
.of_match_table = of_match_ptr(rockchip_dp_dt_ids), .of_match_table = rockchip_dp_dt_ids,
}, },
}; };

View File

@ -697,7 +697,6 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
struct device *dev = dp->dev; struct device *dev = dp->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct resource *res;
dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(dp->grf)) { if (IS_ERR(dp->grf)) {
@ -705,8 +704,7 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
return PTR_ERR(dp->grf); return PTR_ERR(dp->grf);
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dp->regs = devm_platform_ioremap_resource(pdev, 0);
dp->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(dp->regs)) { if (IS_ERR(dp->regs)) {
DRM_DEV_ERROR(dev, "ioremap reg failed\n"); DRM_DEV_ERROR(dev, "ioremap reg failed\n");
return PTR_ERR(dp->regs); return PTR_ERR(dp->regs);

View File

@ -14,7 +14,6 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <video/mipi_display.h> #include <video/mipi_display.h>
@ -643,7 +642,7 @@ struct hstt {
} }
/* Table A-3 High-Speed Transition Times */ /* Table A-3 High-Speed Transition Times */
struct hstt hstt_table[] = { static struct hstt hstt_table[] = {
HSTT( 90, 32, 20, 26, 13), HSTT( 90, 32, 20, 26, 13),
HSTT( 100, 35, 23, 28, 14), HSTT( 100, 35, 23, 28, 14),
HSTT( 110, 32, 22, 26, 13), HSTT( 110, 32, 22, 26, 13),

View File

@ -810,7 +810,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data; struct drm_device *drm = data;
struct inno_hdmi *hdmi; struct inno_hdmi *hdmi;
struct resource *iores;
int irq; int irq;
int ret; int ret;
@ -821,8 +820,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
hdmi->dev = dev; hdmi->dev = dev;
hdmi->drm_dev = drm; hdmi->drm_dev = drm;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs)) if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs); return PTR_ERR(hdmi->regs);

View File

@ -138,9 +138,6 @@ static int rockchip_drm_bind(struct device *dev)
drm_dev->dev_private = private; drm_dev->dev_private = private;
INIT_LIST_HEAD(&private->psr_list);
mutex_init(&private->psr_list_lock);
ret = rockchip_drm_init_iommu(drm_dev); ret = rockchip_drm_init_iommu(drm_dev);
if (ret) if (ret)
goto err_free; goto err_free;
@ -275,10 +272,17 @@ int rockchip_drm_endpoint_is_subdriver(struct device_node *ep)
return -ENODEV; return -ENODEV;
/* status disabled will prevent creation of platform-devices */ /* status disabled will prevent creation of platform-devices */
if (!of_device_is_available(node)) {
of_node_put(node);
return -ENODEV;
}
pdev = of_find_device_by_node(node); pdev = of_find_device_by_node(node);
of_node_put(node); of_node_put(node);
/* enabled non-platform-devices can immediately return here */
if (!pdev) if (!pdev)
return -ENODEV; return false;
/* /*
* All rockchip subdrivers have probed at this point, so * All rockchip subdrivers have probed at this point, so
@ -370,7 +374,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
} }
iommu = of_parse_phandle(port->parent, "iommus", 0); iommu = of_parse_phandle(port->parent, "iommus", 0);
if (!iommu || !of_device_is_available(iommu->parent)) { if (!iommu || !of_device_is_available(iommu)) {
DRM_DEV_DEBUG(dev, DRM_DEV_DEBUG(dev,
"no iommu attached for %pOF, using non-iommu buffers\n", "no iommu attached for %pOF, using non-iommu buffers\n",
port->parent); port->parent);

View File

@ -48,8 +48,6 @@ struct rockchip_drm_private {
struct iommu_domain *domain; struct iommu_domain *domain;
struct mutex mm_lock; struct mutex mm_lock;
struct drm_mm mm; struct drm_mm mm;
struct list_head psr_list;
struct mutex psr_list_lock;
}; };
int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,

View File

@ -19,6 +19,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
@ -439,11 +440,9 @@ struct drm_encoder_helper_funcs px30_lvds_encoder_helper_funcs = {
static int rk3288_lvds_probe(struct platform_device *pdev, static int rk3288_lvds_probe(struct platform_device *pdev,
struct rockchip_lvds *lvds) struct rockchip_lvds *lvds)
{ {
struct resource *res;
int ret; int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); lvds->regs = devm_platform_ioremap_resource(pdev, 0);
lvds->regs = devm_ioremap_resource(lvds->dev, res);
if (IS_ERR(lvds->regs)) if (IS_ERR(lvds->regs))
return PTR_ERR(lvds->regs); return PTR_ERR(lvds->regs);
@ -612,9 +611,9 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
} }
drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs); drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs);
connector = &lvds->connector;
if (lvds->panel) { if (lvds->panel) {
connector = &lvds->connector;
connector->dpms = DRM_MODE_DPMS_OFF; connector->dpms = DRM_MODE_DPMS_OFF;
ret = drm_connector_init(drm_dev, connector, ret = drm_connector_init(drm_dev, connector,
&rockchip_lvds_connector_funcs, &rockchip_lvds_connector_funcs,
@ -627,17 +626,27 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
drm_connector_helper_add(connector, drm_connector_helper_add(connector,
&rockchip_lvds_connector_helper_funcs); &rockchip_lvds_connector_helper_funcs);
ret = drm_connector_attach_encoder(connector, encoder);
if (ret < 0) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to attach encoder: %d\n", ret);
goto err_free_connector;
}
} else { } else {
ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0); ret = drm_bridge_attach(encoder, lvds->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) if (ret)
goto err_free_encoder; goto err_free_encoder;
connector = drm_bridge_connector_init(lvds->drm_dev, encoder);
if (IS_ERR(connector)) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to initialize bridge connector: %pe\n",
connector);
ret = PTR_ERR(connector);
goto err_free_encoder;
}
}
ret = drm_connector_attach_encoder(connector, encoder);
if (ret < 0) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to attach encoder: %d\n", ret);
goto err_free_connector;
} }
pm_runtime_enable(dev); pm_runtime_enable(dev);

View File

@ -10,6 +10,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_dp_helper.h> #include <drm/drm_dp_helper.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
@ -27,6 +28,7 @@ struct rockchip_rgb {
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct drm_bridge *bridge; struct drm_bridge *bridge;
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_connector connector;
int output_mode; int output_mode;
}; };
@ -80,6 +82,7 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
int ret = 0, child_count = 0; int ret = 0, child_count = 0;
struct drm_panel *panel; struct drm_panel *panel;
struct drm_bridge *bridge; struct drm_bridge *bridge;
struct drm_connector *connector;
rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL); rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
if (!rgb) if (!rgb)
@ -142,12 +145,32 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
rgb->bridge = bridge; rgb->bridge = bridge;
ret = drm_bridge_attach(encoder, rgb->bridge, NULL, 0); ret = drm_bridge_attach(encoder, rgb->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) if (ret)
goto err_free_encoder; goto err_free_encoder;
connector = &rgb->connector;
connector = drm_bridge_connector_init(rgb->drm_dev, encoder);
if (IS_ERR(connector)) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to initialize bridge connector: %pe\n",
connector);
ret = PTR_ERR(connector);
goto err_free_encoder;
}
ret = drm_connector_attach_encoder(connector, encoder);
if (ret < 0) {
DRM_DEV_ERROR(drm_dev->dev,
"failed to attach encoder: %d\n", ret);
goto err_free_connector;
}
return rgb; return rgb;
err_free_connector:
drm_connector_cleanup(connector);
err_free_encoder: err_free_encoder:
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
return ERR_PTR(ret); return ERR_PTR(ret);
@ -157,6 +180,7 @@ EXPORT_SYMBOL_GPL(rockchip_rgb_init);
void rockchip_rgb_fini(struct rockchip_rgb *rgb) void rockchip_rgb_fini(struct rockchip_rgb *rgb)
{ {
drm_panel_bridge_remove(rgb->bridge); drm_panel_bridge_remove(rgb->bridge);
drm_connector_cleanup(&rgb->connector);
drm_encoder_cleanup(&rgb->encoder); drm_encoder_cleanup(&rgb->encoder);
} }
EXPORT_SYMBOL_GPL(rockchip_rgb_fini); EXPORT_SYMBOL_GPL(rockchip_rgb_fini);

View File

@ -1124,6 +1124,6 @@ struct platform_driver vop_platform_driver = {
.remove = vop_remove, .remove = vop_remove,
.driver = { .driver = {
.name = "rockchip-vop", .name = "rockchip-vop",
.of_match_table = of_match_ptr(vop_driver_dt_match), .of_match_table = vop_driver_dt_match,
}, },
}; };

View File

@ -1126,10 +1126,9 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
} }
dsi->regulator = devm_regulator_get(dev, "vcc-dsi"); dsi->regulator = devm_regulator_get(dev, "vcc-dsi");
if (IS_ERR(dsi->regulator)) { if (IS_ERR(dsi->regulator))
dev_err(dev, "Couldn't get VCC-DSI supply\n"); return dev_err_probe(dev, PTR_ERR(dsi->regulator),
return PTR_ERR(dsi->regulator); "Couldn't get VCC-DSI supply\n");
}
dsi->reset = devm_reset_control_get_shared(dev, NULL); dsi->reset = devm_reset_control_get_shared(dev, NULL);
if (IS_ERR(dsi->reset)) { if (IS_ERR(dsi->reset)) {
@ -1144,10 +1143,9 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
} }
dsi->bus_clk = devm_clk_get(dev, bus_clk_name); dsi->bus_clk = devm_clk_get(dev, bus_clk_name);
if (IS_ERR(dsi->bus_clk)) { if (IS_ERR(dsi->bus_clk))
dev_err(dev, "Couldn't get the DSI bus clock\n"); return dev_err_probe(dev, PTR_ERR(dsi->bus_clk),
return PTR_ERR(dsi->bus_clk); "Couldn't get the DSI bus clock\n");
}
ret = regmap_mmio_attach_clk(dsi->regs, dsi->bus_clk); ret = regmap_mmio_attach_clk(dsi->regs, dsi->bus_clk);
if (ret) if (ret)

View File

@ -153,22 +153,19 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
return -EPROBE_DEFER; return -EPROBE_DEFER;
hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl"); hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl");
if (IS_ERR(hdmi->rst_ctrl)) { if (IS_ERR(hdmi->rst_ctrl))
dev_err(dev, "Could not get ctrl reset control\n"); return dev_err_probe(dev, PTR_ERR(hdmi->rst_ctrl),
return PTR_ERR(hdmi->rst_ctrl); "Could not get ctrl reset control\n");
}
hdmi->clk_tmds = devm_clk_get(dev, "tmds"); hdmi->clk_tmds = devm_clk_get(dev, "tmds");
if (IS_ERR(hdmi->clk_tmds)) { if (IS_ERR(hdmi->clk_tmds))
dev_err(dev, "Couldn't get the tmds clock\n"); return dev_err_probe(dev, PTR_ERR(hdmi->clk_tmds),
return PTR_ERR(hdmi->clk_tmds); "Couldn't get the tmds clock\n");
}
hdmi->regulator = devm_regulator_get(dev, "hvcc"); hdmi->regulator = devm_regulator_get(dev, "hvcc");
if (IS_ERR(hdmi->regulator)) { if (IS_ERR(hdmi->regulator))
dev_err(dev, "Couldn't get regulator\n"); return dev_err_probe(dev, PTR_ERR(hdmi->regulator),
return PTR_ERR(hdmi->regulator); "Couldn't get regulator\n");
}
ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev); ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev);
if (!ret) { if (!ret) {

View File

@ -206,10 +206,7 @@ MODULE_DEVICE_TABLE(of, v3d_of_match);
static int static int
map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name) map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name)
{ {
struct resource *res = *regs = devm_platform_ioremap_resource_byname(v3d_to_pdev(v3d), name);
platform_get_resource_byname(v3d_to_pdev(v3d), IORESOURCE_MEM, name);
*regs = devm_ioremap_resource(v3d->drm.dev, res);
return PTR_ERR_OR_ZERO(*regs); return PTR_ERR_OR_ZERO(*regs);
} }

View File

@ -567,14 +567,14 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
if (args->bcl_start != args->bcl_end) { if (args->bcl_start != args->bcl_end) {
bin = kcalloc(1, sizeof(*bin), GFP_KERNEL); bin = kcalloc(1, sizeof(*bin), GFP_KERNEL);
if (!bin) { if (!bin) {
v3d_job_put(&render->base); v3d_job_cleanup(&render->base);
return -ENOMEM; return -ENOMEM;
} }
ret = v3d_job_init(v3d, file_priv, &bin->base, ret = v3d_job_init(v3d, file_priv, &bin->base,
v3d_job_free, args->in_sync_bcl, V3D_BIN); v3d_job_free, args->in_sync_bcl, V3D_BIN);
if (ret) { if (ret) {
v3d_job_put(&render->base); v3d_job_cleanup(&render->base);
kfree(bin); kfree(bin);
return ret; return ret;
} }
@ -716,7 +716,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles), job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles),
sizeof(*job->base.bo), GFP_KERNEL); sizeof(*job->base.bo), GFP_KERNEL);
if (!job->base.bo) { if (!job->base.bo) {
v3d_job_put(&job->base); v3d_job_cleanup(&job->base);
return -ENOMEM; return -ENOMEM;
} }
@ -810,14 +810,13 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL); clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
if (!clean_job) { if (!clean_job) {
v3d_job_put(&job->base); v3d_job_cleanup(&job->base);
kfree(job);
return -ENOMEM; return -ENOMEM;
} }
ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, V3D_CACHE_CLEAN); ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, V3D_CACHE_CLEAN);
if (ret) { if (ret) {
v3d_job_put(&job->base); v3d_job_cleanup(&job->base);
kfree(clean_job); kfree(clean_job);
return ret; return ret;
} }

View File

@ -91,9 +91,7 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
{ {
struct virtio_gpu_vbuffer *vbuf; struct virtio_gpu_vbuffer *vbuf;
vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL); vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL | __GFP_NOFAIL);
if (!vbuf)
return ERR_PTR(-ENOMEM);
BUG_ON(size > MAX_INLINE_CMD_SIZE || BUG_ON(size > MAX_INLINE_CMD_SIZE ||
size < sizeof(struct virtio_gpu_ctrl_hdr)); size < sizeof(struct virtio_gpu_ctrl_hdr));
@ -147,10 +145,6 @@ static void *virtio_gpu_alloc_cmd_resp(struct virtio_gpu_device *vgdev,
vbuf = virtio_gpu_get_vbuf(vgdev, cmd_size, vbuf = virtio_gpu_get_vbuf(vgdev, cmd_size,
resp_size, resp_buf, cb); resp_size, resp_buf, cb);
if (IS_ERR(vbuf)) {
*vbuffer_p = NULL;
return ERR_CAST(vbuf);
}
*vbuffer_p = vbuf; *vbuffer_p = vbuf;
return (struct virtio_gpu_command *)vbuf->buf; return (struct virtio_gpu_command *)vbuf->buf;
} }

View File

@ -508,6 +508,50 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld)
return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK;
} }
/**
* drm_edid_encode_panel_id - Encode an ID for matching against drm_edid_get_panel_id()
* @vend: 3-character vendor string
* @product_id: The 16-bit product ID.
*
* This is a macro so that it can be calculated at compile time and used
* as an initializer.
*
* For instance:
* drm_edid_encode_panel_id("BOE", 0x2d08) => 0x09e52d08
*
* Return: a 32-bit ID per panel.
*/
#define drm_edid_encode_panel_id(vend, product_id) \
((((u32)((vend)[0]) - '@') & 0x1f) << 26 | \
(((u32)((vend)[1]) - '@') & 0x1f) << 21 | \
(((u32)((vend)[2]) - '@') & 0x1f) << 16 | \
((product_id) & 0xffff))
/**
* drm_edid_decode_panel_id - Decode a panel ID from drm_edid_encode_panel_id()
* @panel_id: The panel ID to decode.
* @vend: A 4-byte buffer to store the 3-letter vendor string plus a '\0'
* termination
* @product_id: The product ID will be returned here.
*
* For instance, after:
* drm_edid_decode_panel_id(0x09e52d08, vend, &product_id)
* These will be true:
* vend[0] = 'B'
* vend[1] = 'O'
* vend[2] = 'E'
* vend[3] = '\0'
* product_id = 0x2d08
*/
static inline void drm_edid_decode_panel_id(u32 panel_id, char vend[4], u16 *product_id)
{
*product_id = (u16)(panel_id & 0xffff);
vend[0] = '@' + ((panel_id >> 26) & 0x1f);
vend[1] = '@' + ((panel_id >> 21) & 0x1f);
vend[2] = '@' + ((panel_id >> 16) & 0x1f);
vend[3] = '\0';
}
bool drm_probe_ddc(struct i2c_adapter *adapter); bool drm_probe_ddc(struct i2c_adapter *adapter);
struct edid *drm_do_get_edid(struct drm_connector *connector, struct edid *drm_do_get_edid(struct drm_connector *connector,
int (*get_edid_block)(void *data, u8 *buf, unsigned int block, int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
@ -515,6 +559,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
void *data); void *data);
struct edid *drm_get_edid(struct drm_connector *connector, struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter); struct i2c_adapter *adapter);
u32 drm_edid_get_panel_id(struct i2c_adapter *adapter);
struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
struct i2c_adapter *adapter); struct i2c_adapter *adapter);
struct edid *drm_edid_duplicate(const struct edid *edid); struct edid *drm_edid_duplicate(const struct edid *edid);