Commit f602a96e authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20210923074522.zaja7mzxeimxf6g3@gilmour
parents 0dfc7081 9c2fce13
# 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>;
};
};
};
};
};
};
......@@ -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
......
/*
* Copyright (C) 2013, NVIDIA Corporation. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <video/display_timing.h>
#include <video/of_display_timing.h>
#include <video/videomode.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_dp_aux_bus.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
/**
* struct panel_delay - Describes delays for a simple panel.
*/
struct panel_delay {
/**
* @hpd_reliable: Time for HPD to be reliable
*
* The time (in milliseconds) that it takes after powering the panel
* before the HPD signal is reliable. Ideally this is 0 but some panels,
* board designs, or bad pulldown configs can cause a glitch here.
*
* NOTE: on some old panel data this number appers to be much too big.
* Presumably some old panels simply didn't have HPD hooked up and put
* the hpd_absent here because this field predates the
* hpd_absent. While that works, it's non-ideal.
*/
unsigned int hpd_reliable;
/**
* @hpd_absent: Time to wait if HPD isn't hooked up.
*
* Add this to the prepare delay if we know Hot Plug Detect isn't used.
*
* This is T3-max on eDP timing diagrams or the delay from power on
* until HPD is guaranteed to be asserted.
*/
unsigned int hpd_absent;
/**
* @prepare_to_enable: Time between prepare and enable.
*
* The minimum time, in milliseconds, that needs to have passed
* between when prepare finished and enable may begin. If at
* enable time less time has passed since prepare finished,
* the driver waits for the remaining time.
*
* If a fixed enable delay is also specified, we'll start
* counting before delaying for the fixed delay.
*
* If a fixed prepare delay is also specified, we won't start
* counting until after the fixed delay. We can't overlap this
* fixed delay with the min time because the fixed delay
* doesn't happen at the end of the function if a HPD GPIO was
* specified.
*
* In other words:
* prepare()
* ...
* // do fixed prepare delay
* // wait for HPD GPIO if applicable
* // start counting for prepare_to_enable
*
* enable()
* // do fixed enable delay
* // enforce prepare_to_enable min time
*
* This is not specified in a standard way on eDP timing diagrams.
* It is effectively the time from HPD going high till you can
* turn on the backlight.
*/
unsigned int prepare_to_enable;
/**
* @enable: Time for the panel to display a valid frame.
*
* The time (in milliseconds) that it takes for the panel to
* display the first valid frame after starting to receive
* video data.
*
* This is (T6-min + max(T7-max, T8-min)) on eDP timing diagrams or
* the delay after link training finishes until we can turn the
* backlight on and see valid data.
*/
unsigned int enable;
/**
* @disable: Time for the panel to turn the display off.
*
* The time (in milliseconds) that it takes for the panel to
* turn the display off (no content is visible).
*
* This is T9-min (delay from backlight off to end of valid video
* data) on eDP timing diagrams. It is not common to set.
*/
unsigned int disable;
/**
* @unprepare: Time to power down completely.
*
* The time (in milliseconds) that it takes for the panel
* to power itself down completely.
*
* This time is used to prevent a future "prepare" from
* starting until at least this many milliseconds has passed.
* If at prepare time less time has passed since unprepare
* finished, the driver waits for the remaining time.
*
* This is T12-min on eDP timing diagrams.
*/
unsigned int unprepare;
};
/**
* struct panel_desc - Describes a simple panel.
*/
struct panel_desc {
/**
* @modes: Pointer to array of fixed modes appropriate for this panel.
*
* If only one mode then this can just be the address of the mode.
* NOTE: cannot be used with "timings" and also if this is specified
* then you cannot override the mode in the device tree.
*/
const struct drm_display_mode *modes;
/** @num_modes: Number of elements in modes array. */
unsigned int num_modes;
/**
* @timings: Pointer to array of display timings
*
* NOTE: cannot be used with "modes" and also these will be used to
* validate a device tree override if one is present.
*/
const struct display_timing *timings;
/** @num_timings: Number of elements in timings array. */
unsigned int num_timings;
/** @bpc: Bits per color. */
unsigned int bpc;
/** @size: Structure containing the physical size of this panel. */
struct {
/**
* @size.width: Width (in mm) of the active display area.
*/
unsigned int width;
/**
* @size.height: Height (in mm) of the active display area.
*/
unsigned int height;
} size;
/** @delay: Structure containing various delay values for this panel. */
struct panel_delay delay;
};
/**
* struct edp_panel_entry - Maps panel ID to delay / panel name.
*/
struct edp_panel_entry {
/** @panel_id: 32-bit ID for panel, encoded with drm_edid_encode_panel_id(). */
u32 panel_id;
/* @delay: The power sequencing delays needed for this panel. */
const struct panel_delay *delay;
/* @name: Name of this panel (for printing to logs). */
const char *name;
};
struct panel_edp {
struct drm_panel base;
bool enabled;
bool no_hpd;
bool prepared;
ktime_t prepared_time;
ktime_t unprepared_time;
const struct panel_desc *desc;
struct regulator *supply;
struct i2c_adapter *ddc;
struct drm_dp_aux *aux;
struct gpio_desc *enable_gpio;
struct gpio_desc *hpd_gpio;
struct edid *edid;
struct drm_display_mode override_mode;
enum drm_panel_orientation orientation;
};
static inline struct panel_edp *to_panel_edp(struct drm_panel *panel)
{
return container_of(panel, struct panel_edp, base);
}
static unsigned int panel_edp_get_timings_modes(struct panel_edp *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
unsigned int i, num = 0;
for (i = 0; i < panel->desc->num_timings; i++) {
const struct display_timing *dt = &panel->desc->timings[i];
struct videomode vm;
videomode_from_timing(dt, &vm);
mode = drm_mode_create(connector->dev);
if (!mode) {
dev_err(panel->base.dev, "failed to add mode %ux%u\n",
dt->hactive.typ, dt->vactive.typ);
continue;
}
drm_display_mode_from_videomode(&vm, mode);
mode->type |= DRM_MODE_TYPE_DRIVER;
if (panel->desc->num_timings == 1)
mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
num++;
}
return num;
}
static unsigned int panel_edp_get_display_modes(struct panel_edp *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
unsigned int i, num = 0;
for (i = 0; i < panel->desc->num_modes; i++) {
const struct drm_display_mode *m = &panel->desc->modes[i];
mode = drm_mode_duplicate(connector->dev, m);
if (!mode) {
dev_err(panel->base.dev, "failed to add mode %ux%u@%u\n",
m->hdisplay, m->vdisplay,
drm_mode_vrefresh(m));
continue;
}
mode->type |= DRM_MODE_TYPE_DRIVER;
if (panel->desc->num_modes == 1)
mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
num++;
}
return num;
}
static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
bool has_override = panel->override_mode.type;
unsigned int num = 0;
if (!panel->desc)
return 0;
if (has_override) {
mode = drm_mode_duplicate(connector->dev,
&panel->override_mode);
if (mode) {
drm_mode_probed_add(connector, mode);
num = 1;
} else {
dev_err(panel->base.dev, "failed to add override mode\n");
}
}
/* Only add timings if override was not there or failed to validate */
if (num == 0 && panel->desc->num_timings)
num = panel_edp_get_timings_modes(panel, connector);
/*
* Only add fixed modes if timings/override added no mode.
*
* We should only ever have either the display timings specified
* or a fixed mode. Anything else is rather bogus.
*/
WARN_ON(panel->desc->num_timings && panel->desc->num_modes);
if (num == 0)
num = panel_edp_get_display_modes(panel, connector);
connector->display_info.bpc = panel->desc->bpc;
connector->display_info.width_mm = panel->desc->size.width;
connector->display_info.height_mm = panel->desc->size.height;
return num;
}
static void panel_edp_wait(ktime_t start_ktime, unsigned int min_ms)
{
ktime_t now_ktime, min_ktime;
if (!min_ms)
return;
min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
now_ktime = ktime_get();
if (ktime_before(now_ktime, min_ktime))
msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
}
static int panel_edp_disable(struct drm_panel *panel)
{
struct panel_edp *p = to_panel_edp(panel);
if (!p->enabled)
return 0;
if (p->desc->delay.disable)
msleep(p->desc->delay.disable);
p->enabled = false;
return 0;
}
static int panel_edp_suspend(struct device *dev)
{
struct panel_edp *p = dev_get_drvdata(dev);
gpiod_set_value_cansleep(p->enable_gpio, 0);
regulator_disable(p->supply);
p->unprepared_time = ktime_get();
return 0;
}
static int panel_edp_unprepare(struct drm_panel *panel)
{
struct panel_edp *p = to_panel_edp(panel);
int ret;
/* Unpreparing when already unprepared is a no-op */
if (!p->prepared)
return 0;
pm_runtime_mark_last_busy(panel->dev);
ret = pm_runtime_put_autosuspend(panel->dev);
if (ret < 0)
return ret;
p->prepared = false;
return 0;
}
static int panel_edp_get_hpd_gpio(struct device *dev, struct panel_edp *p)
{
int err;
p->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
if (IS_ERR(p->hpd_gpio)) {
err = PTR_ERR(p->hpd_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to get 'hpd' GPIO: %d\n", err);
return err;
}
return 0;
}
static int panel_edp_prepare_once(struct panel_edp *p)
{
struct device *dev = p->base.dev;
unsigned int delay;
int err;
int hpd_asserted;
unsigned long hpd_wait_us;
panel_edp_wait(p->unprepared_time, p->desc->delay.unprepare);
err = regulator_enable(p->supply);
if (err < 0) {
dev_err(dev, "failed to enable supply: %d\n", err);
return err;
}
gpiod_set_value_cansleep(p->enable_gpio, 1);
delay = p->desc->delay.hpd_reliable;
if (p->no_hpd)
delay = max(delay, p->desc->delay.hpd_absent);
if (delay)
msleep(delay);
if (p->hpd_gpio) {
if (p->desc->delay.hpd_absent)
hpd_wait_us = p->desc->delay.hpd_absent * 1000UL;
else
hpd_wait_us = 2000000;
err = readx_poll_timeout(gpiod_get_value_cansleep, p->hpd_gpio,
hpd_asserted, hpd_asserted,
1000, hpd_wait_us);
if (hpd_asserted < 0)
err = hpd_asserted;
if (err) {
if (err != -ETIMEDOUT)
dev_err(dev,
"error waiting for hpd GPIO: %d\n", err);
goto error;
}
}
p->prepared_time = ktime_get();
return 0;
error:
gpiod_set_value_cansleep(p->enable_gpio, 0);
regulator_disable(p->supply);
p->unprepared_time = ktime_get();
return err;
}
/*
* Some panels simply don't always come up and need to be power cycled to
* work properly. We'll allow for a handful of retries.
*/
#define MAX_PANEL_PREPARE_TRIES 5
static int panel_edp_resume(struct device *dev)
{
struct panel_edp *p = dev_get_drvdata(dev);
int ret;
int try;
for (try = 0; try < MAX_PANEL_PREPARE_TRIES; try++) {
ret = panel_edp_prepare_once(p);
if (ret != -ETIMEDOUT)
break;
}
if (ret == -ETIMEDOUT)
dev_err(dev, "Prepare timeout after %d tries\n", try);
else if (try)
dev_warn(dev, "Prepare needed %d retries\n", try);
return ret;
}
static int panel_edp_prepare(struct drm_panel *panel)
{
struct panel_edp *p = to_panel_edp(panel);
int ret;
/* Preparing when already prepared is a no-op */
if (p->prepared)
return 0;
ret = pm_runtime_get_sync(panel->dev);
if (ret < 0) {
pm_runtime_put_autosuspend(panel->dev);
return ret;
}
p->prepared = true;
return 0;
}
static int panel_edp_enable(struct drm_panel *panel)
{
struct panel_edp *p = to_panel_edp(panel);
unsigned int delay;
if (p->enabled)
return 0;
delay = p->desc->delay.enable;
/*
* If there is a "prepare_to_enable" delay then that's supposed to be
* the delay from HPD going high until we can turn the backlight on.
* However, we can only count this if HPD is handled by the panel
* driver, not if it goes to a dedicated pin on the controller.
* If we aren't handling the HPD pin ourselves then the best we
* can do is assume that HPD went high immediately before we were
* called (and link training took zero time).
*
* NOTE: if we ever end up in this "if" statement then we're
* guaranteed that the panel_edp_wait() call below will do no delay.
* It already handles that case, though, so we don't need any special
* code for it.
*/
if (p->desc->delay.prepare_to_enable && !p->hpd_gpio && !p->no_hpd)
delay = max(delay, p->desc->delay.prepare_to_enable);
if (delay)
msleep(delay);
panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
p->enabled = true;
return 0;
}
static int panel_edp_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
/* probe EDID if a DDC bus is available */
if (p->ddc) {
pm_runtime_get_sync(panel->dev);
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
if (p->edid)
num += drm_add_edid_modes(connector, p->edid);
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
}
/*
* Add hard-coded panel modes. Don't call this if there are no timings
* and no modes (the generic edp-panel case) because it will clobber
* the display_info that was already set by drm_add_edid_modes().
*/
if (p->desc->num_timings || p->desc->num_modes)
num += panel_edp_get_non_edid_modes(p, connector);
else if (!num)
dev_warn(p->base.dev, "No display modes\n");
/* set up connector's "panel orientation" property */
drm_connector_set_panel_orientation(connector, p->orientation);
return num;
}
static int panel_edp_get_timings(struct drm_panel *panel,
unsigned int num_timings,
struct display_timing *timings)
{
struct panel_edp *p = to_panel_edp(panel);
unsigned int i;
if (p->desc->num_timings < num_timings)
num_timings = p->desc->num_timings;
if (timings)
for (i = 0; i < num_timings; i++)
timings[i] = p->desc->timings[i];
return p->desc->num_timings;
}
static const struct drm_panel_funcs panel_edp_funcs = {
.disable = panel_edp_disable,
.unprepare = panel_edp_unprepare,
.prepare = panel_edp_prepare,
.enable = panel_edp_enable,
.get_modes = panel_edp_get_modes,
.get_timings = panel_edp_get_timings,
};
#define PANEL_EDP_BOUNDS_CHECK(to_check, bounds, field) \
(to_check->field.typ >= bounds->field.min && \
to_check->field.typ <= bounds->field.max)
static void panel_edp_parse_panel_timing_node(struct device *dev,
struct panel_edp *panel,
const struct display_timing *ot)
{
const struct panel_desc *desc = panel->desc;
struct videomode vm;
unsigned int i;
if (WARN_ON(desc->num_modes)) {
dev_err(dev, "Reject override mode: panel has a fixed mode\n");
return;
}
if (WARN_ON(!desc->num_timings)) {
dev_err(dev, "Reject override mode: no timings specified\n");
return;
}
for (i = 0; i < panel->desc->num_timings; i++) {
const struct display_timing *dt = &panel->desc->timings[i];
if (!PANEL_EDP_BOUNDS_CHECK(ot, dt, hactive) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, hfront_porch) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, hback_porch) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, hsync_len) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, vactive) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, vfront_porch) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, vback_porch) ||
!PANEL_EDP_BOUNDS_CHECK(ot, dt, vsync_len))
continue;
if (ot->flags != dt->flags)
continue;
videomode_from_timing(ot, &vm);
drm_display_mode_from_videomode(&vm, &panel->override_mode);
panel->override_mode.type |= DRM_MODE_TYPE_DRIVER |
DRM_MODE_TYPE_PREFERRED;
break;
}
if (WARN_ON(!panel->override_mode.type))
dev_err(dev, "Reject override mode: No display_timing found\n");
}
static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
{
const struct edp_panel_entry *edp_panel;
struct panel_desc *desc;
u32 panel_id;
char vend[4];
u16 product_id;
u32 reliable_ms = 0;
u32 absent_ms = 0;
int ret;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
panel->desc = desc;
/*
* Read the dts properties for the initial probe. These are used by
* the runtime resume code which will get called by the
* pm_runtime_get_sync() call below.
*/
of_property_read_u32(dev->of_node, "hpd-reliable-delay-ms", &reliable_ms);
desc->delay.hpd_reliable = reliable_ms;
of_property_read_u32(dev->of_node, "hpd-absent-delay-ms", &absent_ms);
desc->delay.hpd_reliable = absent_ms;
/* Power the panel on so we can read the EDID */
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "Couldn't power on panel to read EDID: %d\n", ret);
goto exit;
}
panel_id = drm_edid_get_panel_id(panel->ddc);
if (!panel_id) {
dev_err(dev, "Couldn't identify panel via EDID\n");
ret = -EIO;
goto exit;
}
drm_edid_decode_panel_id(panel_id, vend, &product_id);
edp_panel = find_edp_panel(panel_id);
/*
* We're using non-optimized timings and want it really obvious that
* someone needs to add an entry to the table, so we'll do a WARN_ON
* splat.
*/
if (WARN_ON(!edp_panel)) {
dev_warn(dev,
"Unknown panel %s %#06x, using conservative timings\n",
vend, product_id);
/*
* It's highly likely that the panel will work if we use very
* conservative timings, so let's do that. We already know that
* the HPD-related delays must have worked since we got this
* far, so we really just need the "unprepare" / "enable"
* delays. We don't need "prepare_to_enable" since that
* overlaps the "enable" delay anyway.
*
* Nearly all panels have a "unprepare" delay of 500 ms though
* there are a few with 1000. Let's stick 2000 in just to be
* super conservative.
*
* An "enable" delay of 80 ms seems the most common, but we'll
* throw in 200 ms to be safe.
*/
desc->delay.unprepare = 2000;
desc->delay.enable = 200;
} else {
dev_info(dev, "Detected %s %s (%#06x)\n",
vend, edp_panel->name, product_id);
/* Update the delay; everything else comes from EDID */
desc->delay = *edp_panel->delay;
}
ret = 0;
exit:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
struct drm_dp_aux *aux)
{
struct panel_edp *panel;
struct display_timing dt;
struct device_node *ddc;
int err;
panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
if (!panel)
return -ENOMEM;
panel->enabled = false;
panel->prepared_time = 0;
panel->desc = desc;
panel->aux = aux;
panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd");
if (!panel->no_hpd) {
err = panel_edp_get_hpd_gpio(dev, panel);
if (err)
return err;
}
panel->supply = devm_regulator_get(dev, "power");
if (IS_ERR(panel->supply))
return PTR_ERR(panel->supply);
panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(panel->enable_gpio)) {
err = PTR_ERR(panel->enable_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to request GPIO: %d\n", err);
return err;
}
err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
if (err) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
return err;
}
ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
if (ddc) {
panel->ddc = of_find_i2c_adapter_by_node(ddc);
of_node_put(ddc);
if (!panel->ddc)
return -EPROBE_DEFER;
} else if (aux) {
panel->ddc = &aux->ddc;
}
if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
panel_edp_parse_panel_timing_node(dev, panel, &dt);
dev_set_drvdata(dev, panel);
drm_panel_init(&panel->base, dev, &panel_edp_funcs, DRM_MODE_CONNECTOR_eDP);
err = drm_panel_of_backlight(&panel->base);
if (err)
goto err_finished_ddc_init;
/*
* We use runtime PM for prepare / unprepare since those power the panel
* on and off and those can be very slow operations. This is important
* to optimize powering the panel on briefly to read the EDID before
* fully enabling the panel.
*/
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
if (of_device_is_compatible(dev->of_node, "edp-panel")) {
err = generic_edp_panel_probe(dev, panel);
if (err) {
dev_err_probe(dev, err,
"Couldn't detect panel nor find a fallback\n");
goto err_finished_pm_runtime;
}
/* generic_edp_panel_probe() replaces desc in the panel */
desc = panel->desc;
} else if (desc->bpc != 6 && desc->bpc != 8 && desc->bpc != 10) {
dev_warn(dev, "Expected bpc in {6,8,10} but got: %u\n", desc->bpc);
}
if (!panel->base.backlight && panel->aux) {
pm_runtime_get_sync(dev);
err = drm_panel_dp_aux_backlight(&panel->base, panel->aux);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (err)
goto err_finished_pm_runtime;
}
drm_panel_add(&panel->base);
return 0;
err_finished_pm_runtime:
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
err_finished_ddc_init:
if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
put_device(&panel->ddc->dev);
return err;
}
static int panel_edp_remove(struct device *dev)
{
struct panel_edp *panel = dev_get_drvdata(dev);
drm_panel_remove(&panel->base);
drm_panel_disable(&panel->base);
drm_panel_unprepare(&panel->base);
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
put_device(&panel->ddc->dev);
kfree(panel->edid);
panel->edid = NULL;
return 0;
}
static void panel_edp_shutdown(struct device *dev)
{
struct panel_edp *panel = dev_get_drvdata(dev);
drm_panel_disable(&panel->base);
drm_panel_unprepare(&panel->base);
}
static const struct display_timing auo_b101ean01_timing = {
.pixelclock = { 65300000, 72500000, 75000000 },
.hactive = { 1280, 1280, 1280 },
.hfront_porch = { 18, 119, 119 },
.hback_porch = { 21, 21, 21 },
.hsync_len = { 32, 32, 32 },
.vactive = { 800, 800, 800 },
.vfront_porch = { 4, 4, 4 },
.vback_porch = { 8, 8, 8 },
.vsync_len = { 18, 20, 20 },
};
static const struct panel_desc auo_b101ean01 = {
.timings = &auo_b101ean01_timing,
.num_timings = 1,
.bpc = 6,
.size = {
.width = 217,
.height = 136,
},
};
static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
.hsync_start = 1366 + 48,
.hsync_end = 1366 + 48 + 32,
.htotal = 1366 + 48 + 32 + 10,
.vdisplay = 768,
.vsync_start = 768 + 4,
.vsync_end = 768 + 4 + 6,
.vtotal = 768 + 4 + 6 + 15,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc auo_b116xak01 = {
.modes = &auo_b116xak01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.hpd_absent = 200,
},
};
static const struct drm_display_mode auo_b116xw03_mode = {
.clock = 70589,
.hdisplay = 1366,
.hsync_start = 1366 + 40,
.hsync_end = 1366 + 40 + 40,
.htotal = 1366 + 40 + 40 + 32,
.vdisplay = 768,
.vsync_start = 768 + 10,
.vsync_end = 768 + 10 + 12,
.vtotal = 768 + 10 + 12 + 6,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc auo_b116xw03 = {
.modes = &auo_b116xw03_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.enable = 400,
},
};
static const struct drm_display_mode auo_b133han05_mode = {
.clock = 142600,
.hdisplay = 1920,
.hsync_start = 1920 + 58,
.hsync_end = 1920 + 58 + 42,
.htotal = 1920 + 58 + 42 + 60,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1080 + 3 + 5 + 54,
};
static const struct panel_desc auo_b133han05 = {
.modes = &auo_b133han05_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 293,
.height = 165,
},
.delay = {
.hpd_reliable = 100,
.enable = 20,
.unprepare = 50,
},
};
static const struct drm_display_mode auo_b133htn01_mode = {
.clock = 150660,
.hdisplay = 1920,
.hsync_start = 1920 + 172,
.hsync_end = 1920 + 172 + 80,
.htotal = 1920 + 172 + 80 + 60,
.vdisplay = 1080,
.vsync_start = 1080 + 25,
.vsync_end = 1080 + 25 + 10,
.vtotal = 1080 + 25 + 10 + 10,
};
static const struct panel_desc auo_b133htn01 = {
.modes = &auo_b133htn01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 293,
.height = 165,
},
.delay = {
.hpd_reliable = 105,
.enable = 20,
.unprepare = 50,
},
};
static const struct drm_display_mode auo_b133xtn01_mode = {
.clock = 69500,
.hdisplay = 1366,
.hsync_start = 1366 + 48,
.hsync_end = 1366 + 48 + 32,
.htotal = 1366 + 48 + 32 + 20,
.vdisplay = 768,
.vsync_start = 768 + 3,
.vsync_end = 768 + 3 + 6,
.vtotal = 768 + 3 + 6 + 13,
};
static const struct panel_desc auo_b133xtn01 = {
.modes = &auo_b133xtn01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 293,
.height = 165,
},
};
static const struct drm_display_mode auo_b140han06_mode = {
.clock = 141000,
.hdisplay = 1920,
.hsync_start = 1920 + 16,
.hsync_end = 1920 + 16 + 16,
.htotal = 1920 + 16 + 16 + 152,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 14,
.vtotal = 1080 + 3 + 14 + 19,
};
static const struct panel_desc auo_b140han06 = {
.modes = &auo_b140han06_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 309,
.height = 174,
},
.delay = {
.hpd_reliable = 100,
.enable = 20,
.unprepare = 50,
},
};
static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
{
.clock = 71900,
.hdisplay = 1280,
.hsync_start = 1280 + 48,
.hsync_end = 1280 + 48 + 32,
.htotal = 1280 + 48 + 32 + 80,
.vdisplay = 800,
.vsync_start = 800 + 3,
.vsync_end = 800 + 3 + 5,
.vtotal = 800 + 3 + 5 + 24,
},
{
.clock = 57500,
.hdisplay = 1280,
.hsync_start = 1280 + 48,
.hsync_end = 1280 + 48 + 32,
.htotal = 1280 + 48 + 32 + 80,
.vdisplay = 800,
.vsync_start = 800 + 3,
.vsync_end = 800 + 3 + 5,
.vtotal = 800 + 3 + 5 + 24,
},
};
static const struct panel_desc boe_nv101wxmn51 = {
.modes = boe_nv101wxmn51_modes,
.num_modes = ARRAY_SIZE(boe_nv101wxmn51_modes),
.bpc = 8,
.size = {
.width = 217,
.height = 136,
},
.delay = {
/* TODO: should be hpd-absent and no-hpd should be set? */
.hpd_reliable = 210,
.enable = 50,
.unprepare = 160,
},
};
static const struct drm_display_mode boe_nv110wtm_n61_modes[] = {
{
.clock = 207800,
.hdisplay = 2160,
.hsync_start = 2160 + 48,
.hsync_end = 2160 + 48 + 32,
.htotal = 2160 + 48 + 32 + 100,
.vdisplay = 1440,
.vsync_start = 1440 + 3,
.vsync_end = 1440 + 3 + 6,
.vtotal = 1440 + 3 + 6 + 31,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
},
{
.clock = 138500,
.hdisplay = 2160,
.hsync_start = 2160 + 48,
.hsync_end = 2160 + 48 + 32,
.htotal = 2160 + 48 + 32 + 100,
.vdisplay = 1440,
.vsync_start = 1440 + 3,
.vsync_end = 1440 + 3 + 6,
.vtotal = 1440 + 3 + 6 + 31,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
},
};
static const struct panel_desc boe_nv110wtm_n61 = {
.modes = boe_nv110wtm_n61_modes,
.num_modes = ARRAY_SIZE(boe_nv110wtm_n61_modes),
.bpc = 8,
.size = {
.width = 233,
.height = 155,
},
.delay = {
.hpd_absent = 200,
.prepare_to_enable = 80,
.enable = 50,
.unprepare = 500,
},
};
/* Also used for boe_nv133fhm_n62 */
static const struct drm_display_mode boe_nv133fhm_n61_modes = {
.clock = 147840,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 200,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 6,
.vtotal = 1080 + 3 + 6 + 31,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
};
/* Also used for boe_nv133fhm_n62 */
static const struct panel_desc boe_nv133fhm_n61 = {
.modes = &boe_nv133fhm_n61_modes,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 294,
.height = 165,
},
.delay = {
/*
* When power is first given to the panel there's a short
* spike on the HPD line. It was explained that this spike
* was until the TCON data download was complete. On
* one system this was measured at 8 ms. We'll put 15 ms
* in the prepare delay just to be safe. That means:
* - If HPD isn't hooked up you still have 200 ms delay.
* - If HPD is hooked up we won't try to look at it for the
* first 15 ms.
*/
.hpd_reliable = 15,
.hpd_absent = 200,
.unprepare = 500,
},
};
static const struct drm_display_mode boe_nv140fhmn49_modes[] = {
{
.clock = 148500,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 2200,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1125,
},
};
static const struct panel_desc boe_nv140fhmn49 = {
.modes = boe_nv140fhmn49_modes,
.num_modes = ARRAY_SIZE(boe_nv140fhmn49_modes),
.bpc = 6,
.size = {
.width = 309,
.height = 174,
},
.delay = {
/* TODO: should be hpd-absent and no-hpd should be set? */
.hpd_reliable = 210,
.enable = 50,
.unprepare = 160,
},
};
static const struct drm_display_mode innolux_n116bca_ea1_mode = {
.clock = 76420,
.hdisplay = 1366,
.hsync_start = 1366 + 136,
.hsync_end = 1366 + 136 + 30,
.htotal = 1366 + 136 + 30 + 60,
.vdisplay = 768,
.vsync_start = 768 + 8,
.vsync_end = 768 + 8 + 12,
.vtotal = 768 + 8 + 12 + 12,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
};
static const struct panel_desc innolux_n116bca_ea1 = {
.modes = &innolux_n116bca_ea1_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.hpd_absent = 200,
.prepare_to_enable = 80,
.unprepare = 500,
},
};
/*
* Datasheet specifies that at 60 Hz refresh rate:
* - total horizontal time: { 1506, 1592, 1716 }
* - total vertical time: { 788, 800, 868 }
*
* ...but doesn't go into exactly how that should be split into a front
* porch, back porch, or sync length. For now we'll leave a single setting
* here which allows a bit of tweaking of the pixel clock at the expense of
* refresh rate.
*/
static const struct display_timing innolux_n116bge_timing = {
.pixelclock = { 72600000, 76420000, 80240000 },
.hactive = { 1366, 1366, 1366 },
.hfront_porch = { 136, 136, 136 },
.hback_porch = { 60, 60, 60 },
.hsync_len = { 30, 30, 30 },
.vactive = { 768, 768, 768 },
.vfront_porch = { 8, 8, 8 },
.vback_porch = { 12, 12, 12 },
.vsync_len = { 12, 12, 12 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
};
static const struct panel_desc innolux_n116bge = {
.timings = &innolux_n116bge_timing,
.num_timings = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
};
static const struct drm_display_mode innolux_n125hce_gn1_mode = {
.clock = 162000,
.hdisplay = 1920,
.hsync_start = 1920 + 40,
.hsync_end = 1920 + 40 + 40,
.htotal = 1920 + 40 + 40 + 80,
.vdisplay = 1080,
.vsync_start = 1080 + 4,
.vsync_end = 1080 + 4 + 4,
.vtotal = 1080 + 4 + 4 + 24,
};
static const struct panel_desc innolux_n125hce_gn1 = {
.modes = &innolux_n125hce_gn1_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 276,
.height = 155,
},
};
static const struct drm_display_mode innolux_p120zdg_bf1_mode = {
.clock = 206016,
.hdisplay = 2160,
.hsync_start = 2160 + 48,
.hsync_end = 2160 + 48 + 32,
.htotal = 2160 + 48 + 32 + 80,
.vdisplay = 1440,
.vsync_start = 1440 + 3,
.vsync_end = 1440 + 3 + 10,
.vtotal = 1440 + 3 + 10 + 27,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc innolux_p120zdg_bf1 = {
.modes = &innolux_p120zdg_bf1_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 254,
.height = 169,
},
.delay = {
.hpd_absent = 200,
.unprepare = 500,
},
};
static const struct drm_display_mode ivo_m133nwf4_r0_mode = {
.clock = 138778,
.hdisplay = 1920,
.hsync_start = 1920 + 24,
.hsync_end = 1920 + 24 + 48,
.htotal = 1920 + 24 + 48 + 88,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 12,
.vtotal = 1080 + 3 + 12 + 17,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc ivo_m133nwf4_r0 = {
.modes = &ivo_m133nwf4_r0_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 294,
.height = 165,
},
.delay = {
.hpd_absent = 200,
.unprepare = 500,
},
};
static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = {
.clock = 81000,
.hdisplay = 1366,
.hsync_start = 1366 + 40,
.hsync_end = 1366 + 40 + 32,
.htotal = 1366 + 40 + 32 + 62,
.vdisplay = 768,
.vsync_start = 768 + 5,
.vsync_end = 768 + 5 + 5,
.vtotal = 768 + 5 + 5 + 122,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc kingdisplay_kd116n21_30nv_a010 = {
.modes = &kingdisplay_kd116n21_30nv_a010_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.hpd_absent = 200,
},
};
static const struct drm_display_mode lg_lp079qx1_sp0v_mode = {
.clock = 200000,
.hdisplay = 1536,
.hsync_start = 1536 + 12,
.hsync_end = 1536 + 12 + 16,
.htotal = 1536 + 12 + 16 + 48,
.vdisplay = 2048,
.vsync_start = 2048 + 8,
.vsync_end = 2048 + 8 + 4,
.vtotal = 2048 + 8 + 4 + 8,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc lg_lp079qx1_sp0v = {
.modes = &lg_lp079qx1_sp0v_mode,
.num_modes = 1,
.size = {
.width = 129,
.height = 171,
},
};
static const struct drm_display_mode lg_lp097qx1_spa1_mode = {
.clock = 205210,
.hdisplay = 2048,
.hsync_start = 2048 + 150,
.hsync_end = 2048 + 150 + 5,
.htotal = 2048 + 150 + 5 + 5,
.vdisplay = 1536,
.vsync_start = 1536 + 3,
.vsync_end = 1536 + 3 + 1,
.vtotal = 1536 + 3 + 1 + 9,
};
static const struct panel_desc lg_lp097qx1_spa1 = {
.modes = &lg_lp097qx1_spa1_mode,
.num_modes = 1,
.size = {
.width = 208,
.height = 147,
},
};
static const struct drm_display_mode lg_lp120up1_mode = {
.clock = 162300,
.hdisplay = 1920,
.hsync_start = 1920 + 40,
.hsync_end = 1920 + 40 + 40,
.htotal = 1920 + 40 + 40 + 80,
.vdisplay = 1280,
.vsync_start = 1280 + 4,
.vsync_end = 1280 + 4 + 4,
.vtotal = 1280 + 4 + 4 + 12,
};
static const struct panel_desc lg_lp120up1 = {
.modes = &lg_lp120up1_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 267,
.height = 183,
},
};
static const struct drm_display_mode lg_lp129qe_mode = {
.clock = 285250,
.hdisplay = 2560,
.hsync_start = 2560 + 48,
.hsync_end = 2560 + 48 + 32,
.htotal = 2560 + 48 + 32 + 80,
.vdisplay = 1700,
.vsync_start = 1700 + 3,
.vsync_end = 1700 + 3 + 10,
.vtotal = 1700 + 3 + 10 + 36,
};
static const struct panel_desc lg_lp129qe = {
.modes = &lg_lp129qe_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 272,
.height = 181,
},
};
static const struct drm_display_mode neweast_wjfh116008a_modes[] = {
{
.clock = 138500,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 80,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1080 + 3 + 5 + 23,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
}, {
.clock = 110920,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 80,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1080 + 3 + 5 + 23,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
}
};
static const struct panel_desc neweast_wjfh116008a = {
.modes = neweast_wjfh116008a_modes,
.num_modes = 2,
.bpc = 6,
.size = {
.width = 260,
.height = 150,
},
.delay = {
.hpd_reliable = 110,
.enable = 20,
.unprepare = 500,
},
};
static const struct drm_display_mode samsung_lsn122dl01_c01_mode = {
.clock = 271560,
.hdisplay = 2560,
.hsync_start = 2560 + 48,
.hsync_end = 2560 + 48 + 32,
.htotal = 2560 + 48 + 32 + 80,
.vdisplay = 1600,
.vsync_start = 1600 + 2,
.vsync_end = 1600 + 2 + 5,
.vtotal = 1600 + 2 + 5 + 57,
};
static const struct panel_desc samsung_lsn122dl01_c01 = {
.modes = &samsung_lsn122dl01_c01_mode,
.num_modes = 1,
.size = {
.width = 263,
.height = 164,
},
};
static const struct drm_display_mode samsung_ltn140at29_301_mode = {
.clock = 76300,
.hdisplay = 1366,
.hsync_start = 1366 + 64,
.hsync_end = 1366 + 64 + 48,
.htotal = 1366 + 64 + 48 + 128,
.vdisplay = 768,
.vsync_start = 768 + 2,
.vsync_end = 768 + 2 + 5,
.vtotal = 768 + 2 + 5 + 17,
};
static const struct panel_desc samsung_ltn140at29_301 = {
.modes = &samsung_ltn140at29_301_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 320,
.height = 187,
},
};
static const struct drm_display_mode sharp_ld_d5116z01b_mode = {
.clock = 168480,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 80,
.vdisplay = 1280,
.vsync_start = 1280 + 3,
.vsync_end = 1280 + 3 + 10,
.vtotal = 1280 + 3 + 10 + 57,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc sharp_ld_d5116z01b = {
.modes = &sharp_ld_d5116z01b_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 260,
.height = 120,
},
};
static const struct display_timing sharp_lq123p1jx31_timing = {
.pixelclock = { 252750000, 252750000, 266604720 },
.hactive = { 2400, 2400, 2400 },
.hfront_porch = { 48, 48, 48 },
.hback_porch = { 80, 80, 84 },
.hsync_len = { 32, 32, 32 },
.vactive = { 1600, 1600, 1600 },
.vfront_porch = { 3, 3, 3 },
.vback_porch = { 33, 33, 120 },
.vsync_len = { 10, 10, 10 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
};
static const struct panel_desc sharp_lq123p1jx31 = {
.timings = &sharp_lq123p1jx31_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 259,
.height = 173,
},
.delay = {
.hpd_reliable = 110,
.enable = 50,
.unprepare = 550,
},
};
static const struct drm_display_mode starry_kr122ea0sra_mode = {
.clock = 147000,
.hdisplay = 1920,
.hsync_start = 1920 + 16,
.hsync_end = 1920 + 16 + 16,
.htotal = 1920 + 16 + 16 + 32,
.vdisplay = 1200,
.vsync_start = 1200 + 15,
.vsync_end = 1200 + 15 + 2,
.vtotal = 1200 + 15 + 2 + 18,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc starry_kr122ea0sra = {
.modes = &starry_kr122ea0sra_mode,
.num_modes = 1,
.size = {
.width = 263,
.height = 164,
},
.delay = {
/* TODO: should be hpd-absent and no-hpd should be set? */
.hpd_reliable = 10 + 200,
.enable = 50,
.unprepare = 10 + 500,
},
};
static const struct of_device_id platform_of_match[] = {
{
/* Must be first */
.compatible = "edp-panel",
}, {
.compatible = "auo,b101ean01",
.data = &auo_b101ean01,
}, {
.compatible = "auo,b116xa01",
.data = &auo_b116xak01,
}, {
.compatible = "auo,b116xw03",
.data = &auo_b116xw03,
}, {
.compatible = "auo,b133han05",
.data = &auo_b133han05,
}, {
.compatible = "auo,b133htn01",
.data = &auo_b133htn01,
}, {
.compatible = "auo,b133xtn01",
.data = &auo_b133xtn01,
}, {
.compatible = "auo,b140han06",
.data = &auo_b140han06,
}, {
.compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51,
}, {
.compatible = "boe,nv110wtm-n61",
.data = &boe_nv110wtm_n61,
}, {
.compatible = "boe,nv133fhm-n61",
.data = &boe_nv133fhm_n61,
}, {
.compatible = "boe,nv133fhm-n62",
.data = &boe_nv133fhm_n61,
}, {
.compatible = "boe,nv140fhmn49",
.data = &boe_nv140fhmn49,
}, {
.compatible = "innolux,n116bca-ea1",
.data = &innolux_n116bca_ea1,
}, {
.compatible = "innolux,n116bge",
.data = &innolux_n116bge,
}, {
.compatible = "innolux,n125hce-gn1",
.data = &innolux_n125hce_gn1,
}, {
.compatible = "innolux,p120zdg-bf1",
.data = &innolux_p120zdg_bf1,
}, {
.compatible = "ivo,m133nwf4-r0",
.data = &ivo_m133nwf4_r0,
}, {
.compatible = "kingdisplay,kd116n21-30nv-a010",
.data = &kingdisplay_kd116n21_30nv_a010,
}, {
.compatible = "lg,lp079qx1-sp0v",
.data = &lg_lp079qx1_sp0v,
}, {
.compatible = "lg,lp097qx1-spa1",
.data = &lg_lp097qx1_spa1,
}, {
.compatible = "lg,lp120up1",
.data = &lg_lp120up1,
}, {
.compatible = "lg,lp129qe",
.data = &lg_lp129qe,
}, {
.compatible = "neweast,wjfh116008a",
.data = &neweast_wjfh116008a,
}, {
.compatible = "samsung,lsn122dl01-c01",
.data = &samsung_lsn122dl01_c01,
}, {
.compatible = "samsung,ltn140at29-301",
.data = &samsung_ltn140at29_301,
}, {
.compatible = "sharp,ld-d5116z01b",
.data = &sharp_ld_d5116z01b,
}, {
.compatible = "sharp,lq123p1jx31",
.data = &sharp_lq123p1jx31,
}, {
.compatible = "starry,kr122ea0sra",
.data = &starry_kr122ea0sra,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, platform_of_match);
static const struct panel_delay delay_200_500_p2e80 = {
.hpd_absent = 200,
.unprepare = 500,
.prepare_to_enable = 80,
};
static const struct panel_delay delay_200_500_p2e100 = {
.hpd_absent = 200,
.unprepare = 500,
.prepare_to_enable = 100,
};
static const struct panel_delay delay_200_500_e50 = {
.hpd_absent = 200,
.unprepare = 500,
.enable = 50,
};
#define EDP_PANEL_ENTRY(vend, product_id, _delay, _name) \
{ \
.name = _name, \
.panel_id = drm_edid_encode_panel_id(vend, product_id), \
.delay = _delay \
}
/*
* This table is used to figure out power sequencing delays for panels that
* are detected by EDID. Entries here may point to entries in the
* platform_of_match table (if a panel is listed in both places).
*
* Sort first by vendor, then by product ID.
*/
static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY("AUO", 0x405c, &auo_b116xak01.delay, "B116XAK01"),
EDP_PANEL_ENTRY("AUO", 0x615c, &delay_200_500_e50, "B116XAN06.1"),
EDP_PANEL_ENTRY("BOE", 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"),
EDP_PANEL_ENTRY("BOE", 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"),
EDP_PANEL_ENTRY("BOE", 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"),
EDP_PANEL_ENTRY("BOE", 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"),
EDP_PANEL_ENTRY("CMN", 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"),
EDP_PANEL_ENTRY("KDB", 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
EDP_PANEL_ENTRY("SHP", 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
{ /* sentinal */ }
};
static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
{
const struct edp_panel_entry *panel;
if (!panel_id)
return NULL;
for (panel = edp_panels; panel->panel_id; panel++)
if (panel->panel_id == panel_id)
return panel;
return NULL;
}
static int panel_edp_platform_probe(struct platform_device *pdev)
{
const struct of_device_id *id;
/* Skip one since "edp-panel" is only supported on DP AUX bus */
id = of_match_node(platform_of_match + 1, pdev->dev.of_node);
if (!id)
return -ENODEV;
return panel_edp_probe(&pdev->dev, id->data, NULL);
}
static int panel_edp_platform_remove(struct platform_device *pdev)
{
return panel_edp_remove(&pdev->dev);
}
static void panel_edp_platform_shutdown(struct platform_device *pdev)
{
panel_edp_shutdown(&pdev->dev);
}
static const struct dev_pm_ops panel_edp_pm_ops = {
SET_RUNTIME_PM_OPS(panel_edp_suspend, panel_edp_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static struct platform_driver panel_edp_platform_driver = {
.driver = {
.name = "panel-edp",
.of_match_table = platform_of_match,
.pm = &panel_edp_pm_ops,
},
.probe = panel_edp_platform_probe,
.remove = panel_edp_platform_remove,
.shutdown = panel_edp_platform_shutdown,
};
static int panel_edp_dp_aux_ep_probe(struct dp_aux_ep_device *aux_ep)
{
const struct of_device_id *id;
id = of_match_node(platform_of_match, aux_ep->dev.of_node);
if (!id)
return -ENODEV;
return panel_edp_probe(&aux_ep->dev, id->data, aux_ep->aux);
}
static void panel_edp_dp_aux_ep_remove(struct dp_aux_ep_device *aux_ep)
{
panel_edp_remove(&aux_ep->dev);
}
static void panel_edp_dp_aux_ep_shutdown(struct dp_aux_ep_device *aux_ep)
{
panel_edp_shutdown(&aux_ep->dev);
}
static struct dp_aux_ep_driver panel_edp_dp_aux_ep_driver = {
.driver = {
.name = "panel-simple-dp-aux",
.of_match_table = platform_of_match, /* Same as platform one! */
.pm = &panel_edp_pm_ops,
},
.probe = panel_edp_dp_aux_ep_probe,
.remove = panel_edp_dp_aux_ep_remove,
.shutdown = panel_edp_dp_aux_ep_shutdown,
};
static int __init panel_edp_init(void)
{
int err;
err = platform_driver_register(&panel_edp_platform_driver);
if (err < 0)
return err;
err = dp_aux_dp_driver_register(&panel_edp_dp_aux_ep_driver);
if (err < 0)
goto err_did_platform_register;
return 0;
err_did_platform_register:
platform_driver_unregister(&panel_edp_platform_driver);
return err;
}
module_init(panel_edp_init);
static void __exit panel_edp_exit(void)
{
dp_aux_dp_driver_unregister(&panel_edp_dp_aux_ep_driver);
platform_driver_unregister(&panel_edp_platform_driver);
}
module_exit(panel_edp_exit);
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
MODULE_DESCRIPTION("DRM Driver for Simple eDP Panels");
MODULE_LICENSE("GPL and additional rights");
......@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
......@@ -36,8 +35,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_dp_aux_bus.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
......@@ -94,44 +91,6 @@ struct panel_desc {
*/
unsigned int prepare;
/**
* @delay.hpd_absent_delay: Time to wait if HPD isn't hooked up.
*
* Add this to the prepare delay if we know Hot Plug Detect
* isn't used.
*/
unsigned int hpd_absent_delay;
/**
* @delay.prepare_to_enable: Time between prepare and enable.
*
* The minimum time, in milliseconds, that needs to have passed
* between when prepare finished and enable may begin. If at
* enable time less time has passed since prepare finished,
* the driver waits for the remaining time.
*
* If a fixed enable delay is also specified, we'll start
* counting before delaying for the fixed delay.
*
* If a fixed prepare delay is also specified, we won't start
* counting until after the fixed delay. We can't overlap this
* fixed delay with the min time because the fixed delay
* doesn't happen at the end of the function if a HPD GPIO was
* specified.
*
* In other words:
* prepare()
* ...
* // do fixed prepare delay
* // wait for HPD GPIO if applicable
* // start counting for prepare_to_enable
*
* enable()
* // do fixed enable delay
* // enforce prepare_to_enable min time
*/
unsigned int prepare_to_enable;
/**
* @delay.enable: Time for the panel to display a valid frame.
*
......@@ -176,7 +135,6 @@ struct panel_desc {
struct panel_simple {
struct drm_panel base;
bool enabled;
bool no_hpd;
bool prepared;
......@@ -187,10 +145,8 @@ struct panel_simple {
struct regulator *supply;
struct i2c_adapter *ddc;
struct drm_dp_aux *aux;
struct gpio_desc *enable_gpio;
struct gpio_desc *hpd_gpio;
struct edid *edid;
......@@ -374,30 +330,10 @@ static int panel_simple_unprepare(struct drm_panel *panel)
return 0;
}
static int panel_simple_get_hpd_gpio(struct device *dev, struct panel_simple *p)
{
int err;
p->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
if (IS_ERR(p->hpd_gpio)) {
err = PTR_ERR(p->hpd_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to get 'hpd' GPIO: %d\n", err);
return err;
}
return 0;
}
static int panel_simple_prepare_once(struct panel_simple *p)
static int panel_simple_resume(struct device *dev)
{
struct device *dev = p->base.dev;
unsigned int delay;
struct panel_simple *p = dev_get_drvdata(dev);
int err;
int hpd_asserted;
unsigned long hpd_wait_us;
panel_simple_wait(p->unprepared_time, p->desc->delay.unprepare);
......@@ -409,68 +345,12 @@ static int panel_simple_prepare_once(struct panel_simple *p)
gpiod_set_value_cansleep(p->enable_gpio, 1);
delay = p->desc->delay.prepare;
if (p->no_hpd)
delay += p->desc->delay.hpd_absent_delay;
if (delay)
msleep(delay);
if (p->hpd_gpio) {
if (p->desc->delay.hpd_absent_delay)
hpd_wait_us = p->desc->delay.hpd_absent_delay * 1000UL;
else
hpd_wait_us = 2000000;
err = readx_poll_timeout(gpiod_get_value_cansleep, p->hpd_gpio,
hpd_asserted, hpd_asserted,
1000, hpd_wait_us);
if (hpd_asserted < 0)
err = hpd_asserted;
if (err) {
if (err != -ETIMEDOUT)
dev_err(dev,
"error waiting for hpd GPIO: %d\n", err);
goto error;
}
}
if (p->desc->delay.prepare)
msleep(p->desc->delay.prepare);
p->prepared_time = ktime_get();
return 0;
error:
gpiod_set_value_cansleep(p->enable_gpio, 0);
regulator_disable(p->supply);
p->unprepared_time = ktime_get();
return err;
}
/*
* Some panels simply don't always come up and need to be power cycled to
* work properly. We'll allow for a handful of retries.
*/
#define MAX_PANEL_PREPARE_TRIES 5
static int panel_simple_resume(struct device *dev)
{
struct panel_simple *p = dev_get_drvdata(dev);
int ret;
int try;
for (try = 0; try < MAX_PANEL_PREPARE_TRIES; try++) {
ret = panel_simple_prepare_once(p);
if (ret != -ETIMEDOUT)
break;
}
if (ret == -ETIMEDOUT)
dev_err(dev, "Prepare timeout after %d tries\n", try);
else if (try)
dev_warn(dev, "Prepare needed %d retries\n", try);
return ret;
}
static int panel_simple_prepare(struct drm_panel *panel)
......@@ -503,8 +383,6 @@ static int panel_simple_enable(struct drm_panel *panel)
if (p->desc->delay.enable)
msleep(p->desc->delay.enable);
panel_simple_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
p->enabled = true;
return 0;
......@@ -660,8 +538,7 @@ static void panel_simple_parse_panel_timing_node(struct device *dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
}
static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
struct drm_dp_aux *aux)
static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
{
struct panel_simple *panel;
struct display_timing dt;
......@@ -677,14 +554,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
panel->enabled = false;
panel->prepared_time = 0;
panel->desc = desc;
panel->aux = aux;
panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd");
if (!panel->no_hpd) {
err = panel_simple_get_hpd_gpio(dev, panel);
if (err)
return err;
}
panel->supply = devm_regulator_get(dev, "power");
if (IS_ERR(panel->supply))
......@@ -712,8 +581,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
if (!panel->ddc)
return -EPROBE_DEFER;
} else if (aux) {
panel->ddc = &aux->ddc;
}
if (desc == &panel_dpi) {
......@@ -749,9 +616,9 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
desc->bpc != 8);
break;
case DRM_MODE_CONNECTOR_eDP:
if (desc->bpc != 6 && desc->bpc != 8 && desc->bpc != 10)
dev_warn(dev, "Expected bpc in {6,8,10} but got: %u\n", desc->bpc);
break;
dev_warn(dev, "eDP panels moved to panel-edp\n");
err = -EINVAL;
goto free_ddc;
case DRM_MODE_CONNECTOR_DSI:
if (desc->bpc != 6 && desc->bpc != 8)
dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
......@@ -798,15 +665,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
if (err)
goto disable_pm_runtime;
if (!panel->base.backlight && panel->aux) {
pm_runtime_get_sync(dev);
err = drm_panel_dp_aux_backlight(&panel->base, panel->aux);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (err)
goto disable_pm_runtime;
}
drm_panel_add(&panel->base);
return 0;
......@@ -815,7 +673,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc,
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
free_ddc:
if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
if (panel->ddc)
put_device(&panel->ddc->dev);
return err;
......@@ -831,7 +689,7 @@ static int panel_simple_remove(struct device *dev)
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
if (panel->ddc)
put_device(&panel->ddc->dev);
return 0;
......@@ -970,28 +828,6 @@ static const struct panel_desc auo_b101aw03 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing auo_b101ean01_timing = {
.pixelclock = { 65300000, 72500000, 75000000 },
.hactive = { 1280, 1280, 1280 },
.hfront_porch = { 18, 119, 119 },
.hback_porch = { 21, 21, 21 },
.hsync_len = { 32, 32, 32 },
.vactive = { 800, 800, 800 },
.vfront_porch = { 4, 4, 4 },
.vback_porch = { 8, 8, 8 },
.vsync_len = { 18, 20, 20 },
};
static const struct panel_desc auo_b101ean01 = {
.timings = &auo_b101ean01_timing,
.num_timings = 1,
.bpc = 6,
.size = {
.width = 217,
.height = 136,
},
};
static const struct drm_display_mode auo_b101xtn01_mode = {
.clock = 72000,
.hdisplay = 1366,
......@@ -1015,172 +851,6 @@ static const struct panel_desc auo_b101xtn01 = {
},
};
static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
.hsync_start = 1366 + 48,
.hsync_end = 1366 + 48 + 32,
.htotal = 1366 + 48 + 32 + 10,
.vdisplay = 768,
.vsync_start = 768 + 4,
.vsync_end = 768 + 4 + 6,
.vtotal = 768 + 4 + 6 + 15,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc auo_b116xak01 = {
.modes = &auo_b116xak01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.hpd_absent_delay = 200,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode auo_b116xw03_mode = {
.clock = 70589,
.hdisplay = 1366,
.hsync_start = 1366 + 40,
.hsync_end = 1366 + 40 + 40,
.htotal = 1366 + 40 + 40 + 32,
.vdisplay = 768,
.vsync_start = 768 + 10,
.vsync_end = 768 + 10 + 12,
.vtotal = 768 + 10 + 12 + 6,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc auo_b116xw03 = {
.modes = &auo_b116xw03_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.enable = 400,
},
.bus_flags = DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE,
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode auo_b133xtn01_mode = {
.clock = 69500,
.hdisplay = 1366,
.hsync_start = 1366 + 48,
.hsync_end = 1366 + 48 + 32,
.htotal = 1366 + 48 + 32 + 20,
.vdisplay = 768,
.vsync_start = 768 + 3,
.vsync_end = 768 + 3 + 6,
.vtotal = 768 + 3 + 6 + 13,
};
static const struct panel_desc auo_b133xtn01 = {
.modes = &auo_b133xtn01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 293,
.height = 165,
},
};
static const struct drm_display_mode auo_b133han05_mode = {
.clock = 142600,
.hdisplay = 1920,
.hsync_start = 1920 + 58,
.hsync_end = 1920 + 58 + 42,
.htotal = 1920 + 58 + 42 + 60,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1080 + 3 + 5 + 54,
};
static const struct panel_desc auo_b133han05 = {
.modes = &auo_b133han05_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 293,
.height = 165,
},
.delay = {
.prepare = 100,
.enable = 20,
.unprepare = 50,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode auo_b133htn01_mode = {
.clock = 150660,
.hdisplay = 1920,
.hsync_start = 1920 + 172,
.hsync_end = 1920 + 172 + 80,
.htotal = 1920 + 172 + 80 + 60,
.vdisplay = 1080,
.vsync_start = 1080 + 25,
.vsync_end = 1080 + 25 + 10,
.vtotal = 1080 + 25 + 10 + 10,
};
static const struct panel_desc auo_b133htn01 = {
.modes = &auo_b133htn01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 293,
.height = 165,
},
.delay = {
.prepare = 105,
.enable = 20,
.unprepare = 50,
},
};
static const struct drm_display_mode auo_b140han06_mode = {
.clock = 141000,
.hdisplay = 1920,
.hsync_start = 1920 + 16,
.hsync_end = 1920 + 16 + 16,
.htotal = 1920 + 16 + 16 + 152,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 14,
.vtotal = 1080 + 3 + 14 + 19,
};
static const struct panel_desc auo_b140han06 = {
.modes = &auo_b140han06_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 309,
.height = 174,
},
.delay = {
.prepare = 100,
.enable = 20,
.unprepare = 50,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct display_timing auo_g070vvn01_timings = {
.pixelclock = { 33300000, 34209000, 45000000 },
.hactive = { 800, 800, 800 },
......@@ -1524,169 +1194,6 @@ static const struct panel_desc boe_hv070wsa = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
{
.clock = 71900,
.hdisplay = 1280,
.hsync_start = 1280 + 48,
.hsync_end = 1280 + 48 + 32,
.htotal = 1280 + 48 + 32 + 80,
.vdisplay = 800,
.vsync_start = 800 + 3,
.vsync_end = 800 + 3 + 5,
.vtotal = 800 + 3 + 5 + 24,
},
{
.clock = 57500,
.hdisplay = 1280,
.hsync_start = 1280 + 48,
.hsync_end = 1280 + 48 + 32,
.htotal = 1280 + 48 + 32 + 80,
.vdisplay = 800,
.vsync_start = 800 + 3,
.vsync_end = 800 + 3 + 5,
.vtotal = 800 + 3 + 5 + 24,
},
};
static const struct panel_desc boe_nv101wxmn51 = {
.modes = boe_nv101wxmn51_modes,
.num_modes = ARRAY_SIZE(boe_nv101wxmn51_modes),
.bpc = 8,
.size = {
.width = 217,
.height = 136,
},
.delay = {
.prepare = 210,
.enable = 50,
.unprepare = 160,
},
};
static const struct drm_display_mode boe_nv110wtm_n61_modes[] = {
{
.clock = 207800,
.hdisplay = 2160,
.hsync_start = 2160 + 48,
.hsync_end = 2160 + 48 + 32,
.htotal = 2160 + 48 + 32 + 100,
.vdisplay = 1440,
.vsync_start = 1440 + 3,
.vsync_end = 1440 + 3 + 6,
.vtotal = 1440 + 3 + 6 + 31,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
},
{
.clock = 138500,
.hdisplay = 2160,
.hsync_start = 2160 + 48,
.hsync_end = 2160 + 48 + 32,
.htotal = 2160 + 48 + 32 + 100,
.vdisplay = 1440,
.vsync_start = 1440 + 3,
.vsync_end = 1440 + 3 + 6,
.vtotal = 1440 + 3 + 6 + 31,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
},
};
static const struct panel_desc boe_nv110wtm_n61 = {
.modes = boe_nv110wtm_n61_modes,
.num_modes = ARRAY_SIZE(boe_nv110wtm_n61_modes),
.bpc = 8,
.size = {
.width = 233,
.height = 155,
},
.delay = {
.hpd_absent_delay = 200,
.prepare_to_enable = 80,
.enable = 50,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
/* Also used for boe_nv133fhm_n62 */
static const struct drm_display_mode boe_nv133fhm_n61_modes = {
.clock = 147840,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 200,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 6,
.vtotal = 1080 + 3 + 6 + 31,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC,
};
/* Also used for boe_nv133fhm_n62 */
static const struct panel_desc boe_nv133fhm_n61 = {
.modes = &boe_nv133fhm_n61_modes,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 294,
.height = 165,
},
.delay = {
/*
* When power is first given to the panel there's a short
* spike on the HPD line. It was explained that this spike
* was until the TCON data download was complete. On
* one system this was measured at 8 ms. We'll put 15 ms
* in the prepare delay just to be safe and take it away
* from the hpd_absent_delay (which would otherwise be 200 ms)
* to handle this. That means:
* - If HPD isn't hooked up you still have 200 ms delay.
* - If HPD is hooked up we won't try to look at it for the
* first 15 ms.
*/
.prepare = 15,
.hpd_absent_delay = 185,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode boe_nv140fhmn49_modes[] = {
{
.clock = 148500,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 2200,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1125,
},
};
static const struct panel_desc boe_nv140fhmn49 = {
.modes = boe_nv140fhmn49_modes,
.num_modes = ARRAY_SIZE(boe_nv140fhmn49_modes),
.bpc = 6,
.size = {
.width = 309,
.height = 174,
},
.delay = {
.prepare = 210,
.enable = 50,
.unprepare = 160,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode cdtech_s043wq26h_ct7_mode = {
.clock = 9000,
.hdisplay = 480,
......@@ -2609,96 +2116,6 @@ static const struct panel_desc innolux_g121x1_l03 = {
},
};
static const struct drm_display_mode innolux_n116bca_ea1_mode = {
.clock = 76420,
.hdisplay = 1366,
.hsync_start = 1366 + 136,
.hsync_end = 1366 + 136 + 30,
.htotal = 1366 + 136 + 30 + 60,
.vdisplay = 768,
.vsync_start = 768 + 8,
.vsync_end = 768 + 8 + 12,
.vtotal = 768 + 8 + 12 + 12,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
};
static const struct panel_desc innolux_n116bca_ea1 = {
.modes = &innolux_n116bca_ea1_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.hpd_absent_delay = 200,
.prepare_to_enable = 80,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
/*
* Datasheet specifies that at 60 Hz refresh rate:
* - total horizontal time: { 1506, 1592, 1716 }
* - total vertical time: { 788, 800, 868 }
*
* ...but doesn't go into exactly how that should be split into a front
* porch, back porch, or sync length. For now we'll leave a single setting
* here which allows a bit of tweaking of the pixel clock at the expense of
* refresh rate.
*/
static const struct display_timing innolux_n116bge_timing = {
.pixelclock = { 72600000, 76420000, 80240000 },
.hactive = { 1366, 1366, 1366 },
.hfront_porch = { 136, 136, 136 },
.hback_porch = { 60, 60, 60 },
.hsync_len = { 30, 30, 30 },
.vactive = { 768, 768, 768 },
.vfront_porch = { 8, 8, 8 },
.vback_porch = { 12, 12, 12 },
.vsync_len = { 12, 12, 12 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
};
static const struct panel_desc innolux_n116bge = {
.timings = &innolux_n116bge_timing,
.num_timings = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode innolux_n125hce_gn1_mode = {
.clock = 162000,
.hdisplay = 1920,
.hsync_start = 1920 + 40,
.hsync_end = 1920 + 40 + 40,
.htotal = 1920 + 40 + 40 + 80,
.vdisplay = 1080,
.vsync_start = 1080 + 4,
.vsync_end = 1080 + 4 + 4,
.vtotal = 1080 + 4 + 4 + 24,
};
static const struct panel_desc innolux_n125hce_gn1 = {
.modes = &innolux_n125hce_gn1_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 276,
.height = 155,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode innolux_n156bge_l21_mode = {
.clock = 69300,
.hdisplay = 1366,
......@@ -2724,33 +2141,6 @@ static const struct panel_desc innolux_n156bge_l21 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode innolux_p120zdg_bf1_mode = {
.clock = 206016,
.hdisplay = 2160,
.hsync_start = 2160 + 48,
.hsync_end = 2160 + 48 + 32,
.htotal = 2160 + 48 + 32 + 80,
.vdisplay = 1440,
.vsync_start = 1440 + 3,
.vsync_end = 1440 + 3 + 10,
.vtotal = 1440 + 3 + 10 + 27,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc innolux_p120zdg_bf1 = {
.modes = &innolux_p120zdg_bf1_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 254,
.height = 169,
},
.delay = {
.hpd_absent_delay = 200,
.unprepare = 500,
},
};
static const struct drm_display_mode innolux_zj070na_01p_mode = {
.clock = 51501,
.hdisplay = 1024,
......@@ -2773,64 +2163,6 @@ static const struct panel_desc innolux_zj070na_01p = {
},
};
static const struct drm_display_mode ivo_m133nwf4_r0_mode = {
.clock = 138778,
.hdisplay = 1920,
.hsync_start = 1920 + 24,
.hsync_end = 1920 + 24 + 48,
.htotal = 1920 + 24 + 48 + 88,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 12,
.vtotal = 1080 + 3 + 12 + 17,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc ivo_m133nwf4_r0 = {
.modes = &ivo_m133nwf4_r0_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 294,
.height = 165,
},
.delay = {
.hpd_absent_delay = 200,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = {
.clock = 81000,
.hdisplay = 1366,
.hsync_start = 1366 + 40,
.hsync_end = 1366 + 40 + 32,
.htotal = 1366 + 40 + 32 + 62,
.vdisplay = 768,
.vsync_start = 768 + 5,
.vsync_end = 768 + 5 + 5,
.vtotal = 768 + 5 + 5 + 122,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc kingdisplay_kd116n21_30nv_a010 = {
.modes = &kingdisplay_kd116n21_30nv_a010_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 256,
.height = 144,
},
.delay = {
.hpd_absent_delay = 200,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct display_timing koe_tx14d24vm1bpa_timing = {
.pixelclock = { 5580000, 5850000, 6200000 },
.hactive = { 320, 320, 320 },
......@@ -2982,94 +2314,6 @@ static const struct panel_desc lg_lb070wv8 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode lg_lp079qx1_sp0v_mode = {
.clock = 200000,
.hdisplay = 1536,
.hsync_start = 1536 + 12,
.hsync_end = 1536 + 12 + 16,
.htotal = 1536 + 12 + 16 + 48,
.vdisplay = 2048,
.vsync_start = 2048 + 8,
.vsync_end = 2048 + 8 + 4,
.vtotal = 2048 + 8 + 4 + 8,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc lg_lp079qx1_sp0v = {
.modes = &lg_lp079qx1_sp0v_mode,
.num_modes = 1,
.size = {
.width = 129,
.height = 171,
},
};
static const struct drm_display_mode lg_lp097qx1_spa1_mode = {
.clock = 205210,
.hdisplay = 2048,
.hsync_start = 2048 + 150,
.hsync_end = 2048 + 150 + 5,
.htotal = 2048 + 150 + 5 + 5,
.vdisplay = 1536,
.vsync_start = 1536 + 3,
.vsync_end = 1536 + 3 + 1,
.vtotal = 1536 + 3 + 1 + 9,
};
static const struct panel_desc lg_lp097qx1_spa1 = {
.modes = &lg_lp097qx1_spa1_mode,
.num_modes = 1,
.size = {
.width = 208,
.height = 147,
},
};
static const struct drm_display_mode lg_lp120up1_mode = {
.clock = 162300,
.hdisplay = 1920,
.hsync_start = 1920 + 40,
.hsync_end = 1920 + 40 + 40,
.htotal = 1920 + 40 + 40+ 80,
.vdisplay = 1280,
.vsync_start = 1280 + 4,
.vsync_end = 1280 + 4 + 4,
.vtotal = 1280 + 4 + 4 + 12,
};
static const struct panel_desc lg_lp120up1 = {
.modes = &lg_lp120up1_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 267,
.height = 183,
},
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode lg_lp129qe_mode = {
.clock = 285250,
.hdisplay = 2560,
.hsync_start = 2560 + 48,
.hsync_end = 2560 + 48 + 32,
.htotal = 2560 + 48 + 32 + 80,
.vdisplay = 1700,
.vsync_start = 1700 + 3,
.vsync_end = 1700 + 3 + 10,
.vtotal = 1700 + 3 + 10 + 36,
};
static const struct panel_desc lg_lp129qe = {
.modes = &lg_lp129qe_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 272,
.height = 181,
},
};
static const struct display_timing logictechno_lt161010_2nh_timing = {
.pixelclock = { 26400000, 33300000, 46800000 },
.hactive = { 800, 800, 800 },
......@@ -3330,49 +2574,6 @@ static const struct panel_desc netron_dy_e231732 = {
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
};
static const struct drm_display_mode neweast_wjfh116008a_modes[] = {
{
.clock = 138500,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 80,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1080 + 3 + 5 + 23,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
}, {
.clock = 110920,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 80,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 5,
.vtotal = 1080 + 3 + 5 + 23,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
}
};
static const struct panel_desc neweast_wjfh116008a = {
.modes = neweast_wjfh116008a_modes,
.num_modes = 2,
.bpc = 6,
.size = {
.width = 260,
.height = 150,
},
.delay = {
.prepare = 110,
.enable = 20,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode newhaven_nhd_43_480272ef_atxl_mode = {
.clock = 9000,
.hdisplay = 480,
......@@ -3783,27 +2984,6 @@ static const struct panel_desc rocktech_rk101ii01d_ct = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode samsung_lsn122dl01_c01_mode = {
.clock = 271560,
.hdisplay = 2560,
.hsync_start = 2560 + 48,
.hsync_end = 2560 + 48 + 32,
.htotal = 2560 + 48 + 32 + 80,
.vdisplay = 1600,
.vsync_start = 1600 + 2,
.vsync_end = 1600 + 2 + 5,
.vtotal = 1600 + 2 + 5 + 57,
};
static const struct panel_desc samsung_lsn122dl01_c01 = {
.modes = &samsung_lsn122dl01_c01_mode,
.num_modes = 1,
.size = {
.width = 263,
.height = 164,
},
};
static const struct drm_display_mode samsung_ltn101nt05_mode = {
.clock = 54030,
.hdisplay = 1024,
......@@ -3829,28 +3009,6 @@ static const struct panel_desc samsung_ltn101nt05 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode samsung_ltn140at29_301_mode = {
.clock = 76300,
.hdisplay = 1366,
.hsync_start = 1366 + 64,
.hsync_end = 1366 + 64 + 48,
.htotal = 1366 + 64 + 48 + 128,
.vdisplay = 768,
.vsync_start = 768 + 2,
.vsync_end = 768 + 2 + 5,
.vtotal = 768 + 2 + 5 + 17,
};
static const struct panel_desc samsung_ltn140at29_301 = {
.modes = &samsung_ltn140at29_301_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 320,
.height = 187,
},
};
static const struct display_timing satoz_sat050at40h12r2_timing = {
.pixelclock = {33300000, 33300000, 50000000},
.hactive = {800, 800, 800},
......@@ -3875,31 +3033,6 @@ static const struct panel_desc satoz_sat050at40h12r2 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode sharp_ld_d5116z01b_mode = {
.clock = 168480,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 80,
.vdisplay = 1280,
.vsync_start = 1280 + 3,
.vsync_end = 1280 + 3 + 10,
.vtotal = 1280 + 3 + 10 + 57,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc sharp_ld_d5116z01b = {
.modes = &sharp_ld_d5116z01b_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 260,
.height = 120,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
};
static const struct drm_display_mode sharp_lq070y3dg3b_mode = {
.clock = 33260,
.hdisplay = 800,
......@@ -3974,34 +3107,6 @@ static const struct panel_desc sharp_lq101k1ly04 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing sharp_lq123p1jx31_timing = {
.pixelclock = { 252750000, 252750000, 266604720 },
.hactive = { 2400, 2400, 2400 },
.hfront_porch = { 48, 48, 48 },
.hback_porch = { 80, 80, 84 },
.hsync_len = { 32, 32, 32 },
.vactive = { 1600, 1600, 1600 },
.vfront_porch = { 3, 3, 3 },
.vback_porch = { 33, 33, 120 },
.vsync_len = { 10, 10, 10 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
};
static const struct panel_desc sharp_lq123p1jx31 = {
.timings = &sharp_lq123p1jx31_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 259,
.height = 173,
},
.delay = {
.prepare = 110,
.enable = 50,
.unprepare = 550,
},
};
static const struct drm_display_mode sharp_ls020b1dd01d_modes[] = {
{ /* 50 Hz */
.clock = 3000,
......@@ -4090,33 +3195,6 @@ static const struct panel_desc starry_kr070pe2t = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct drm_display_mode starry_kr122ea0sra_mode = {
.clock = 147000,
.hdisplay = 1920,
.hsync_start = 1920 + 16,
.hsync_end = 1920 + 16 + 16,
.htotal = 1920 + 16 + 16 + 32,
.vdisplay = 1200,
.vsync_start = 1200 + 15,
.vsync_end = 1200 + 15 + 2,
.vtotal = 1200 + 15 + 2 + 18,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc starry_kr122ea0sra = {
.modes = &starry_kr122ea0sra_mode,
.num_modes = 1,
.size = {
.width = 263,
.height = 164,
},
.delay = {
.prepare = 10 + 200,
.enable = 50,
.unprepare = 10 + 500,
},
};
static const struct drm_display_mode tfc_s9700rtwv43tr_01b_mode = {
.clock = 30000,
.hdisplay = 800,
......@@ -4483,30 +3561,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "auo,b101aw03",
.data = &auo_b101aw03,
}, {
.compatible = "auo,b101ean01",
.data = &auo_b101ean01,
}, {
.compatible = "auo,b101xtn01",
.data = &auo_b101xtn01,
}, {
.compatible = "auo,b116xa01",
.data = &auo_b116xak01,
}, {
.compatible = "auo,b116xw03",
.data = &auo_b116xw03,
}, {
.compatible = "auo,b133han05",
.data = &auo_b133han05,
}, {
.compatible = "auo,b133htn01",
.data = &auo_b133htn01,
}, {
.compatible = "auo,b140han06",
.data = &auo_b140han06,
}, {
.compatible = "auo,b133xtn01",
.data = &auo_b133xtn01,
}, {
.compatible = "auo,g070vvn01",
.data = &auo_g070vvn01,
......@@ -4546,21 +3603,6 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "boe,hv070wsa-100",
.data = &boe_hv070wsa
}, {
.compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51,
}, {
.compatible = "boe,nv110wtm-n61",
.data = &boe_nv110wtm_n61,
}, {
.compatible = "boe,nv133fhm-n61",
.data = &boe_nv133fhm_n61,
}, {
.compatible = "boe,nv133fhm-n62",
.data = &boe_nv133fhm_n61,
}, {
.compatible = "boe,nv140fhmn49",
.data = &boe_nv140fhmn49,
}, {
.compatible = "cdtech,s043wq26h-ct7",
.data = &cdtech_s043wq26h_ct7,
......@@ -4672,30 +3714,12 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "innolux,g121x1-l03",
.data = &innolux_g121x1_l03,
}, {
.compatible = "innolux,n116bca-ea1",
.data = &innolux_n116bca_ea1,
}, {
.compatible = "innolux,n116bge",
.data = &innolux_n116bge,
}, {
.compatible = "innolux,n125hce-gn1",
.data = &innolux_n125hce_gn1,
}, {
.compatible = "innolux,n156bge-l21",
.data = &innolux_n156bge_l21,
}, {
.compatible = "innolux,p120zdg-bf1",
.data = &innolux_p120zdg_bf1,
}, {
.compatible = "innolux,zj070na-01p",
.data = &innolux_zj070na_01p,
}, {
.compatible = "ivo,m133nwf4-r0",
.data = &ivo_m133nwf4_r0,
}, {
.compatible = "kingdisplay,kd116n21-30nv-a010",
.data = &kingdisplay_kd116n21_30nv_a010,
}, {
.compatible = "koe,tx14d24vm1bpa",
.data = &koe_tx14d24vm1bpa,
......@@ -4714,18 +3738,6 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "lg,lb070wv8",
.data = &lg_lb070wv8,
}, {
.compatible = "lg,lp079qx1-sp0v",
.data = &lg_lp079qx1_sp0v,
}, {
.compatible = "lg,lp097qx1-spa1",
.data = &lg_lp097qx1_spa1,
}, {
.compatible = "lg,lp120up1",
.data = &lg_lp120up1,
}, {
.compatible = "lg,lp129qe",
.data = &lg_lp129qe,
}, {
.compatible = "logicpd,type28",
.data = &logicpd_type_28,
......@@ -4756,9 +3768,6 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "netron-dy,e231732",
.data = &netron_dy_e231732,
}, {
.compatible = "neweast,wjfh116008a",
.data = &neweast_wjfh116008a,
}, {
.compatible = "newhaven,nhd-4.3-480272ef-atxl",
.data = &newhaven_nhd_43_480272ef_atxl,
......@@ -4807,21 +3816,12 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "rocktech,rk101ii01d-ct",
.data = &rocktech_rk101ii01d_ct,
}, {
.compatible = "samsung,lsn122dl01-c01",
.data = &samsung_lsn122dl01_c01,
}, {
.compatible = "samsung,ltn101nt05",
.data = &samsung_ltn101nt05,
}, {
.compatible = "samsung,ltn140at29-301",
.data = &samsung_ltn140at29_301,
}, {
.compatible = "satoz,sat050at40h12r2",
.data = &satoz_sat050at40h12r2,
}, {
.compatible = "sharp,ld-d5116z01b",
.data = &sharp_ld_d5116z01b,
}, {
.compatible = "sharp,lq035q7db03",
.data = &sharp_lq035q7db03,
......@@ -4831,9 +3831,6 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "sharp,lq101k1ly04",
.data = &sharp_lq101k1ly04,
}, {
.compatible = "sharp,lq123p1jx31",
.data = &sharp_lq123p1jx31,
}, {
.compatible = "sharp,ls020b1dd01d",
.data = &sharp_ls020b1dd01d,
......@@ -4843,9 +3840,6 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "starry,kr070pe2t",
.data = &starry_kr070pe2t,
}, {
.compatible = "starry,kr122ea0sra",
.data = &starry_kr122ea0sra,
}, {
.compatible = "tfc,s9700rtwv43tr-01b",
.data = &tfc_s9700rtwv43tr_01b,
......@@ -4918,7 +3912,7 @@ static int panel_simple_platform_probe(struct platform_device *pdev)
if (!id)
return -ENODEV;
return panel_simple_probe(&pdev->dev, id->data, NULL);
return panel_simple_probe(&pdev->dev, id->data);
}
static int panel_simple_platform_remove(struct platform_device *pdev)
......@@ -5198,7 +4192,7 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
desc = id->data;
err = panel_simple_probe(&dsi->dev, &desc->desc, NULL);
err = panel_simple_probe(&dsi->dev, &desc->desc);
if (err < 0)
return err;
......@@ -5243,38 +4237,6 @@ static struct mipi_dsi_driver panel_simple_dsi_driver = {
.shutdown = panel_simple_dsi_shutdown,
};
static int panel_simple_dp_aux_ep_probe(struct dp_aux_ep_device *aux_ep)
{
const struct of_device_id *id;
id = of_match_node(platform_of_match, aux_ep->dev.of_node);
if (!id)
return -ENODEV;
return panel_simple_probe(&aux_ep->dev, id->data, aux_ep->aux);
}
static void panel_simple_dp_aux_ep_remove(struct dp_aux_ep_device *aux_ep)
{
panel_simple_remove(&aux_ep->dev);
}
static void panel_simple_dp_aux_ep_shutdown(struct dp_aux_ep_device *aux_ep)
{
panel_simple_shutdown(&aux_ep->dev);
}
static struct dp_aux_ep_driver panel_simple_dp_aux_ep_driver = {
.driver = {
.name = "panel-simple-dp-aux",
.of_match_table = platform_of_match, /* Same as platform one! */
.pm = &panel_simple_pm_ops,
},
.probe = panel_simple_dp_aux_ep_probe,
.remove = panel_simple_dp_aux_ep_remove,
.shutdown = panel_simple_dp_aux_ep_shutdown,
};
static int __init panel_simple_init(void)
{
int err;
......@@ -5283,21 +4245,14 @@ static int __init panel_simple_init(void)
if (err < 0)
return err;
err = dp_aux_dp_driver_register(&panel_simple_dp_aux_ep_driver);
if (err < 0)
goto err_did_platform_register;
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
if (err < 0)
goto err_did_aux_ep_register;
goto err_did_platform_register;
}
return 0;
err_did_aux_ep_register:
dp_aux_dp_driver_unregister(&panel_simple_dp_aux_ep_driver);
err_did_platform_register:
platform_driver_unregister(&panel_simple_platform_driver);
......@@ -5310,7 +4265,6 @@ static void __exit panel_simple_exit(void)
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
mipi_dsi_driver_unregister(&panel_simple_dsi_driver);
dp_aux_dp_driver_unregister(&panel_simple_dp_aux_ep_driver);
platform_driver_unregister(&panel_simple_platform_driver);
}
module_exit(panel_simple_exit);
......
......@@ -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;
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.
*/
region_width = max(fls64(region_start ^ (region_end - 1)),
const_ilog2(AS_LOCK_REGION_MIN_SIZE)) - 1;
/* The size is encoded as ceil(log2) minus(1), which may be calculated
* with fls. The size must be clamped to hardware bounds.
/*
* Mask off the low bits of region_start (which would be ignored by
* the hardware anyway)
*/
size = max_t(u64, size, AS_LOCK_REGION_MIN_SIZE);
region_width = fls64(size - 1) - 1;
region |= region_width;
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,6 +626,21 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
drm_connector_helper_add(connector,
&rockchip_lvds_connector_helper_funcs);
} else {
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) {
......@@ -634,11 +648,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
"failed to attach encoder: %d\n", ret);
goto err_free_connector;
}
} else {
ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0);
if (ret)
goto err_free_encoder;
}
pm_runtime_enable(dev);
of_node_put(remote);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment