mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-29 22:14:41 +08:00
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:
commit
f602a96e02
188
Documentation/devicetree/bindings/display/panel/panel-edp.yaml
Normal file
188
Documentation/devicetree/bindings/display/panel/panel-edp.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
10
MAINTAINERS
10
MAINTAINERS
@ -6022,7 +6022,7 @@ DRM DRIVER FOR SAMSUNG S6D27A1 PANELS
|
||||
M: Markuss Broks <markuss.broks@gmail.com>
|
||||
S: Maintained
|
||||
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
|
||||
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: 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
|
||||
M: Alexey Klimov <klimov.linux@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -144,6 +144,7 @@ CONFIG_VIDEO_MT9V032=m
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_ATMEL_HLCDC=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_FB_ATMEL=y
|
||||
CONFIG_BACKLIGHT_ATMEL_LCDC=y
|
||||
CONFIG_BACKLIGHT_PWM=y
|
||||
|
@ -227,6 +227,7 @@ CONFIG_DRM_EXYNOS_DPI=y
|
||||
CONFIG_DRM_EXYNOS_DSI=y
|
||||
CONFIG_DRM_EXYNOS_HDMI=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_PANEL_SAMSUNG_LD9040=y
|
||||
CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=y
|
||||
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y
|
||||
|
@ -281,6 +281,7 @@ CONFIG_DRM=y
|
||||
CONFIG_DRM_MSM=y
|
||||
CONFIG_DRM_PANEL_LVDS=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
|
||||
CONFIG_DRM_TI_TFP410=y
|
||||
CONFIG_DRM_DW_HDMI_AHB_AUDIO=m
|
||||
|
@ -108,6 +108,7 @@ CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_PL111=y
|
||||
CONFIG_FB_MODE_HELPERS=y
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
|
@ -194,6 +194,7 @@ CONFIG_VIDEO_ATMEL_ISI=m
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_ATMEL_HLCDC=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_ASPEED_GFX=m
|
||||
CONFIG_FB_IMX=y
|
||||
CONFIG_FB_ATMEL=y
|
||||
|
@ -704,6 +704,7 @@ CONFIG_DRM_TEGRA=y
|
||||
CONFIG_DRM_STM=m
|
||||
CONFIG_DRM_STM_DSI=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_PANEL_SAMSUNG_LD9040=m
|
||||
CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
|
||||
CONFIG_DRM_PANEL_RAYDIUM_RM68200=m
|
||||
|
@ -511,6 +511,7 @@ CONFIG_OMAP2_DSS_DSI=y
|
||||
CONFIG_DRM_TILCDC=m
|
||||
CONFIG_DRM_PANEL_DSI_CM=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=m
|
||||
CONFIG_DRM_PANEL_EDP=m
|
||||
CONFIG_DRM_PANEL_LG_LB035Q02=m
|
||||
CONFIG_DRM_PANEL_NEC_NL8048HL11=m
|
||||
CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m
|
||||
|
@ -158,6 +158,7 @@ CONFIG_MEDIA_SUPPORT=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_MSM=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_ANALOGIX_ANX78XX=m
|
||||
CONFIG_FB=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
|
@ -61,6 +61,7 @@ CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_DISPLAY_CONNECTOR=y
|
||||
CONFIG_DRM_SIMPLE_BRIDGE=y
|
||||
CONFIG_DRM_PL111=y
|
||||
|
@ -160,6 +160,7 @@ CONFIG_VIDEO_MT9V032=m
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_ATMEL_HLCDC=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_LCD_CLASS_DEVICE=y
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
CONFIG_BACKLIGHT_PWM=y
|
||||
|
@ -129,6 +129,7 @@ CONFIG_VIDEO_ML86V7667=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_RCAR_DU=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_DISPLAY_CONNECTOR=y
|
||||
CONFIG_DRM_LVDS_CODEC=y
|
||||
CONFIG_DRM_SII902X=y
|
||||
|
@ -108,6 +108,7 @@ CONFIG_DRM_SUN4I_HDMI_CEC=y
|
||||
CONFIG_DRM_SUN8I_DW_HDMI=y
|
||||
CONFIG_DRM_PANEL_LVDS=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_SIMPLE_BRIDGE=y
|
||||
CONFIG_DRM_LIMA=y
|
||||
CONFIG_FB_SIMPLE=y
|
||||
|
@ -199,6 +199,7 @@ CONFIG_DRM_TEGRA=y
|
||||
CONFIG_DRM_TEGRA_STAGING=y
|
||||
CONFIG_DRM_PANEL_LVDS=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_LVDS_CODEC=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
|
@ -57,6 +57,7 @@ CONFIG_GPIO_PL061=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_PANEL_ARM_VERSATILE=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_DISPLAY_CONNECTOR=y
|
||||
CONFIG_DRM_SIMPLE_BRIDGE=y
|
||||
CONFIG_DRM_PL111=y
|
||||
|
@ -77,6 +77,7 @@ CONFIG_SENSORS_VEXPRESS=y
|
||||
CONFIG_REGULATOR_VEXPRESS=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=y
|
||||
CONFIG_DRM_PANEL_EDP=y
|
||||
CONFIG_DRM_SII902X=y
|
||||
CONFIG_DRM_PL111=y
|
||||
CONFIG_FB=y
|
||||
|
@ -697,6 +697,7 @@ CONFIG_DRM_MSM=m
|
||||
CONFIG_DRM_TEGRA=m
|
||||
CONFIG_DRM_PANEL_LVDS=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=m
|
||||
CONFIG_DRM_PANEL_EDP=m
|
||||
CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m
|
||||
CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m
|
||||
CONFIG_DRM_PANEL_RAYDIUM_RM67191=m
|
||||
|
@ -918,11 +918,23 @@ static int it66121_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
|
||||
ep = of_graph_get_remote_node(dev->of_node, 1, -1);
|
||||
if (!ep)
|
||||
return -EPROBE_DEFER;
|
||||
if (!ep) {
|
||||
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);
|
||||
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)
|
||||
return -EPROBE_DEFER;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.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;
|
||||
}
|
||||
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
|
||||
|
@ -1232,40 +1232,6 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)
|
||||
return NULL;
|
||||
}
|
||||
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
|
||||
|
||||
MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
|
||||
|
@ -1620,7 +1620,7 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties);
|
||||
* connectors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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_\*).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This is the atomic version of drm_mode_create_scaling_mode_property().
|
||||
|
@ -100,122 +100,127 @@ struct detailed_mode_closure {
|
||||
#define LEVEL_GTF2 2
|
||||
#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 {
|
||||
char vendor[4];
|
||||
int product_id;
|
||||
u32 panel_id;
|
||||
u32 quirks;
|
||||
} edid_quirk_list[] = {
|
||||
/* Acer AL1706 */
|
||||
{ "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
EDID_QUIRK("ACR", 44358, EDID_QUIRK_PREFER_LARGE_60),
|
||||
/* 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", 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", 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", 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", 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", 0x0771, EDID_QUIRK_FORCE_6BPC },
|
||||
EDID_QUIRK("BOE", 0x0771, EDID_QUIRK_FORCE_6BPC),
|
||||
|
||||
/* Belinea 10 15 55 */
|
||||
{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
EDID_QUIRK("MAX", 1516, EDID_QUIRK_PREFER_LARGE_60),
|
||||
EDID_QUIRK("MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60),
|
||||
|
||||
/* 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 */
|
||||
{ "EPI", 8232, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
EDID_QUIRK("EPI", 8232, EDID_QUIRK_PREFER_LARGE_60),
|
||||
|
||||
/* Funai Electronics PM36B */
|
||||
{ "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
|
||||
EDID_QUIRK_DETAILED_IN_CM },
|
||||
EDID_QUIRK("FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
|
||||
EDID_QUIRK_DETAILED_IN_CM),
|
||||
|
||||
/* 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 */
|
||||
{ "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
|
||||
{ "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
|
||||
EDID_QUIRK("LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE),
|
||||
EDID_QUIRK("LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE),
|
||||
|
||||
/* 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 */
|
||||
{ "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
{ "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
EDID_QUIRK("SAM", 596, 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 */
|
||||
{ "SNY", 0x2541, EDID_QUIRK_FORCE_12BPC },
|
||||
EDID_QUIRK("SNY", 0x2541, EDID_QUIRK_FORCE_12BPC),
|
||||
|
||||
/* ViewSonic VA2026w */
|
||||
{ "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING },
|
||||
EDID_QUIRK("VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING),
|
||||
|
||||
/* Medion MD 30217 PG */
|
||||
{ "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 },
|
||||
EDID_QUIRK("MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75),
|
||||
|
||||
/* Lenovo G50 */
|
||||
{ "SDC", 18514, EDID_QUIRK_FORCE_6BPC },
|
||||
EDID_QUIRK("SDC", 18514, EDID_QUIRK_FORCE_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*/
|
||||
{ "ETR", 13896, EDID_QUIRK_FORCE_8BPC },
|
||||
EDID_QUIRK("ETR", 13896, EDID_QUIRK_FORCE_8BPC),
|
||||
|
||||
/* Valve Index Headset */
|
||||
{ "VLV", 0x91a8, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b0, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b1, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b2, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b3, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b4, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b5, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b6, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b7, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b8, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91b9, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91ba, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91bb, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91bc, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91bd, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91be, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "VLV", 0x91bf, EDID_QUIRK_NON_DESKTOP },
|
||||
EDID_QUIRK("VLV", 0x91a8, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b0, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b1, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b2, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b3, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b4, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b5, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b6, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b7, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b8, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91b9, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91ba, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91bb, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91bc, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91bd, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91be, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("VLV", 0x91bf, EDID_QUIRK_NON_DESKTOP),
|
||||
|
||||
/* HTC Vive and Vive Pro VR Headsets */
|
||||
{ "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP },
|
||||
EDID_QUIRK("HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP),
|
||||
|
||||
/* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */
|
||||
{ "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "OVR", 0x0012, EDID_QUIRK_NON_DESKTOP },
|
||||
EDID_QUIRK("OVR", 0x0001, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("OVR", 0x0003, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("OVR", 0x0004, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("OVR", 0x0012, EDID_QUIRK_NON_DESKTOP),
|
||||
|
||||
/* Windows Mixed Reality Headsets */
|
||||
{ "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP },
|
||||
{ "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP },
|
||||
EDID_QUIRK("ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("HPN", 0x3515, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("LEN", 0x0408, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("LEN", 0xb800, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("SEC", 0x144a, EDID_QUIRK_NON_DESKTOP),
|
||||
EDID_QUIRK("AUS", 0xc102, EDID_QUIRK_NON_DESKTOP),
|
||||
|
||||
/* Sony PlayStation VR Headset */
|
||||
{ "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP },
|
||||
EDID_QUIRK("SNY", 0x0704, EDID_QUIRK_NON_DESKTOP),
|
||||
|
||||
/* Sensics VR Headsets */
|
||||
{ "SEN", 0x1019, EDID_QUIRK_NON_DESKTOP },
|
||||
EDID_QUIRK("SEN", 0x1019, EDID_QUIRK_NON_DESKTOP),
|
||||
|
||||
/* 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);
|
||||
|
||||
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
|
||||
* @connector: connector we're probing
|
||||
@ -1938,25 +1981,16 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
|
||||
if (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;
|
||||
|
||||
/* 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];
|
||||
if (valid_extensions == 0)
|
||||
return (struct edid *)edid;
|
||||
@ -2010,8 +2044,6 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
|
||||
|
||||
return (struct edid *)edid;
|
||||
|
||||
carp:
|
||||
connector_bad_edid(connector, edid, 1);
|
||||
out:
|
||||
kfree(edid);
|
||||
return NULL;
|
||||
@ -2060,6 +2092,72 @@ struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
}
|
||||
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
|
||||
* @connector: connector we're probing
|
||||
@ -2103,25 +2201,6 @@ EXPORT_SYMBOL(drm_edid_duplicate);
|
||||
|
||||
/*** 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: 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)
|
||||
{
|
||||
u32 panel_id = edid_extract_panel_id(edid);
|
||||
const struct edid_quirk *quirk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
|
||||
quirk = &edid_quirk_list[i];
|
||||
|
||||
if (edid_vendor(edid, quirk->vendor) &&
|
||||
(EDID_PRODUCT_ID(edid) == quirk->product_id))
|
||||
if (quirk->panel_id == panel_id)
|
||||
return quirk->quirks;
|
||||
}
|
||||
|
||||
|
@ -77,14 +77,26 @@ config DRM_PANEL_LVDS
|
||||
backlight handling if the panel is attached to a backlight controller.
|
||||
|
||||
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 BACKLIGHT_CLASS_DEVICE
|
||||
depends on PM
|
||||
select VIDEOMODE_HELPERS
|
||||
select DRM_DP_AUX_BUS
|
||||
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
|
||||
that it can be automatically turned off when the panel goes into a
|
||||
low power state.
|
||||
|
@ -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_LVDS) += panel-lvds.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_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
|
||||
obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
|
||||
|
1895
drivers/gpu/drm/panel/panel-edp.c
Normal file
1895
drivers/gpu/drm/panel/panel-edp.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -398,8 +398,7 @@ void panfrost_device_reset(struct panfrost_device *pfdev)
|
||||
#ifdef CONFIG_PM
|
||||
int panfrost_device_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
|
||||
struct panfrost_device *pfdev = dev_get_drvdata(dev);
|
||||
|
||||
panfrost_device_reset(pfdev);
|
||||
panfrost_devfreq_resume(pfdev);
|
||||
@ -409,8 +408,7 @@ int panfrost_device_resume(struct device *dev)
|
||||
|
||||
int panfrost_device_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
|
||||
struct panfrost_device *pfdev = dev_get_drvdata(dev);
|
||||
|
||||
if (!panfrost_job_is_idle(pfdev))
|
||||
return -EBUSY;
|
||||
|
@ -638,8 +638,8 @@ static const struct panfrost_compatible amlogic_data = {
|
||||
.vendor_quirk = panfrost_gpu_amlogic_quirk,
|
||||
};
|
||||
|
||||
const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
|
||||
const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
|
||||
static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
|
||||
static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
|
||||
static const struct panfrost_compatible mediatek_mt8183_data = {
|
||||
.num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
|
||||
.supply_names = mediatek_mt8183_supplies,
|
||||
|
@ -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,
|
||||
u64 iova, u64 size)
|
||||
u64 region_start, u64 size)
|
||||
{
|
||||
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
|
||||
* with fls. The size must be clamped to hardware bounds.
|
||||
if (!size)
|
||||
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 = fls64(size - 1) - 1;
|
||||
region |= region_width;
|
||||
region_width = max(fls64(region_start ^ (region_end - 1)),
|
||||
const_ilog2(AS_LOCK_REGION_MIN_SIZE)) - 1;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), lower_32_bits(region));
|
||||
|
@ -467,6 +467,6 @@ struct platform_driver rockchip_dp_driver = {
|
||||
.driver = {
|
||||
.name = "rockchip-dp",
|
||||
.pm = &rockchip_dp_pm_ops,
|
||||
.of_match_table = of_match_ptr(rockchip_dp_dt_ids),
|
||||
.of_match_table = rockchip_dp_dt_ids,
|
||||
},
|
||||
};
|
||||
|
@ -697,7 +697,6 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
|
||||
struct device *dev = dp->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *res;
|
||||
|
||||
dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,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);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dp->regs = devm_ioremap_resource(dev, res);
|
||||
dp->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(dp->regs)) {
|
||||
DRM_DEV_ERROR(dev, "ioremap reg failed\n");
|
||||
return PTR_ERR(dp->regs);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#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>
|
||||
@ -643,7 +642,7 @@ struct hstt {
|
||||
}
|
||||
|
||||
/* Table A-3 High-Speed Transition Times */
|
||||
struct hstt hstt_table[] = {
|
||||
static struct hstt hstt_table[] = {
|
||||
HSTT( 90, 32, 20, 26, 13),
|
||||
HSTT( 100, 35, 23, 28, 14),
|
||||
HSTT( 110, 32, 22, 26, 13),
|
||||
|
@ -810,7 +810,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm = data;
|
||||
struct inno_hdmi *hdmi;
|
||||
struct resource *iores;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
@ -821,8 +820,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
||||
hdmi->dev = dev;
|
||||
hdmi->drm_dev = drm;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hdmi->regs = devm_ioremap_resource(dev, iores);
|
||||
hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hdmi->regs))
|
||||
return PTR_ERR(hdmi->regs);
|
||||
|
||||
|
@ -138,9 +138,6 @@ static int rockchip_drm_bind(struct device *dev)
|
||||
|
||||
drm_dev->dev_private = private;
|
||||
|
||||
INIT_LIST_HEAD(&private->psr_list);
|
||||
mutex_init(&private->psr_list_lock);
|
||||
|
||||
ret = rockchip_drm_init_iommu(drm_dev);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
@ -275,10 +272,17 @@ int rockchip_drm_endpoint_is_subdriver(struct device_node *ep)
|
||||
return -ENODEV;
|
||||
|
||||
/* 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);
|
||||
of_node_put(node);
|
||||
|
||||
/* enabled non-platform-devices can immediately return here */
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (!iommu || !of_device_is_available(iommu->parent)) {
|
||||
if (!iommu || !of_device_is_available(iommu)) {
|
||||
DRM_DEV_DEBUG(dev,
|
||||
"no iommu attached for %pOF, using non-iommu buffers\n",
|
||||
port->parent);
|
||||
|
@ -48,8 +48,6 @@ struct rockchip_drm_private {
|
||||
struct iommu_domain *domain;
|
||||
struct mutex mm_lock;
|
||||
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,
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_of.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,
|
||||
struct rockchip_lvds *lvds)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
lvds->regs = devm_ioremap_resource(lvds->dev, res);
|
||||
lvds->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_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);
|
||||
connector = &lvds->connector;
|
||||
|
||||
if (lvds->panel) {
|
||||
connector = &lvds->connector;
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
ret = drm_connector_init(drm_dev, connector,
|
||||
&rockchip_lvds_connector_funcs,
|
||||
@ -627,17 +626,27 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
||||
|
||||
drm_connector_helper_add(connector,
|
||||
&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 {
|
||||
ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0);
|
||||
ret = drm_bridge_attach(encoder, lvds->bridge, NULL,
|
||||
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret)
|
||||
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);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
@ -27,6 +28,7 @@ struct rockchip_rgb {
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_encoder encoder;
|
||||
struct drm_connector connector;
|
||||
int output_mode;
|
||||
};
|
||||
|
||||
@ -80,6 +82,7 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
|
||||
int ret = 0, child_count = 0;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_connector *connector;
|
||||
|
||||
rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
|
||||
if (!rgb)
|
||||
@ -142,12 +145,32 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
err_free_connector:
|
||||
drm_connector_cleanup(connector);
|
||||
err_free_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
return ERR_PTR(ret);
|
||||
@ -157,6 +180,7 @@ EXPORT_SYMBOL_GPL(rockchip_rgb_init);
|
||||
void rockchip_rgb_fini(struct rockchip_rgb *rgb)
|
||||
{
|
||||
drm_panel_bridge_remove(rgb->bridge);
|
||||
drm_connector_cleanup(&rgb->connector);
|
||||
drm_encoder_cleanup(&rgb->encoder);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_rgb_fini);
|
||||
|
@ -1124,6 +1124,6 @@ struct platform_driver vop_platform_driver = {
|
||||
.remove = vop_remove,
|
||||
.driver = {
|
||||
.name = "rockchip-vop",
|
||||
.of_match_table = of_match_ptr(vop_driver_dt_match),
|
||||
.of_match_table = vop_driver_dt_match,
|
||||
},
|
||||
};
|
||||
|
@ -1126,10 +1126,9 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
dsi->regulator = devm_regulator_get(dev, "vcc-dsi");
|
||||
if (IS_ERR(dsi->regulator)) {
|
||||
dev_err(dev, "Couldn't get VCC-DSI supply\n");
|
||||
return PTR_ERR(dsi->regulator);
|
||||
}
|
||||
if (IS_ERR(dsi->regulator))
|
||||
return dev_err_probe(dev, PTR_ERR(dsi->regulator),
|
||||
"Couldn't get VCC-DSI supply\n");
|
||||
|
||||
dsi->reset = devm_reset_control_get_shared(dev, NULL);
|
||||
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);
|
||||
if (IS_ERR(dsi->bus_clk)) {
|
||||
dev_err(dev, "Couldn't get the DSI bus clock\n");
|
||||
return PTR_ERR(dsi->bus_clk);
|
||||
}
|
||||
if (IS_ERR(dsi->bus_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(dsi->bus_clk),
|
||||
"Couldn't get the DSI bus clock\n");
|
||||
|
||||
ret = regmap_mmio_attach_clk(dsi->regs, dsi->bus_clk);
|
||||
if (ret)
|
||||
|
@ -153,22 +153,19 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl");
|
||||
if (IS_ERR(hdmi->rst_ctrl)) {
|
||||
dev_err(dev, "Could not get ctrl reset control\n");
|
||||
return PTR_ERR(hdmi->rst_ctrl);
|
||||
}
|
||||
if (IS_ERR(hdmi->rst_ctrl))
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->rst_ctrl),
|
||||
"Could not get ctrl reset control\n");
|
||||
|
||||
hdmi->clk_tmds = devm_clk_get(dev, "tmds");
|
||||
if (IS_ERR(hdmi->clk_tmds)) {
|
||||
dev_err(dev, "Couldn't get the tmds clock\n");
|
||||
return PTR_ERR(hdmi->clk_tmds);
|
||||
}
|
||||
if (IS_ERR(hdmi->clk_tmds))
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->clk_tmds),
|
||||
"Couldn't get the tmds clock\n");
|
||||
|
||||
hdmi->regulator = devm_regulator_get(dev, "hvcc");
|
||||
if (IS_ERR(hdmi->regulator)) {
|
||||
dev_err(dev, "Couldn't get regulator\n");
|
||||
return PTR_ERR(hdmi->regulator);
|
||||
}
|
||||
if (IS_ERR(hdmi->regulator))
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->regulator),
|
||||
"Couldn't get regulator\n");
|
||||
|
||||
ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev);
|
||||
if (!ret) {
|
||||
|
@ -206,10 +206,7 @@ MODULE_DEVICE_TABLE(of, v3d_of_match);
|
||||
static int
|
||||
map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name)
|
||||
{
|
||||
struct resource *res =
|
||||
platform_get_resource_byname(v3d_to_pdev(v3d), IORESOURCE_MEM, name);
|
||||
|
||||
*regs = devm_ioremap_resource(v3d->drm.dev, res);
|
||||
*regs = devm_platform_ioremap_resource_byname(v3d_to_pdev(v3d), name);
|
||||
return PTR_ERR_OR_ZERO(*regs);
|
||||
}
|
||||
|
||||
|
@ -567,14 +567,14 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (args->bcl_start != args->bcl_end) {
|
||||
bin = kcalloc(1, sizeof(*bin), GFP_KERNEL);
|
||||
if (!bin) {
|
||||
v3d_job_put(&render->base);
|
||||
v3d_job_cleanup(&render->base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, &bin->base,
|
||||
v3d_job_free, args->in_sync_bcl, V3D_BIN);
|
||||
if (ret) {
|
||||
v3d_job_put(&render->base);
|
||||
v3d_job_cleanup(&render->base);
|
||||
kfree(bin);
|
||||
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),
|
||||
sizeof(*job->base.bo), GFP_KERNEL);
|
||||
if (!job->base.bo) {
|
||||
v3d_job_put(&job->base);
|
||||
v3d_job_cleanup(&job->base);
|
||||
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);
|
||||
if (!clean_job) {
|
||||
v3d_job_put(&job->base);
|
||||
kfree(job);
|
||||
v3d_job_cleanup(&job->base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0, V3D_CACHE_CLEAN);
|
||||
if (ret) {
|
||||
v3d_job_put(&job->base);
|
||||
v3d_job_cleanup(&job->base);
|
||||
kfree(clean_job);
|
||||
return ret;
|
||||
}
|
||||
|
@ -91,9 +91,7 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
|
||||
{
|
||||
struct virtio_gpu_vbuffer *vbuf;
|
||||
|
||||
vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL);
|
||||
if (!vbuf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL | __GFP_NOFAIL);
|
||||
|
||||
BUG_ON(size > MAX_INLINE_CMD_SIZE ||
|
||||
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,
|
||||
resp_size, resp_buf, cb);
|
||||
if (IS_ERR(vbuf)) {
|
||||
*vbuffer_p = NULL;
|
||||
return ERR_CAST(vbuf);
|
||||
}
|
||||
*vbuffer_p = vbuf;
|
||||
return (struct virtio_gpu_command *)vbuf->buf;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
struct edid *drm_do_get_edid(struct drm_connector *connector,
|
||||
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);
|
||||
struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
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 i2c_adapter *adapter);
|
||||
struct edid *drm_edid_duplicate(const struct edid *edid);
|
||||
|
Loading…
Reference in New Issue
Block a user