mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:07:50 +01:00
drm-misc-next for v7.4:
Driver Changes: host1x: - support partitioning panel: - fix fallout from bridge-related changes tegra: - improve syncobj handling on submit -----BEGIN PGP SIGNATURE----- iQFPBAABCgA5FiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmq/nSUbFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyAAoJEGgNwR1TC3ojrqwH/jHm9C9kKKYzuqGYMPXg 6NEYXWdSWKwT3ASY6Me/dHDTPK9ceqo17W3wMY9LVJl0jWqTZpsLVGx9zwHsmVrE Z28z4kFbqF61h7FnQDPPPtcvLzAVz3/FzdcwQD1EjX9EJuOIaM129gHjrPSTxh4x ZXQXrKU7F5TBDY7mM3PKnM+43FIkdJ8ICIQJ+1n/dVtF2EBW3CqJSDOzWbtDzKge UPG2BLbv5ZHDdsg7ukLiZek4bb6DxDWzxL23X9TnI9BgzUPHdtPODyCPr2GvV7nG oDiDU0llBMbl6x/RXlrGrsjxE4RCQmw8WOmY4ILDh8RQh57q73Is5AtybdV4bET4 /KI= =jTkR -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2026-10-02' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next drm-misc-next for v7.4: Cross-subsystem Changes: Documentation: - Fix indention in display-related DT bindings Core Changes: - Provide helpers for calculating absolute and relative timeouts clients: - fbdev: Move helpers from drm_kms_helper.ko to drm_client_lib.ko display: - dp/mst: Improve DPCD compliance sched: - fix locking Driver changes: amdxdna: - Support AIE2 rev 9 - Fix UAF access in scheduler fences - Update workqueue interface bridge: - Select DRM_PANEL_BRIDGE for various drivers that require it host1x: - Support partitioning imagination - Clean up firmware interface imx: - Replace simple-display with regular atomic helpers ivpu: - Simplify NULL-pointer handling in cleanup code mxsfb: - Support bus formats plus DT bindings panel: - ebbg-ft8719: Fix MODULE_LICENSE() string; Improve initialization - edp: NV140WU2-M70 - ilitek-ili9882t: Support Ilitek IL79600A plus DT bindings - simple: Support Truly TFT320240-229-E plus DT bindings; Support BOE DV215FHM-R01 plus DT bindings - Refactor struct drm_panel to contain struct drm_bridge plus fallout in various panel drivers panthor: - Validate user-space input against firmware limits renesas: - Support RZ/G3L SoC ssd130x: - ssd132x: Set correct hardware window when clearing screen host1x: - support partitioning panel: - fix fallout from bridge-related changes tegra: - improve syncobj handling on submit Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patch.msgid.link/20261002120720.GA720384@linux.fritz.box
This commit is contained in:
commit
1b15fa434b
|
|
@ -119,11 +119,11 @@ examples:
|
|||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "bananapi,lhr050h41", "ilitek,ili9881c";
|
||||
reg = <0>;
|
||||
power-supply = <®_display>;
|
||||
reset-gpios = <&r_pio 0 5 1>; /* PL05 */
|
||||
backlight = <&pwm_bl>;
|
||||
compatible = "bananapi,lhr050h41", "ilitek,ili9881c";
|
||||
reg = <0>;
|
||||
power-supply = <®_display>;
|
||||
reset-gpios = <&r_pio 0 5 1>; /* PL05 */
|
||||
backlight = <&pwm_bl>;
|
||||
};
|
||||
|
||||
port {
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ examples:
|
|||
};
|
||||
|
||||
mipi_lvds_0_pxl2dpi_dc_pixel_link1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&dc_pixel_link1_mipi_lvds_0_pxl2dpi>;
|
||||
reg = <1>;
|
||||
remote-endpoint = <&dc_pixel_link1_mipi_lvds_0_pxl2dpi>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -107,11 +107,11 @@ examples:
|
|||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
reg = <1>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&hdmi_in>;
|
||||
};
|
||||
endpoint {
|
||||
remote-endpoint = <&hdmi_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ examples:
|
|||
endpoint {
|
||||
remote-endpoint = <&stdp2690_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ examples:
|
|||
video-ports = <0x230145>;
|
||||
|
||||
#sound-dai-cells = <1>;
|
||||
/* DAI-format / AP_ENA reg value */
|
||||
/* DAI-format / AP_ENA reg value */
|
||||
audio-ports = <TDA998x_SPDIF 0x04>,
|
||||
<TDA998x_I2S 0x03>;
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ examples:
|
|||
port@1 {
|
||||
reg = <1>;
|
||||
lvds_ep: endpoint {
|
||||
remote-endpoint = <&panel_ep>;
|
||||
remote-endpoint = <&panel_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -161,9 +161,9 @@ examples:
|
|||
dsi0_out: endpoint {
|
||||
remote-endpoint = <&d2l_in_test>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
/* For dual-link LVDS display panel */
|
||||
|
|
@ -227,7 +227,7 @@ examples:
|
|||
dsi0_out_dual: endpoint {
|
||||
remote-endpoint = <&d2l_in_dual>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ examples:
|
|||
display-controller@6a000000 {
|
||||
compatible = "faraday,tve200";
|
||||
reg = <0x6a000000 0x1000>;
|
||||
interrupts = <13 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
|
||||
resets = <&syscon GEMINI_RESET_TVC>;
|
||||
clocks = <&syscon GEMINI_CLK_GATE_TVC>,
|
||||
<&syscon GEMINI_CLK_TVC>;
|
||||
|
|
|
|||
|
|
@ -68,9 +68,19 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: The LCDIF output port
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
bus-width:
|
||||
enum: [ 16, 18, 24 ]
|
||||
|
||||
display:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle to display panel
|
||||
|
|
|
|||
|
|
@ -74,5 +74,5 @@ examples:
|
|||
dc-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
|
||||
rotation = <90>;
|
||||
backlight = <&backlight>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ examples:
|
|||
|
||||
port {
|
||||
parallel_out: endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -150,44 +150,44 @@ examples:
|
|||
|
||||
/* Using an of-graph endpoint link to connect the panel */
|
||||
lvds-channel@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&ipu_di0_lvds0>;
|
||||
};
|
||||
endpoint {
|
||||
remote-endpoint = <&ipu_di0_lvds0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* Using display-timings and fsl,data-mapping/width instead */
|
||||
lvds-channel@1 {
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
fsl,data-mapping = "spwg";
|
||||
fsl,data-width = <24>;
|
||||
|
||||
display-timings {/* ... */
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
fsl,data-mapping = "spwg";
|
||||
fsl,data-width = <24>;
|
||||
|
||||
display-timings {/* ... */
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&ipu_di1_lvds1>;
|
||||
};
|
||||
endpoint {
|
||||
remote-endpoint = <&ipu_di1_lvds1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -158,51 +158,51 @@ examples:
|
|||
#size-cells = <2>;
|
||||
|
||||
hdr-engine@1c114000 {
|
||||
compatible = "mediatek,mt8195-disp-ethdr";
|
||||
reg = <0 0x1c114000 0 0x1000>,
|
||||
<0 0x1c115000 0 0x1000>,
|
||||
<0 0x1c117000 0 0x1000>,
|
||||
<0 0x1c119000 0 0x1000>,
|
||||
<0 0x1c11a000 0 0x1000>,
|
||||
<0 0x1c11b000 0 0x1000>,
|
||||
<0 0x1c11c000 0 0x1000>;
|
||||
reg-names = "mixer", "vdo_fe0", "vdo_fe1", "gfx_fe0", "gfx_fe1",
|
||||
"vdo_be", "adl_ds";
|
||||
mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0x4000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0x5000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0x7000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0x9000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0xa000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0xb000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0xc000 0x1000>;
|
||||
clocks = <&vdosys1 CLK_VDO1_DISP_MIXER>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE0>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE1>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE0>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE1>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_BE>,
|
||||
<&vdosys1 CLK_VDO1_26M_SLOW>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE0_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE1_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE0_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE1_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_BE_DL_ASYNC>,
|
||||
<&topckgen CLK_TOP_ETHDR>;
|
||||
clock-names = "mixer", "vdo_fe0", "vdo_fe1", "gfx_fe0", "gfx_fe1",
|
||||
"vdo_be", "adl_ds", "vdo_fe0_async", "vdo_fe1_async",
|
||||
"gfx_fe0_async", "gfx_fe1_async","vdo_be_async",
|
||||
"ethdr_top";
|
||||
power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
|
||||
iommus = <&iommu_vpp M4U_PORT_L3_HDR_DS>,
|
||||
<&iommu_vpp M4U_PORT_L3_HDR_ADL>;
|
||||
interrupts = <GIC_SPI 517 IRQ_TYPE_LEVEL_HIGH 0>; /* disp mixer */
|
||||
resets = <&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE0_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE1_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE0_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE1_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_BE_DL_ASYNC>;
|
||||
reset-names = "vdo_fe0_async", "vdo_fe1_async", "gfx_fe0_async",
|
||||
"gfx_fe1_async", "vdo_be_async";
|
||||
compatible = "mediatek,mt8195-disp-ethdr";
|
||||
reg = <0 0x1c114000 0 0x1000>,
|
||||
<0 0x1c115000 0 0x1000>,
|
||||
<0 0x1c117000 0 0x1000>,
|
||||
<0 0x1c119000 0 0x1000>,
|
||||
<0 0x1c11a000 0 0x1000>,
|
||||
<0 0x1c11b000 0 0x1000>,
|
||||
<0 0x1c11c000 0 0x1000>;
|
||||
reg-names = "mixer", "vdo_fe0", "vdo_fe1", "gfx_fe0", "gfx_fe1",
|
||||
"vdo_be", "adl_ds";
|
||||
mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0x4000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0x5000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0x7000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0x9000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0xa000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0xb000 0x1000>,
|
||||
<&gce0 SUBSYS_1c11XXXX 0xc000 0x1000>;
|
||||
clocks = <&vdosys1 CLK_VDO1_DISP_MIXER>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE0>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE1>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE0>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE1>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_BE>,
|
||||
<&vdosys1 CLK_VDO1_26M_SLOW>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE0_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_FE1_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE0_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_GFX_FE1_DL_ASYNC>,
|
||||
<&vdosys1 CLK_VDO1_HDR_VDO_BE_DL_ASYNC>,
|
||||
<&topckgen CLK_TOP_ETHDR>;
|
||||
clock-names = "mixer", "vdo_fe0", "vdo_fe1", "gfx_fe0", "gfx_fe1",
|
||||
"vdo_be", "adl_ds", "vdo_fe0_async", "vdo_fe1_async",
|
||||
"gfx_fe0_async", "gfx_fe1_async","vdo_be_async",
|
||||
"ethdr_top";
|
||||
power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
|
||||
iommus = <&iommu_vpp M4U_PORT_L3_HDR_DS>,
|
||||
<&iommu_vpp M4U_PORT_L3_HDR_ADL>;
|
||||
interrupts = <GIC_SPI 517 IRQ_TYPE_LEVEL_HIGH 0>; /* disp mixer */
|
||||
resets = <&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE0_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE1_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE0_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE1_DL_ASYNC>,
|
||||
<&vdosys1 MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_BE_DL_ASYNC>;
|
||||
reset-names = "vdo_fe0_async", "vdo_fe1_async", "gfx_fe0_async",
|
||||
"gfx_fe1_async", "vdo_be_async";
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -112,24 +112,24 @@ examples:
|
|||
mediatek,syscon-hdmi = <&mmsys 0x900>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi0_in: endpoint {
|
||||
remote-endpoint = <&dpi0_out>;
|
||||
hdmi0_in: endpoint {
|
||||
remote-endpoint = <&dpi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi0_out: endpoint {
|
||||
remote-endpoint = <&hdmi_con_in>;
|
||||
hdmi0_out: endpoint {
|
||||
remote-endpoint = <&hdmi_con_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,15 @@ allOf:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- tianma,tl121bvms07-00
|
||||
- const: ilitek,il79900a
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- raspberrypi,dsi-10inch
|
||||
- const: ilitek,il79600a
|
||||
- items:
|
||||
- enum:
|
||||
- tianma,tl121bvms07-00
|
||||
- const: ilitek,il79900a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ properties:
|
|||
- auo,t215hvn01
|
||||
# BOE AV123Z7M-N17 12.3" (1920x720) LVDS TFT LCD panel
|
||||
- boe,av123z7m-n17
|
||||
# BOE DV215FHM-R01 21.5" FHD (1920x1080) dual-channel LVDS panel
|
||||
- boe,dv215fhm-r01
|
||||
# InnoLux 15.6" FHD (1920x1080) TFT LCD panel
|
||||
- innolux,g156hce-l01
|
||||
# Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel
|
||||
|
|
|
|||
|
|
@ -338,6 +338,8 @@ properties:
|
|||
- tpk,f07a-0102
|
||||
# TPK U.S.A. LLC Fusion 10.1" 1024 x 600 (WSVGA) LCD panel with capacitive touch
|
||||
- tpk,f10a-0102
|
||||
# Truly Semiconductors Limited 3.5" QVGA (320 x 240) TFT LCD panel
|
||||
- truly,tft320240-229-e
|
||||
# United Radiant Technology UMSH-8596MD-xT 7.0" WVGA TFT LCD panel
|
||||
# Supported are LVDS versions (-11T, -19T) and parallel ones
|
||||
# (-T, -1T, -7T, -20T).
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ examples:
|
|||
|
||||
port {
|
||||
mipi_in_panel: endpoint {
|
||||
remote-endpoint = <&mipi_out_panel>;
|
||||
remote-endpoint = <&mipi_out_panel>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,5 +64,5 @@ examples:
|
|||
vfront-porch = <0>;
|
||||
vsync-len = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -101,35 +101,35 @@ examples:
|
|||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
dsi_in: endpoint {
|
||||
remote-endpoint = <<dc_ep1_out>;
|
||||
};
|
||||
};
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
dsi_in: endpoint {
|
||||
remote-endpoint = <<dc_ep1_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
dsi_out: endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
dsi_out: endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
panel@0 {
|
||||
compatible = "orisetech,otm8009a";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>;
|
||||
power-supply = <&v3v3>;
|
||||
compatible = "orisetech,otm8009a";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>;
|
||||
power-supply = <&v3v3>;
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&dsi_out>;
|
||||
};
|
||||
};
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&dsi_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ examples:
|
|||
resets = <&rcc LTDC_R>;
|
||||
|
||||
port {
|
||||
ltdc_out_dsi: endpoint {
|
||||
remote-endpoint = <&dsi_in>;
|
||||
};
|
||||
ltdc_out_dsi: endpoint {
|
||||
remote-endpoint = <&dsi_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -114,14 +114,14 @@ examples:
|
|||
port@0 {
|
||||
reg = <0>;
|
||||
lvds_in: endpoint {
|
||||
remote-endpoint = <<dc_ep1_out>;
|
||||
remote-endpoint = <<dc_ep1_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
lvds_out0: endpoint {
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
remote-endpoint = <&lvds_panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -98,6 +98,18 @@ properties:
|
|||
items:
|
||||
- description: phandle to the HEG or core power domain
|
||||
|
||||
nvidia,channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
description: Describes range of usable Host1x channels as a <base count> tuple.
|
||||
|
||||
nvidia,syncpoints:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
description: Describes range of writable Host1x syncpoints as a <base count> tuple.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
|
|
@ -147,14 +159,20 @@ allOf:
|
|||
then:
|
||||
properties:
|
||||
reg-names:
|
||||
items:
|
||||
- const: hypervisor
|
||||
- const: vm
|
||||
oneOf:
|
||||
- items:
|
||||
- const: hypervisor
|
||||
- const: vm
|
||||
- items:
|
||||
- const: vm
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: region used by the hypervisor
|
||||
- description: region assigned to the virtual machine
|
||||
oneOf:
|
||||
- items:
|
||||
- description: region used by the hypervisor
|
||||
- description: region assigned to the virtual machine
|
||||
- items:
|
||||
- description: region assigned to the virtual machine
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
|
@ -198,16 +216,22 @@ allOf:
|
|||
then:
|
||||
properties:
|
||||
reg-names:
|
||||
items:
|
||||
- const: common
|
||||
- const: hypervisor
|
||||
- const: vm
|
||||
oneOf:
|
||||
- items:
|
||||
- const: common
|
||||
- const: hypervisor
|
||||
- const: vm
|
||||
- items:
|
||||
- const: vm
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: region used by host1x server
|
||||
- description: region used by the hypervisor
|
||||
- description: region assigned to the virtual machine
|
||||
oneOf:
|
||||
- items:
|
||||
- description: region used by host1x server
|
||||
- description: region used by the hypervisor
|
||||
- description: region assigned to the virtual machine
|
||||
- items:
|
||||
- description: region assigned to the virtual machine
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -109,13 +109,13 @@ VBLANK Helper Reference
|
|||
fbdev Helper Functions Reference
|
||||
================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/clients/drm_fbdev_helper.c
|
||||
:doc: fbdev helpers
|
||||
|
||||
.. kernel-doc:: include/drm/drm_fb_helper.h
|
||||
.. kernel-doc:: include/drm/clients/drm_fbdev_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/clients/drm_fbdev_helper.c
|
||||
:export:
|
||||
|
||||
Draw Helper Functions Reference
|
||||
|
|
@ -218,7 +218,7 @@ Bridge Connector Helper Reference
|
|||
Panel-Bridge Helper Reference
|
||||
-----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/bridge/panel.c
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_panel.c
|
||||
:export:
|
||||
|
||||
.. _drm_panel_helper:
|
||||
|
|
|
|||
|
|
@ -484,21 +484,30 @@ Contact: Douglas Anderson <dianders@chromium.org>
|
|||
|
||||
Level: Starter
|
||||
|
||||
Remove devm_drm_put_bridge()
|
||||
----------------------------
|
||||
Remove panel_bridge API functions
|
||||
---------------------------------
|
||||
|
||||
Due to how the panel bridge handles the drm_bridge object lifetime, special
|
||||
care must be taken to dispose of the drm_bridge object when the
|
||||
panel_bridge is removed. This is currently managed using
|
||||
devm_drm_put_bridge(), but that is an unsafe, temporary workaround. To fix
|
||||
that, the DRM panel lifetime needs to be reworked. After the rework is
|
||||
done, remove devm_drm_put_bridge() and the TODO in
|
||||
drm_panel_bridge_remove().
|
||||
Now that a drm_bridge is embedded into every drm_panel, the panel_bridge is
|
||||
not needed anymore. Its APIs are just accessing the embedded drm_bridge
|
||||
transparently, and the are deprecated.
|
||||
|
||||
Contact: Maxime Ripard <mripard@kernel.org>,
|
||||
Luca Ceresoli <luca.ceresoli@bootlin.com>
|
||||
The funcions to remove are:
|
||||
- drm_panel_bridge_add_typed()
|
||||
- devm_drm_of_get_bridge()
|
||||
- drmm_of_get_bridge()
|
||||
- drm_panel_bridge_remove()
|
||||
- drmm_drm_panel_bridge_release()
|
||||
- devm_drm_panel_bridge_release()
|
||||
- their direct or indirect callers
|
||||
|
||||
Level: Intermediate
|
||||
Convert users of those functions and eventually remove them when unused, or
|
||||
make them static drm_panel.c functions when used internally by the
|
||||
``drm_panel.c`` code.
|
||||
|
||||
Contact: Luca Ceresoli <luca.ceresoli@bootlin.com>
|
||||
Maxime Ripard <mripard@kernel.org>,
|
||||
|
||||
Level: Easy
|
||||
|
||||
Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge()
|
||||
---------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_syncobj.h>
|
||||
#include <linux/hmm.h>
|
||||
|
|
@ -99,9 +100,9 @@ static void aie2_job_put(struct amdxdna_sched_job *job)
|
|||
static void aie2_hwctx_stop(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwctx,
|
||||
struct drm_sched_job *bad_job)
|
||||
{
|
||||
drm_sched_stop(&hwctx->priv->sched, bad_job);
|
||||
drm_sched_stop(hwctx->priv->sched, bad_job);
|
||||
aie2_destroy_context(xdna->dev_handle, hwctx);
|
||||
drm_sched_start(&hwctx->priv->sched, 0);
|
||||
drm_sched_start(hwctx->priv->sched, 0);
|
||||
}
|
||||
|
||||
static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwctx)
|
||||
|
|
@ -659,10 +660,19 @@ static void aie2_ctx_syncobj_destroy(struct amdxdna_hwctx *hwctx)
|
|||
drm_syncobj_put(hwctx->priv->syncobj);
|
||||
}
|
||||
|
||||
int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
void aie2_hwctx_sched_fini(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ndev->priv->hwctx_limit; i++)
|
||||
drm_sched_fini(&ndev->hwctx_sched[i]);
|
||||
|
||||
ida_destroy(&ndev->hwctx_sched_ida);
|
||||
}
|
||||
|
||||
int aie2_hwctx_sched_init(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
const struct drm_sched_init_args args = {
|
||||
.ops = &sched_ops,
|
||||
.num_rqs = DRM_SCHED_PRIORITY_COUNT,
|
||||
|
|
@ -673,7 +683,55 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
.name = "amdxdna_js",
|
||||
.dev = xdna->ddev.dev,
|
||||
};
|
||||
struct drm_gpu_scheduler *sched;
|
||||
int i, ret;
|
||||
|
||||
ndev->hwctx_sched = drmm_kcalloc(&xdna->ddev, ndev->priv->hwctx_limit,
|
||||
sizeof(*ndev->hwctx_sched), GFP_KERNEL);
|
||||
if (!ndev->hwctx_sched)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ndev->priv->hwctx_limit; i++) {
|
||||
ret = drm_sched_init(&ndev->hwctx_sched[i], &args);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to init DRM scheduler. ret %d", ret);
|
||||
goto fini_sched;
|
||||
}
|
||||
}
|
||||
|
||||
ida_init(&ndev->hwctx_sched_ida);
|
||||
|
||||
return 0;
|
||||
|
||||
fini_sched:
|
||||
while (--i >= 0)
|
||||
drm_sched_fini(&ndev->hwctx_sched[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct drm_gpu_scheduler *aie2_hwctx_sched_alloc(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ida_alloc_range(&ndev->hwctx_sched_ida, 0,
|
||||
ndev->priv->hwctx_limit - 1, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return &ndev->hwctx_sched[ret];
|
||||
}
|
||||
|
||||
static void aie2_hwctx_sched_free(struct amdxdna_dev_hdl *ndev,
|
||||
struct drm_gpu_scheduler *sched)
|
||||
{
|
||||
ida_free(&ndev->hwctx_sched_ida, sched - ndev->hwctx_sched);
|
||||
}
|
||||
|
||||
int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
struct amdxdna_hwctx_priv *priv;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
int i, ret;
|
||||
|
|
@ -683,13 +741,26 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
return -ENOMEM;
|
||||
hwctx->priv = priv;
|
||||
|
||||
priv->sched = aie2_hwctx_sched_alloc(ndev);
|
||||
if (IS_ERR(priv->sched)) {
|
||||
ret = PTR_ERR(priv->sched);
|
||||
goto free_priv;
|
||||
}
|
||||
|
||||
ret = drm_sched_entity_init(&priv->entity, DRM_SCHED_PRIORITY_NORMAL,
|
||||
&priv->sched, 1, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to initial sched entity. ret %d", ret);
|
||||
goto free_sched;
|
||||
}
|
||||
|
||||
mutex_lock(&client->mm_lock);
|
||||
heap = xa_load(&client->dev_heap_xa, 0);
|
||||
if (!heap) {
|
||||
XDNA_ERR(xdna, "The client dev heap object not exist");
|
||||
mutex_unlock(&client->mm_lock);
|
||||
ret = -ENOENT;
|
||||
goto free_priv;
|
||||
goto free_entity;
|
||||
}
|
||||
drm_gem_object_get(to_gobj(heap));
|
||||
mutex_unlock(&client->mm_lock);
|
||||
|
|
@ -722,30 +793,16 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
priv->cmd_buf[i] = abo;
|
||||
}
|
||||
|
||||
sched = &priv->sched;
|
||||
mutex_init(&priv->io_lock);
|
||||
|
||||
fs_reclaim_acquire(GFP_KERNEL);
|
||||
might_lock(&priv->io_lock);
|
||||
fs_reclaim_release(GFP_KERNEL);
|
||||
|
||||
ret = drm_sched_init(sched, &args);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to init DRM scheduler. ret %d", ret);
|
||||
goto free_cmd_bufs;
|
||||
}
|
||||
|
||||
ret = drm_sched_entity_init(&priv->entity, DRM_SCHED_PRIORITY_NORMAL,
|
||||
&sched, 1, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to initial sched entiry. ret %d", ret);
|
||||
goto free_sched;
|
||||
}
|
||||
|
||||
ret = aie2_hwctx_col_list(hwctx);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Create col list failed, ret %d", ret);
|
||||
goto free_entity;
|
||||
goto free_cmd_bufs;
|
||||
}
|
||||
|
||||
ret = amdxdna_pm_resume_get_locked(xdna);
|
||||
|
|
@ -791,10 +848,6 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
amdxdna_pm_suspend_put(xdna);
|
||||
free_col_list:
|
||||
kfree(hwctx->col_list);
|
||||
free_entity:
|
||||
drm_sched_entity_destroy(&priv->entity);
|
||||
free_sched:
|
||||
drm_sched_fini(&priv->sched);
|
||||
free_cmd_bufs:
|
||||
for (i = 0; i < ARRAY_SIZE(priv->cmd_buf); i++) {
|
||||
if (!priv->cmd_buf[i])
|
||||
|
|
@ -805,6 +858,10 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
amdxdna_gem_unpin(heap);
|
||||
put_heap:
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
free_entity:
|
||||
drm_sched_entity_destroy(&priv->entity);
|
||||
free_sched:
|
||||
aie2_hwctx_sched_free(ndev, priv->sched);
|
||||
free_priv:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
|
|
@ -812,18 +869,20 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
|
||||
void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
struct amdxdna_dev *xdna;
|
||||
int idx;
|
||||
|
||||
xdna = hwctx->client->xdna;
|
||||
ndev = xdna->dev_handle;
|
||||
|
||||
XDNA_DBG(xdna, "%s sequence number %lld", hwctx->name, hwctx->priv->seq);
|
||||
aie2_hwctx_wait_for_idle(hwctx);
|
||||
|
||||
/* Request fw to destroy hwctx and cancel the rest pending requests */
|
||||
drm_sched_stop(&hwctx->priv->sched, NULL);
|
||||
drm_sched_stop(hwctx->priv->sched, NULL);
|
||||
aie2_release_resource(hwctx);
|
||||
drm_sched_start(&hwctx->priv->sched, 0);
|
||||
drm_sched_start(hwctx->priv->sched, 0);
|
||||
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
drm_sched_entity_destroy(&hwctx->priv->entity);
|
||||
|
|
@ -834,7 +893,7 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx)
|
|||
atomic64_read(&hwctx->job_free_cnt));
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
|
||||
drm_sched_fini(&hwctx->priv->sched);
|
||||
aie2_hwctx_sched_free(ndev, hwctx->priv->sched);
|
||||
aie2_ctx_syncobj_destroy(hwctx);
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(hwctx->priv->cmd_buf); idx++) {
|
||||
|
|
|
|||
|
|
@ -530,6 +530,7 @@ enum aie2_dev_revision {
|
|||
AIE2_DEV_REVISION_GPT1,
|
||||
AIE2_DEV_REVISION_GPT2,
|
||||
AIE2_DEV_REVISION_GPT3,
|
||||
AIE2_DEV_REVISION_GRGH,
|
||||
AIE2_DEV_REVISION_UNKN,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -503,10 +503,16 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
|||
ndev->priv = xdna->dev_info->dev_priv;
|
||||
ndev->aie.xdna = xdna;
|
||||
|
||||
ret = aie2_hwctx_sched_init(ndev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(npu_fw); i++) {
|
||||
fw_full_path = kasprintf(GFP_KERNEL, "%s%s", ndev->priv->fw_path, npu_fw[i]);
|
||||
if (!fw_full_path)
|
||||
return -ENOMEM;
|
||||
if (!fw_full_path) {
|
||||
ret = -ENOMEM;
|
||||
goto free_hwctx_sched;
|
||||
}
|
||||
|
||||
ret = firmware_request_nowarn(&fw, fw_full_path, &pdev->dev);
|
||||
kfree(fw_full_path);
|
||||
|
|
@ -519,7 +525,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
|||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to request_firmware %s, ret %d",
|
||||
ndev->priv->fw_path, ret);
|
||||
return ret;
|
||||
goto free_hwctx_sched;
|
||||
}
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
|
|
@ -623,6 +629,8 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
|||
aie2_hw_stop(xdna);
|
||||
release_fw:
|
||||
release_firmware(fw);
|
||||
free_hwctx_sched:
|
||||
aie2_hwctx_sched_fini(ndev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -631,6 +639,7 @@ static void aie2_fini(struct amdxdna_dev *xdna)
|
|||
{
|
||||
amdxdna_pm_fini(xdna);
|
||||
aie2_hw_stop(xdna);
|
||||
aie2_hwctx_sched_fini(xdna->dev_handle);
|
||||
}
|
||||
|
||||
static int aie2_get_aie_status(struct amdxdna_client *client,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ struct amdxdna_hwctx_priv {
|
|||
struct amdxdna_gem_obj *heap;
|
||||
void *mbox_chann;
|
||||
|
||||
struct drm_gpu_scheduler sched;
|
||||
struct drm_gpu_scheduler *sched;
|
||||
struct drm_sched_entity entity;
|
||||
|
||||
struct mutex io_lock; /* protect seq and cmd order */
|
||||
|
|
@ -152,6 +152,8 @@ struct amdxdna_dev_hdl {
|
|||
u32 total_col;
|
||||
struct amdxdna_drm_query_aie_version version;
|
||||
struct aie2_exec_msg_ops *exec_msg_ops;
|
||||
struct drm_gpu_scheduler *hwctx_sched;
|
||||
struct ida hwctx_sched_ida;
|
||||
|
||||
/* power management and clock*/
|
||||
enum amdxdna_power_mode_type pw_mode;
|
||||
|
|
@ -294,6 +296,8 @@ int aie2_update_prop_time_quota(struct amdxdna_dev_hdl *ndev, u32 us);
|
|||
/* aie2_hwctx.c */
|
||||
int aie2_hwctx_init(struct amdxdna_hwctx *hwctx);
|
||||
void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx);
|
||||
int aie2_hwctx_sched_init(struct amdxdna_dev_hdl *ndev);
|
||||
void aie2_hwctx_sched_fini(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
|
||||
int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl);
|
||||
void aie2_hwctx_suspend(struct amdxdna_client *client);
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb)
|
|||
return NULL;
|
||||
|
||||
INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
|
||||
mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
|
||||
mb_chann->work_q = alloc_ordered_workqueue(MAILBOX_NAME, WQ_MEM_RECLAIM);
|
||||
if (!mb_chann->work_q) {
|
||||
MB_ERR(mb_chann, "Create workqueue failed");
|
||||
goto free_chann;
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ const struct amdxdna_rev_vbnv npu4_rev_vbnv_tbl[] = {
|
|||
{ AIE2_DEV_REVISION_GPT1, "NPU Gorgon Point 1" },
|
||||
{ AIE2_DEV_REVISION_GPT2, "NPU Gorgon Point 2" },
|
||||
{ AIE2_DEV_REVISION_GPT3, "NPU Gorgon Point 3" },
|
||||
{ AIE2_DEV_REVISION_GRGH, "NPU Gorgon Halo" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_ioctl.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_accel.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_timeout.h>
|
||||
#include <drm/ethosu_accel.h>
|
||||
|
||||
#include "ethosu_drv.h"
|
||||
|
|
|
|||
|
|
@ -364,6 +364,25 @@ static void ivpu_fw_release(struct ivpu_device *vdev)
|
|||
}
|
||||
|
||||
|
||||
static void ivpu_fw_mem_fini(struct ivpu_device *vdev)
|
||||
{
|
||||
struct ivpu_fw_info *fw = vdev->fw;
|
||||
|
||||
ivpu_bo_free(fw->mem_shave_nn);
|
||||
ivpu_bo_free(fw->mem_log_verb);
|
||||
ivpu_bo_free(fw->mem_log_crit);
|
||||
ivpu_bo_free(fw->mem);
|
||||
ivpu_bo_free(fw->mem_fw_ver);
|
||||
ivpu_bo_free(fw->mem_bp);
|
||||
|
||||
fw->mem_shave_nn = NULL;
|
||||
fw->mem_log_verb = NULL;
|
||||
fw->mem_log_crit = NULL;
|
||||
fw->mem = NULL;
|
||||
fw->mem_fw_ver = NULL;
|
||||
fw->mem_bp = NULL;
|
||||
}
|
||||
|
||||
static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
||||
{
|
||||
struct ivpu_fw_info *fw = vdev->fw;
|
||||
|
|
@ -382,7 +401,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
|||
if (!fw->mem_fw_ver) {
|
||||
ivpu_err(vdev, "Failed to create firmware version memory buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_bp;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
fw->mem = ivpu_bo_create_runtime(vdev, fw->runtime_addr, fw->runtime_size,
|
||||
|
|
@ -390,14 +409,14 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
|||
if (!fw->mem) {
|
||||
ivpu_err(vdev, "Failed to create firmware runtime memory buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_fw_ver;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ret = ivpu_mmu_context_set_pages_ro(vdev, &vdev->gctx, fw->read_only_addr,
|
||||
fw->read_only_size);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to set firmware image read-only\n");
|
||||
goto err_free_fw_mem;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
fw->mem_log_crit = ivpu_bo_create_global(vdev, IVPU_FW_CRITICAL_BUFFER_SIZE,
|
||||
|
|
@ -405,7 +424,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
|||
if (!fw->mem_log_crit) {
|
||||
ivpu_err(vdev, "Failed to create critical log buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_fw_mem;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (ivpu_fw_log_level <= IVPU_FW_LOG_INFO)
|
||||
|
|
@ -418,7 +437,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
|||
if (!fw->mem_log_verb) {
|
||||
ivpu_err(vdev, "Failed to create verbose log buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_log_crit;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (fw->shave_nn_size) {
|
||||
|
|
@ -427,47 +446,17 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
|
|||
if (!fw->mem_shave_nn) {
|
||||
ivpu_err(vdev, "Failed to create shavenn buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_log_verb;
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_log_verb:
|
||||
ivpu_bo_free(fw->mem_log_verb);
|
||||
err_free_log_crit:
|
||||
ivpu_bo_free(fw->mem_log_crit);
|
||||
err_free_fw_mem:
|
||||
ivpu_bo_free(fw->mem);
|
||||
err_free_fw_ver:
|
||||
ivpu_bo_free(fw->mem_fw_ver);
|
||||
err_free_bp:
|
||||
ivpu_bo_free(fw->mem_bp);
|
||||
err_free:
|
||||
ivpu_fw_mem_fini(vdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ivpu_fw_mem_fini(struct ivpu_device *vdev)
|
||||
{
|
||||
struct ivpu_fw_info *fw = vdev->fw;
|
||||
|
||||
if (fw->mem_shave_nn) {
|
||||
ivpu_bo_free(fw->mem_shave_nn);
|
||||
fw->mem_shave_nn = NULL;
|
||||
}
|
||||
|
||||
ivpu_bo_free(fw->mem_log_verb);
|
||||
ivpu_bo_free(fw->mem_log_crit);
|
||||
ivpu_bo_free(fw->mem);
|
||||
ivpu_bo_free(fw->mem_fw_ver);
|
||||
ivpu_bo_free(fw->mem_bp);
|
||||
|
||||
fw->mem_log_verb = NULL;
|
||||
fw->mem_log_crit = NULL;
|
||||
fw->mem = NULL;
|
||||
fw->mem_fw_ver = NULL;
|
||||
fw->mem_bp = NULL;
|
||||
}
|
||||
|
||||
int ivpu_fw_init(struct ivpu_device *vdev)
|
||||
{
|
||||
int ret;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <drm/drm_cache.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_timeout.h>
|
||||
|
||||
#include "ivpu_drv.h"
|
||||
#include "ivpu_fw.h"
|
||||
|
|
@ -471,6 +471,9 @@ struct ivpu_bo *ivpu_bo_create_global(struct ivpu_device *vdev, u64 size, u32 fl
|
|||
|
||||
void ivpu_bo_free(struct ivpu_bo *bo)
|
||||
{
|
||||
if (!bo)
|
||||
return;
|
||||
|
||||
struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr);
|
||||
|
||||
if (bo->flags & DRM_IVPU_BO_MAPPABLE) {
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ int ivpu_ipc_init(struct ivpu_device *vdev)
|
|||
if (!ipc->mem_rx) {
|
||||
ivpu_err(vdev, "Failed to allocate mem_rx\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_tx;
|
||||
goto err_free_bo;
|
||||
}
|
||||
|
||||
ipc->mm_tx = devm_gen_pool_create(vdev->drm.dev, __ffs(IVPU_IPC_ALIGNMENT),
|
||||
|
|
@ -517,13 +517,13 @@ int ivpu_ipc_init(struct ivpu_device *vdev)
|
|||
if (IS_ERR(ipc->mm_tx)) {
|
||||
ret = PTR_ERR(ipc->mm_tx);
|
||||
ivpu_err(vdev, "Failed to create gen pool, %pe\n", ipc->mm_tx);
|
||||
goto err_free_rx;
|
||||
goto err_free_bo;
|
||||
}
|
||||
|
||||
ret = gen_pool_add(ipc->mm_tx, ipc->mem_tx->vpu_addr, ivpu_bo_size(ipc->mem_tx), -1);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "gen_pool_add failed, ret %d\n", ret);
|
||||
goto err_free_rx;
|
||||
goto err_free_bo;
|
||||
}
|
||||
|
||||
spin_lock_init(&ipc->cons_lock);
|
||||
|
|
@ -532,14 +532,13 @@ int ivpu_ipc_init(struct ivpu_device *vdev)
|
|||
ret = drmm_mutex_init(&vdev->drm, &ipc->lock);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to initialize ipc->lock, ret %d\n", ret);
|
||||
goto err_free_rx;
|
||||
goto err_free_bo;
|
||||
}
|
||||
ivpu_ipc_reset(vdev);
|
||||
return 0;
|
||||
|
||||
err_free_rx:
|
||||
err_free_bo:
|
||||
ivpu_bo_free(ipc->mem_rx);
|
||||
err_free_tx:
|
||||
ivpu_bo_free(ipc->mem_tx);
|
||||
err_destroy_cache:
|
||||
kmem_cache_destroy(ipc->rx_msg_cache);
|
||||
|
|
|
|||
|
|
@ -64,10 +64,8 @@ static int ivpu_preemption_buffers_create(struct ivpu_device *vdev,
|
|||
static void ivpu_preemption_buffers_free(struct ivpu_device *vdev,
|
||||
struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
|
||||
{
|
||||
if (cmdq->primary_preempt_buf)
|
||||
ivpu_bo_free(cmdq->primary_preempt_buf);
|
||||
if (cmdq->secondary_preempt_buf)
|
||||
ivpu_bo_free(cmdq->secondary_preempt_buf);
|
||||
ivpu_bo_free(cmdq->primary_preempt_buf);
|
||||
ivpu_bo_free(cmdq->secondary_preempt_buf);
|
||||
}
|
||||
|
||||
static int ivpu_preemption_job_init(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
|||
|
||||
ret = ivpu_jsm_metric_streamer_info(vdev, ms->mask, 0, 0, &sample_size, NULL);
|
||||
if (ret)
|
||||
goto err_free_ms;
|
||||
goto err_free;
|
||||
|
||||
buf_size = PAGE_ALIGN((u64)args->read_period_samples * sample_size *
|
||||
MS_READ_PERIOD_MULTIPLIER * MS_NUM_BUFFERS);
|
||||
|
|
@ -77,14 +77,14 @@ int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
|||
ivpu_dbg(vdev, IOCTL, "Requested MS buffer size %llu exceeds range size %llu\n",
|
||||
buf_size, ivpu_hw_range_size(&vdev->hw->ranges.global));
|
||||
ret = -EINVAL;
|
||||
goto err_free_ms;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ms->bo = ivpu_bo_create_global(vdev, buf_size, DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
|
||||
if (!ms->bo) {
|
||||
ivpu_dbg(vdev, IOCTL, "Failed to allocate MS buffer (size %llu)\n", buf_size);
|
||||
ret = -ENOMEM;
|
||||
goto err_free_ms;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ms->buff_size = ivpu_bo_size(ms->bo) / MS_NUM_BUFFERS;
|
||||
|
|
@ -96,16 +96,15 @@ int ivpu_ms_start_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
|||
ret = ivpu_jsm_metric_streamer_start(vdev, ms->mask, args->sampling_period_ns,
|
||||
ms->active_buff_vpu_addr, ms->buff_size);
|
||||
if (ret)
|
||||
goto err_free_bo;
|
||||
goto err_free;
|
||||
|
||||
args->sample_size = sample_size;
|
||||
args->max_data_size = ivpu_bo_size(ms->bo);
|
||||
list_add_tail(&ms->ms_instance_node, &file_priv->ms_instance_list);
|
||||
goto unlock;
|
||||
|
||||
err_free_bo:
|
||||
err_free:
|
||||
ivpu_bo_free(ms->bo);
|
||||
err_free_ms:
|
||||
kfree(ms);
|
||||
unlock:
|
||||
mutex_unlock(&file_priv->ms_lock);
|
||||
|
|
@ -322,10 +321,8 @@ void ivpu_ms_cleanup(struct ivpu_file_priv *file_priv)
|
|||
|
||||
mutex_lock(&file_priv->ms_lock);
|
||||
|
||||
if (file_priv->ms_info_bo) {
|
||||
ivpu_bo_free(file_priv->ms_info_bo);
|
||||
file_priv->ms_info_bo = NULL;
|
||||
}
|
||||
ivpu_bo_free(file_priv->ms_info_bo);
|
||||
file_priv->ms_info_bo = NULL;
|
||||
|
||||
list_for_each_entry_safe(ms, tmp, &file_priv->ms_instance_list, ms_instance_node)
|
||||
free_instance(file_priv, ms);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_timeout.h>
|
||||
#include <drm/rocket_accel.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iommu.h>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ config DRM_KMS_HELPER
|
|||
tristate
|
||||
depends on DRM
|
||||
select DRM_PANIC_HELPER if DRM_PANIC
|
||||
select FB_CORE if DRM_FBDEV_EMULATION
|
||||
help
|
||||
CRTC helpers for KMS drivers.
|
||||
|
||||
|
|
@ -256,7 +255,7 @@ config DRM_TTM_HELPER
|
|||
tristate
|
||||
depends on DRM
|
||||
select DRM_TTM
|
||||
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
|
||||
select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION
|
||||
select FB_CORE if DRM_FBDEV_EMULATION
|
||||
select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION
|
||||
help
|
||||
|
|
@ -265,7 +264,7 @@ config DRM_TTM_HELPER
|
|||
config DRM_GEM_DMA_HELPER
|
||||
tristate
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
|
||||
select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION
|
||||
select FB_CORE if DRM_FBDEV_EMULATION
|
||||
select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION
|
||||
help
|
||||
|
|
@ -274,7 +273,7 @@ config DRM_GEM_DMA_HELPER
|
|||
config DRM_GEM_SHMEM_HELPER
|
||||
tristate
|
||||
depends on DRM && MMU
|
||||
select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
|
||||
select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION
|
||||
select FB_CORE if DRM_FBDEV_EMULATION
|
||||
select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION
|
||||
help
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ drm-y := \
|
|||
drm_rect.o \
|
||||
drm_syncobj.o \
|
||||
drm_sysfs.o \
|
||||
drm_timeout.o \
|
||||
drm_trace_points.o \
|
||||
drm_vblank.o \
|
||||
drm_vblank_work.o \
|
||||
|
|
@ -79,7 +80,6 @@ drm-$(CONFIG_DRM_CLIENT) += \
|
|||
drm_client_modeset.o \
|
||||
drm_client_sysrq.o
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
|
||||
drm-$(CONFIG_OF) += drm_of.o
|
||||
drm-$(CONFIG_PCI) += drm_pci.o
|
||||
drm-$(CONFIG_DEBUG_FS) += \
|
||||
|
|
@ -95,6 +95,7 @@ drm-$(CONFIG_DRM_DRAW) += drm_draw.o
|
|||
drm-$(CONFIG_DRM_RAS) += drm_ras.o drm_ras_nl.o drm_ras_genl_family.o
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
|
||||
obj-$(CONFIG_DRM_PANEL) += drm_panel.o
|
||||
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
|
||||
obj-$(CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS) += drm_panel_backlight_quirks.o
|
||||
|
||||
|
|
@ -155,10 +156,8 @@ drm_kms_helper-y := \
|
|||
drm_self_refresh_helper.o \
|
||||
drm_simple_kms_helper.o \
|
||||
drm_vblank_helper.o
|
||||
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
|
||||
drm_kms_helper-$(CONFIG_DRM_PANIC_HELPER) += drm_panic_helper.o
|
||||
drm_kms_helper-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_helper_qr.o
|
||||
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
|
||||
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#define DSI_GEN_HDR 0x6c
|
||||
#define DSI_GEN_PLD_DATA 0x70
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@
|
|||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
* Alex Deucher
|
||||
* Jerome Glisse
|
||||
*/
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
|
@ -40,6 +39,7 @@
|
|||
#include <drm/drm_gem_ttm_helper.h>
|
||||
#include <drm/ttm/ttm_tt.h>
|
||||
#include <drm/drm_syncobj.h>
|
||||
#include <drm/drm_timeout.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_display.h"
|
||||
|
|
@ -652,23 +652,11 @@ int amdgpu_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
|||
*/
|
||||
unsigned long amdgpu_gem_timeout(uint64_t timeout_ns)
|
||||
{
|
||||
unsigned long timeout_jiffies;
|
||||
ktime_t timeout;
|
||||
|
||||
/* clamp timeout if it's to large */
|
||||
if (((int64_t)timeout_ns) < 0)
|
||||
/* Map anything that doesn't fit in a s64 to an infinite wait */
|
||||
if (timeout_ns > S64_MAX)
|
||||
return MAX_SCHEDULE_TIMEOUT;
|
||||
|
||||
timeout = ktime_sub(ns_to_ktime(timeout_ns), ktime_get());
|
||||
if (ktime_to_ns(timeout) < 0)
|
||||
return 0;
|
||||
|
||||
timeout_jiffies = nsecs_to_jiffies(ktime_to_ns(timeout));
|
||||
/* clamp timeout to avoid unsigned-> signed overflow */
|
||||
if (timeout_jiffies > MAX_SCHEDULE_TIMEOUT)
|
||||
return MAX_SCHEDULE_TIMEOUT - 1;
|
||||
|
||||
return timeout_jiffies;
|
||||
return drm_timeout_abs_to_jiffies(timeout_ns);
|
||||
}
|
||||
|
||||
int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
#include "amdgpu.h"
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
#include "atom.h"
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@
|
|||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_eld.h>
|
||||
#include <drm/drm_mode.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_colorop.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
#include <linux/backlight.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_panel_quirks.h>
|
||||
|
||||
#include <acpi/video.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@
|
|||
#include <drm/drm_fixed.h>
|
||||
#include <drm/drm_mode.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/display/drm_dp_mst_helper.h>
|
||||
#include <drm/display/drm_hdmi_helper.h>
|
||||
#include <drm/drm_privacy_screen_consumer.h>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "komeda_dev.h"
|
||||
#include "komeda_kms.h"
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ config DRM_FSL_LDB
|
|||
depends on OF
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL_BRIDGE
|
||||
help
|
||||
Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
|
||||
|
||||
|
|
@ -151,6 +150,7 @@ config DRM_LONTIUM_LT8912B
|
|||
config DRM_LONTIUM_LT9211
|
||||
tristate "Lontium LT9211 DSI/LVDS/DPI bridge"
|
||||
depends on OF
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
|
|
@ -259,7 +259,7 @@ config DRM_NXP_PTN3460
|
|||
tristate "NXP PTN3460 DP/LVDS bridge"
|
||||
depends on OF
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
help
|
||||
NXP PTN3460 eDP-LVDS bridge chip driver.
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ config DRM_OF_DISPLAY_MODE_BRIDGE
|
|||
config DRM_PARADE_PS8622
|
||||
tristate "Parade eDP/LVDS bridge"
|
||||
depends on OF
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_KMS_HELPER
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
|
|
@ -302,7 +302,6 @@ config DRM_SAMSUNG_DSIM
|
|||
depends on OF && HAS_IOMEM
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL_BRIDGE
|
||||
select GENERIC_PHY
|
||||
select GENERIC_PHY_MIPI_DPHY
|
||||
help
|
||||
|
|
@ -350,7 +349,6 @@ config DRM_SOLOMON_SSD2825
|
|||
depends on SPI_MASTER && OF
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
help
|
||||
Say Y here if you want support for the Solomon SSD2825 RGB/DSI
|
||||
SPI bridge driver.
|
||||
|
|
@ -388,7 +386,7 @@ config DRM_TOSHIBA_TC358764
|
|||
depends on OF
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
help
|
||||
Toshiba TC358764 DSI/LVDS bridge driver.
|
||||
|
||||
|
|
@ -400,7 +398,6 @@ config DRM_TOSHIBA_TC358767
|
|||
select DRM_KMS_HELPER
|
||||
select REGMAP_I2C
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL
|
||||
help
|
||||
Toshiba TC358767 eDP bridge chip driver.
|
||||
|
||||
|
|
@ -409,7 +406,6 @@ config DRM_TOSHIBA_TC358768
|
|||
depends on OF
|
||||
select DRM_KMS_HELPER
|
||||
select REGMAP_I2C
|
||||
select DRM_PANEL
|
||||
select DRM_MIPI_DSI
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
|
|
@ -422,16 +418,17 @@ config DRM_TOSHIBA_TC358775
|
|||
select DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
select REGMAP_I2C
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Toshiba TC358775 DSI/LVDS bridge chip driver.
|
||||
|
||||
config DRM_TI_DLPC3433
|
||||
tristate "TI DLPC3433 Display controller"
|
||||
depends on DRM && DRM_PANEL
|
||||
depends on DRM
|
||||
depends on OF
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL_BRIDGE
|
||||
help
|
||||
TI DLPC3433 is a MIPI DSI based display controller bridge
|
||||
for processing high resolution DMD based projectors.
|
||||
|
|
@ -494,6 +491,7 @@ config DRM_WAVESHARE_BRIDGE
|
|||
tristate "Waveshare DSI bridge"
|
||||
depends on OF
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ config DRM_ANALOGIX_ANX6345
|
|||
select DRM_DISPLAY_DP_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
select REGMAP_I2C
|
||||
help
|
||||
ANX6345 is an ultra-low power Full-HD DisplayPort/eDP
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
|
|
@ -1567,15 +1566,6 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
|
|||
if (ret)
|
||||
goto err_unregister_aux;
|
||||
|
||||
if (dp->plat_data->panel) {
|
||||
dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev,
|
||||
dp->plat_data->panel);
|
||||
if (IS_ERR(dp->plat_data->next_bridge)) {
|
||||
ret = PTR_ERR(dp->plat_data->next_bridge);
|
||||
goto err_unregister_aux;
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create bridge (%d)\n", ret);
|
||||
|
|
@ -1647,6 +1637,11 @@ struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
|
||||
|
||||
static void analogix_dp_put_bridge(void *data)
|
||||
{
|
||||
drm_bridge_put(data);
|
||||
}
|
||||
|
||||
static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
|
||||
{
|
||||
struct analogix_dp_device *dp = to_dp(aux);
|
||||
|
|
@ -1655,14 +1650,25 @@ static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
|
|||
int ret;
|
||||
|
||||
/*
|
||||
* If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
|
||||
* or bridge nodes. The driver should go on for the driver-free bridge or the DP
|
||||
* mode applications.
|
||||
* If of_drm_get_bridge_by_endpoint() returns -ENODEV, there may be no
|
||||
* valid panel or bridge nodes. The driver should go on for the
|
||||
* driver-free bridge or the DP mode applications.
|
||||
*/
|
||||
ret = drm_of_find_panel_or_bridge(dp->dev->of_node, port, 0,
|
||||
&plat_data->panel, &plat_data->next_bridge);
|
||||
if (ret && ret != -ENODEV)
|
||||
return ret;
|
||||
plat_data->next_bridge = of_drm_get_bridge_by_endpoint(dp->dev->of_node,
|
||||
port, 0);
|
||||
if (IS_ERR(plat_data->next_bridge)) {
|
||||
if (PTR_ERR(plat_data->next_bridge) == -ENODEV)
|
||||
plat_data->next_bridge = NULL;
|
||||
else
|
||||
return PTR_ERR(plat_data->next_bridge);
|
||||
}
|
||||
|
||||
if (plat_data->next_bridge) {
|
||||
ret = devm_add_action_or_reset(dp->dev, analogix_dp_put_bridge,
|
||||
plat_data->next_bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return component_add(dp->dev, plat_data->ops);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/bridge/aux-bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
static DEFINE_IDA(drm_aux_bridge_ida);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <video/mipi_display.h>
|
||||
#include <video/videomode.h>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#define LDB_CTRL_CH0_ENABLE BIT(0)
|
||||
#define LDB_CTRL_CH0_DI_SELECT BIT(1)
|
||||
|
|
@ -86,7 +85,6 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
|
|||
struct fsl_ldb {
|
||||
struct device *dev;
|
||||
struct drm_bridge bridge;
|
||||
struct drm_bridge *panel_bridge;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
const struct fsl_ldb_devdata *devdata;
|
||||
|
|
@ -119,7 +117,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
|
|||
{
|
||||
struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
|
||||
|
||||
return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
|
||||
return drm_bridge_attach(encoder, fsl_ldb->bridge.next_bridge,
|
||||
bridge, flags);
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +296,6 @@ static int fsl_ldb_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct device_node *panel_node;
|
||||
struct device_node *remote1, *remote2;
|
||||
struct drm_panel *panel;
|
||||
struct fsl_ldb *fsl_ldb;
|
||||
int dual_link;
|
||||
|
||||
|
|
@ -339,19 +336,13 @@ static int fsl_ldb_probe(struct platform_device *pdev)
|
|||
fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
|
||||
fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
|
||||
|
||||
panel = of_drm_find_panel(panel_node);
|
||||
of_node_put(panel_node);
|
||||
if (IS_ERR(panel))
|
||||
return PTR_ERR(panel);
|
||||
|
||||
if (of_property_present(dev->of_node, "nxp,enable-termination-resistor"))
|
||||
fsl_ldb->use_termination_resistor = true;
|
||||
|
||||
fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(fsl_ldb->panel_bridge))
|
||||
return PTR_ERR(fsl_ldb->panel_bridge);
|
||||
|
||||
fsl_ldb->bridge.next_bridge = of_drm_find_and_get_bridge(panel_node);
|
||||
of_node_put(panel_node);
|
||||
if (!fsl_ldb->bridge.next_bridge)
|
||||
return -ENODEV;
|
||||
|
||||
if (fsl_ldb_is_dual(fsl_ldb)) {
|
||||
struct device_node *port1, *port2;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#define IMX93_DISPLAY_MUX_REG 0x60
|
||||
#define PARALLEL_DISP_FORMAT GENMASK(10, 8)
|
||||
|
|
|
|||
|
|
@ -1,563 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
* Copyright (C) 2017 Broadcom
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_managed.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>
|
||||
|
||||
struct panel_bridge {
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector connector;
|
||||
struct drm_panel *panel;
|
||||
u32 connector_type;
|
||||
};
|
||||
|
||||
static inline struct panel_bridge *
|
||||
drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct panel_bridge, bridge);
|
||||
}
|
||||
|
||||
static inline struct panel_bridge *
|
||||
drm_connector_to_panel_bridge(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct panel_bridge, connector);
|
||||
}
|
||||
|
||||
static int panel_bridge_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct panel_bridge *panel_bridge =
|
||||
drm_connector_to_panel_bridge(connector);
|
||||
|
||||
return drm_panel_get_modes(panel_bridge->panel, connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs
|
||||
panel_bridge_connector_helper_funcs = {
|
||||
.get_modes = panel_bridge_connector_get_modes,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs panel_bridge_connector_funcs = {
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int panel_bridge_attach(struct drm_bridge *bridge,
|
||||
struct drm_encoder *encoder,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_connector *connector = &panel_bridge->connector;
|
||||
int ret;
|
||||
|
||||
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
|
||||
return 0;
|
||||
|
||||
drm_connector_helper_add(connector,
|
||||
&panel_bridge_connector_helper_funcs);
|
||||
|
||||
ret = drm_connector_init(bridge->dev, connector,
|
||||
&panel_bridge_connector_funcs,
|
||||
panel_bridge->connector_type);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize connector\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_panel_bridge_set_orientation(connector, bridge);
|
||||
|
||||
drm_connector_attach_encoder(&panel_bridge->connector,
|
||||
encoder);
|
||||
|
||||
if (bridge->dev->registered) {
|
||||
if (connector->funcs->reset)
|
||||
connector->funcs->reset(connector);
|
||||
drm_connector_register(connector);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_bridge_detach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_connector *connector = &panel_bridge->connector;
|
||||
|
||||
/*
|
||||
* Cleanup the connector if we know it was initialized.
|
||||
*
|
||||
* FIXME: This wouldn't be needed if the panel_bridge structure was
|
||||
* allocated with drmm_kzalloc(). This might be tricky since the
|
||||
* drm_device pointer can only be retrieved when the bridge is attached.
|
||||
*/
|
||||
if (connector->dev)
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_prepare(panel_bridge->panel);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_enable(panel_bridge->panel);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
|
||||
if (new_crtc_state && new_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_disable(panel_bridge->panel);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
|
||||
if (new_crtc_state && new_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_unprepare(panel_bridge->panel);
|
||||
}
|
||||
|
||||
static int panel_bridge_get_modes(struct drm_bridge *bridge,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
|
||||
return drm_panel_get_modes(panel_bridge->panel, connector);
|
||||
}
|
||||
|
||||
static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
|
||||
struct dentry *root)
|
||||
{
|
||||
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
struct drm_panel *panel = panel_bridge->panel;
|
||||
|
||||
root = debugfs_create_dir("panel", root);
|
||||
if (panel->funcs->debugfs_init)
|
||||
panel->funcs->debugfs_init(panel, root);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
|
||||
.attach = panel_bridge_attach,
|
||||
.detach = panel_bridge_detach,
|
||||
.atomic_pre_enable = panel_bridge_atomic_pre_enable,
|
||||
.atomic_enable = panel_bridge_atomic_enable,
|
||||
.atomic_disable = panel_bridge_atomic_disable,
|
||||
.atomic_post_disable = panel_bridge_atomic_post_disable,
|
||||
.get_modes = panel_bridge_get_modes,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
|
||||
.debugfs_init = panel_bridge_debugfs_init,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
|
||||
*
|
||||
* @bridge: The drm_bridge to be checked.
|
||||
*
|
||||
* Returns true if the bridge is a panel bridge, or false otherwise.
|
||||
*/
|
||||
bool drm_bridge_is_panel(const struct drm_bridge *bridge)
|
||||
{
|
||||
return bridge->funcs == &panel_bridge_bridge_funcs;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_is_panel);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
|
||||
* just calls the appropriate functions from &drm_panel.
|
||||
*
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
*
|
||||
* For drivers converting from directly using drm_panel: The expected
|
||||
* usage pattern is that during either encoder module probe or DSI
|
||||
* host attach, a drm_panel will be looked up through
|
||||
* drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
|
||||
* wrap that panel in the new bridge, and the result can then be
|
||||
* passed to drm_bridge_attach(). The drm_panel_prepare() and related
|
||||
* functions can be dropped from the encoder driver (they're now
|
||||
* called by the KMS helpers before calling into the encoder), along
|
||||
* with connector creation. When done with the bridge (after
|
||||
* drm_mode_config_cleanup() if the bridge has already been attached), then
|
||||
* drm_panel_bridge_remove() to free it.
|
||||
*
|
||||
* The connector type is set to @panel->connector_type, which must be set to a
|
||||
* known type. Calling this function with a panel whose connector type is
|
||||
* DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
|
||||
*
|
||||
* See devm_drm_panel_bridge_add() for an automatically managed version of this
|
||||
* function.
|
||||
*/
|
||||
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
|
||||
{
|
||||
if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return drm_panel_bridge_add_typed(panel, panel->connector_type);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_add);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
|
||||
* an explicit connector type.
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
* @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
|
||||
*
|
||||
* This is just like drm_panel_bridge_add(), but forces the connector type to
|
||||
* @connector_type instead of infering it from the panel.
|
||||
*
|
||||
* This function is deprecated and should not be used in new drivers. Use
|
||||
* drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
|
||||
* don't report a connector type.
|
||||
*/
|
||||
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
|
||||
u32 connector_type)
|
||||
{
|
||||
struct panel_bridge *panel_bridge;
|
||||
|
||||
if (!panel)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
panel_bridge = devm_drm_bridge_alloc(panel->dev, struct panel_bridge, bridge,
|
||||
&panel_bridge_bridge_funcs);
|
||||
if (IS_ERR(panel_bridge))
|
||||
return (void *)panel_bridge;
|
||||
|
||||
panel_bridge->connector_type = connector_type;
|
||||
panel_bridge->panel = drm_panel_get(panel);
|
||||
|
||||
panel_bridge->bridge.of_node = panel->dev->of_node;
|
||||
panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
|
||||
panel_bridge->bridge.type = connector_type;
|
||||
panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;
|
||||
|
||||
drm_bridge_add(&panel_bridge->bridge);
|
||||
|
||||
return &panel_bridge->bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_add_typed);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_remove - Unregisters and frees a drm_bridge
|
||||
* created by drm_panel_bridge_add().
|
||||
*
|
||||
* @bridge: The drm_bridge being freed.
|
||||
*/
|
||||
void drm_panel_bridge_remove(struct drm_bridge *bridge)
|
||||
{
|
||||
struct panel_bridge *panel_bridge;
|
||||
struct drm_panel *panel;
|
||||
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
if (!drm_bridge_is_panel(bridge)) {
|
||||
drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
panel = panel_bridge->panel;
|
||||
|
||||
drm_bridge_remove(bridge);
|
||||
/* TODO remove this after reworking panel_bridge lifetime */
|
||||
devm_drm_put_bridge(panel->dev, bridge);
|
||||
drm_panel_put(panel);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_remove);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_set_orientation - Set the connector's panel orientation
|
||||
* from the bridge that can be transformed to panel bridge.
|
||||
*
|
||||
* @connector: The connector to be set panel orientation.
|
||||
* @bridge: The drm_bridge to be transformed to panel bridge.
|
||||
*
|
||||
* Returns 0 on success, negative errno on failure.
|
||||
*/
|
||||
int drm_panel_bridge_set_orientation(struct drm_connector *connector,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
struct panel_bridge *panel_bridge;
|
||||
|
||||
panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
|
||||
return drm_connector_set_orientation_from_panel(connector,
|
||||
panel_bridge->panel);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
|
||||
|
||||
static void devm_drm_panel_bridge_release(struct device *dev, void *res)
|
||||
{
|
||||
struct drm_bridge *bridge = *(struct drm_bridge **)res;
|
||||
struct panel_bridge *panel_bridge;
|
||||
struct drm_panel *panel;
|
||||
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
panel_bridge = drm_bridge_to_panel_bridge(bridge);
|
||||
panel = panel_bridge->panel;
|
||||
drm_bridge_remove(bridge);
|
||||
drm_panel_put(panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
|
||||
* that just calls the appropriate functions from &drm_panel.
|
||||
* @dev: device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
*
|
||||
* This is the managed version of drm_panel_bridge_add() which automatically
|
||||
* calls drm_panel_bridge_remove() when @dev is unbound.
|
||||
*/
|
||||
struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
|
||||
struct drm_panel *panel)
|
||||
{
|
||||
if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return devm_drm_panel_bridge_add_typed(dev, panel,
|
||||
panel->connector_type);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_panel_bridge_add);
|
||||
|
||||
/**
|
||||
* devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
|
||||
* &drm_connector with an explicit connector type.
|
||||
* @dev: device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
* @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
|
||||
*
|
||||
* This is just like devm_drm_panel_bridge_add(), but forces the connector type
|
||||
* to @connector_type instead of infering it from the panel.
|
||||
*
|
||||
* This function is deprecated and should not be used in new drivers. Use
|
||||
* devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
|
||||
* they don't report a connector type.
|
||||
*/
|
||||
struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
|
||||
struct drm_panel *panel,
|
||||
u32 connector_type)
|
||||
{
|
||||
struct drm_bridge **ptr, *bridge;
|
||||
|
||||
ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
bridge = drm_panel_bridge_add_typed(panel, connector_type);
|
||||
if (IS_ERR(bridge)) {
|
||||
devres_free(ptr);
|
||||
return bridge;
|
||||
}
|
||||
|
||||
*ptr = bridge;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
|
||||
|
||||
static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
|
||||
{
|
||||
struct drm_bridge *bridge = ptr;
|
||||
|
||||
drm_panel_bridge_remove(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
|
||||
* &drm_connector that just calls the
|
||||
* appropriate functions from &drm_panel.
|
||||
*
|
||||
* @drm: DRM device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
*
|
||||
* This is the DRM-managed version of drm_panel_bridge_add() which
|
||||
* automatically calls drm_panel_bridge_remove() when @dev is cleaned
|
||||
* up.
|
||||
*/
|
||||
struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
|
||||
struct drm_panel *panel)
|
||||
{
|
||||
struct drm_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
|
||||
if (IS_ERR(bridge))
|
||||
return bridge;
|
||||
|
||||
ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
|
||||
bridge);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(drmm_panel_bridge_add);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_connector - return the connector for the panel bridge
|
||||
* @bridge: The drm_bridge.
|
||||
*
|
||||
* drm_panel_bridge creates the connector.
|
||||
* This function gives external access to the connector.
|
||||
*
|
||||
* Returns: Pointer to drm_connector
|
||||
*/
|
||||
struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
|
||||
{
|
||||
struct panel_bridge *panel_bridge;
|
||||
|
||||
panel_bridge = drm_bridge_to_panel_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);
|
||||
drm_panel_put(panel);
|
||||
}
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_of_get_bridge);
|
||||
|
||||
/**
|
||||
* drmm_of_get_bridge - Return next bridge in the chain
|
||||
* @drm: 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 drmm managed pointer to the bridge if successful, or an error
|
||||
* pointer otherwise.
|
||||
*/
|
||||
struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
|
||||
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 = drmm_panel_bridge_add(drm, panel);
|
||||
drm_panel_put(panel);
|
||||
}
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(drmm_of_get_bridge);
|
||||
|
||||
#endif
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/bridge/samsung-dsim.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
/* returns true iff both arguments logically differs */
|
||||
|
|
@ -1898,7 +1897,6 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
|
|||
struct device *dev = dsi->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *remote;
|
||||
struct drm_panel *panel;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
|
|
@ -1913,7 +1911,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
|
|||
of_node_name_eq(remote, "ports"))
|
||||
continue;
|
||||
|
||||
goto of_find_panel_or_bridge;
|
||||
goto of_find_bridge;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1927,25 +1925,13 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
|
|||
|
||||
remote = of_graph_get_remote_node(np, 1, 0);
|
||||
|
||||
of_find_panel_or_bridge:
|
||||
of_find_bridge:
|
||||
if (!remote)
|
||||
return -ENODEV;
|
||||
|
||||
panel = of_drm_find_panel(remote);
|
||||
if (!IS_ERR(panel)) {
|
||||
next_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(next_bridge)) {
|
||||
ret = PTR_ERR(next_bridge);
|
||||
next_bridge = NULL; // Inhibit the cleanup action on an ERR_PTR
|
||||
} else {
|
||||
drm_bridge_get(next_bridge);
|
||||
}
|
||||
} else {
|
||||
next_bridge = of_drm_find_and_get_bridge(remote);
|
||||
if (!next_bridge)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
next_bridge = of_drm_find_and_get_bridge(remote);
|
||||
if (!next_bridge)
|
||||
ret = -EINVAL;
|
||||
|
||||
of_node_put(remote);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#define SSD2825_DEVICE_ID_REG 0xb0
|
||||
|
|
@ -114,7 +113,6 @@ static const struct regulator_bulk_data ssd2825_supplies[] = {
|
|||
|
||||
struct ssd2825_dsi_output {
|
||||
struct mipi_dsi_device *dev;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
};
|
||||
|
||||
|
|
@ -277,7 +275,6 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
|
|||
{
|
||||
struct ssd2825_priv *priv = dsi_host_to_ssd2825(host);
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
struct device_node *ep;
|
||||
int ret;
|
||||
|
||||
|
|
@ -295,20 +292,14 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, &bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
bridge = of_drm_get_bridge_by_endpoint(host->dev->of_node, 1, 0);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
|
||||
if (panel) {
|
||||
bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
}
|
||||
bridge->type = DRM_MODE_CONNECTOR_DSI;
|
||||
|
||||
priv->output.dev = dev;
|
||||
priv->output.bridge = bridge;
|
||||
priv->output.panel = panel;
|
||||
|
||||
priv->dsi_lanes = dev->lanes;
|
||||
|
||||
|
|
@ -333,8 +324,7 @@ static int ssd2825_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_d
|
|||
struct ssd2825_priv *priv = dsi_host_to_ssd2825(host);
|
||||
|
||||
drm_bridge_remove(&priv->bridge);
|
||||
if (priv->output.panel)
|
||||
drm_panel_bridge_remove(priv->output.bridge);
|
||||
drm_bridge_put(priv->output.bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -579,9 +569,6 @@ static void ssd2825_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
|||
/* Initial DSI configuration register set */
|
||||
ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, config);
|
||||
ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0);
|
||||
|
||||
if (priv->output.panel)
|
||||
drm_panel_enable(priv->output.panel);
|
||||
}
|
||||
|
||||
static void ssd2825_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
|
|
|
|||
|
|
@ -244,7 +244,6 @@ struct debugfs_entries {
|
|||
struct dw_mipi_dsi {
|
||||
struct drm_bridge bridge;
|
||||
struct mipi_dsi_host dsi_host;
|
||||
struct drm_bridge *panel_bridge;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
|
||||
|
|
@ -333,12 +332,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
dsi->format = device->format;
|
||||
dsi->mode_flags = device->mode_flags;
|
||||
|
||||
bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);
|
||||
bridge = of_drm_get_bridge_by_endpoint(dsi->dev->of_node, 1, 0);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
|
||||
bridge->pre_enable_prev_first = true;
|
||||
dsi->panel_bridge = bridge;
|
||||
dsi->bridge.next_bridge = bridge;
|
||||
|
||||
drm_bridge_add(&dsi->bridge);
|
||||
|
||||
|
|
@ -352,6 +351,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
|
||||
err_remove_bridge:
|
||||
drm_bridge_remove(&dsi->bridge);
|
||||
drm_bridge_clear_and_put(&dsi->bridge.next_bridge);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -368,9 +368,8 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
|
|||
return ret;
|
||||
}
|
||||
|
||||
drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
|
||||
|
||||
drm_bridge_remove(&dsi->bridge);
|
||||
drm_bridge_clear_and_put(&dsi->bridge.next_bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1086,7 +1085,7 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
|
|||
encoder->encoder_type = DRM_MODE_ENCODER_DSI;
|
||||
|
||||
/* Attach the panel-bridge to the dsi bridge */
|
||||
return drm_bridge_attach(encoder, dsi->panel_bridge, bridge,
|
||||
return drm_bridge_attach(encoder, dsi->bridge.next_bridge, bridge,
|
||||
flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@ struct cmd_header {
|
|||
struct dw_mipi_dsi2 {
|
||||
struct drm_bridge bridge;
|
||||
struct mipi_dsi_host dsi_host;
|
||||
struct drm_bridge *panel_bridge;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct clk *pclk;
|
||||
|
|
@ -528,12 +527,12 @@ static int dw_mipi_dsi2_host_attach(struct mipi_dsi_host *host,
|
|||
dsi2->format = device->format;
|
||||
dsi2->mode_flags = device->mode_flags;
|
||||
|
||||
bridge = devm_drm_of_get_bridge(dsi2->dev, dsi2->dev->of_node, 1, 0);
|
||||
bridge = of_drm_get_bridge_by_endpoint(dsi2->dev->of_node, 1, 0);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
|
||||
bridge->pre_enable_prev_first = true;
|
||||
dsi2->panel_bridge = bridge;
|
||||
dsi2->bridge.next_bridge = bridge;
|
||||
|
||||
drm_bridge_add(&dsi2->bridge);
|
||||
|
||||
|
|
@ -547,6 +546,7 @@ static int dw_mipi_dsi2_host_attach(struct mipi_dsi_host *host,
|
|||
|
||||
err_remove_bridge:
|
||||
drm_bridge_remove(&dsi2->bridge);
|
||||
drm_bridge_clear_and_put(&dsi2->bridge.next_bridge);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -564,8 +564,7 @@ static int dw_mipi_dsi2_host_detach(struct mipi_dsi_host *host,
|
|||
}
|
||||
|
||||
drm_bridge_remove(&dsi2->bridge);
|
||||
|
||||
drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
|
||||
drm_bridge_clear_and_put(&dsi2->bridge.next_bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -884,7 +883,7 @@ static int dw_mipi_dsi2_bridge_attach(struct drm_bridge *bridge,
|
|||
encoder->encoder_type = DRM_MODE_ENCODER_DSI;
|
||||
|
||||
/* Attach the panel-bridge to the dsi bridge */
|
||||
return drm_bridge_attach(encoder, dsi2->panel_bridge, bridge,
|
||||
return drm_bridge_attach(encoder, dsi2->bridge.next_bridge, bridge,
|
||||
flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
|
|
@ -370,7 +369,6 @@ struct tc_data {
|
|||
struct drm_dp_aux aux;
|
||||
|
||||
struct drm_bridge bridge;
|
||||
struct drm_bridge *panel_bridge;
|
||||
struct drm_connector connector;
|
||||
|
||||
struct mipi_dsi_device *dsi;
|
||||
|
|
@ -1742,8 +1740,8 @@ static int tc_connector_get_modes(struct drm_connector *connector)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (tc->panel_bridge) {
|
||||
num_modes = drm_bridge_get_modes(tc->panel_bridge, connector);
|
||||
if (tc->bridge.next_bridge) {
|
||||
num_modes = drm_bridge_get_modes(tc->bridge.next_bridge, connector);
|
||||
if (num_modes > 0)
|
||||
return num_modes;
|
||||
}
|
||||
|
|
@ -1788,7 +1786,7 @@ tc_connector_detect(struct drm_connector *connector, bool force)
|
|||
if (tc->hpd_pin >= 0)
|
||||
return tc_bridge_detect(&tc->bridge, connector);
|
||||
|
||||
if (tc->panel_bridge)
|
||||
if (tc->bridge.next_bridge)
|
||||
return connector_status_connected;
|
||||
else
|
||||
return connector_status_unknown;
|
||||
|
|
@ -1809,10 +1807,10 @@ static int tc_dpi_bridge_attach(struct drm_bridge *bridge,
|
|||
{
|
||||
struct tc_data *tc = bridge_to_tc(bridge);
|
||||
|
||||
if (!tc->panel_bridge)
|
||||
if (!tc->bridge.next_bridge)
|
||||
return 0;
|
||||
|
||||
return drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
|
||||
return drm_bridge_attach(tc->bridge.encoder, tc->bridge.next_bridge,
|
||||
&tc->bridge, flags);
|
||||
}
|
||||
|
||||
|
|
@ -1825,9 +1823,9 @@ static int tc_edp_bridge_attach(struct drm_bridge *bridge,
|
|||
struct drm_device *drm = bridge->dev;
|
||||
int ret;
|
||||
|
||||
if (tc->panel_bridge) {
|
||||
if (tc->bridge.next_bridge) {
|
||||
/* If a connector is required then this driver shall create it */
|
||||
ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
|
||||
ret = drm_bridge_attach(tc->bridge.encoder, tc->bridge.next_bridge,
|
||||
&tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -2318,53 +2316,31 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
|
|||
{
|
||||
struct device *dev = tc->dev;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
int ret;
|
||||
|
||||
/* port@1 is the DPI input/output port */
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, &bridge);
|
||||
if (ret && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Could not find DPI panel or bridge\n");
|
||||
bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, 0);
|
||||
if (IS_ERR(bridge))
|
||||
return dev_err_probe(dev, PTR_ERR(bridge),
|
||||
"Could not find DPI bridge\n");
|
||||
|
||||
if (panel) {
|
||||
bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
}
|
||||
tc->bridge.next_bridge = bridge;
|
||||
tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
|
||||
|
||||
if (bridge) {
|
||||
tc->panel_bridge = bridge;
|
||||
tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
|
||||
{
|
||||
struct device *dev = tc->dev;
|
||||
struct drm_panel *panel;
|
||||
int ret;
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
/* port@2 is the output port */
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
|
||||
if (ret && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Could not find DSI panel or bridge\n");
|
||||
bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 2, 0);
|
||||
if (IS_ERR(bridge) && PTR_ERR(bridge) != -ENODEV)
|
||||
return dev_err_probe(dev, PTR_ERR(bridge), "Could not find DSI bridge\n");
|
||||
|
||||
if (panel) {
|
||||
struct drm_bridge *panel_bridge;
|
||||
|
||||
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(panel_bridge))
|
||||
return PTR_ERR(panel_bridge);
|
||||
|
||||
tc->panel_bridge = panel_bridge;
|
||||
if (!IS_ERR(bridge)) {
|
||||
tc->bridge.next_bridge = bridge;
|
||||
tc->bridge.type = DRM_MODE_CONNECTOR_eDP;
|
||||
} else {
|
||||
tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <video/mipi_display.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
|
|
@ -137,7 +136,6 @@ static const char * const tc358768_supplies[] = {
|
|||
|
||||
struct tc358768_dsi_output {
|
||||
struct mipi_dsi_device *dev;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
};
|
||||
|
||||
|
|
@ -443,7 +441,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
{
|
||||
struct tc358768_priv *priv = dsi_host_to_tc358768(host);
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
struct device_node *ep;
|
||||
int ret;
|
||||
|
||||
|
|
@ -471,24 +468,15 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel,
|
||||
&bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
bridge = of_drm_get_bridge_by_endpoint(host->dev->of_node, 1, 0);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
|
||||
if (panel) {
|
||||
bridge = drm_panel_bridge_add_typed(panel,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
|
||||
bridge->pre_enable_prev_first = true;
|
||||
}
|
||||
bridge->type = DRM_MODE_CONNECTOR_DSI;
|
||||
bridge->pre_enable_prev_first = true;
|
||||
|
||||
priv->output.dev = dev;
|
||||
priv->output.bridge = bridge;
|
||||
priv->output.panel = panel;
|
||||
|
||||
priv->dsi_lanes = dev->lanes;
|
||||
priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format);
|
||||
|
|
@ -518,8 +506,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host,
|
|||
struct tc358768_priv *priv = dsi_host_to_tc358768(host);
|
||||
|
||||
drm_bridge_remove(&priv->bridge);
|
||||
if (priv->output.panel)
|
||||
drm_panel_bridge_remove(priv->output.bridge);
|
||||
drm_bridge_put(priv->output.bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
struct tdp158 {
|
||||
struct drm_bridge bridge;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,9 @@
|
|||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
struct ws_bridge {
|
||||
struct drm_bridge bridge;
|
||||
struct drm_bridge *next_bridge;
|
||||
struct backlight_device *backlight;
|
||||
struct device *dev;
|
||||
struct regmap *reg_map;
|
||||
|
|
@ -89,7 +87,7 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge,
|
|||
{
|
||||
struct ws_bridge *ws = bridge_to_ws_bridge(bridge);
|
||||
|
||||
return drm_bridge_attach(encoder, ws->next_bridge,
|
||||
return drm_bridge_attach(encoder, ws->bridge.next_bridge,
|
||||
&ws->bridge, flags);
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +148,6 @@ static struct backlight_device *ws_bridge_create_backlight(struct ws_bridge *ws)
|
|||
static int ws_bridge_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct device *dev = &i2c->dev;
|
||||
struct drm_panel *panel;
|
||||
struct ws_bridge *ws;
|
||||
int ret;
|
||||
|
||||
|
|
@ -164,14 +161,10 @@ static int ws_bridge_probe(struct i2c_client *i2c)
|
|||
if (IS_ERR(ws->reg_map))
|
||||
return dev_err_probe(dev, PTR_ERR(ws->reg_map), "Failed to allocate regmap\n");
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, &panel, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to find remote panel\n");
|
||||
|
||||
ws->next_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(ws->next_bridge))
|
||||
return PTR_ERR(ws->next_bridge);
|
||||
ws->bridge.next_bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, -1);
|
||||
if (IS_ERR(ws->bridge.next_bridge))
|
||||
return dev_err_probe(dev, PTR_ERR(ws->bridge.next_bridge),
|
||||
"Failed to find remote bridge\n");
|
||||
|
||||
ws->backlight = ws_bridge_create_backlight(ws);
|
||||
if (IS_ERR(ws->backlight)) {
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@ subdir-ccflags-y += -I$(src)/..
|
|||
|
||||
drm_client_lib-y := drm_client_setup.o
|
||||
drm_client_lib-$(CONFIG_DRM_CLIENT_LOG) += drm_log.o
|
||||
drm_client_lib-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_client.o
|
||||
drm_client_lib-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_client.o \
|
||||
drm_fbdev_helper.o
|
||||
obj-$(CONFIG_DRM_CLIENT_LIB) += drm_client_lib.o
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_client.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@
|
|||
#include <linux/console.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
|
@ -43,39 +43,9 @@
|
|||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "drm_internal.h"
|
||||
#include "drm_crtc_helper_internal.h"
|
||||
#include "drm_crtc_internal.h"
|
||||
|
||||
static bool drm_fbdev_emulation = true;
|
||||
module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
|
||||
MODULE_PARM_DESC(fbdev_emulation,
|
||||
"Enable legacy fbdev emulation [default=true]");
|
||||
|
||||
static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
|
||||
module_param(drm_fbdev_overalloc, int, 0444);
|
||||
MODULE_PARM_DESC(drm_fbdev_overalloc,
|
||||
"Overallocation of the fbdev buffer (%) [default="
|
||||
__MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
|
||||
|
||||
/*
|
||||
* In order to keep user-space compatibility, we want in certain use-cases
|
||||
* to keep leaking the fbdev physical address to the user-space program
|
||||
* handling the fbdev buffer.
|
||||
*
|
||||
* This is a bad habit, essentially kept to support closed-source OpenGL
|
||||
* drivers that should really be moved into open-source upstream projects
|
||||
* instead of using legacy physical addresses in user space to communicate
|
||||
* with other out-of-tree kernel modules.
|
||||
*
|
||||
* This module_param *should* be removed as soon as possible and be
|
||||
* considered as a broken and legacy behaviour from a modern fbdev device.
|
||||
*/
|
||||
static bool drm_leak_fbdev_smem;
|
||||
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
|
||||
module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
|
||||
MODULE_PARM_DESC(drm_leak_fbdev_smem,
|
||||
"Allow unsafe leaking fbdev physical smem address [default=false]");
|
||||
#endif
|
||||
|
||||
/**
|
||||
* DOC: fbdev helpers
|
||||
*
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/display/drm_hdcp_helper.h>
|
||||
|
|
|
|||
|
|
@ -2161,6 +2161,9 @@ ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
|
|||
struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port,
|
||||
aux);
|
||||
|
||||
if (!port->ddps)
|
||||
return -EIO;
|
||||
|
||||
return drm_dp_send_dpcd_read(port->mgr, port,
|
||||
offset, size, buffer);
|
||||
}
|
||||
|
|
@ -2184,6 +2187,9 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
|
|||
struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port,
|
||||
aux);
|
||||
|
||||
if (!port->ddps)
|
||||
return -EIO;
|
||||
|
||||
return drm_dp_send_dpcd_write(port->mgr, port,
|
||||
offset, size, buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1741,23 +1741,6 @@ struct drm_bridge *of_drm_get_bridge_by_endpoint(const struct device_node *np,
|
|||
EXPORT_SYMBOL_GPL(of_drm_get_bridge_by_endpoint);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* devm_drm_put_bridge - Release a bridge reference obtained via devm
|
||||
* @dev: device that got the bridge via devm
|
||||
* @bridge: pointer to a struct drm_bridge obtained via devm
|
||||
*
|
||||
* Same as drm_bridge_put() for bridge pointers obtained via devm functions
|
||||
* such as devm_drm_bridge_alloc().
|
||||
*
|
||||
* This function is a temporary workaround and MUST NOT be used. Manual
|
||||
* handling of bridge lifetime is inherently unsafe.
|
||||
*/
|
||||
void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge)
|
||||
{
|
||||
devm_release_action(dev, drm_bridge_put_void, bridge);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_put_bridge);
|
||||
|
||||
static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,
|
||||
struct drm_bridge *bridge,
|
||||
unsigned int idx,
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@
|
|||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_panel_quirks.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_privacy_screen_consumer.h>
|
||||
#include <drm/drm_sysfs.h>
|
||||
#include <drm/drm_utils.h>
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#ifndef __DRM_CRTC_HELPER_INTERNAL_H__
|
||||
#define __DRM_CRTC_HELPER_INTERNAL_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum drm_mode_status;
|
||||
struct drm_connector;
|
||||
struct drm_crtc;
|
||||
|
|
@ -36,6 +38,13 @@ struct drm_display_mode;
|
|||
struct drm_encoder;
|
||||
struct drm_modeset_acquire_ctx;
|
||||
|
||||
/* drm_kms_helper_common.c */
|
||||
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
|
||||
extern bool drm_fbdev_emulation;
|
||||
extern int drm_fbdev_overalloc;
|
||||
extern bool drm_leak_fbdev_smem;
|
||||
#endif
|
||||
|
||||
/* drm_probe_helper.c */
|
||||
enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fbdev_dma.h>
|
||||
#include <drm/drm_fb_dma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_dma_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fbdev_shmem.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
|
|
|||
|
|
@ -25,10 +25,49 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include "drm_crtc_helper_internal.h"
|
||||
#include "drm_panic_internal.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
|
||||
bool drm_fbdev_emulation = true;
|
||||
EXPORT_SYMBOL(drm_fbdev_emulation);
|
||||
module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
|
||||
MODULE_PARM_DESC(fbdev_emulation, "Enable legacy fbdev emulation [default=true]");
|
||||
|
||||
int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
|
||||
EXPORT_SYMBOL(drm_fbdev_overalloc);
|
||||
module_param(drm_fbdev_overalloc, int, 0444);
|
||||
MODULE_PARM_DESC(drm_fbdev_overalloc,
|
||||
"Overallocation of the fbdev buffer (%) [default="
|
||||
__MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
|
||||
|
||||
/*
|
||||
* In order to keep user-space compatibility, we want in certain use-cases
|
||||
* to keep leaking the fbdev physical address to the user-space program
|
||||
* handling the fbdev buffer.
|
||||
*
|
||||
* This is a bad habit, essentially kept to support closed-source OpenGL
|
||||
* drivers that should really be moved into open-source upstream projects
|
||||
* instead of using legacy physical addresses in user space to communicate
|
||||
* with other out-of-tree kernel modules.
|
||||
*
|
||||
* This module_param *should* be removed as soon as possible and be
|
||||
* considered as a broken and legacy behaviour from a modern fbdev device.
|
||||
*/
|
||||
bool drm_leak_fbdev_smem;
|
||||
EXPORT_SYMBOL(drm_leak_fbdev_smem);
|
||||
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
|
||||
module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
|
||||
MODULE_PARM_DESC(drm_leak_fbdev_smem,
|
||||
"Allow unsafe leaking fbdev physical smem address [default=false]");
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static int __init drm_kms_helper_init(void)
|
||||
{
|
||||
return drm_panic_helper_init();
|
||||
|
|
|
|||
|
|
@ -264,69 +264,6 @@ int drm_of_get_panel_orientation(const struct device_node *np,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(drm_of_get_panel_orientation);
|
||||
|
||||
/**
|
||||
* drm_of_find_panel_or_bridge - return connected panel or bridge device
|
||||
* @np: device tree node containing encoder output ports
|
||||
* @port: port in the device tree node
|
||||
* @endpoint: endpoint in the device tree node
|
||||
* @panel: pointer to hold returned drm_panel, must not be NULL. On success
|
||||
* the caller must call drm_panel_put() when done with the panel
|
||||
* @bridge: pointer to hold returned drm_bridge
|
||||
*
|
||||
* Given a DT node's port and endpoint number, find the connected node and
|
||||
* return either the associated struct drm_panel or drm_bridge device.
|
||||
*
|
||||
* This function is deprecated and should not be used in new drivers. Use
|
||||
* of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
|
||||
* devm_drm_of_get_bridge() otherwise.
|
||||
*
|
||||
* Returns zero if successful, or one of the standard error codes if it fails.
|
||||
*/
|
||||
int drm_of_find_panel_or_bridge(const struct device_node *np,
|
||||
int port, int endpoint,
|
||||
struct drm_panel **panel,
|
||||
struct drm_bridge **bridge)
|
||||
{
|
||||
if (WARN_ON(!panel))
|
||||
return -EINVAL;
|
||||
|
||||
*panel = NULL;
|
||||
if (bridge)
|
||||
*bridge = NULL;
|
||||
|
||||
/*
|
||||
* of_graph_get_remote_node() produces a noisy error message if port
|
||||
* node isn't found and the absence of the port is a legit case here,
|
||||
* so at first we silently check whether a graph is present in the
|
||||
* device-tree node.
|
||||
*/
|
||||
if (!of_graph_is_present(np))
|
||||
return -ENODEV;
|
||||
|
||||
struct device_node *remote __free(device_node) =
|
||||
of_graph_get_remote_node(np, port, endpoint);
|
||||
if (!remote)
|
||||
return -ENODEV;
|
||||
|
||||
*panel = of_drm_find_panel(remote);
|
||||
if (!IS_ERR(*panel))
|
||||
return 0;
|
||||
|
||||
*panel = NULL;
|
||||
|
||||
if (bridge) {
|
||||
/* No panel found yet, check for a bridge next. */
|
||||
*bridge = of_drm_find_bridge(remote);
|
||||
if (*bridge)
|
||||
return 0;
|
||||
|
||||
*bridge = NULL;
|
||||
}
|
||||
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
|
||||
|
||||
enum drm_of_lvds_pixels {
|
||||
DRM_OF_LVDS_EVEN = BIT(0),
|
||||
DRM_OF_LVDS_ODD = BIT(1),
|
||||
|
|
|
|||
|
|
@ -1,36 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* 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.
|
||||
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
* Copyright (C) 2017 Broadcom
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_managed.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>
|
||||
|
||||
static DEFINE_MUTEX(panel_lock);
|
||||
static LIST_HEAD(panel_list);
|
||||
|
|
@ -46,6 +38,526 @@ static LIST_HEAD(panel_list);
|
|||
* take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
|
||||
*/
|
||||
|
||||
static inline struct drm_panel *
|
||||
drm_bridge_to_panel(const struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct drm_panel, bridge);
|
||||
}
|
||||
|
||||
static inline struct drm_panel *
|
||||
drm_connector_to_panel(const struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct drm_panel, connector);
|
||||
}
|
||||
|
||||
struct panel_bridge {
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector connector;
|
||||
struct drm_panel *panel;
|
||||
u32 connector_type;
|
||||
};
|
||||
|
||||
static int panel_bridge_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_panel *panel = drm_connector_to_panel(connector);
|
||||
|
||||
return drm_panel_get_modes(panel, connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs
|
||||
panel_bridge_connector_helper_funcs = {
|
||||
.get_modes = panel_bridge_connector_get_modes,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs panel_bridge_connector_funcs = {
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int panel_bridge_attach(struct drm_bridge *bridge,
|
||||
struct drm_encoder *encoder,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
struct drm_connector *connector = &panel->connector;
|
||||
int ret;
|
||||
|
||||
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
|
||||
return 0;
|
||||
|
||||
drm_connector_helper_add(connector,
|
||||
&panel_bridge_connector_helper_funcs);
|
||||
|
||||
ret = drm_connector_init(bridge->dev, connector,
|
||||
&panel_bridge_connector_funcs,
|
||||
panel->connector_type);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize connector\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_panel_bridge_set_orientation(connector, bridge);
|
||||
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
if (bridge->dev->registered) {
|
||||
if (connector->funcs->reset)
|
||||
connector->funcs->reset(connector);
|
||||
drm_connector_register(connector);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_bridge_detach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
struct drm_connector *connector = &panel->connector;
|
||||
|
||||
/* Cleanup the connector if we know it was initialized */
|
||||
if (connector->dev)
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_prepare(panel);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_enable(panel);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
|
||||
if (new_crtc_state && new_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_disable(panel);
|
||||
}
|
||||
|
||||
static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *atomic_state)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
|
||||
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
|
||||
if (new_crtc_state && new_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
drm_panel_unprepare(panel);
|
||||
}
|
||||
|
||||
static int panel_bridge_get_modes(struct drm_bridge *bridge,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
|
||||
return drm_panel_get_modes(panel, connector);
|
||||
}
|
||||
|
||||
static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
|
||||
struct dentry *root)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
|
||||
root = debugfs_create_dir("panel", root);
|
||||
if (panel->funcs->debugfs_init)
|
||||
panel->funcs->debugfs_init(panel, root);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
|
||||
.attach = panel_bridge_attach,
|
||||
.detach = panel_bridge_detach,
|
||||
.atomic_pre_enable = panel_bridge_atomic_pre_enable,
|
||||
.atomic_enable = panel_bridge_atomic_enable,
|
||||
.atomic_disable = panel_bridge_atomic_disable,
|
||||
.atomic_post_disable = panel_bridge_atomic_post_disable,
|
||||
.get_modes = panel_bridge_get_modes,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
|
||||
.debugfs_init = panel_bridge_debugfs_init,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
|
||||
*
|
||||
* @bridge: The drm_bridge to be checked.
|
||||
*
|
||||
* Returns true if the bridge is a panel bridge, or false otherwise.
|
||||
*/
|
||||
bool drm_bridge_is_panel(const struct drm_bridge *bridge)
|
||||
{
|
||||
return bridge->funcs == &panel_bridge_bridge_funcs;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_is_panel);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
|
||||
* just calls the appropriate functions from &drm_panel.
|
||||
*
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and update your driver to stop using it.
|
||||
*
|
||||
* For drivers converting from directly using drm_panel: The expected
|
||||
* usage pattern is that during either encoder module probe or DSI
|
||||
* host attach, a drm_panel will be looked up through
|
||||
* drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
|
||||
* wrap that panel in the new bridge, and the result can then be
|
||||
* passed to drm_bridge_attach(). The drm_panel_prepare() and related
|
||||
* functions can be dropped from the encoder driver (they're now
|
||||
* called by the KMS helpers before calling into the encoder), along
|
||||
* with connector creation. When done with the bridge (after
|
||||
* drm_mode_config_cleanup() if the bridge has already been attached), then
|
||||
* drm_panel_bridge_remove() to free it.
|
||||
*
|
||||
* The connector type is set to @panel->connector_type, which must be set to a
|
||||
* known type. Calling this function with a panel whose connector type is
|
||||
* DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
|
||||
*
|
||||
* See devm_drm_panel_bridge_add() for an automatically managed version of this
|
||||
* function.
|
||||
*/
|
||||
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
|
||||
{
|
||||
if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return drm_panel_bridge_add_typed(panel, panel->connector_type);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_add);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_add_typed - Pretend to create a &drm_bridge and &drm_connector with
|
||||
* an explicit connector type.
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
* @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
|
||||
*
|
||||
* This is just like drm_panel_bridge_add(), but forces the connector type to
|
||||
* @connector_type instead of infering it from the panel.
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and update your driver to stop using it.
|
||||
*/
|
||||
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
|
||||
u32 connector_type)
|
||||
{
|
||||
if (!panel)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return drm_bridge_get(&panel->bridge);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_add_typed);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_remove - Unregisters and frees a drm_bridge
|
||||
* created by drm_panel_bridge_add().
|
||||
*
|
||||
* @bridge: The drm_bridge being freed.
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel
|
||||
* and removed when the panel is removed. Don't use it in new drivers and
|
||||
* update your driver to stop using it.
|
||||
*/
|
||||
void drm_panel_bridge_remove(struct drm_bridge *bridge)
|
||||
{
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
if (!drm_bridge_is_panel(bridge)) {
|
||||
drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
drm_bridge_put(bridge);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_remove);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_set_orientation - Set the connector's panel orientation
|
||||
* from the bridge that can be transformed to panel bridge.
|
||||
*
|
||||
* @connector: The connector to be set panel orientation.
|
||||
* @bridge: The drm_bridge whose orientation should be set.
|
||||
*
|
||||
* Returns 0 on success, negative errno on failure.
|
||||
*/
|
||||
int drm_panel_bridge_set_orientation(struct drm_connector *connector,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_panel *panel = drm_bridge_to_panel(bridge);
|
||||
|
||||
return drm_connector_set_orientation_from_panel(connector, panel);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
|
||||
|
||||
static void devm_drm_panel_bridge_release(struct device *dev, void *res)
|
||||
{
|
||||
struct drm_bridge *bridge = *(struct drm_bridge **)res;
|
||||
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
drm_bridge_put(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
|
||||
* that just calls the appropriate functions from &drm_panel.
|
||||
* @dev: device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and update your driver to stop using it.
|
||||
*
|
||||
* This is the managed version of drm_panel_bridge_add() which automatically
|
||||
* calls drm_panel_bridge_remove() when @dev is unbound.
|
||||
*/
|
||||
struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
|
||||
struct drm_panel *panel)
|
||||
{
|
||||
if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return devm_drm_panel_bridge_add_typed(dev, panel,
|
||||
panel->connector_type);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_panel_bridge_add);
|
||||
|
||||
/**
|
||||
* devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
|
||||
* &drm_connector with an explicit connector type.
|
||||
* @dev: device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
* @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
|
||||
*
|
||||
* This is just like devm_drm_panel_bridge_add(), but forces the connector type
|
||||
* to @connector_type instead of infering it from the panel.
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and update your driver to stop using it.
|
||||
*/
|
||||
struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
|
||||
struct drm_panel *panel,
|
||||
u32 connector_type)
|
||||
{
|
||||
struct drm_bridge **ptr, *bridge;
|
||||
|
||||
ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
bridge = drm_panel_bridge_add_typed(panel, connector_type);
|
||||
if (IS_ERR(bridge)) {
|
||||
devres_free(ptr);
|
||||
return bridge;
|
||||
}
|
||||
|
||||
*ptr = bridge;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return &panel->bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
|
||||
|
||||
static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
|
||||
{
|
||||
struct drm_bridge *bridge = ptr;
|
||||
|
||||
drm_panel_bridge_remove(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
|
||||
* &drm_connector that just calls the
|
||||
* appropriate functions from &drm_panel.
|
||||
*
|
||||
* @drm: DRM device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and update your driver to stop using it.
|
||||
*
|
||||
* This is the DRM-managed version of drm_panel_bridge_add() which
|
||||
* automatically calls drm_panel_bridge_remove() when @dev is cleaned
|
||||
* up.
|
||||
*/
|
||||
struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
|
||||
struct drm_panel *panel)
|
||||
{
|
||||
struct drm_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
|
||||
if (IS_ERR(bridge))
|
||||
return bridge;
|
||||
|
||||
ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
|
||||
bridge);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(drmm_panel_bridge_add);
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_connector - return the connector for the panel (for
|
||||
* legacy drivers not using DRM_BRIDGE_ATTACH_NO_CONNECTOR)
|
||||
* @bridge: The drm_bridge.
|
||||
*
|
||||
* This function gives external access to the connector.
|
||||
*
|
||||
* Returns: Pointer to drm_connector
|
||||
*/
|
||||
struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_panel *panel;
|
||||
|
||||
panel = drm_bridge_to_panel(bridge);
|
||||
|
||||
return &panel->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
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and convert your driver to
|
||||
* of_drm_get_bridge_by_endpoint().
|
||||
*
|
||||
* 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);
|
||||
drm_panel_put(panel);
|
||||
}
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_drm_of_get_bridge);
|
||||
|
||||
/**
|
||||
* drmm_of_get_bridge - Return next bridge in the chain
|
||||
* @drm: 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
|
||||
*
|
||||
* This function is deprecated. A drm_bridge is embedded into every panel.
|
||||
* Don't use it in new drivers and convert your driver to
|
||||
* of_drm_get_bridge_by_endpoint().
|
||||
*
|
||||
* 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 drmm managed pointer to the bridge if successful, or an error
|
||||
* pointer otherwise.
|
||||
*/
|
||||
struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
|
||||
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 = drmm_panel_bridge_add(drm, panel);
|
||||
drm_panel_put(panel);
|
||||
}
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(drmm_of_get_bridge);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* drm_panel_init - initialize a panel
|
||||
* @panel: DRM panel
|
||||
|
|
@ -86,6 +598,13 @@ void drm_panel_add(struct drm_panel *panel)
|
|||
mutex_lock(&panel_lock);
|
||||
list_add_tail(&panel->list, &panel_list);
|
||||
mutex_unlock(&panel_lock);
|
||||
|
||||
panel->bridge.of_node = panel->dev->of_node;
|
||||
panel->bridge.ops = DRM_BRIDGE_OP_MODES;
|
||||
panel->bridge.type = panel->connector_type;
|
||||
panel->bridge.pre_enable_prev_first = panel->prepare_prev_first;
|
||||
|
||||
drm_bridge_add(&panel->bridge);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_add);
|
||||
|
||||
|
|
@ -97,6 +616,7 @@ EXPORT_SYMBOL(drm_panel_add);
|
|||
*/
|
||||
void drm_panel_remove(struct drm_panel *panel)
|
||||
{
|
||||
drm_bridge_remove(&panel->bridge);
|
||||
mutex_lock(&panel_lock);
|
||||
list_del_init(&panel->list);
|
||||
mutex_unlock(&panel_lock);
|
||||
|
|
@ -370,13 +890,6 @@ int drm_panel_get_modes(struct drm_panel *panel,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_panel_get_modes);
|
||||
|
||||
static void __drm_panel_free(struct kref *kref)
|
||||
{
|
||||
struct drm_panel *panel = container_of(kref, struct drm_panel, refcount);
|
||||
|
||||
kfree(panel->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_panel_get - Acquire a panel reference
|
||||
* @panel: DRM panel
|
||||
|
|
@ -387,10 +900,8 @@ static void __drm_panel_free(struct kref *kref)
|
|||
*/
|
||||
struct drm_panel *drm_panel_get(struct drm_panel *panel)
|
||||
{
|
||||
if (!panel)
|
||||
return panel;
|
||||
|
||||
kref_get(&panel->refcount);
|
||||
if (panel)
|
||||
drm_bridge_get(&panel->bridge);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
|
@ -406,7 +917,7 @@ EXPORT_SYMBOL(drm_panel_get);
|
|||
void drm_panel_put(struct drm_panel *panel)
|
||||
{
|
||||
if (panel)
|
||||
kref_put(&panel->refcount, __drm_panel_free);
|
||||
drm_bridge_put(&panel->bridge);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_panel_put);
|
||||
|
||||
|
|
@ -429,8 +940,22 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
|
|||
const struct drm_panel_funcs *funcs,
|
||||
int connector_type)
|
||||
{
|
||||
void *container;
|
||||
/*
|
||||
* Struct embedding and offsets:
|
||||
*
|
||||
* |--------------- user container struct ------------|
|
||||
* : |---------- struct drm_panel ------------|
|
||||
* : : |----- struct drm_bridge ------|
|
||||
* A B C
|
||||
*
|
||||
* B - A = offset (passed as argument)
|
||||
* C - B = panel_bridge_offset
|
||||
* C - A = alloc_bridge_offset
|
||||
*/
|
||||
const size_t panel_bridge_offset = offsetof(struct drm_panel, bridge);
|
||||
const size_t alloc_bridge_offset = offset + panel_bridge_offset;
|
||||
struct drm_panel *panel;
|
||||
void *container;
|
||||
int err;
|
||||
|
||||
if (!funcs) {
|
||||
|
|
@ -438,14 +963,16 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
container = kzalloc(size, GFP_KERNEL);
|
||||
if (!container)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
container = __devm_drm_bridge_alloc(dev, size, alloc_bridge_offset,
|
||||
&panel_bridge_bridge_funcs);
|
||||
if (IS_ERR(container))
|
||||
return container;
|
||||
|
||||
panel = container + offset;
|
||||
panel->container = container;
|
||||
panel->funcs = funcs;
|
||||
kref_init(&panel->refcount);
|
||||
panel->bridge.of_node = dev->of_node;
|
||||
|
||||
drm_panel_get(panel);
|
||||
|
||||
err = devm_add_action_or_reset(dev, drm_panel_put_void, panel);
|
||||
if (err)
|
||||
|
|
@ -498,6 +1025,69 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
|
|||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
EXPORT_SYMBOL(of_drm_find_panel);
|
||||
|
||||
/**
|
||||
* drm_of_find_panel_or_bridge - return connected panel or bridge device
|
||||
* @np: device tree node containing encoder output ports
|
||||
* @port: port in the device tree node
|
||||
* @endpoint: endpoint in the device tree node
|
||||
* @panel: pointer to hold returned drm_panel, must not be NULL. On success
|
||||
* the caller must call drm_panel_put() when done with the panel
|
||||
* @bridge: pointer to hold returned drm_bridge
|
||||
*
|
||||
* Given a DT node's port and endpoint number, find the connected node and
|
||||
* return either the associated struct drm_panel or drm_bridge device.
|
||||
*
|
||||
* This function is deprecated and should not be used in new drivers. Use
|
||||
* of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
|
||||
* devm_drm_of_get_bridge() otherwise.
|
||||
*
|
||||
* Returns zero if successful, or one of the standard error codes if it fails.
|
||||
*/
|
||||
int drm_of_find_panel_or_bridge(const struct device_node *np,
|
||||
int port, int endpoint,
|
||||
struct drm_panel **panel,
|
||||
struct drm_bridge **bridge)
|
||||
{
|
||||
if (WARN_ON(!panel))
|
||||
return -EINVAL;
|
||||
|
||||
*panel = NULL;
|
||||
if (bridge)
|
||||
*bridge = NULL;
|
||||
|
||||
/*
|
||||
* of_graph_get_remote_node() produces a noisy error message if port
|
||||
* node isn't found and the absence of the port is a legit case here,
|
||||
* so at first we silently check whether a graph is present in the
|
||||
* device-tree node.
|
||||
*/
|
||||
if (!of_graph_is_present(np))
|
||||
return -ENODEV;
|
||||
|
||||
struct device_node *remote __free(device_node) =
|
||||
of_graph_get_remote_node(np, port, endpoint);
|
||||
if (!remote)
|
||||
return -ENODEV;
|
||||
|
||||
*panel = of_drm_find_panel(remote);
|
||||
if (!IS_ERR(*panel))
|
||||
return 0;
|
||||
|
||||
*panel = NULL;
|
||||
|
||||
if (bridge) {
|
||||
/* No panel found yet, check for a bridge next. */
|
||||
*bridge = of_drm_find_bridge(remote);
|
||||
if (*bridge)
|
||||
return 0;
|
||||
|
||||
*bridge = NULL;
|
||||
}
|
||||
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_panel_quirks.h>
|
||||
|
||||
struct drm_panel_match {
|
||||
enum dmi_field field;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_panel_quirks.h>
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@
|
|||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_syncobj.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_timeout.h>
|
||||
|
||||
#include "drm_internal.h"
|
||||
|
||||
|
|
@ -1193,39 +1193,6 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
|
|||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
|
||||
*
|
||||
* @timeout_nsec: timeout nsec component in ns, 0 for poll
|
||||
*
|
||||
* Calculate the timeout in jiffies from an absolute time in sec/nsec.
|
||||
*/
|
||||
signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
|
||||
{
|
||||
ktime_t abs_timeout, now;
|
||||
u64 timeout_ns, timeout_jiffies64;
|
||||
|
||||
/* make 0 timeout means poll - absolute 0 doesn't seem valid */
|
||||
if (timeout_nsec == 0)
|
||||
return 0;
|
||||
|
||||
abs_timeout = ns_to_ktime(timeout_nsec);
|
||||
now = ktime_get();
|
||||
|
||||
if (!ktime_after(abs_timeout, now))
|
||||
return 0;
|
||||
|
||||
timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
|
||||
|
||||
timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
|
||||
/* clamp timeout to avoid infinite timeout */
|
||||
if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
|
||||
return MAX_SCHEDULE_TIMEOUT - 1;
|
||||
|
||||
return timeout_jiffies64 + 1;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
|
||||
|
||||
static int drm_syncobj_array_wait(struct drm_device *dev,
|
||||
struct drm_file *file_private,
|
||||
struct drm_syncobj_wait *wait,
|
||||
|
|
|
|||
95
drivers/gpu/drm/drm_timeout.c
Normal file
95
drivers/gpu/drm/drm_timeout.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Timeout conversion helpers for wait ioctls.
|
||||
*
|
||||
* Copyright 2017 Red Hat
|
||||
* Copyright 2016 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <drm/drm_timeout.h>
|
||||
|
||||
/**
|
||||
* drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
|
||||
* @timeout_nsec: timeout nsec component in ns, 0 for poll
|
||||
*
|
||||
* Calculate the timeout in jiffies from an absolute time in ns. The result is
|
||||
* clamped to MAX_SCHEDULE_TIMEOUT - 1 to avoid infinite timeouts.
|
||||
*
|
||||
* Returns:
|
||||
* The number of jiffies until the given timeout, or the upper limit.
|
||||
*/
|
||||
signed long drm_timeout_abs_to_jiffies(s64 timeout_nsec)
|
||||
{
|
||||
ktime_t abs_timeout, now;
|
||||
u64 timeout_ns, timeout_jiffies64;
|
||||
|
||||
/* make 0 timeout means poll - absolute 0 doesn't seem valid */
|
||||
if (timeout_nsec == 0)
|
||||
return 0;
|
||||
|
||||
abs_timeout = ns_to_ktime(timeout_nsec);
|
||||
now = ktime_get();
|
||||
|
||||
if (!ktime_after(abs_timeout, now))
|
||||
return 0;
|
||||
|
||||
timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
|
||||
|
||||
timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
|
||||
/* clamp timeout to avoid infinite timeout */
|
||||
if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
|
||||
return MAX_SCHEDULE_TIMEOUT - 1;
|
||||
|
||||
return timeout_jiffies64 + 1;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
|
||||
|
||||
/**
|
||||
* drm_timeout_rel_to_jiffies - calculate jiffies timeout from relative value
|
||||
* @timeout_nsec: relative timeout in ns, 0 for poll
|
||||
*
|
||||
* Calculate the timeout in jiffies from a relative timeout in ns, for drivers
|
||||
* whose UAPI expresses a wait as a duration rather than as a deadline.
|
||||
*
|
||||
* The result is clamped to MAX_JIFFY_OFFSET. That keeps it positive once it is
|
||||
* converted to the signed long taken by dma_fence_wait_timeout() and friends,
|
||||
* which matters on 32-bit, and keeps it distinct from MAX_SCHEDULE_TIMEOUT so
|
||||
* that a finite wait is never understood as an infinite one.
|
||||
*
|
||||
* It's strongly discouraged to use relative timeouts in uAPIs, as they do not
|
||||
* survive a restarted ioctl. A signal-interrupted ioctl is re-entered with the
|
||||
* same arguments, so the duration starts counting from zero again. New uAPIs
|
||||
* should take an absolute deadline and use drm_timeout_abs_to_jiffies().
|
||||
*
|
||||
* Returns:
|
||||
* 0 if @timeout_nsec is 0. Otherwise the equivalent number of jiffies and
|
||||
* clamped to MAX_JIFFY_OFFSET.
|
||||
*/
|
||||
unsigned long drm_timeout_rel_to_jiffies(u64 timeout_nsec)
|
||||
{
|
||||
u64 secs;
|
||||
u32 rem;
|
||||
|
||||
/* Make 0 timeout means poll, as for the absolute variant. */
|
||||
if (timeout_nsec == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* As nsecs_to_jiffies64() does not guard against overflow, split
|
||||
* the timeout into whole seconds and nanoseconds. This way
|
||||
* nsecs_to_jiffies64() is always handed a value below a second.
|
||||
*/
|
||||
secs = div_u64_rem(timeout_nsec, NSEC_PER_SEC, &rem);
|
||||
if (secs >= MAX_JIFFY_OFFSET / HZ)
|
||||
return MAX_JIFFY_OFFSET;
|
||||
|
||||
return min_t(u64, MAX_JIFFY_OFFSET,
|
||||
secs_to_jiffies(secs) + nsecs_to_jiffies64(rem) + 1);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_timeout_rel_to_jiffies);
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/exynos_drm.h>
|
||||
|
|
@ -147,7 +146,6 @@ static const struct component_ops exynos_dp_ops = {
|
|||
static int exynos_dp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np;
|
||||
struct exynos_dp_device *dp;
|
||||
|
||||
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
|
||||
|
|
@ -163,18 +161,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
|||
*/
|
||||
platform_set_drvdata(pdev, dp);
|
||||
|
||||
/* This is for the backward compatibility. */
|
||||
np = of_parse_phandle(dev->of_node, "panel", 0);
|
||||
if (np) {
|
||||
dp->plat_data.panel = of_drm_find_panel(np);
|
||||
|
||||
of_node_put(np);
|
||||
if (IS_ERR(dp->plat_data.panel))
|
||||
return PTR_ERR(dp->plat_data.panel);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (of_get_display_timings(dev->of_node)) {
|
||||
dp->plat_data.next_bridge = devm_drm_of_display_mode_bridge(dp->dev,
|
||||
dp->dev->of_node,
|
||||
|
|
@ -189,19 +175,11 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
|||
dp->plat_data.power_off = exynos_dp_poweroff;
|
||||
dp->plat_data.ops = &exynos_dp_ops;
|
||||
|
||||
out:
|
||||
dp->adp = analogix_dp_probe(dev, &dp->plat_data);
|
||||
if (IS_ERR(dp->adp)) {
|
||||
/*
|
||||
* The driver core does not invoke remove() for failed probes,
|
||||
* so release the probe-time panel reference here.
|
||||
*/
|
||||
if (dp->plat_data.panel)
|
||||
drm_panel_put(dp->plat_data.panel);
|
||||
if (IS_ERR(dp->adp))
|
||||
return PTR_ERR(dp->adp);
|
||||
}
|
||||
|
||||
if (dp->plat_data.panel || dp->plat_data.next_bridge)
|
||||
if (dp->plat_data.next_bridge)
|
||||
return component_add(&pdev->dev, &exynos_dp_ops);
|
||||
else
|
||||
return analogix_dp_finish_probe(dp->adp);
|
||||
|
|
@ -209,16 +187,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
|||
|
||||
static void exynos_dp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Release the probe-time reference from of_drm_find_panel(). If bind
|
||||
* ran, the panel_bridge holds a second reference that devm cleanup
|
||||
* will release when the bridge is destroyed after remove() returns.
|
||||
*/
|
||||
if (dp->plat_data.panel)
|
||||
drm_panel_put(dp->plat_data.panel);
|
||||
|
||||
component_del(&pdev->dev, &exynos_dp_ops);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_prime.h>
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
||||
#include "gem.h"
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@
|
|||
#include <linux/vga_switcheroo.h>
|
||||
|
||||
#include <drm/clients/drm_client_setup.h>
|
||||
#include <drm/clients/drm_fbdev_helper.h>
|
||||
#include <drm/intel/display_parent_interface.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include <linux/dma-fence-chain.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <drm/drm_timeout.h>
|
||||
|
||||
#include "gt/intel_engine.h"
|
||||
#include "gt/intel_rps.h"
|
||||
|
||||
|
|
@ -184,25 +186,12 @@ i915_gem_object_wait(struct drm_i915_gem_object *obj,
|
|||
return !timeout ? -ETIME : 0;
|
||||
}
|
||||
|
||||
static inline unsigned long nsecs_to_jiffies_timeout(const u64 n)
|
||||
{
|
||||
/* nsecs_to_jiffies64() does not guard against overflow */
|
||||
if ((NSEC_PER_SEC % HZ) != 0 &&
|
||||
div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ)
|
||||
return MAX_JIFFY_OFFSET;
|
||||
|
||||
return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1);
|
||||
}
|
||||
|
||||
static unsigned long to_wait_timeout(s64 timeout_ns)
|
||||
{
|
||||
if (timeout_ns < 0)
|
||||
return MAX_SCHEDULE_TIMEOUT;
|
||||
|
||||
if (timeout_ns == 0)
|
||||
return 0;
|
||||
|
||||
return nsecs_to_jiffies_timeout(timeout_ns);
|
||||
return drm_timeout_rel_to_jiffies(timeout_ns);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -278,37 +278,6 @@ pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
pvr_fw_create_fwif_connection_ctl(struct pvr_device *pvr_dev)
|
||||
{
|
||||
struct drm_device *drm_dev = from_pvr_device(pvr_dev);
|
||||
struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
|
||||
|
||||
fw_dev->fwif_connection_ctl =
|
||||
pvr_fw_object_create_and_map_offset(pvr_dev,
|
||||
fw_dev->fw_heap_info.config_offset +
|
||||
PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
|
||||
sizeof(*fw_dev->fwif_connection_ctl),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
NULL, NULL,
|
||||
&fw_dev->mem.fwif_connection_ctl_obj);
|
||||
if (IS_ERR(fw_dev->fwif_connection_ctl)) {
|
||||
drm_err(drm_dev,
|
||||
"Unable to allocate FWIF connection control memory\n");
|
||||
return PTR_ERR(fw_dev->fwif_connection_ctl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pvr_fw_fini_fwif_connection_ctl(struct pvr_device *pvr_dev)
|
||||
{
|
||||
struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
|
||||
|
||||
pvr_fw_object_unmap_and_destroy(fw_dev->mem.fwif_connection_ctl_obj);
|
||||
}
|
||||
|
||||
static void
|
||||
fw_osinit_init(void *cpu_ptr, void *priv)
|
||||
{
|
||||
|
|
@ -459,21 +428,34 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
|
|||
struct pvr_fw_mem *fw_mem = &fw_dev->mem;
|
||||
int err;
|
||||
|
||||
err = pvr_fw_object_create_offset(pvr_dev,
|
||||
fw_dev->fw_heap_info.config_offset +
|
||||
PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
|
||||
sizeof(struct rogue_fwif_connection_ctl),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
NULL, NULL,
|
||||
&fw_mem->fwif_connection_ctl_obj);
|
||||
if (err) {
|
||||
drm_err(drm_dev,
|
||||
"Unable to allocate FWIF connection control memory\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
fw_dev->power_sync = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->power_sync),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
NULL, NULL, &fw_mem->power_sync_obj);
|
||||
if (IS_ERR(fw_dev->power_sync)) {
|
||||
drm_err(drm_dev, "Unable to allocate FW power_sync structure\n");
|
||||
return PTR_ERR(fw_dev->power_sync);
|
||||
err = PTR_ERR(fw_dev->power_sync);
|
||||
goto err_release_connection_ctl;
|
||||
}
|
||||
|
||||
fw_dev->hwrinfobuf = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->hwrinfobuf),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
NULL, NULL, &fw_mem->hwrinfobuf_obj);
|
||||
if (IS_ERR(fw_dev->hwrinfobuf)) {
|
||||
err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrinfobuf),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
NULL, NULL, &fw_mem->hwrinfobuf_obj);
|
||||
if (err) {
|
||||
drm_err(drm_dev,
|
||||
"Unable to allocate FW hwrinfobuf structure\n");
|
||||
err = PTR_ERR(fw_dev->hwrinfobuf);
|
||||
goto err_release_power_sync;
|
||||
}
|
||||
|
||||
|
|
@ -536,16 +518,14 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
|
|||
goto err_fw_trace_fini;
|
||||
}
|
||||
|
||||
fw_dev->fwif_osinit =
|
||||
pvr_fw_object_create_and_map_offset(pvr_dev,
|
||||
fw_dev->fw_heap_info.config_offset +
|
||||
PVR_ROGUE_FWIF_OSINIT_OFFSET,
|
||||
sizeof(*fw_dev->fwif_osinit),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
fw_osinit_init, pvr_dev, &fw_mem->osinit_obj);
|
||||
if (IS_ERR(fw_dev->fwif_osinit)) {
|
||||
err = pvr_fw_object_create_offset(pvr_dev,
|
||||
fw_dev->fw_heap_info.config_offset +
|
||||
PVR_ROGUE_FWIF_OSINIT_OFFSET,
|
||||
sizeof(struct rogue_fwif_osinit),
|
||||
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
|
||||
fw_osinit_init, pvr_dev, &fw_mem->osinit_obj);
|
||||
if (err) {
|
||||
drm_err(drm_dev, "Unable to allocate FW OSINIT structure\n");
|
||||
err = PTR_ERR(fw_dev->fwif_osinit);
|
||||
goto err_release_osdata;
|
||||
}
|
||||
|
||||
|
|
@ -565,7 +545,7 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
|
|||
return 0;
|
||||
|
||||
err_release_osinit:
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj);
|
||||
pvr_fw_object_destroy(fw_mem->osinit_obj);
|
||||
|
||||
err_release_osdata:
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj);
|
||||
|
|
@ -589,11 +569,14 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
|
|||
pvr_fw_object_destroy(fw_mem->mmucache_sync_obj);
|
||||
|
||||
err_release_hwrinfobuf:
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj);
|
||||
pvr_fw_object_destroy(fw_mem->hwrinfobuf_obj);
|
||||
|
||||
err_release_power_sync:
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj);
|
||||
|
||||
err_release_connection_ctl:
|
||||
pvr_fw_object_destroy(fw_mem->fwif_connection_ctl_obj);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -611,10 +594,11 @@ pvr_fw_destroy_structures(struct pvr_device *pvr_dev)
|
|||
pvr_fw_object_unmap_and_destroy(fw_mem->sysinit_obj);
|
||||
|
||||
pvr_fw_object_destroy(fw_mem->mmucache_sync_obj);
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj);
|
||||
pvr_fw_object_destroy(fw_mem->hwrinfobuf_obj);
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj);
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj);
|
||||
pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj);
|
||||
pvr_fw_object_destroy(fw_mem->osinit_obj);
|
||||
pvr_fw_object_destroy(fw_mem->fwif_connection_ctl_obj);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -755,10 +739,6 @@ pvr_fw_process(struct pvr_device *pvr_dev)
|
|||
pvr_fw_object_vunmap(fw_mem->code_obj);
|
||||
fw_code_ptr = NULL;
|
||||
|
||||
err = pvr_fw_create_fwif_connection_ctl(pvr_dev);
|
||||
if (err)
|
||||
goto err_free_kdata;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_kdata:
|
||||
|
|
@ -842,8 +822,6 @@ pvr_fw_cleanup(struct pvr_device *pvr_dev)
|
|||
{
|
||||
struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem;
|
||||
|
||||
pvr_fw_fini_fwif_connection_ctl(pvr_dev);
|
||||
|
||||
kfree(fw_mem->core_data);
|
||||
kfree(fw_mem->core_code);
|
||||
kfree(fw_mem->data);
|
||||
|
|
@ -1402,6 +1380,46 @@ pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev,
|
|||
fw_obj_out);
|
||||
}
|
||||
|
||||
/**
|
||||
* pvr_fw_object_create_offset() - Create a FW object and map to firmware
|
||||
* at the provided offset.
|
||||
* @pvr_dev: PowerVR device pointer.
|
||||
* @fw_addr: Base address of desired FW mapping, offset from start of FW heap.
|
||||
* If a specific FW address is not required, pass %U32_MAX.
|
||||
* @size: Size of object, in bytes.
|
||||
* @flags: Options which affect both this operation and future mapping
|
||||
* operations performed on the returned object. Must be a combination of
|
||||
* DRM_PVR_BO_* and/or PVR_BO_* flags.
|
||||
* @init: Initialisation callback.
|
||||
* @init_priv: Private pointer to pass to initialisation callback.
|
||||
* @fw_obj_out: Pointer to location to store created object pointer.
|
||||
*
|
||||
* %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently,
|
||||
* this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS
|
||||
* set.
|
||||
*
|
||||
* Returns:
|
||||
* * 0 on success, or
|
||||
* * Any error returned by pvr_fw_object_create_and_map().
|
||||
*/
|
||||
int
|
||||
pvr_fw_object_create_offset(struct pvr_device *pvr_dev, u32 fw_addr,
|
||||
size_t size, u64 flags,
|
||||
void (*init)(void *cpu_ptr, void *priv),
|
||||
void *init_priv, struct pvr_fw_object **fw_obj_out)
|
||||
{
|
||||
void *cpu_ptr;
|
||||
|
||||
cpu_ptr = pvr_fw_object_create_and_map_offset(pvr_dev, fw_addr, size, flags,
|
||||
init, init_priv, fw_obj_out);
|
||||
if (IS_ERR(cpu_ptr))
|
||||
return PTR_ERR(cpu_ptr);
|
||||
|
||||
pvr_fw_object_vunmap(*fw_obj_out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pvr_fw_object_destroy() - Destroy a pvr_fw_object
|
||||
* @fw_obj: Pointer to object to destroy.
|
||||
|
|
|
|||
|
|
@ -349,30 +349,18 @@ struct pvr_fw_device {
|
|||
/** @fw_mm_base: Base address of address space managed by @fw_mm. */
|
||||
u64 fw_mm_base;
|
||||
|
||||
/**
|
||||
* @fwif_connection_ctl: Pointer to CPU mapping of FWIF connection
|
||||
* control structure.
|
||||
*/
|
||||
struct rogue_fwif_connection_ctl *fwif_connection_ctl;
|
||||
|
||||
/** @fwif_sysinit: Pointer to CPU mapping of FW SYSINIT structure. */
|
||||
struct rogue_fwif_sysinit *fwif_sysinit;
|
||||
|
||||
/** @fwif_sysdata: Pointer to CPU mapping of FW SYSDATA structure. */
|
||||
struct rogue_fwif_sysdata *fwif_sysdata;
|
||||
|
||||
/** @fwif_osinit: Pointer to CPU mapping of FW OSINIT structure. */
|
||||
struct rogue_fwif_osinit *fwif_osinit;
|
||||
|
||||
/** @fwif_osdata: Pointer to CPU mapping of FW OSDATA structure. */
|
||||
struct rogue_fwif_osdata *fwif_osdata;
|
||||
|
||||
/** @power_sync: Pointer to CPU mapping of power sync state. */
|
||||
u32 *power_sync;
|
||||
|
||||
/** @hwrinfobuf: Pointer to CPU mapping of FW HWR info buffer. */
|
||||
struct rogue_fwif_hwrinfobuf *hwrinfobuf;
|
||||
|
||||
/** @fw_trace: Device firmware trace buffer state. */
|
||||
struct pvr_fw_trace fw_trace;
|
||||
|
||||
|
|
@ -430,6 +418,12 @@ void *pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64
|
|||
void (*init)(void *cpu_ptr, void *priv),
|
||||
void *init_priv, struct pvr_fw_object **pvr_obj_out);
|
||||
|
||||
int
|
||||
pvr_fw_object_create_offset(struct pvr_device *pvr_dev, u32 fw_addr,
|
||||
size_t size, u64 flags,
|
||||
void (*init)(void *cpu_ptr, void *priv),
|
||||
void *init_priv, struct pvr_fw_object **pvr_obj_out);
|
||||
|
||||
void *
|
||||
pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, u32 dev_offset, size_t size,
|
||||
u64 flags, void (*init)(void *cpu_ptr, void *priv),
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_mode_config.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ config DRM_IMX_DCSS
|
|||
select DRM_DISPLAY_HELPER
|
||||
select DRM_BRIDGE_CONNECTOR
|
||||
select DRM_GEM_DMA_HELPER
|
||||
select DRM_PANEL
|
||||
select VIDEOMODE_HELPERS
|
||||
depends on DRM && ((ARCH_MXC && ARM64) || COMPILE_TEST)
|
||||
help
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-FileCopyrightText: 2020 Marian Cichy <M.Cichy@pengutronix.de>
|
||||
|
||||
#include <drm/clients/drm_client_setup.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
|
|
@ -14,10 +15,11 @@
|
|||
#include <drm/drm_gem_dma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_vblank_helper.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
|
@ -101,7 +103,9 @@
|
|||
|
||||
struct imx_lcdc {
|
||||
struct drm_device drm;
|
||||
struct drm_simple_display_pipe pipe;
|
||||
struct drm_plane plane;
|
||||
struct drm_crtc crtc;
|
||||
struct drm_encoder encoder;
|
||||
struct drm_connector *connector;
|
||||
void __iomem *base;
|
||||
|
||||
|
|
@ -134,14 +138,15 @@ static unsigned int imx_lcdc_get_format(unsigned int drm_format)
|
|||
}
|
||||
}
|
||||
|
||||
static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state,
|
||||
static void imx_lcdc_update_hw_registers(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state,
|
||||
struct drm_crtc_state *new_crtc_state,
|
||||
struct drm_plane_state *new_state,
|
||||
bool mode_set)
|
||||
{
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_plane_state *new_state = pipe->plane.state;
|
||||
struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
|
||||
const struct drm_display_mode *mode = &new_crtc_state->mode;
|
||||
struct drm_framebuffer *fb = new_state->fb;
|
||||
struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
|
||||
u32 lpcr, lvcr, lhcr;
|
||||
u32 framesize;
|
||||
dma_addr_t addr;
|
||||
|
|
@ -154,24 +159,24 @@ static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
|
|||
return;
|
||||
|
||||
/* Disable PER clock to make register write possible */
|
||||
if (old_state && old_state->crtc && old_state->crtc->enabled)
|
||||
if (old_crtc_state && old_crtc_state->enable)
|
||||
clk_disable_unprepare(lcdc->clk_per);
|
||||
|
||||
/* Framesize */
|
||||
framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, crtc->mode.hdisplay >> 4) |
|
||||
FIELD_PREP(IMX21LCDC_LSR_YMAX, crtc->mode.vdisplay);
|
||||
framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, mode->hdisplay >> 4) |
|
||||
FIELD_PREP(IMX21LCDC_LSR_YMAX, mode->vdisplay);
|
||||
writel(framesize, lcdc->base + IMX21LCDC_LSR);
|
||||
|
||||
/* HSYNC */
|
||||
lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, crtc->mode.hsync_start - crtc->mode.hdisplay - 1) |
|
||||
FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, crtc->mode.hsync_end - crtc->mode.hsync_start - 1) |
|
||||
FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, crtc->mode.htotal - crtc->mode.hsync_end - 3);
|
||||
lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, mode->hsync_start - mode->hdisplay - 1) |
|
||||
FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, mode->hsync_end - mode->hsync_start - 1) |
|
||||
FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, mode->htotal - mode->hsync_end - 3);
|
||||
writel(lhcr, lcdc->base + IMX21LCDC_LHCR);
|
||||
|
||||
/* VSYNC */
|
||||
lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, crtc->mode.vsync_start - crtc->mode.vdisplay) |
|
||||
FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, crtc->mode.vsync_end - crtc->mode.vsync_start) |
|
||||
FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, crtc->mode.vtotal - crtc->mode.vsync_end);
|
||||
lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, mode->vsync_start - mode->vdisplay) |
|
||||
FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, mode->vsync_end - mode->vsync_start) |
|
||||
FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, mode->vtotal - mode->vsync_end);
|
||||
writel(lvcr, lcdc->base + IMX21LCDC_LVCR);
|
||||
|
||||
lpcr = readl(lcdc->base + IMX21LCDC_LPCR);
|
||||
|
|
@ -183,19 +188,20 @@ static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
|
|||
writel(new_state->fb->pitches[0] / 4, lcdc->base + IMX21LCDC_LVPWR);
|
||||
|
||||
/* Enable PER clock */
|
||||
if (new_state->crtc->enabled)
|
||||
if (new_crtc_state->enable)
|
||||
clk_prepare_enable(lcdc->clk_per);
|
||||
}
|
||||
|
||||
static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plane_state)
|
||||
static void imx_lcdc_crtc_helper_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
int ret;
|
||||
int clk_div;
|
||||
int bpp;
|
||||
struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
|
||||
struct drm_display_mode *mode = &pipe->crtc.mode;
|
||||
struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
|
||||
struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc);
|
||||
struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, &lcdc->plane);
|
||||
struct drm_display_mode *mode = &cstate->mode;
|
||||
struct drm_display_info *disp_info = &lcdc->connector->display_info;
|
||||
const int hsync_pol = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : 1;
|
||||
const int vsync_pol = (mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : 1;
|
||||
|
|
@ -206,7 +212,7 @@ static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
|
|||
|
||||
clk_div = DIV_ROUND_CLOSEST_ULL(clk_get_rate(lcdc->clk_per),
|
||||
mode->clock * 1000);
|
||||
bpp = imx_lcdc_get_format(plane_state->fb->format->format);
|
||||
bpp = imx_lcdc_get_format(pstate->fb->format->format);
|
||||
|
||||
writel(FIELD_PREP(IMX21LCDC_LPCR_PCD, clk_div - 1) |
|
||||
FIELD_PREP(IMX21LCDC_LPCR_LPPOL, hsync_pol) |
|
||||
|
|
@ -230,40 +236,46 @@ static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
|
|||
|
||||
ret = clk_prepare_enable(lcdc->clk_ipg);
|
||||
if (ret) {
|
||||
dev_err(pipe->crtc.dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret));
|
||||
dev_err(crtc->dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret));
|
||||
return;
|
||||
}
|
||||
ret = clk_prepare_enable(lcdc->clk_ahb);
|
||||
if (ret) {
|
||||
dev_err(pipe->crtc.dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret));
|
||||
dev_err(crtc->dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret));
|
||||
|
||||
clk_disable_unprepare(lcdc->clk_ipg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
imx_lcdc_update_hw_registers(pipe, NULL, true);
|
||||
imx_lcdc_update_hw_registers(crtc, NULL, cstate, pstate, true);
|
||||
|
||||
/* Enable VBLANK Interrupt */
|
||||
writel(INTR_EOF, lcdc->base + IMX21LCDC_LIER);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe)
|
||||
static void imx_lcdc_crtc_helper_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
|
||||
struct drm_crtc *crtc = &lcdc->pipe.crtc;
|
||||
struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(commit, crtc);
|
||||
struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(commit, crtc);
|
||||
struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
clk_disable_unprepare(lcdc->clk_ahb);
|
||||
clk_disable_unprepare(lcdc->clk_ipg);
|
||||
|
||||
if (pipe->crtc.enabled)
|
||||
if (old_crtc_state->enable)
|
||||
clk_disable_unprepare(lcdc->clk_per);
|
||||
|
||||
spin_lock_irq(&lcdc->drm.event_lock);
|
||||
event = crtc->state->event;
|
||||
event = new_crtc_state->event;
|
||||
if (event) {
|
||||
crtc->state->event = NULL;
|
||||
new_crtc_state->event = NULL;
|
||||
drm_crtc_send_vblank_event(crtc, event);
|
||||
}
|
||||
spin_unlock_irq(&lcdc->drm.event_lock);
|
||||
|
|
@ -272,65 +284,132 @@ static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe)
|
|||
writel(0, lcdc->base + IMX21LCDC_LIER);
|
||||
}
|
||||
|
||||
static int imx_lcdc_pipe_check(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *plane_state,
|
||||
struct drm_crtc_state *crtc_state)
|
||||
static int imx_lcdc_crtc_helper_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc);
|
||||
struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(commit, crtc);
|
||||
const struct drm_display_mode *mode = &crtc_state->mode;
|
||||
const struct drm_display_mode *old_mode = &pipe->crtc.state->mode;
|
||||
const struct drm_display_mode *old_mode = &old_crtc_state->mode;
|
||||
int ret;
|
||||
|
||||
if (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES ||
|
||||
mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES ||
|
||||
mode->hdisplay % 0x10) { /* must be multiple of 16 */
|
||||
drm_err(pipe->crtc.dev, "unsupported display mode (%u x %u)\n",
|
||||
if (crtc_state->enable) {
|
||||
ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (crtc_state->enable &&
|
||||
(mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES ||
|
||||
mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES ||
|
||||
mode->hdisplay % 0x10)) { /* must be multiple of 16 */
|
||||
drm_err(crtc->dev, "unsupported display mode (%u x %u)\n",
|
||||
mode->hdisplay, mode->vdisplay);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
crtc_state->mode_changed =
|
||||
old_mode->hdisplay != mode->hdisplay ||
|
||||
old_mode->vdisplay != mode->vdisplay;
|
||||
if (old_mode->hdisplay != mode->hdisplay ||
|
||||
old_mode->vdisplay != mode->vdisplay)
|
||||
crtc_state->mode_changed = true;
|
||||
|
||||
return 0;
|
||||
return drm_atomic_add_affected_planes(commit, crtc);
|
||||
}
|
||||
|
||||
static void imx_lcdc_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
static void imx_lcdc_plane_helper_atomic_update(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_pending_vblank_event *event = crtc->state->event;
|
||||
struct drm_plane_state *new_state = pipe->plane.state;
|
||||
struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(commit, plane);
|
||||
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(commit, plane);
|
||||
struct drm_crtc *crtc = new_state->crtc;
|
||||
struct drm_crtc_state *old_crtc_state = NULL;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct drm_framebuffer *fb = new_state->fb;
|
||||
struct drm_framebuffer *old_fb = old_state->fb;
|
||||
struct drm_crtc *old_crtc = old_state->crtc;
|
||||
bool mode_changed = false;
|
||||
|
||||
if (!fb || !crtc)
|
||||
return;
|
||||
|
||||
if (old_crtc)
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(commit, old_crtc);
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(commit, crtc);
|
||||
if (!new_crtc_state)
|
||||
return;
|
||||
|
||||
if (old_fb && old_fb->format != fb->format)
|
||||
mode_changed = true;
|
||||
else if (old_crtc != crtc)
|
||||
mode_changed = true;
|
||||
|
||||
imx_lcdc_update_hw_registers(pipe, old_state, mode_changed);
|
||||
|
||||
if (event) {
|
||||
crtc->state->event = NULL;
|
||||
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
|
||||
if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
|
||||
drm_crtc_arm_vblank_event(crtc, event);
|
||||
else
|
||||
drm_crtc_send_vblank_event(crtc, event);
|
||||
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
|
||||
imx_lcdc_update_hw_registers(crtc, old_crtc_state, new_crtc_state,
|
||||
new_state, mode_changed);
|
||||
}
|
||||
|
||||
static const struct drm_simple_display_pipe_funcs imx_lcdc_pipe_funcs = {
|
||||
.enable = imx_lcdc_pipe_enable,
|
||||
.disable = imx_lcdc_pipe_disable,
|
||||
.check = imx_lcdc_pipe_check,
|
||||
.update = imx_lcdc_pipe_update,
|
||||
static int imx_lcdc_plane_helper_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane);
|
||||
struct drm_crtc_state *crtc_state = NULL;
|
||||
|
||||
if (plane_state->crtc) {
|
||||
crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
}
|
||||
|
||||
return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
false, false);
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs imx_lcdc_plane_helper_funcs = {
|
||||
.prepare_fb = drm_gem_plane_helper_prepare_fb,
|
||||
.atomic_check = imx_lcdc_plane_helper_atomic_check,
|
||||
.atomic_update = imx_lcdc_plane_helper_atomic_update,
|
||||
};
|
||||
|
||||
static const struct drm_plane_funcs imx_lcdc_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = drm_plane_cleanup,
|
||||
.atomic_create_state = drm_atomic_helper_plane_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs imx_lcdc_crtc_helper_funcs = {
|
||||
.atomic_check = imx_lcdc_crtc_helper_atomic_check,
|
||||
.atomic_enable = imx_lcdc_crtc_helper_atomic_enable,
|
||||
.atomic_disable = imx_lcdc_crtc_helper_atomic_disable,
|
||||
.atomic_flush = drm_crtc_vblank_atomic_flush,
|
||||
};
|
||||
|
||||
static int imx_lcdc_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx_lcdc_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs imx_lcdc_crtc_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_crtc_create_state,
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = imx_lcdc_crtc_enable_vblank,
|
||||
.disable_vblank = imx_lcdc_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs imx_lcdc_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static const struct drm_mode_config_funcs imx_lcdc_mode_config_funcs = {
|
||||
|
|
@ -368,7 +447,7 @@ MODULE_DEVICE_TABLE(of, imx_lcdc_of_dev_id);
|
|||
static irqreturn_t imx_lcdc_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct imx_lcdc *lcdc = arg;
|
||||
struct drm_crtc *crtc = &lcdc->pipe.crtc;
|
||||
struct drm_crtc *crtc = &lcdc->crtc;
|
||||
unsigned int status;
|
||||
|
||||
status = readl(lcdc->base + IMX21LCDC_LISR);
|
||||
|
|
@ -385,7 +464,9 @@ static int imx_lcdc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct imx_lcdc *lcdc;
|
||||
struct drm_device *drm;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_plane *plane;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
int irq;
|
||||
int ret;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -401,7 +482,8 @@ static int imx_lcdc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(lcdc->base))
|
||||
return dev_err_probe(dev, PTR_ERR(lcdc->base), "Cannot get IO memory\n");
|
||||
|
||||
bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
|
||||
struct drm_bridge *bridge __free(drm_bridge_put) =
|
||||
of_drm_get_bridge_by_endpoint(dev->of_node, 0, 0);
|
||||
if (IS_ERR(bridge))
|
||||
return dev_err_probe(dev, PTR_ERR(bridge), "Failed to find bridge\n");
|
||||
|
||||
|
|
@ -427,23 +509,40 @@ static int imx_lcdc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Cannot initialize mode configuration structure\n");
|
||||
|
||||
/* CRTC, Plane, Encoder */
|
||||
ret = drm_simple_display_pipe_init(drm, &lcdc->pipe,
|
||||
&imx_lcdc_pipe_funcs,
|
||||
imx_lcdc_formats,
|
||||
ARRAY_SIZE(imx_lcdc_formats), NULL, NULL);
|
||||
plane = &lcdc->plane;
|
||||
ret = drm_universal_plane_init(drm, plane, 0,
|
||||
&imx_lcdc_plane_funcs,
|
||||
imx_lcdc_formats,
|
||||
ARRAY_SIZE(imx_lcdc_formats),
|
||||
NULL,
|
||||
DRM_PLANE_TYPE_PRIMARY, NULL);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(drm->dev, ret, "Cannot setup simple display pipe\n");
|
||||
return dev_err_probe(drm->dev, ret, "Cannot initialize primary plane\n");
|
||||
drm_plane_helper_add(plane, &imx_lcdc_plane_helper_funcs);
|
||||
|
||||
crtc = &lcdc->crtc;
|
||||
ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL,
|
||||
&imx_lcdc_crtc_funcs, NULL);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(drm->dev, ret, "Cannot initialize CRTC\n");
|
||||
drm_crtc_helper_add(crtc, &imx_lcdc_crtc_helper_funcs);
|
||||
|
||||
encoder = &lcdc->encoder;
|
||||
ret = drm_encoder_init(drm, encoder, &imx_lcdc_encoder_funcs,
|
||||
DRM_MODE_ENCODER_NONE, NULL);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(drm->dev, ret, "Cannot initialize encoder\n");
|
||||
encoder->possible_crtcs = drm_crtc_mask(crtc);
|
||||
|
||||
ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(drm->dev, ret, "Failed to initialize vblank\n");
|
||||
|
||||
ret = drm_bridge_attach(&lcdc->pipe.encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret)
|
||||
return dev_err_probe(drm->dev, ret, "Cannot attach bridge\n");
|
||||
|
||||
lcdc->connector = drm_bridge_connector_init(drm, &lcdc->pipe.encoder);
|
||||
lcdc->connector = drm_bridge_connector_init(drm, encoder);
|
||||
if (IS_ERR(lcdc->connector))
|
||||
return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n");
|
||||
|
||||
|
|
@ -482,7 +581,9 @@ static int imx_lcdc_probe(struct platform_device *pdev)
|
|||
drm->mode_config.funcs = &imx_lcdc_mode_config_funcs;
|
||||
drm->mode_config.helper_private = &imx_lcdc_mode_config_helpers;
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
ret = drm_mode_config_create_initial_state(drm);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Cannot create initial state\n");
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ config DRM_INGENIC
|
|||
depends on COMMON_CLK
|
||||
select DRM_BRIDGE
|
||||
select DRM_CLIENT_SELECTION
|
||||
select DRM_PANEL
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_syncobj.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_timeout.h>
|
||||
|
||||
#include <drm/lima_drm.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ config DRM_LOGICVC
|
|||
select DRM_CLIENT_SELECTION
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_DMA_HELPER
|
||||
select DRM_PANEL
|
||||
select REGMAP
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ config DRM_MCDE
|
|||
select DRM_CLIENT_SELECTION
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_BRIDGE
|
||||
select DRM_PANEL_BRIDGE
|
||||
select DRM_PANEL
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_DMA_HELPER
|
||||
help
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_gem_dma_helper.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
|
|
|||
|
|
@ -11,17 +11,15 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_mipi_dsi.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>
|
||||
|
||||
#include "mcde_drm.h"
|
||||
#include "mcde_dsi_regs.h"
|
||||
|
|
@ -39,7 +37,6 @@ struct mcde_dsi {
|
|||
struct device *dev;
|
||||
struct mcde *mcde;
|
||||
struct drm_bridge bridge;
|
||||
struct drm_panel *panel;
|
||||
struct mipi_dsi_host dsi_host;
|
||||
struct mipi_dsi_device *mdsi;
|
||||
const struct drm_display_mode *mode;
|
||||
|
|
@ -1076,7 +1073,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
|
|||
struct drm_device *drm = data;
|
||||
struct mcde *mcde = to_mcde(drm);
|
||||
struct mcde_dsi *d = dev_get_drvdata(dev);
|
||||
struct drm_panel *panel = NULL;
|
||||
struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
|
||||
|
||||
if (!of_get_available_child_count(dev->of_node)) {
|
||||
|
|
@ -1104,40 +1100,21 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
|
|||
|
||||
/* Look for a panel as a child to this node */
|
||||
for_each_available_child_of_node_scoped(dev->of_node, child) {
|
||||
panel = of_drm_find_panel(child);
|
||||
if (IS_ERR(panel)) {
|
||||
dev_err(dev, "failed to find panel try bridge (%ld)\n",
|
||||
PTR_ERR(panel));
|
||||
panel = NULL;
|
||||
|
||||
bridge = of_drm_find_and_get_bridge(child);
|
||||
if (!bridge) {
|
||||
dev_err(dev, "failed to find bridge\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
bridge = of_drm_find_and_get_bridge(child);
|
||||
if (!bridge) {
|
||||
dev_err(dev, "failed to find bridge\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (panel || bridge)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
if (panel) {
|
||||
bridge = drm_panel_bridge_add_typed(panel,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
drm_panel_put(panel);
|
||||
if (IS_ERR(bridge)) {
|
||||
dev_err(dev, "error adding panel bridge\n");
|
||||
return PTR_ERR(bridge);
|
||||
}
|
||||
drm_bridge_get(bridge);
|
||||
dev_info(dev, "connected to panel\n");
|
||||
d->panel = panel;
|
||||
} else if (bridge) {
|
||||
if (!bridge) {
|
||||
dev_err(dev, "no bridge\n");
|
||||
return -ENODEV;
|
||||
} else if (!drm_bridge_is_panel(bridge)) {
|
||||
/* TODO: AV8100 HDMI encoder goes here for example */
|
||||
dev_info(dev, "connected to non-panel bridge (unsupported)\n");
|
||||
return -ENODEV;
|
||||
} else {
|
||||
dev_err(dev, "no panel or bridge\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
d->bridge.next_bridge = drm_bridge_get(bridge);
|
||||
|
|
@ -1159,8 +1136,6 @@ static void mcde_dsi_unbind(struct device *dev, struct device *master,
|
|||
{
|
||||
struct mcde_dsi *d = dev_get_drvdata(dev);
|
||||
|
||||
if (d->panel)
|
||||
drm_panel_bridge_remove(d->bridge.next_bridge);
|
||||
regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
|
||||
PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <drm/display/drm_dp_aux_bus.h>
|
||||
#include <drm/display/drm_hdmi_audio_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "msm_kms.h"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user