drm-misc-next for 6.17:
UAPI Changes: Cross-subsystem Changes: Core Changes: - bridge: More reference counting - dp: Implement backlight control helpers - fourcc: Add half-float and 32b float formats, RGB161616, BGR161616 - mipi-dsi: Drop MIPI_DSI_MODE_VSYNC_FLUSH flag - ttm: Improve eviction Driver Changes: - i915: Use backlight control helpers for eDP - tidss: Add AM65x OLDI bridge support - panels: - panel-edp: Add CMN N116BCJ-EAK support - raydium-rm67200: misc cleanups, optional reset - new panel: DJN HX83112B -----BEGIN PGP SIGNATURE----- iJUEABMJAB0WIQTkHFbLp4ejekA/qfgnX84Zoj2+dgUCaGY7aQAKCRAnX84Zoj2+ dncVAYC+7mGk8UDugcIEn51fCLxv92DKeMRq/qsmGPz/x5c3TaXX7sN0/FLo91ek bLrwR9ABfjx+Qz+jO21LuwRBxgHv7XH5Bk1sPay1n7+TokndCj55+YG8vCbXISsk gsxtheA8Ig== =ybn3 -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2025-07-03' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next drm-misc-next for 6.17: UAPI Changes: Cross-subsystem Changes: Core Changes: - bridge: More reference counting - dp: Implement backlight control helpers - fourcc: Add half-float and 32b float formats, RGB161616, BGR161616 - mipi-dsi: Drop MIPI_DSI_MODE_VSYNC_FLUSH flag - ttm: Improve eviction Driver Changes: - i915: Use backlight control helpers for eDP - tidss: Add AM65x OLDI bridge support - panels: - panel-edp: Add CMN N116BCJ-EAK support - raydium-rm67200: misc cleanups, optional reset - new panel: DJN HX83112B Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <mripard@redhat.com> Link: https://lore.kernel.org/r/20250703-chirpy-lilac-dalmatian-2c5838@houat
This commit is contained in:
commit
17d081ef84
|
@ -0,0 +1,73 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/display/panel/himax,hx83112b.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Himax HX83112B-based DSI display panels
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Luca Weiss <luca@lucaweiss.eu>
|
||||||
|
|
||||||
|
description:
|
||||||
|
The Himax HX83112B is a generic DSI Panel IC used to control
|
||||||
|
LCD panels.
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: panel-common.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: djn,98-03057-6598b-i
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
iovcc-supply:
|
||||||
|
description: I/O voltage rail
|
||||||
|
|
||||||
|
vsn-supply:
|
||||||
|
description: Positive source voltage rail
|
||||||
|
|
||||||
|
vsp-supply:
|
||||||
|
description: Negative source voltage rail
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- reset-gpios
|
||||||
|
- iovcc-supply
|
||||||
|
- vsn-supply
|
||||||
|
- vsp-supply
|
||||||
|
- port
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
|
||||||
|
dsi {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
panel@0 {
|
||||||
|
compatible = "djn,98-03057-6598b-i";
|
||||||
|
reg = <0>;
|
||||||
|
|
||||||
|
reset-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
|
||||||
|
|
||||||
|
iovcc-supply = <&pm8953_l6>;
|
||||||
|
vsn-supply = <&pmi632_lcdb_ncp>;
|
||||||
|
vsp-supply = <&pmi632_lcdb_ldo>;
|
||||||
|
|
||||||
|
port {
|
||||||
|
panel_in_0: endpoint {
|
||||||
|
remote-endpoint = <&dsi0_out>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
|
@ -42,7 +42,6 @@ required:
|
||||||
- compatible
|
- compatible
|
||||||
- port
|
- port
|
||||||
- reg
|
- reg
|
||||||
- reset-gpios
|
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,10 @@ properties:
|
||||||
- description: Pixel clock for video port 0.
|
- description: Pixel clock for video port 0.
|
||||||
- description: Pixel clock for video port 1.
|
- description: Pixel clock for video port 1.
|
||||||
- description: Pixel clock for video port 2.
|
- description: Pixel clock for video port 2.
|
||||||
- description: Pixel clock for video port 3.
|
- {}
|
||||||
- description: Peripheral(vop grf/dsi) clock.
|
- {}
|
||||||
- description: Alternative pixel clock provided by HDMI0 PHY PLL.
|
- {}
|
||||||
- description: Alternative pixel clock provided by HDMI1 PHY PLL.
|
- {}
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 5
|
minItems: 5
|
||||||
|
@ -77,10 +77,10 @@ properties:
|
||||||
- const: dclk_vp0
|
- const: dclk_vp0
|
||||||
- const: dclk_vp1
|
- const: dclk_vp1
|
||||||
- const: dclk_vp2
|
- const: dclk_vp2
|
||||||
- const: dclk_vp3
|
- {}
|
||||||
- const: pclk_vop
|
- {}
|
||||||
- const: pll_hdmiphy0
|
- {}
|
||||||
- const: pll_hdmiphy1
|
- {}
|
||||||
|
|
||||||
rockchip,grf:
|
rockchip,grf:
|
||||||
$ref: /schemas/types.yaml#/definitions/phandle
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
@ -175,10 +175,24 @@ allOf:
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
clocks:
|
clocks:
|
||||||
maxItems: 5
|
minItems: 5
|
||||||
|
items:
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- description: Alternative pixel clock provided by HDMI PHY PLL.
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
maxItems: 5
|
minItems: 5
|
||||||
|
items:
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- const: pll_hdmiphy0
|
||||||
|
|
||||||
interrupts:
|
interrupts:
|
||||||
minItems: 4
|
minItems: 4
|
||||||
|
@ -208,11 +222,29 @@ allOf:
|
||||||
properties:
|
properties:
|
||||||
clocks:
|
clocks:
|
||||||
minItems: 7
|
minItems: 7
|
||||||
maxItems: 9
|
items:
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- description: Pixel clock for video port 3.
|
||||||
|
- description: Peripheral(vop grf/dsi) clock.
|
||||||
|
- description: Alternative pixel clock provided by HDMI0 PHY PLL.
|
||||||
|
- description: Alternative pixel clock provided by HDMI1 PHY PLL.
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 7
|
minItems: 7
|
||||||
maxItems: 9
|
items:
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- {}
|
||||||
|
- const: dclk_vp3
|
||||||
|
- const: pclk_vop
|
||||||
|
- const: pll_hdmiphy0
|
||||||
|
- const: pll_hdmiphy1
|
||||||
|
|
||||||
interrupts:
|
interrupts:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/display/ti/ti,am625-oldi.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Texas Instruments AM625 OLDI Transmitter
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||||
|
- Aradhya Bhatia <aradhya.bhatia@linux.dev>
|
||||||
|
|
||||||
|
description:
|
||||||
|
The AM625 TI Keystone OpenLDI transmitter (OLDI TX) supports serialized RGB
|
||||||
|
pixel data transmission between host and flat panel display over LVDS (Low
|
||||||
|
Voltage Differential Sampling) interface. The OLDI TX consists of 7-to-1 data
|
||||||
|
serializers, and 4-data and 1-clock LVDS outputs. It supports the LVDS output
|
||||||
|
formats "jeida-18", "jeida-24" and "vesa-18", and can accept 24-bit RGB or
|
||||||
|
padded and un-padded 18-bit RGB bus formats as input.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
description: serial clock input for the OLDI transmitters
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: serial
|
||||||
|
|
||||||
|
ti,companion-oldi:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description:
|
||||||
|
phandle to companion OLDI transmitter. This property is required for both
|
||||||
|
the OLDI TXes if they are expected to work either in dual-lvds mode or in
|
||||||
|
clone mode. This property should point to the other OLDI TX's phandle.
|
||||||
|
|
||||||
|
ti,secondary-oldi:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Boolean property to mark the OLDI transmitter as the secondary one, when the
|
||||||
|
OLDI hardware is expected to run as a companion HW, in cases of dual-lvds
|
||||||
|
mode or clone mode. The primary OLDI hardware is responsible for all the
|
||||||
|
hardware configuration.
|
||||||
|
|
||||||
|
ti,oldi-io-ctrl:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description:
|
||||||
|
phandle to syscon device node mapping OLDI IO_CTRL registers found in the
|
||||||
|
control MMR region. These registers are required to toggle the I/O lane
|
||||||
|
power, and control its electrical characteristics.
|
||||||
|
|
||||||
|
ports:
|
||||||
|
$ref: /schemas/graph.yaml#/properties/ports
|
||||||
|
|
||||||
|
properties:
|
||||||
|
port@0:
|
||||||
|
$ref: /schemas/graph.yaml#/properties/port
|
||||||
|
description: Parallel RGB input port
|
||||||
|
|
||||||
|
port@1:
|
||||||
|
$ref: /schemas/graph.yaml#/properties/port
|
||||||
|
description: LVDS output port
|
||||||
|
|
||||||
|
required:
|
||||||
|
- port@0
|
||||||
|
- port@1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- ti,oldi-io-ctrl
|
||||||
|
- ports
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
...
|
|
@ -100,6 +100,24 @@ properties:
|
||||||
For AM62A7 DSS, the port is tied off inside the SoC.
|
For AM62A7 DSS, the port is tied off inside the SoC.
|
||||||
For AM62L DSS, the DSS DPI output port node from video port 1
|
For AM62L DSS, the DSS DPI output port node from video port 1
|
||||||
or DSI Tx controller node connected to video port 1.
|
or DSI Tx controller node connected to video port 1.
|
||||||
|
properties:
|
||||||
|
endpoint@0:
|
||||||
|
$ref: /schemas/graph.yaml#/properties/endpoint
|
||||||
|
description:
|
||||||
|
For AM625 DSS, VP Connection to OLDI0.
|
||||||
|
For AM65X DSS, OLDI output from the SoC.
|
||||||
|
|
||||||
|
endpoint@1:
|
||||||
|
$ref: /schemas/graph.yaml#/properties/endpoint
|
||||||
|
description:
|
||||||
|
For AM625 DSS, VP Connection to OLDI1.
|
||||||
|
|
||||||
|
anyOf:
|
||||||
|
- required:
|
||||||
|
- endpoint
|
||||||
|
- required:
|
||||||
|
- endpoint@0
|
||||||
|
- endpoint@1
|
||||||
|
|
||||||
port@1:
|
port@1:
|
||||||
$ref: /schemas/graph.yaml#/properties/port
|
$ref: /schemas/graph.yaml#/properties/port
|
||||||
|
@ -121,6 +139,25 @@ properties:
|
||||||
Input memory (from main memory to dispc) bandwidth limit in
|
Input memory (from main memory to dispc) bandwidth limit in
|
||||||
bytes per second
|
bytes per second
|
||||||
|
|
||||||
|
oldi-transmitters:
|
||||||
|
description:
|
||||||
|
Child node under the DSS, to describe all the OLDI transmitters connected
|
||||||
|
to the DSS videoports.
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
properties:
|
||||||
|
"#address-cells":
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
"#size-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
'^oldi@[0-1]$':
|
||||||
|
$ref: ti,am625-oldi.yaml#
|
||||||
|
description: OLDI transmitters connected to the DSS VPs
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- if:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
|
@ -129,6 +166,7 @@ allOf:
|
||||||
const: ti,am62a7-dss
|
const: ti,am62a7-dss
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
|
oldi-transmitters: false
|
||||||
ports:
|
ports:
|
||||||
properties:
|
properties:
|
||||||
port@0: false
|
port@0: false
|
||||||
|
@ -143,6 +181,22 @@ allOf:
|
||||||
properties:
|
properties:
|
||||||
port@1: false
|
port@1: false
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- ti,am62l-dss
|
||||||
|
- ti,am65x-dss
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
oldi-transmitters: false
|
||||||
|
ports:
|
||||||
|
properties:
|
||||||
|
port@0:
|
||||||
|
properties:
|
||||||
|
endpoint@1: false
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
@ -161,32 +215,135 @@ examples:
|
||||||
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||||
|
|
||||||
dss: dss@4a00000 {
|
dss: dss@4a00000 {
|
||||||
compatible = "ti,am65x-dss";
|
compatible = "ti,am65x-dss";
|
||||||
reg = <0x04a00000 0x1000>, /* common */
|
reg = <0x04a00000 0x1000>, /* common */
|
||||||
<0x04a02000 0x1000>, /* vidl1 */
|
<0x04a02000 0x1000>, /* vidl1 */
|
||||||
<0x04a06000 0x1000>, /* vid */
|
<0x04a06000 0x1000>, /* vid */
|
||||||
<0x04a07000 0x1000>, /* ovr1 */
|
<0x04a07000 0x1000>, /* ovr1 */
|
||||||
<0x04a08000 0x1000>, /* ovr2 */
|
<0x04a08000 0x1000>, /* ovr2 */
|
||||||
<0x04a0a000 0x1000>, /* vp1 */
|
<0x04a0a000 0x1000>, /* vp1 */
|
||||||
<0x04a0b000 0x1000>, /* vp2 */
|
<0x04a0b000 0x1000>, /* vp2 */
|
||||||
<0x04a01000 0x1000>; /* common1 */
|
<0x04a01000 0x1000>; /* common1 */
|
||||||
|
reg-names = "common", "vidl1", "vid",
|
||||||
|
"ovr1", "ovr2", "vp1", "vp2", "common1";
|
||||||
|
ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>;
|
||||||
|
power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>;
|
||||||
|
clocks = <&k3_clks 67 1>,
|
||||||
|
<&k3_clks 216 1>,
|
||||||
|
<&k3_clks 67 2>;
|
||||||
|
clock-names = "fck", "vp1", "vp2";
|
||||||
|
interrupts = <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
oldi_out0: endpoint {
|
||||||
|
remote-endpoint = <&lcd_in0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||||
|
|
||||||
|
bus {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
dss1: dss@30200000 {
|
||||||
|
compatible = "ti,am625-dss";
|
||||||
|
reg = <0x00 0x30200000 0x00 0x1000>, /* common */
|
||||||
|
<0x00 0x30202000 0x00 0x1000>, /* vidl1 */
|
||||||
|
<0x00 0x30206000 0x00 0x1000>, /* vid */
|
||||||
|
<0x00 0x30207000 0x00 0x1000>, /* ovr1 */
|
||||||
|
<0x00 0x30208000 0x00 0x1000>, /* ovr2 */
|
||||||
|
<0x00 0x3020a000 0x00 0x1000>, /* vp1 */
|
||||||
|
<0x00 0x3020b000 0x00 0x1000>, /* vp2 */
|
||||||
|
<0x00 0x30201000 0x00 0x1000>; /* common1 */
|
||||||
reg-names = "common", "vidl1", "vid",
|
reg-names = "common", "vidl1", "vid",
|
||||||
"ovr1", "ovr2", "vp1", "vp2", "common1";
|
"ovr1", "ovr2", "vp1", "vp2", "common1";
|
||||||
ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>;
|
power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>;
|
||||||
power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>;
|
clocks = <&k3_clks 186 6>,
|
||||||
clocks = <&k3_clks 67 1>,
|
<&vp1_clock>,
|
||||||
<&k3_clks 216 1>,
|
<&k3_clks 186 2>;
|
||||||
<&k3_clks 67 2>;
|
|
||||||
clock-names = "fck", "vp1", "vp2";
|
clock-names = "fck", "vp1", "vp2";
|
||||||
interrupts = <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>;
|
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
oldi-transmitters {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
oldi0: oldi@0 {
|
||||||
|
reg = <0>;
|
||||||
|
clocks = <&k3_clks 186 0>;
|
||||||
|
clock-names = "serial";
|
||||||
|
ti,companion-oldi = <&oldi1>;
|
||||||
|
ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>;
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
oldi0_in: endpoint {
|
||||||
|
remote-endpoint = <&dpi0_out0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
oldi0_out: endpoint {
|
||||||
|
remote-endpoint = <&panel_in0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
oldi1: oldi@1 {
|
||||||
|
reg = <1>;
|
||||||
|
clocks = <&k3_clks 186 0>;
|
||||||
|
clock-names = "serial";
|
||||||
|
ti,secondary-oldi;
|
||||||
|
ti,companion-oldi = <&oldi0>;
|
||||||
|
ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>;
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
oldi1_in: endpoint {
|
||||||
|
remote-endpoint = <&dpi0_out1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
oldi1_out: endpoint {
|
||||||
|
remote-endpoint = <&panel_in1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
ports {
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
port@0 {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
port@0 {
|
reg = <0>;
|
||||||
reg = <0>;
|
dpi0_out0: endpoint@0 {
|
||||||
oldi_out0: endpoint {
|
reg = <0>;
|
||||||
remote-endpoint = <&lcd_in0>;
|
remote-endpoint = <&oldi0_in>;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
dpi0_out1: endpoint@1 {
|
||||||
|
reg = <1>;
|
||||||
|
remote-endpoint = <&oldi1_in>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
dpi1_out: endpoint {
|
||||||
|
remote-endpoint = <&hdmi_bridge>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -398,6 +398,8 @@ patternProperties:
|
||||||
description: Diodes, Inc.
|
description: Diodes, Inc.
|
||||||
"^dioo,.*":
|
"^dioo,.*":
|
||||||
description: Dioo Microcircuit Co., Ltd
|
description: Dioo Microcircuit Co., Ltd
|
||||||
|
"^djn,.*":
|
||||||
|
description: Shenzhen DJN Optronics Technology Co., Ltd
|
||||||
"^dlc,.*":
|
"^dlc,.*":
|
||||||
description: DLC Display Co., Ltd.
|
description: DLC Display Co., Ltd.
|
||||||
"^dlg,.*":
|
"^dlg,.*":
|
||||||
|
|
|
@ -7499,10 +7499,12 @@ M: Javier Martinez Canillas <javierm@redhat.com>
|
||||||
L: dri-devel@lists.freedesktop.org
|
L: dri-devel@lists.freedesktop.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||||
|
F: drivers/firmware/sysfb*.c
|
||||||
F: drivers/gpu/drm/sysfb/
|
F: drivers/gpu/drm/sysfb/
|
||||||
F: drivers/video/aperture.c
|
F: drivers/video/aperture.c
|
||||||
F: drivers/video/nomodeset.c
|
F: drivers/video/nomodeset.c
|
||||||
F: include/linux/aperture.h
|
F: include/linux/aperture.h
|
||||||
|
F: include/linux/sysfb.h
|
||||||
F: include/video/nomodeset.h
|
F: include/video/nomodeset.h
|
||||||
|
|
||||||
DRM DRIVER FOR GENERIC EDP PANELS
|
DRM DRIVER FOR GENERIC EDP PANELS
|
||||||
|
@ -8232,6 +8234,7 @@ M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||||
L: dri-devel@lists.freedesktop.org
|
L: dri-devel@lists.freedesktop.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||||
|
F: Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
|
||||||
F: Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
|
F: Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
|
||||||
F: Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
|
F: Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
|
||||||
F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
|
F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/units.h>
|
||||||
|
|
||||||
#include <video/mipi_display.h>
|
#include <video/mipi_display.h>
|
||||||
|
|
||||||
|
@ -558,10 +559,6 @@ static void samsung_dsim_reset(struct samsung_dsim *dsi)
|
||||||
samsung_dsim_write(dsi, DSIM_SWRST_REG, reset_val);
|
samsung_dsim_write(dsi, DSIM_SWRST_REG, reset_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MHZ
|
|
||||||
#define MHZ (1000 * 1000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi,
|
static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi,
|
||||||
unsigned long fin,
|
unsigned long fin,
|
||||||
unsigned long fout,
|
unsigned long fout,
|
||||||
|
@ -575,8 +572,8 @@ static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi,
|
||||||
u16 _m, best_m;
|
u16 _m, best_m;
|
||||||
u8 _s, best_s;
|
u8 _s, best_s;
|
||||||
|
|
||||||
p_min = DIV_ROUND_UP(fin, (driver_data->pll_fin_max * MHZ));
|
p_min = DIV_ROUND_UP(fin, (driver_data->pll_fin_max * HZ_PER_MHZ));
|
||||||
p_max = fin / (driver_data->pll_fin_min * MHZ);
|
p_max = fin / (driver_data->pll_fin_min * HZ_PER_MHZ);
|
||||||
|
|
||||||
for (_p = p_min; _p <= p_max; ++_p) {
|
for (_p = p_min; _p <= p_max; ++_p) {
|
||||||
for (_s = 0; _s <= 5; ++_s) {
|
for (_s = 0; _s <= 5; ++_s) {
|
||||||
|
@ -591,8 +588,8 @@ static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi,
|
||||||
|
|
||||||
tmp = (u64)_m * fin;
|
tmp = (u64)_m * fin;
|
||||||
do_div(tmp, _p);
|
do_div(tmp, _p);
|
||||||
if (tmp < driver_data->min_freq * MHZ ||
|
if (tmp < driver_data->min_freq * HZ_PER_MHZ ||
|
||||||
tmp > driver_data->max_freq * MHZ)
|
tmp > driver_data->max_freq * HZ_PER_MHZ)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tmp = (u64)_m * fin;
|
tmp = (u64)_m * fin;
|
||||||
|
@ -635,7 +632,7 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi,
|
||||||
* limit.
|
* limit.
|
||||||
*/
|
*/
|
||||||
fin = clk_get_rate(clk_get_parent(dsi->pll_clk));
|
fin = clk_get_rate(clk_get_parent(dsi->pll_clk));
|
||||||
while (fin > driver_data->pll_fin_max * MHZ)
|
while (fin > driver_data->pll_fin_max * HZ_PER_MHZ)
|
||||||
fin /= 2;
|
fin /= 2;
|
||||||
clk_set_rate(dsi->pll_clk, fin);
|
clk_set_rate(dsi->pll_clk, fin);
|
||||||
|
|
||||||
|
@ -661,10 +658,11 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi,
|
||||||
|
|
||||||
if (driver_data->has_freqband) {
|
if (driver_data->has_freqband) {
|
||||||
static const unsigned long freq_bands[] = {
|
static const unsigned long freq_bands[] = {
|
||||||
100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ,
|
100 * HZ_PER_MHZ, 120 * HZ_PER_MHZ, 160 * HZ_PER_MHZ,
|
||||||
270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ,
|
200 * HZ_PER_MHZ, 270 * HZ_PER_MHZ, 320 * HZ_PER_MHZ,
|
||||||
510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ,
|
390 * HZ_PER_MHZ, 450 * HZ_PER_MHZ, 510 * HZ_PER_MHZ,
|
||||||
770 * MHZ, 870 * MHZ, 950 * MHZ,
|
560 * HZ_PER_MHZ, 640 * HZ_PER_MHZ, 690 * HZ_PER_MHZ,
|
||||||
|
770 * HZ_PER_MHZ, 870 * HZ_PER_MHZ, 950 * HZ_PER_MHZ,
|
||||||
};
|
};
|
||||||
int band;
|
int band;
|
||||||
|
|
||||||
|
@ -724,7 +722,7 @@ static int samsung_dsim_enable_clock(struct samsung_dsim *dsi)
|
||||||
esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate);
|
esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate);
|
||||||
esc_clk = byte_clk / esc_div;
|
esc_clk = byte_clk / esc_div;
|
||||||
|
|
||||||
if (esc_clk > 20 * MHZ) {
|
if (esc_clk > 20 * HZ_PER_MHZ) {
|
||||||
++esc_div;
|
++esc_div;
|
||||||
esc_clk = byte_clk / esc_div;
|
esc_clk = byte_clk / esc_div;
|
||||||
}
|
}
|
||||||
|
@ -899,8 +897,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi)
|
||||||
* The user manual describes that following bits are ignored in
|
* The user manual describes that following bits are ignored in
|
||||||
* command mode.
|
* command mode.
|
||||||
*/
|
*/
|
||||||
if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH))
|
|
||||||
reg |= DSIM_MFLUSH_VS;
|
|
||||||
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
||||||
reg |= DSIM_SYNC_INFORM;
|
reg |= DSIM_SYNC_INFORM;
|
||||||
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
||||||
|
@ -1236,43 +1232,34 @@ static void samsung_dsim_transfer_start(struct samsung_dsim *dsi)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct samsung_dsim_transfer *xfer;
|
struct samsung_dsim_transfer *xfer;
|
||||||
bool start = false;
|
|
||||||
|
|
||||||
again:
|
|
||||||
spin_lock_irqsave(&dsi->transfer_lock, flags);
|
spin_lock_irqsave(&dsi->transfer_lock, flags);
|
||||||
|
|
||||||
if (list_empty(&dsi->transfer_list)) {
|
while (!list_empty(&dsi->transfer_list)) {
|
||||||
|
xfer = list_first_entry(&dsi->transfer_list,
|
||||||
|
struct samsung_dsim_transfer, list);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dsi->transfer_lock, flags);
|
spin_unlock_irqrestore(&dsi->transfer_lock, flags);
|
||||||
return;
|
|
||||||
|
if (xfer->packet.payload_length &&
|
||||||
|
xfer->tx_done == xfer->packet.payload_length)
|
||||||
|
/* waiting for RX */
|
||||||
|
return;
|
||||||
|
|
||||||
|
samsung_dsim_send_to_fifo(dsi, xfer);
|
||||||
|
|
||||||
|
if (xfer->packet.payload_length || xfer->rx_len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xfer->result = 0;
|
||||||
|
complete(&xfer->completed);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dsi->transfer_lock, flags);
|
||||||
|
|
||||||
|
list_del_init(&xfer->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
xfer = list_first_entry(&dsi->transfer_list,
|
|
||||||
struct samsung_dsim_transfer, list);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dsi->transfer_lock, flags);
|
spin_unlock_irqrestore(&dsi->transfer_lock, flags);
|
||||||
|
|
||||||
if (xfer->packet.payload_length &&
|
|
||||||
xfer->tx_done == xfer->packet.payload_length)
|
|
||||||
/* waiting for RX */
|
|
||||||
return;
|
|
||||||
|
|
||||||
samsung_dsim_send_to_fifo(dsi, xfer);
|
|
||||||
|
|
||||||
if (xfer->packet.payload_length || xfer->rx_len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xfer->result = 0;
|
|
||||||
complete(&xfer->completed);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dsi->transfer_lock, flags);
|
|
||||||
|
|
||||||
list_del_init(&xfer->list);
|
|
||||||
start = !list_empty(&dsi->transfer_list);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dsi->transfer_lock, flags);
|
|
||||||
|
|
||||||
if (start)
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool samsung_dsim_transfer_finish(struct samsung_dsim *dsi)
|
static bool samsung_dsim_transfer_finish(struct samsung_dsim *dsi)
|
||||||
|
|
|
@ -1677,11 +1677,6 @@ static int ti_sn_bridge_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||||
{
|
{
|
||||||
struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip);
|
struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip);
|
||||||
|
|
||||||
if (!test_bit(offset, pdata->gchip_output)) {
|
|
||||||
dev_err(pdata->dev, "Ignoring GPIO set while input\n");
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
val &= 1;
|
val &= 1;
|
||||||
return regmap_update_bits(pdata->regmap, SN_GPIO_IO_REG,
|
return regmap_update_bits(pdata->regmap, SN_GPIO_IO_REG,
|
||||||
BIT(SN_GPIO_OUTPUT_SHIFT + offset),
|
BIT(SN_GPIO_OUTPUT_SHIFT + offset),
|
||||||
|
|
|
@ -3957,23 +3957,31 @@ EXPORT_SYMBOL(drm_dp_pcon_convert_rgb_to_ycbcr);
|
||||||
* Returns: %0 on success, negative error code on failure
|
* Returns: %0 on success, negative error code on failure
|
||||||
*/
|
*/
|
||||||
int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
||||||
u16 level)
|
u32 level)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u8 buf[2] = { 0 };
|
unsigned int offset = DP_EDP_BACKLIGHT_BRIGHTNESS_MSB;
|
||||||
|
u8 buf[3] = { 0 };
|
||||||
|
|
||||||
/* The panel uses the PWM for controlling brightness levels */
|
/* The panel uses the PWM for controlling brightness levels */
|
||||||
if (!bl->aux_set)
|
if (!(bl->aux_set || bl->luminance_set))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (bl->lsb_reg_used) {
|
if (bl->luminance_set) {
|
||||||
|
level = level * 1000;
|
||||||
|
level &= 0xffffff;
|
||||||
|
buf[0] = (level & 0x0000ff);
|
||||||
|
buf[1] = (level & 0x00ff00) >> 8;
|
||||||
|
buf[2] = (level & 0xff0000) >> 16;
|
||||||
|
offset = DP_EDP_PANEL_TARGET_LUMINANCE_VALUE;
|
||||||
|
} else if (bl->lsb_reg_used) {
|
||||||
buf[0] = (level & 0xff00) >> 8;
|
buf[0] = (level & 0xff00) >> 8;
|
||||||
buf[1] = (level & 0x00ff);
|
buf[1] = (level & 0x00ff);
|
||||||
} else {
|
} else {
|
||||||
buf[0] = level;
|
buf[0] = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = drm_dp_dpcd_write_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, buf, sizeof(buf));
|
ret = drm_dp_dpcd_write_data(aux, offset, buf, sizeof(buf));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
drm_err(aux->drm_dev,
|
drm_err(aux->drm_dev,
|
||||||
"%s: Failed to write aux backlight level: %d\n",
|
"%s: Failed to write aux backlight level: %d\n",
|
||||||
|
@ -4036,7 +4044,7 @@ drm_edp_backlight_set_enable(struct drm_dp_aux *aux, const struct drm_edp_backli
|
||||||
* Returns: %0 on success, negative error code on failure.
|
* Returns: %0 on success, negative error code on failure.
|
||||||
*/
|
*/
|
||||||
int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
||||||
const u16 level)
|
const u32 level)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u8 dpcd_buf;
|
u8 dpcd_buf;
|
||||||
|
@ -4046,6 +4054,9 @@ int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backli
|
||||||
else
|
else
|
||||||
dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_PWM;
|
dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_PWM;
|
||||||
|
|
||||||
|
if (bl->luminance_set)
|
||||||
|
dpcd_buf |= DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE;
|
||||||
|
|
||||||
if (bl->pwmgen_bit_count) {
|
if (bl->pwmgen_bit_count) {
|
||||||
ret = drm_dp_dpcd_write_byte(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count);
|
ret = drm_dp_dpcd_write_byte(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -4209,7 +4220,7 @@ drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_i
|
||||||
u8 *current_mode)
|
u8 *current_mode)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u8 buf[2];
|
u8 buf[3];
|
||||||
u8 mode_reg;
|
u8 mode_reg;
|
||||||
|
|
||||||
ret = drm_dp_dpcd_read_byte(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &mode_reg);
|
ret = drm_dp_dpcd_read_byte(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &mode_reg);
|
||||||
|
@ -4226,17 +4237,37 @@ drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_i
|
||||||
if (*current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
|
if (*current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
|
||||||
int size = 1 + bl->lsb_reg_used;
|
int size = 1 + bl->lsb_reg_used;
|
||||||
|
|
||||||
ret = drm_dp_dpcd_read_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, buf, size);
|
if (bl->luminance_set) {
|
||||||
if (ret < 0) {
|
ret = drm_dp_dpcd_read_data(aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE,
|
||||||
drm_dbg_kms(aux->drm_dev, "%s: Failed to read backlight level: %d\n",
|
buf, sizeof(buf));
|
||||||
aux->name, ret);
|
if (ret < 0) {
|
||||||
return ret;
|
drm_dbg_kms(aux->drm_dev,
|
||||||
|
"%s: Failed to read backlight level: %d\n",
|
||||||
|
aux->name, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bl->lsb_reg_used)
|
/*
|
||||||
return (buf[0] << 8) | buf[1];
|
* Incase luminance is set we want to send the value back in nits but since
|
||||||
else
|
* DP_EDP_PANEL_TARGET_LUMINANCE stores values in millinits we need to divide
|
||||||
return buf[0];
|
* by 1000.
|
||||||
|
*/
|
||||||
|
return (buf[0] | buf[1] << 8 | buf[2] << 16) / 1000;
|
||||||
|
} else {
|
||||||
|
ret = drm_dp_dpcd_read_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
|
||||||
|
buf, size);
|
||||||
|
if (ret < 0) {
|
||||||
|
drm_dbg_kms(aux->drm_dev,
|
||||||
|
"%s: Failed to read backlight level: %d\n",
|
||||||
|
aux->name, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bl->lsb_reg_used)
|
||||||
|
return (buf[0] << 8) | buf[1];
|
||||||
|
else
|
||||||
|
return buf[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4251,10 +4282,12 @@ drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_i
|
||||||
* interface.
|
* interface.
|
||||||
* @aux: The DP aux device to use for probing
|
* @aux: The DP aux device to use for probing
|
||||||
* @bl: The &drm_edp_backlight_info struct to fill out with information on the backlight
|
* @bl: The &drm_edp_backlight_info struct to fill out with information on the backlight
|
||||||
|
* @max_luminance: max luminance when need luminance is set as true
|
||||||
* @driver_pwm_freq_hz: Optional PWM frequency from the driver in hz
|
* @driver_pwm_freq_hz: Optional PWM frequency from the driver in hz
|
||||||
* @edp_dpcd: A cached copy of the eDP DPCD
|
* @edp_dpcd: A cached copy of the eDP DPCD
|
||||||
* @current_level: Where to store the probed brightness level, if any
|
* @current_level: Where to store the probed brightness level, if any
|
||||||
* @current_mode: Where to store the currently set backlight control mode
|
* @current_mode: Where to store the currently set backlight control mode
|
||||||
|
* @need_luminance: Tells us if a we want to manipulate backlight using luminance values
|
||||||
*
|
*
|
||||||
* Initializes a &drm_edp_backlight_info struct by probing @aux for it's backlight capabilities,
|
* Initializes a &drm_edp_backlight_info struct by probing @aux for it's backlight capabilities,
|
||||||
* along with also probing the current and maximum supported brightness levels.
|
* along with also probing the current and maximum supported brightness levels.
|
||||||
|
@ -4266,8 +4299,9 @@ drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_i
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl,
|
drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl,
|
||||||
|
u32 max_luminance,
|
||||||
u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE],
|
u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE],
|
||||||
u16 *current_level, u8 *current_mode)
|
u32 *current_level, u8 *current_mode, bool need_luminance)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -4277,18 +4311,26 @@ drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl
|
||||||
bl->aux_set = true;
|
bl->aux_set = true;
|
||||||
if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
|
if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT)
|
||||||
bl->lsb_reg_used = true;
|
bl->lsb_reg_used = true;
|
||||||
|
if ((edp_dpcd[0] & DP_EDP_15) && edp_dpcd[3] &
|
||||||
|
(DP_EDP_PANEL_LUMINANCE_CONTROL_CAPABLE) && need_luminance)
|
||||||
|
bl->luminance_set = true;
|
||||||
|
|
||||||
/* Sanity check caps */
|
/* Sanity check caps */
|
||||||
if (!bl->aux_set && !(edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) {
|
if (!bl->aux_set && !(edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP) &&
|
||||||
|
!bl->luminance_set) {
|
||||||
drm_dbg_kms(aux->drm_dev,
|
drm_dbg_kms(aux->drm_dev,
|
||||||
"%s: Panel supports neither AUX or PWM brightness control? Aborting\n",
|
"%s: Panel does not support AUX, PWM or luminance-based brightness control. Aborting\n",
|
||||||
aux->name);
|
aux->name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = drm_edp_backlight_probe_max(aux, bl, driver_pwm_freq_hz, edp_dpcd);
|
if (bl->luminance_set) {
|
||||||
if (ret < 0)
|
bl->max = max_luminance;
|
||||||
return ret;
|
} else {
|
||||||
|
ret = drm_edp_backlight_probe_max(aux, bl, driver_pwm_freq_hz, edp_dpcd);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = drm_edp_backlight_probe_state(aux, bl, current_mode);
|
ret = drm_edp_backlight_probe_state(aux, bl, current_mode);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -4367,7 +4409,7 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux)
|
||||||
{
|
{
|
||||||
struct dp_aux_backlight *bl;
|
struct dp_aux_backlight *bl;
|
||||||
struct backlight_properties props = { 0 };
|
struct backlight_properties props = { 0 };
|
||||||
u16 current_level;
|
u32 current_level;
|
||||||
u8 current_mode;
|
u8 current_mode;
|
||||||
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
|
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -4391,8 +4433,8 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux)
|
||||||
|
|
||||||
bl->aux = aux;
|
bl->aux = aux;
|
||||||
|
|
||||||
ret = drm_edp_backlight_init(aux, &bl->info, 0, edp_dpcd,
|
ret = drm_edp_backlight_init(aux, &bl->info, 0, 0, edp_dpcd,
|
||||||
¤t_level, ¤t_mode);
|
¤t_level, ¤t_mode, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -295,6 +295,11 @@ EXPORT_SYMBOL(__devm_drm_bridge_alloc);
|
||||||
*/
|
*/
|
||||||
void drm_bridge_add(struct drm_bridge *bridge)
|
void drm_bridge_add(struct drm_bridge *bridge)
|
||||||
{
|
{
|
||||||
|
if (!bridge->container)
|
||||||
|
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
|
||||||
|
|
||||||
|
drm_bridge_get(bridge);
|
||||||
|
|
||||||
mutex_init(&bridge->hpd_mutex);
|
mutex_init(&bridge->hpd_mutex);
|
||||||
|
|
||||||
if (bridge->ops & DRM_BRIDGE_OP_HDMI)
|
if (bridge->ops & DRM_BRIDGE_OP_HDMI)
|
||||||
|
@ -342,6 +347,8 @@ void drm_bridge_remove(struct drm_bridge *bridge)
|
||||||
mutex_unlock(&bridge_lock);
|
mutex_unlock(&bridge_lock);
|
||||||
|
|
||||||
mutex_destroy(&bridge->hpd_mutex);
|
mutex_destroy(&bridge->hpd_mutex);
|
||||||
|
|
||||||
|
drm_bridge_put(bridge);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_bridge_remove);
|
EXPORT_SYMBOL(drm_bridge_remove);
|
||||||
|
|
||||||
|
@ -407,11 +414,17 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
||||||
if (!encoder || !bridge)
|
if (!encoder || !bridge)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (previous && (!previous->dev || previous->encoder != encoder))
|
drm_bridge_get(bridge);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (bridge->dev)
|
if (previous && (!previous->dev || previous->encoder != encoder)) {
|
||||||
return -EBUSY;
|
ret = -EINVAL;
|
||||||
|
goto err_put_bridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bridge->dev) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto err_put_bridge;
|
||||||
|
}
|
||||||
|
|
||||||
bridge->dev = encoder->dev;
|
bridge->dev = encoder->dev;
|
||||||
bridge->encoder = encoder;
|
bridge->encoder = encoder;
|
||||||
|
@ -460,6 +473,8 @@ err_reset_bridge:
|
||||||
"failed to attach bridge %pOF to encoder %s\n",
|
"failed to attach bridge %pOF to encoder %s\n",
|
||||||
bridge->of_node, encoder->name);
|
bridge->of_node, encoder->name);
|
||||||
|
|
||||||
|
err_put_bridge:
|
||||||
|
drm_bridge_put(bridge);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_bridge_attach);
|
EXPORT_SYMBOL(drm_bridge_attach);
|
||||||
|
@ -480,6 +495,7 @@ void drm_bridge_detach(struct drm_bridge *bridge)
|
||||||
|
|
||||||
list_del(&bridge->chain_node);
|
list_del(&bridge->chain_node);
|
||||||
bridge->dev = NULL;
|
bridge->dev = NULL;
|
||||||
|
drm_bridge_put(bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -559,18 +559,6 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
|
||||||
drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565);
|
drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline u32 drm_xrgb8888_to_rgb565_swab(u32 pix)
|
|
||||||
{
|
|
||||||
return swab16(drm_pixel_xrgb8888_to_rgb565(pix));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
|
|
||||||
static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
|
|
||||||
unsigned int pixels)
|
|
||||||
{
|
|
||||||
drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_xrgb8888_to_rgb565_swab);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
|
* drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
|
||||||
* @dst: Array of RGB565 destination buffers
|
* @dst: Array of RGB565 destination buffers
|
||||||
|
@ -580,7 +568,6 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
|
||||||
* @fb: DRM framebuffer
|
* @fb: DRM framebuffer
|
||||||
* @clip: Clip rectangle area to copy
|
* @clip: Clip rectangle area to copy
|
||||||
* @state: Transform and conversion state
|
* @state: Transform and conversion state
|
||||||
* @swab: Swap bytes
|
|
||||||
*
|
*
|
||||||
* This function copies parts of a framebuffer to display memory and converts the
|
* This function copies parts of a framebuffer to display memory and converts the
|
||||||
* color format during the process. Destination and framebuffer formats must match. The
|
* color format during the process. Destination and framebuffer formats must match. The
|
||||||
|
@ -595,24 +582,57 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
|
||||||
*/
|
*/
|
||||||
void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
|
void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
|
||||||
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
||||||
const struct drm_rect *clip, struct drm_format_conv_state *state,
|
const struct drm_rect *clip, struct drm_format_conv_state *state)
|
||||||
bool swab)
|
|
||||||
{
|
{
|
||||||
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
|
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
|
||||||
2,
|
2,
|
||||||
};
|
};
|
||||||
|
|
||||||
void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels);
|
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
|
||||||
|
drm_fb_xrgb8888_to_rgb565_line);
|
||||||
if (swab)
|
|
||||||
xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line;
|
|
||||||
else
|
|
||||||
xfrm_line = drm_fb_xrgb8888_to_rgb565_line;
|
|
||||||
|
|
||||||
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
|
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
|
||||||
|
|
||||||
|
static void drm_fb_xrgb8888_to_rgb565be_line(void *dbuf, const void *sbuf,
|
||||||
|
unsigned int pixels)
|
||||||
|
{
|
||||||
|
drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565be);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_fb_xrgb8888_to_rgb565be - Convert XRGB8888 to RGB565|DRM_FORMAT_BIG_ENDIAN clip buffer
|
||||||
|
* @dst: Array of RGB565BE destination buffers
|
||||||
|
* @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
|
||||||
|
* within @dst; can be NULL if scanlines are stored next to each other.
|
||||||
|
* @src: Array of XRGB8888 source buffer
|
||||||
|
* @fb: DRM framebuffer
|
||||||
|
* @clip: Clip rectangle area to copy
|
||||||
|
* @state: Transform and conversion state
|
||||||
|
*
|
||||||
|
* This function copies parts of a framebuffer to display memory and converts the
|
||||||
|
* color format during the process. Destination and framebuffer formats must match. The
|
||||||
|
* parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
|
||||||
|
* least as many entries as there are planes in @fb's format. Each entry stores the
|
||||||
|
* value for the format's respective color plane at the same index.
|
||||||
|
*
|
||||||
|
* This function does not apply clipping on @dst (i.e. the destination is at the
|
||||||
|
* top-left corner).
|
||||||
|
*
|
||||||
|
* Drivers can use this function for RGB565BE devices that don't support XRGB8888 natively.
|
||||||
|
*/
|
||||||
|
void drm_fb_xrgb8888_to_rgb565be(struct iosys_map *dst, const unsigned int *dst_pitch,
|
||||||
|
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
||||||
|
const struct drm_rect *clip, struct drm_format_conv_state *state)
|
||||||
|
{
|
||||||
|
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
|
||||||
|
2,
|
||||||
|
};
|
||||||
|
|
||||||
|
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
|
||||||
|
drm_fb_xrgb8888_to_rgb565be_line);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565be);
|
||||||
|
|
||||||
static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
|
static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
|
||||||
{
|
{
|
||||||
drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb1555);
|
drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_xrgb1555);
|
||||||
|
@ -1188,7 +1208,7 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
|
||||||
return 0;
|
return 0;
|
||||||
} else if (fb_format == DRM_FORMAT_XRGB8888) {
|
} else if (fb_format == DRM_FORMAT_XRGB8888) {
|
||||||
if (dst_format == DRM_FORMAT_RGB565) {
|
if (dst_format == DRM_FORMAT_RGB565) {
|
||||||
drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false);
|
drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (dst_format == DRM_FORMAT_XRGB1555) {
|
} else if (dst_format == DRM_FORMAT_XRGB1555) {
|
||||||
drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state);
|
drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/swab.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each pixel-format conversion helper takes a raw pixel in a
|
* Each pixel-format conversion helper takes a raw pixel in a
|
||||||
|
@ -59,6 +60,11 @@ static inline u32 drm_pixel_xrgb8888_to_rgb565(u32 pix)
|
||||||
((pix & 0x000000f8) >> 3);
|
((pix & 0x000000f8) >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 drm_pixel_xrgb8888_to_rgb565be(u32 pix)
|
||||||
|
{
|
||||||
|
return swab16(drm_pixel_xrgb8888_to_rgb565(pix));
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 drm_pixel_xrgb8888_to_rgbx5551(u32 pix)
|
static inline u32 drm_pixel_xrgb8888_to_rgbx5551(u32 pix)
|
||||||
{
|
{
|
||||||
return ((pix & 0x00f80000) >> 8) |
|
return ((pix & 0x00f80000) >> 8) |
|
||||||
|
|
|
@ -238,6 +238,14 @@ const struct drm_format_info *__drm_format_info(u32 format)
|
||||||
{ .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
{ .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
||||||
{ .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
{ .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
||||||
{ .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
{ .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
||||||
|
{ .format = DRM_FORMAT_RGB161616, .depth = 0,
|
||||||
|
.num_planes = 1, .char_per_block = { 6, 0, 0 },
|
||||||
|
.block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
|
||||||
|
.hsub = 1, .vsub = 1, .has_alpha = false },
|
||||||
|
{ .format = DRM_FORMAT_BGR161616, .depth = 0,
|
||||||
|
.num_planes = 1, .char_per_block = { 6, 0, 0 },
|
||||||
|
.block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
|
||||||
|
.hsub = 1, .vsub = 1, .has_alpha = false },
|
||||||
{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
||||||
{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
||||||
{ .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
{ .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
|
||||||
|
|
|
@ -230,7 +230,13 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *
|
||||||
case DRM_FORMAT_XRGB8888:
|
case DRM_FORMAT_XRGB8888:
|
||||||
switch (dbidev->pixel_format) {
|
switch (dbidev->pixel_format) {
|
||||||
case DRM_FORMAT_RGB565:
|
case DRM_FORMAT_RGB565:
|
||||||
drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap);
|
if (swap) {
|
||||||
|
drm_fb_xrgb8888_to_rgb565be(&dst_map, NULL, src, fb, clip,
|
||||||
|
fmtcnv_state);
|
||||||
|
} else {
|
||||||
|
drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip,
|
||||||
|
fmtcnv_state);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_RGB888:
|
case DRM_FORMAT_RGB888:
|
||||||
drm_fb_xrgb8888_to_rgb888(&dst_map, NULL, src, fb, clip, fmtcnv_state);
|
drm_fb_xrgb8888_to_rgb888(&dst_map, NULL, src, fb, clip, fmtcnv_state);
|
||||||
|
|
|
@ -188,8 +188,13 @@ retry:
|
||||||
} else if (format->format == DRM_FORMAT_RGB332) {
|
} else if (format->format == DRM_FORMAT_RGB332) {
|
||||||
drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect, fmtcnv_state);
|
drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect, fmtcnv_state);
|
||||||
} else if (format->format == DRM_FORMAT_RGB565) {
|
} else if (format->format == DRM_FORMAT_RGB565) {
|
||||||
drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, fmtcnv_state,
|
if (gud_is_big_endian()) {
|
||||||
gud_is_big_endian());
|
drm_fb_xrgb8888_to_rgb565be(&dst, NULL, src, fb, rect,
|
||||||
|
fmtcnv_state);
|
||||||
|
} else {
|
||||||
|
drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect,
|
||||||
|
fmtcnv_state);
|
||||||
|
}
|
||||||
} else if (format->format == DRM_FORMAT_RGB888) {
|
} else if (format->format == DRM_FORMAT_RGB888) {
|
||||||
drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect, fmtcnv_state);
|
drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect, fmtcnv_state);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -475,31 +475,6 @@ static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, en
|
||||||
return connector->panel.backlight.level;
|
return connector->panel.backlight.level;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
intel_dp_aux_vesa_set_luminance(struct intel_connector *connector, u32 level)
|
|
||||||
{
|
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
|
||||||
u8 buf[3];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
level = level * 1000;
|
|
||||||
level &= 0xffffff;
|
|
||||||
buf[0] = (level & 0x0000ff);
|
|
||||||
buf[1] = (level & 0x00ff00) >> 8;
|
|
||||||
buf[2] = (level & 0xff0000) >> 16;
|
|
||||||
|
|
||||||
ret = drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE,
|
|
||||||
buf, sizeof(buf));
|
|
||||||
if (ret != sizeof(buf)) {
|
|
||||||
drm_err(intel_dp->aux.drm_dev,
|
|
||||||
"%s: Failed to set VESA Aux Luminance: %d\n",
|
|
||||||
intel_dp->aux.name, ret);
|
|
||||||
return -EINVAL;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
|
intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||||
{
|
{
|
||||||
|
@ -507,11 +482,6 @@ intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u3
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
|
|
||||||
if (panel->backlight.edp.vesa.luminance_control_support) {
|
|
||||||
if (!intel_dp_aux_vesa_set_luminance(connector, level))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!panel->backlight.edp.vesa.info.aux_set) {
|
if (!panel->backlight.edp.vesa.info.aux_set) {
|
||||||
const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
|
const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
|
||||||
|
|
||||||
|
@ -528,18 +498,6 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||||
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (panel->backlight.edp.vesa.luminance_control_support) {
|
|
||||||
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER,
|
|
||||||
DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE);
|
|
||||||
|
|
||||||
if (ret == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!intel_dp_aux_vesa_set_luminance(connector, level))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!panel->backlight.edp.vesa.info.aux_enable) {
|
if (!panel->backlight.edp.vesa.info.aux_enable) {
|
||||||
u32 pwm_level;
|
u32 pwm_level;
|
||||||
|
@ -580,13 +538,41 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector,
|
||||||
&connector->base.display_info.luminance_range;
|
&connector->base.display_info.luminance_range;
|
||||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u16 current_level;
|
u32 current_level;
|
||||||
u8 current_mode;
|
u8 current_mode;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (panel->backlight.edp.vesa.luminance_control_support) {
|
ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
|
||||||
|
luminance_range->max_luminance,
|
||||||
|
panel->vbt.backlight.pwm_freq_hz,
|
||||||
|
intel_dp->edp_dpcd, ¤t_level, ¤t_mode,
|
||||||
|
false);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
drm_dbg_kms(display->drm,
|
||||||
|
"[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n",
|
||||||
|
connector->base.base.id, connector->base.name,
|
||||||
|
dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable));
|
||||||
|
drm_dbg_kms(display->drm,
|
||||||
|
"[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n",
|
||||||
|
connector->base.base.id, connector->base.name,
|
||||||
|
dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set));
|
||||||
|
|
||||||
|
if (!panel->backlight.edp.vesa.info.aux_set ||
|
||||||
|
!panel->backlight.edp.vesa.info.aux_enable) {
|
||||||
|
ret = panel->backlight.pwm_funcs->setup(connector, pipe);
|
||||||
|
if (ret < 0) {
|
||||||
|
drm_err(display->drm,
|
||||||
|
"[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n",
|
||||||
|
connector->base.base.id, connector->base.name, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panel->backlight.edp.vesa.info.luminance_set) {
|
||||||
if (luminance_range->max_luminance) {
|
if (luminance_range->max_luminance) {
|
||||||
panel->backlight.max = luminance_range->max_luminance;
|
panel->backlight.max = panel->backlight.edp.vesa.info.max;
|
||||||
panel->backlight.min = luminance_range->min_luminance;
|
panel->backlight.min = luminance_range->min_luminance;
|
||||||
} else {
|
} else {
|
||||||
panel->backlight.max = 512;
|
panel->backlight.max = 512;
|
||||||
|
@ -597,54 +583,26 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector,
|
||||||
drm_dbg_kms(display->drm,
|
drm_dbg_kms(display->drm,
|
||||||
"[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n",
|
"[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n",
|
||||||
connector->base.base.id, connector->base.name);
|
connector->base.base.id, connector->base.name);
|
||||||
} else {
|
} else if (panel->backlight.edp.vesa.info.aux_set) {
|
||||||
ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
|
panel->backlight.max = panel->backlight.edp.vesa.info.max;
|
||||||
panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
|
panel->backlight.min = 0;
|
||||||
¤t_level, ¤t_mode);
|
if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
|
||||||
if (ret < 0)
|
panel->backlight.level = current_level;
|
||||||
return ret;
|
panel->backlight.enabled = panel->backlight.level != 0;
|
||||||
|
|
||||||
drm_dbg_kms(display->drm,
|
|
||||||
"[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n",
|
|
||||||
connector->base.base.id, connector->base.name,
|
|
||||||
dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable));
|
|
||||||
drm_dbg_kms(display->drm,
|
|
||||||
"[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n",
|
|
||||||
connector->base.base.id, connector->base.name,
|
|
||||||
dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set));
|
|
||||||
|
|
||||||
if (!panel->backlight.edp.vesa.info.aux_set ||
|
|
||||||
!panel->backlight.edp.vesa.info.aux_enable) {
|
|
||||||
ret = panel->backlight.pwm_funcs->setup(connector, pipe);
|
|
||||||
if (ret < 0) {
|
|
||||||
drm_err(display->drm,
|
|
||||||
"[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n",
|
|
||||||
connector->base.base.id, connector->base.name, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (panel->backlight.edp.vesa.info.aux_set) {
|
|
||||||
panel->backlight.max = panel->backlight.edp.vesa.info.max;
|
|
||||||
panel->backlight.min = 0;
|
|
||||||
if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
|
|
||||||
panel->backlight.level = current_level;
|
|
||||||
panel->backlight.enabled = panel->backlight.level != 0;
|
|
||||||
} else {
|
|
||||||
panel->backlight.level = panel->backlight.max;
|
|
||||||
panel->backlight.enabled = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
panel->backlight.max = panel->backlight.pwm_level_max;
|
panel->backlight.level = panel->backlight.max;
|
||||||
panel->backlight.min = panel->backlight.pwm_level_min;
|
panel->backlight.enabled = false;
|
||||||
if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
|
}
|
||||||
panel->backlight.level =
|
} else {
|
||||||
panel->backlight.pwm_funcs->get(connector, pipe);
|
panel->backlight.max = panel->backlight.pwm_level_max;
|
||||||
panel->backlight.enabled = panel->backlight.pwm_enabled;
|
panel->backlight.min = panel->backlight.pwm_level_min;
|
||||||
} else {
|
if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
|
||||||
panel->backlight.level = panel->backlight.max;
|
panel->backlight.level =
|
||||||
panel->backlight.enabled = false;
|
panel->backlight.pwm_funcs->get(connector, pipe);
|
||||||
}
|
panel->backlight.enabled = panel->backlight.pwm_enabled;
|
||||||
|
} else {
|
||||||
|
panel->backlight.level = panel->backlight.max;
|
||||||
|
panel->backlight.enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1839,7 +1839,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
|
||||||
backlight = nv_connector->backlight;
|
backlight = nv_connector->backlight;
|
||||||
if (backlight && backlight->uses_dpcd)
|
if (backlight && backlight->uses_dpcd)
|
||||||
drm_edp_backlight_enable(&nv_connector->aux, &backlight->edp_info,
|
drm_edp_backlight_enable(&nv_connector->aux, &backlight->edp_info,
|
||||||
(u16)backlight->dev->props.brightness);
|
backlight->dev->props.brightness);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -245,7 +245,7 @@ nv50_backlight_init(struct nouveau_backlight *bl,
|
||||||
|
|
||||||
if (nv_conn->type == DCB_CONNECTOR_eDP) {
|
if (nv_conn->type == DCB_CONNECTOR_eDP) {
|
||||||
int ret;
|
int ret;
|
||||||
u16 current_level;
|
u32 current_level;
|
||||||
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
|
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
|
||||||
u8 current_mode;
|
u8 current_mode;
|
||||||
|
|
||||||
|
@ -261,8 +261,9 @@ nv50_backlight_init(struct nouveau_backlight *bl,
|
||||||
NV_DEBUG(drm, "DPCD backlight controls supported on %s\n",
|
NV_DEBUG(drm, "DPCD backlight controls supported on %s\n",
|
||||||
nv_conn->base.name);
|
nv_conn->base.name);
|
||||||
|
|
||||||
ret = drm_edp_backlight_init(&nv_conn->aux, &bl->edp_info, 0, edp_dpcd,
|
ret = drm_edp_backlight_init(&nv_conn->aux, &bl->edp_info,
|
||||||
¤t_level, ¤t_mode);
|
0, 0, edp_dpcd,
|
||||||
|
¤t_level, ¤t_mode, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,16 @@ config DRM_PANEL_HIMAX_HX83112A
|
||||||
Say Y here if you want to enable support for Himax HX83112A-based
|
Say Y here if you want to enable support for Himax HX83112A-based
|
||||||
display panels, such as the one found in the Fairphone 4 smartphone.
|
display panels, such as the one found in the Fairphone 4 smartphone.
|
||||||
|
|
||||||
|
config DRM_PANEL_HIMAX_HX83112B
|
||||||
|
tristate "Himax HX83112B-based DSI panel"
|
||||||
|
depends on OF
|
||||||
|
depends on DRM_MIPI_DSI
|
||||||
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
|
select DRM_KMS_HELPER
|
||||||
|
help
|
||||||
|
Say Y here if you want to enable support for Himax HX83112B-based
|
||||||
|
display panels, such as the one found in the Fairphone 3 smartphone.
|
||||||
|
|
||||||
config DRM_PANEL_HIMAX_HX8394
|
config DRM_PANEL_HIMAX_HX8394
|
||||||
tristate "HIMAX HX8394 MIPI-DSI LCD panels"
|
tristate "HIMAX HX8394 MIPI-DSI LCD panels"
|
||||||
depends on OF
|
depends on OF
|
||||||
|
|
|
@ -20,6 +20,7 @@ obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d
|
||||||
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8279) += panel-himax-hx8279.o
|
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8279) += panel-himax-hx8279.o
|
||||||
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o
|
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o
|
||||||
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o
|
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o
|
||||||
|
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o
|
||||||
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
|
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
|
||||||
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
|
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
|
||||||
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
|
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
|
||||||
|
|
|
@ -1967,6 +1967,7 @@ static const struct edp_panel_entry edp_panels[] = {
|
||||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x115e, &delay_200_500_e80_d50, "N116BCA-EA1"),
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x115e, &delay_200_500_e80_d50, "N116BCA-EA1"),
|
||||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"),
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"),
|
||||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"),
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"),
|
||||||
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"),
|
||||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
|
||||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"),
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"),
|
||||||
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"),
|
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"),
|
||||||
|
|
|
@ -0,0 +1,430 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
|
||||||
|
* Copyright (c) 2025 Luca Weiss <luca@lucaweiss.eu>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/backlight.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
|
#include <video/mipi_display.h>
|
||||||
|
|
||||||
|
#include <drm/drm_mipi_dsi.h>
|
||||||
|
#include <drm/drm_modes.h>
|
||||||
|
#include <drm/drm_panel.h>
|
||||||
|
#include <drm/drm_probe_helper.h>
|
||||||
|
|
||||||
|
/* Manufacturer specific DSI commands */
|
||||||
|
#define HX83112B_SETPOWER1 0xb1
|
||||||
|
#define HX83112B_SETDISP 0xb2
|
||||||
|
#define HX83112B_SETDRV 0xb4
|
||||||
|
#define HX83112B_SETEXTC 0xb9
|
||||||
|
#define HX83112B_SETBANK 0xbd
|
||||||
|
#define HX83112B_SETDGCLUT 0xc1
|
||||||
|
#define HX83112B_SETDISMO 0xc2
|
||||||
|
#define HX83112B_UNKNOWN1 0xc6
|
||||||
|
#define HX83112B_SETPANEL 0xcc
|
||||||
|
#define HX83112B_UNKNOWN2 0xd1
|
||||||
|
#define HX83112B_SETPOWER2 0xd2
|
||||||
|
#define HX83112B_SETGIP0 0xd3
|
||||||
|
#define HX83112B_SETGIP1 0xd5
|
||||||
|
#define HX83112B_SETGIP2 0xd6
|
||||||
|
#define HX83112B_SETGIP3 0xd8
|
||||||
|
#define HX83112B_SETIDLE 0xdd
|
||||||
|
#define HX83112B_UNKNOWN3 0xe7
|
||||||
|
#define HX83112B_UNKNOWN4 0xe9
|
||||||
|
|
||||||
|
struct hx83112b_panel {
|
||||||
|
struct drm_panel panel;
|
||||||
|
struct mipi_dsi_device *dsi;
|
||||||
|
struct regulator_bulk_data *supplies;
|
||||||
|
struct gpio_desc *reset_gpio;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_bulk_data hx83112b_supplies[] = {
|
||||||
|
{ .supply = "iovcc" },
|
||||||
|
{ .supply = "vsn" },
|
||||||
|
{ .supply = "vsp" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct hx83112b_panel *to_hx83112b_panel(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
return container_of(panel, struct hx83112b_panel, panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hx83112b_reset(struct hx83112b_panel *ctx)
|
||||||
|
{
|
||||||
|
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||||
|
usleep_range(10000, 11000);
|
||||||
|
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||||
|
usleep_range(10000, 11000);
|
||||||
|
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||||
|
usleep_range(10000, 11000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hx83112b_on(struct hx83112b_panel *ctx)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||||
|
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETEXTC, 0x83, 0x11, 0x2b);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0x08, 0x70);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x04, 0x38, 0x08, 0x70);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER1,
|
||||||
|
0xf8, 0x27, 0x27, 0x00, 0x00, 0x0b, 0x0e,
|
||||||
|
0x0b, 0x0e, 0x33);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER2, 0x2d, 0x2d);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP,
|
||||||
|
0x80, 0x02, 0x18, 0x80, 0x70, 0x00, 0x08,
|
||||||
|
0x1c, 0x08, 0x11, 0x05);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd1);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x00, 0x08);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0xb5, 0x0a);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETIDLE,
|
||||||
|
0x00, 0x00, 0x08, 0x1c, 0x08, 0x34, 0x34,
|
||||||
|
0x88);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV,
|
||||||
|
0x65, 0x6b, 0x00, 0x00, 0xd0, 0xd4, 0x36,
|
||||||
|
0xcf, 0x06, 0xce, 0x00, 0xce, 0x00, 0x00,
|
||||||
|
0x00, 0x07, 0x00, 0x2a, 0x07, 0x01, 0x07,
|
||||||
|
0x00, 0x00, 0x2a);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc3);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 0x01, 0x67, 0x2a);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 0x01);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT,
|
||||||
|
0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef,
|
||||||
|
0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda,
|
||||||
|
0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe,
|
||||||
|
0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85,
|
||||||
|
0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e,
|
||||||
|
0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07,
|
||||||
|
0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25,
|
||||||
|
0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b,
|
||||||
|
0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT,
|
||||||
|
0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef,
|
||||||
|
0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda,
|
||||||
|
0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe,
|
||||||
|
0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85,
|
||||||
|
0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e,
|
||||||
|
0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07,
|
||||||
|
0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25,
|
||||||
|
0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b,
|
||||||
|
0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT,
|
||||||
|
0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef,
|
||||||
|
0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda,
|
||||||
|
0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe,
|
||||||
|
0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85,
|
||||||
|
0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e,
|
||||||
|
0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07,
|
||||||
|
0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25,
|
||||||
|
0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b,
|
||||||
|
0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0xc8);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPANEL, 0x08);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0,
|
||||||
|
0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
0x04, 0x00, 0x01, 0x13, 0x40, 0x04, 0x09,
|
||||||
|
0x09, 0x0b, 0x0b, 0x32, 0x10, 0x08, 0x00,
|
||||||
|
0x08, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32,
|
||||||
|
0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x0a,
|
||||||
|
0x08, 0x7b);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc5);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0xf7);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd4);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0x6e);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xef);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0x0c);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc8);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0xa1);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP1,
|
||||||
|
0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x18,
|
||||||
|
0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00,
|
||||||
|
0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18,
|
||||||
|
0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||||
|
0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35,
|
||||||
|
0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18,
|
||||||
|
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xfc,
|
||||||
|
0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP2,
|
||||||
|
0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x19,
|
||||||
|
0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00,
|
||||||
|
0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18,
|
||||||
|
0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||||
|
0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35,
|
||||||
|
0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18,
|
||||||
|
0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
|
||||||
|
0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa,
|
||||||
|
0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa,
|
||||||
|
0xab, 0xaf, 0xef, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||||
|
0xaf, 0xea, 0xaa);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
|
||||||
|
0xaa, 0xaa, 0xab, 0xaf, 0xea, 0xaa, 0xaa,
|
||||||
|
0xaa, 0xae, 0xaf, 0xea, 0xaa);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
|
||||||
|
0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa,
|
||||||
|
0xaa, 0xaa, 0xaf, 0xea, 0xaa);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
|
||||||
|
0xba, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa,
|
||||||
|
0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xba, 0xaa,
|
||||||
|
0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||||
|
0xaf, 0xea, 0xaa);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xe4);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x17, 0x69);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
|
||||||
|
0x09, 0x09, 0x00, 0x07, 0xe8, 0x00, 0x26,
|
||||||
|
0x00, 0x07, 0x00, 0x00, 0xe8, 0x32, 0x00,
|
||||||
|
0xe9, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x01, 0x00, 0x12, 0x04);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
|
||||||
|
0x02, 0x00, 0x01, 0x20, 0x01, 0x18, 0x08,
|
||||||
|
0xa8, 0x09);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x20, 0x20, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
|
||||||
|
0x00, 0xdc, 0x11, 0x70, 0x00, 0x20);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc9);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
|
||||||
|
0x2a, 0xce, 0x02, 0x70, 0x01, 0x04);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN2, 0x27);
|
||||||
|
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||||
|
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||||
|
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||||
|
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||||
|
mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000);
|
||||||
|
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
|
||||||
|
0x24);
|
||||||
|
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||||
|
|
||||||
|
return dsi_ctx.accum_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hx83112b_off(struct hx83112b_panel *ctx)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||||
|
|
||||||
|
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||||
|
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||||
|
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||||
|
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||||
|
|
||||||
|
return dsi_ctx.accum_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hx83112b_prepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct hx83112b_panel *ctx = to_hx83112b_panel(panel);
|
||||||
|
struct device *dev = &ctx->dsi->dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regulator_bulk_enable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "Failed to enable regulators: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hx83112b_reset(ctx);
|
||||||
|
|
||||||
|
ret = hx83112b_on(ctx);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "Failed to initialize panel: %d\n", ret);
|
||||||
|
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||||
|
regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hx83112b_unprepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct hx83112b_panel *ctx = to_hx83112b_panel(panel);
|
||||||
|
struct device *dev = &ctx->dsi->dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = hx83112b_off(ctx);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
|
||||||
|
|
||||||
|
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||||
|
regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_display_mode hx83112b_mode = {
|
||||||
|
.clock = (1080 + 40 + 4 + 12) * (2160 + 32 + 2 + 2) * 60 / 1000,
|
||||||
|
.hdisplay = 1080,
|
||||||
|
.hsync_start = 1080 + 40,
|
||||||
|
.hsync_end = 1080 + 40 + 4,
|
||||||
|
.htotal = 1080 + 40 + 4 + 12,
|
||||||
|
.vdisplay = 2160,
|
||||||
|
.vsync_start = 2160 + 32,
|
||||||
|
.vsync_end = 2160 + 32 + 2,
|
||||||
|
.vtotal = 2160 + 32 + 2 + 2,
|
||||||
|
.width_mm = 65,
|
||||||
|
.height_mm = 128,
|
||||||
|
.type = DRM_MODE_TYPE_DRIVER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hx83112b_get_modes(struct drm_panel *panel,
|
||||||
|
struct drm_connector *connector)
|
||||||
|
{
|
||||||
|
return drm_connector_helper_get_modes_fixed(connector, &hx83112b_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_panel_funcs hx83112b_panel_funcs = {
|
||||||
|
.prepare = hx83112b_prepare,
|
||||||
|
.unprepare = hx83112b_unprepare,
|
||||||
|
.get_modes = hx83112b_get_modes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hx83112b_bl_update_status(struct backlight_device *bl)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_device *dsi = bl_get_data(bl);
|
||||||
|
u16 brightness = backlight_get_brightness(bl);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct backlight_ops hx83112b_bl_ops = {
|
||||||
|
.update_status = hx83112b_bl_update_status,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct backlight_device *
|
||||||
|
hx83112b_create_backlight(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct device *dev = &dsi->dev;
|
||||||
|
const struct backlight_properties props = {
|
||||||
|
.type = BACKLIGHT_RAW,
|
||||||
|
.brightness = 4095,
|
||||||
|
.max_brightness = 4095,
|
||||||
|
};
|
||||||
|
|
||||||
|
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
|
||||||
|
&hx83112b_bl_ops, &props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hx83112b_probe(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct device *dev = &dsi->dev;
|
||||||
|
struct hx83112b_panel *ctx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ctx = devm_drm_panel_alloc(dev, struct hx83112b_panel, panel,
|
||||||
|
&hx83112b_panel_funcs,
|
||||||
|
DRM_MODE_CONNECTOR_DSI);
|
||||||
|
if (IS_ERR(ctx))
|
||||||
|
return PTR_ERR(ctx);
|
||||||
|
|
||||||
|
ret = devm_regulator_bulk_get_const(dev,
|
||||||
|
ARRAY_SIZE(hx83112b_supplies),
|
||||||
|
hx83112b_supplies,
|
||||||
|
&ctx->supplies);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||||
|
if (IS_ERR(ctx->reset_gpio))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
||||||
|
"Failed to get reset-gpios\n");
|
||||||
|
|
||||||
|
ctx->dsi = dsi;
|
||||||
|
mipi_dsi_set_drvdata(dsi, ctx);
|
||||||
|
|
||||||
|
dsi->lanes = 4;
|
||||||
|
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||||
|
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
|
||||||
|
MIPI_DSI_CLOCK_NON_CONTINUOUS |
|
||||||
|
MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
ctx->panel.prepare_prev_first = true;
|
||||||
|
|
||||||
|
ctx->panel.backlight = hx83112b_create_backlight(dsi);
|
||||||
|
if (IS_ERR(ctx->panel.backlight))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
|
||||||
|
"Failed to create backlight\n");
|
||||||
|
|
||||||
|
drm_panel_add(&ctx->panel);
|
||||||
|
|
||||||
|
ret = mipi_dsi_attach(dsi);
|
||||||
|
if (ret < 0) {
|
||||||
|
drm_panel_remove(&ctx->panel);
|
||||||
|
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hx83112b_remove(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct hx83112b_panel *ctx = mipi_dsi_get_drvdata(dsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mipi_dsi_detach(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
|
||||||
|
|
||||||
|
drm_panel_remove(&ctx->panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id hx83112b_of_match[] = {
|
||||||
|
{ .compatible = "djn,98-03057-6598b-i" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, hx83112b_of_match);
|
||||||
|
|
||||||
|
static struct mipi_dsi_driver hx83112b_driver = {
|
||||||
|
.probe = hx83112b_probe,
|
||||||
|
.remove = hx83112b_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "panel-himax-hx83112b",
|
||||||
|
.of_match_table = hx83112b_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_mipi_dsi_driver(hx83112b_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("DRM driver for hx83112b-equipped DSI panels");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -36,12 +36,14 @@ static inline struct raydium_rm67200 *to_raydium_rm67200(struct drm_panel *panel
|
||||||
|
|
||||||
static void raydium_rm67200_reset(struct raydium_rm67200 *ctx)
|
static void raydium_rm67200_reset(struct raydium_rm67200 *ctx)
|
||||||
{
|
{
|
||||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
if (ctx->reset_gpio) {
|
||||||
msleep(60);
|
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
msleep(60);
|
||||||
msleep(60);
|
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
msleep(60);
|
||||||
msleep(60);
|
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||||
|
msleep(60);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raydium_rm67200_write(struct mipi_dsi_multi_context *ctx,
|
static void raydium_rm67200_write(struct mipi_dsi_multi_context *ctx,
|
||||||
|
@ -318,6 +320,7 @@ static void w552793baa_setup(struct mipi_dsi_multi_context *ctx)
|
||||||
static int raydium_rm67200_prepare(struct drm_panel *panel)
|
static int raydium_rm67200_prepare(struct drm_panel *panel)
|
||||||
{
|
{
|
||||||
struct raydium_rm67200 *ctx = to_raydium_rm67200(panel);
|
struct raydium_rm67200 *ctx = to_raydium_rm67200(panel);
|
||||||
|
struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = regulator_bulk_enable(ctx->num_supplies, ctx->supplies);
|
ret = regulator_bulk_enable(ctx->num_supplies, ctx->supplies);
|
||||||
|
@ -328,6 +331,12 @@ static int raydium_rm67200_prepare(struct drm_panel *panel)
|
||||||
|
|
||||||
msleep(60);
|
msleep(60);
|
||||||
|
|
||||||
|
ctx->panel_info->panel_setup(&mctx);
|
||||||
|
mipi_dsi_dcs_exit_sleep_mode_multi(&mctx);
|
||||||
|
mipi_dsi_msleep(&mctx, 120);
|
||||||
|
mipi_dsi_dcs_set_display_on_multi(&mctx);
|
||||||
|
mipi_dsi_msleep(&mctx, 30);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,20 +352,6 @@ static int raydium_rm67200_unprepare(struct drm_panel *panel)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raydium_rm67200_enable(struct drm_panel *panel)
|
|
||||||
{
|
|
||||||
struct raydium_rm67200 *rm67200 = to_raydium_rm67200(panel);
|
|
||||||
struct mipi_dsi_multi_context ctx = { .dsi = rm67200->dsi };
|
|
||||||
|
|
||||||
rm67200->panel_info->panel_setup(&ctx);
|
|
||||||
mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
|
|
||||||
mipi_dsi_msleep(&ctx, 120);
|
|
||||||
mipi_dsi_dcs_set_display_on_multi(&ctx);
|
|
||||||
mipi_dsi_msleep(&ctx, 30);
|
|
||||||
|
|
||||||
return ctx.accum_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int raydium_rm67200_disable(struct drm_panel *panel)
|
static int raydium_rm67200_disable(struct drm_panel *panel)
|
||||||
{
|
{
|
||||||
struct raydium_rm67200 *rm67200 = to_raydium_rm67200(panel);
|
struct raydium_rm67200 *rm67200 = to_raydium_rm67200(panel);
|
||||||
|
@ -381,7 +376,6 @@ static const struct drm_panel_funcs raydium_rm67200_funcs = {
|
||||||
.prepare = raydium_rm67200_prepare,
|
.prepare = raydium_rm67200_prepare,
|
||||||
.unprepare = raydium_rm67200_unprepare,
|
.unprepare = raydium_rm67200_unprepare,
|
||||||
.get_modes = raydium_rm67200_get_modes,
|
.get_modes = raydium_rm67200_get_modes,
|
||||||
.enable = raydium_rm67200_enable,
|
|
||||||
.disable = raydium_rm67200_disable,
|
.disable = raydium_rm67200_disable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -409,7 +403,7 @@ static int raydium_rm67200_probe(struct mipi_dsi_device *dsi)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||||
if (IS_ERR(ctx->reset_gpio))
|
if (IS_ERR(ctx->reset_gpio))
|
||||||
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
||||||
"Failed to get reset-gpios\n");
|
"Failed to get reset-gpios\n");
|
||||||
|
@ -470,6 +464,7 @@ static const struct raydium_rm67200_panel_info w552793baa_info = {
|
||||||
.vtotal = 1952,
|
.vtotal = 1952,
|
||||||
.width_mm = 68, /* 68.04mm */
|
.width_mm = 68, /* 68.04mm */
|
||||||
.height_mm = 121, /* 120.96mm */
|
.height_mm = 121, /* 120.96mm */
|
||||||
|
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
|
||||||
.type = DRM_MODE_TYPE_DRIVER,
|
.type = DRM_MODE_TYPE_DRIVER,
|
||||||
},
|
},
|
||||||
.regulators = w552793baa_regulators,
|
.regulators = w552793baa_regulators,
|
||||||
|
|
|
@ -244,7 +244,7 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = {
|
||||||
.init_func = s6d7aa0_lsl080al02_init,
|
.init_func = s6d7aa0_lsl080al02_init,
|
||||||
.off_func = s6d7aa0_lsl080al02_off,
|
.off_func = s6d7aa0_lsl080al02_off,
|
||||||
.drm_mode = &s6d7aa0_lsl080al02_mode,
|
.drm_mode = &s6d7aa0_lsl080al02_mode,
|
||||||
.mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP,
|
.mode_flags = MIPI_DSI_MODE_VIDEO_NO_HFP,
|
||||||
.bus_flags = 0,
|
.bus_flags = 0,
|
||||||
|
|
||||||
.has_backlight = false,
|
.has_backlight = false,
|
||||||
|
|
|
@ -992,7 +992,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
|
||||||
dsi->lanes = 4;
|
dsi->lanes = 4;
|
||||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
|
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
|
||||||
| MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
|
| MIPI_DSI_MODE_VIDEO_AUTO_VERT;
|
||||||
|
|
||||||
ret = s6e8aa0_parse_dt(ctx);
|
ret = s6e8aa0_parse_dt(ctx);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -297,8 +297,9 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev,
|
||||||
|
|
||||||
gpu_write64(ptdev, pwron_reg, mask);
|
gpu_write64(ptdev, pwron_reg, mask);
|
||||||
|
|
||||||
ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val,
|
ret = gpu_read64_relaxed_poll_timeout(ptdev, rdy_reg, val,
|
||||||
!(mask & val), 100, timeout_us);
|
(mask & val) == val,
|
||||||
|
100, timeout_us);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
drm_err(&ptdev->base, "timeout waiting on %s:%llx readiness",
|
drm_err(&ptdev->base, "timeout waiting on %s:%llx readiness",
|
||||||
blk_name, mask);
|
blk_name, mask);
|
||||||
|
|
|
@ -200,12 +200,36 @@ static struct dma_fence *mock_sched_run_job(struct drm_sched_job *sched_job)
|
||||||
return &job->hw_fence;
|
return &job->hw_fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Normally, drivers would take appropriate measures in this callback, such as
|
||||||
|
* killing the entity the faulty job is associated with, resetting the hardware
|
||||||
|
* and / or resubmitting non-faulty jobs.
|
||||||
|
*
|
||||||
|
* For the mock scheduler, there are no hardware rings to be resetted nor jobs
|
||||||
|
* to be resubmitted. Thus, this function merely ensures that
|
||||||
|
* a) timedout fences get signaled properly and removed from the pending list
|
||||||
|
* b) the mock scheduler framework gets informed about the timeout via a flag
|
||||||
|
* c) The drm_sched_job, not longer needed, gets freed
|
||||||
|
*/
|
||||||
static enum drm_gpu_sched_stat
|
static enum drm_gpu_sched_stat
|
||||||
mock_sched_timedout_job(struct drm_sched_job *sched_job)
|
mock_sched_timedout_job(struct drm_sched_job *sched_job)
|
||||||
{
|
{
|
||||||
|
struct drm_mock_scheduler *sched = drm_sched_to_mock_sched(sched_job->sched);
|
||||||
struct drm_mock_sched_job *job = drm_sched_job_to_mock_job(sched_job);
|
struct drm_mock_sched_job *job = drm_sched_job_to_mock_job(sched_job);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
job->flags |= DRM_MOCK_SCHED_JOB_TIMEDOUT;
|
spin_lock_irqsave(&sched->lock, flags);
|
||||||
|
if (!dma_fence_is_signaled_locked(&job->hw_fence)) {
|
||||||
|
list_del(&job->link);
|
||||||
|
job->flags |= DRM_MOCK_SCHED_JOB_TIMEDOUT;
|
||||||
|
dma_fence_set_error(&job->hw_fence, -ETIMEDOUT);
|
||||||
|
dma_fence_signal_locked(&job->hw_fence);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&sched->lock, flags);
|
||||||
|
|
||||||
|
dma_fence_put(&job->hw_fence);
|
||||||
|
drm_sched_job_cleanup(sched_job);
|
||||||
|
/* Mock job itself is freed by the kunit framework. */
|
||||||
|
|
||||||
return DRM_GPU_SCHED_STAT_NOMINAL;
|
return DRM_GPU_SCHED_STAT_NOMINAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -735,13 +735,13 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
|
||||||
NULL : &result->dst_pitch;
|
NULL : &result->dst_pitch;
|
||||||
|
|
||||||
drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip,
|
drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip,
|
||||||
&fmtcnv_state, false);
|
&fmtcnv_state);
|
||||||
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
|
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
|
||||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||||
|
|
||||||
buf = dst.vaddr; /* restore original value of buf */
|
buf = dst.vaddr; /* restore original value of buf */
|
||||||
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip,
|
drm_fb_xrgb8888_to_rgb565be(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip,
|
||||||
&fmtcnv_state, true);
|
&fmtcnv_state);
|
||||||
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
|
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
|
||||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
|
KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
|
||||||
|
|
||||||
|
@ -749,7 +749,7 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
|
||||||
memset(buf, 0, dst_size);
|
memset(buf, 0, dst_size);
|
||||||
|
|
||||||
drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip,
|
drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, ¶ms->clip,
|
||||||
&fmtcnv_state, false);
|
&fmtcnv_state);
|
||||||
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
|
buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
|
||||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ tidss-y := tidss_crtc.o \
|
||||||
tidss_irq.o \
|
tidss_irq.o \
|
||||||
tidss_plane.o \
|
tidss_plane.o \
|
||||||
tidss_scale_coefs.o \
|
tidss_scale_coefs.o \
|
||||||
tidss_dispc.o
|
tidss_dispc.o \
|
||||||
|
tidss_oldi.o
|
||||||
|
|
||||||
obj-$(CONFIG_DRM_TIDSS) += tidss.o
|
obj-$(CONFIG_DRM_TIDSS) += tidss.o
|
||||||
|
|
|
@ -146,7 +146,7 @@ static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
|
||||||
const struct dispc_features dispc_am65x_feats = {
|
const struct dispc_features dispc_am65x_feats = {
|
||||||
.max_pclk_khz = {
|
.max_pclk_khz = {
|
||||||
[DISPC_VP_DPI] = 165000,
|
[DISPC_VP_DPI] = 165000,
|
||||||
[DISPC_VP_OLDI] = 165000,
|
[DISPC_VP_OLDI_AM65X] = 165000,
|
||||||
},
|
},
|
||||||
|
|
||||||
.scaling = {
|
.scaling = {
|
||||||
|
@ -176,7 +176,7 @@ const struct dispc_features dispc_am65x_feats = {
|
||||||
.vp_name = { "vp1", "vp2" },
|
.vp_name = { "vp1", "vp2" },
|
||||||
.ovr_name = { "ovr1", "ovr2" },
|
.ovr_name = { "ovr1", "ovr2" },
|
||||||
.vpclk_name = { "vp1", "vp2" },
|
.vpclk_name = { "vp1", "vp2" },
|
||||||
.vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI },
|
.vp_bus_type = { DISPC_VP_OLDI_AM65X, DISPC_VP_DPI },
|
||||||
|
|
||||||
.vp_feat = { .color = {
|
.vp_feat = { .color = {
|
||||||
.has_ctm = true,
|
.has_ctm = true,
|
||||||
|
@ -491,7 +491,7 @@ struct dispc_device {
|
||||||
void __iomem *base_ovr[TIDSS_MAX_PORTS];
|
void __iomem *base_ovr[TIDSS_MAX_PORTS];
|
||||||
void __iomem *base_vp[TIDSS_MAX_PORTS];
|
void __iomem *base_vp[TIDSS_MAX_PORTS];
|
||||||
|
|
||||||
struct regmap *oldi_io_ctrl;
|
struct regmap *am65x_oldi_io_ctrl;
|
||||||
|
|
||||||
struct clk *vp_clk[TIDSS_MAX_PORTS];
|
struct clk *vp_clk[TIDSS_MAX_PORTS];
|
||||||
|
|
||||||
|
@ -566,6 +566,29 @@ static u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
|
||||||
return ioread32(base + reg);
|
return ioread32(base + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tidss_configure_oldi(struct tidss_device *tidss, u32 hw_videoport,
|
||||||
|
u32 oldi_cfg)
|
||||||
|
{
|
||||||
|
u32 count = 0;
|
||||||
|
u32 oldi_reset_bit = BIT(5 + hw_videoport);
|
||||||
|
|
||||||
|
dispc_vp_write(tidss->dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, oldi_cfg);
|
||||||
|
|
||||||
|
while (!(oldi_reset_bit & dispc_read(tidss->dispc, DSS_SYSSTATUS)) &&
|
||||||
|
count < 10000)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (!(oldi_reset_bit & dispc_read(tidss->dispc, DSS_SYSSTATUS)))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tidss_disable_oldi(struct tidss_device *tidss, u32 hw_videoport)
|
||||||
|
{
|
||||||
|
dispc_vp_write(tidss->dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TRM gives bitfields as start:end, where start is the higher bit
|
* TRM gives bitfields as start:end, where start is the higher bit
|
||||||
* number. For example 7:0
|
* number. For example 7:0
|
||||||
|
@ -1016,13 +1039,11 @@ void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum dispc_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 };
|
|
||||||
|
|
||||||
struct dispc_bus_format {
|
struct dispc_bus_format {
|
||||||
u32 bus_fmt;
|
u32 bus_fmt;
|
||||||
u32 data_width;
|
u32 data_width;
|
||||||
bool is_oldi_fmt;
|
bool is_oldi_fmt;
|
||||||
enum dispc_oldi_mode_reg_val oldi_mode_reg_val;
|
enum oldi_mode_reg_val am65x_oldi_mode_reg_val;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct dispc_bus_format dispc_bus_formats[] = {
|
static const struct dispc_bus_format dispc_bus_formats[] = {
|
||||||
|
@ -1066,7 +1087,7 @@ int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI &&
|
if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI_AM65X &&
|
||||||
fmt->is_oldi_fmt) {
|
fmt->is_oldi_fmt) {
|
||||||
dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
|
dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
|
||||||
__func__, dispc->feat->vp_name[hw_videoport]);
|
__func__, dispc->feat->vp_name[hw_videoport]);
|
||||||
|
@ -1076,23 +1097,23 @@ int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispc_oldi_tx_power(struct dispc_device *dispc, bool power)
|
static void dispc_am65x_oldi_tx_power(struct dispc_device *dispc, bool power)
|
||||||
{
|
{
|
||||||
u32 val = power ? 0 : OLDI_PWRDN_TX;
|
u32 val = power ? 0 : AM65X_OLDI_PWRDN_TX;
|
||||||
|
|
||||||
if (WARN_ON(!dispc->oldi_io_ctrl))
|
if (WARN_ON(!dispc->am65x_oldi_io_ctrl))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL,
|
regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT0_IO_CTRL,
|
||||||
OLDI_PWRDN_TX, val);
|
AM65X_OLDI_PWRDN_TX, val);
|
||||||
regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL,
|
regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT1_IO_CTRL,
|
||||||
OLDI_PWRDN_TX, val);
|
AM65X_OLDI_PWRDN_TX, val);
|
||||||
regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL,
|
regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT2_IO_CTRL,
|
||||||
OLDI_PWRDN_TX, val);
|
AM65X_OLDI_PWRDN_TX, val);
|
||||||
regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL,
|
regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT3_IO_CTRL,
|
||||||
OLDI_PWRDN_TX, val);
|
AM65X_OLDI_PWRDN_TX, val);
|
||||||
regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL,
|
regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_CLK_IO_CTRL,
|
||||||
OLDI_PWRDN_TX, val);
|
AM65X_OLDI_PWRDN_TX, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispc_set_num_datalines(struct dispc_device *dispc,
|
static void dispc_set_num_datalines(struct dispc_device *dispc,
|
||||||
|
@ -1121,8 +1142,8 @@ static void dispc_set_num_datalines(struct dispc_device *dispc,
|
||||||
VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8);
|
VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport,
|
static void dispc_enable_am65x_oldi(struct dispc_device *dispc, u32 hw_videoport,
|
||||||
const struct dispc_bus_format *fmt)
|
const struct dispc_bus_format *fmt)
|
||||||
{
|
{
|
||||||
u32 oldi_cfg = 0;
|
u32 oldi_cfg = 0;
|
||||||
u32 oldi_reset_bit = BIT(5 + hw_videoport);
|
u32 oldi_reset_bit = BIT(5 + hw_videoport);
|
||||||
|
@ -1141,7 +1162,7 @@ static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport,
|
||||||
|
|
||||||
oldi_cfg |= BIT(7); /* DEPOL */
|
oldi_cfg |= BIT(7); /* DEPOL */
|
||||||
|
|
||||||
oldi_cfg = FLD_MOD(oldi_cfg, fmt->oldi_mode_reg_val, 3, 1);
|
oldi_cfg = FLD_MOD(oldi_cfg, fmt->am65x_oldi_mode_reg_val, 3, 1);
|
||||||
|
|
||||||
oldi_cfg |= BIT(12); /* SOFTRST */
|
oldi_cfg |= BIT(12); /* SOFTRST */
|
||||||
|
|
||||||
|
@ -1170,10 +1191,10 @@ void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
|
||||||
if (WARN_ON(!fmt))
|
if (WARN_ON(!fmt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
|
if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X) {
|
||||||
dispc_oldi_tx_power(dispc, true);
|
dispc_am65x_oldi_tx_power(dispc, true);
|
||||||
|
|
||||||
dispc_enable_oldi(dispc, hw_videoport, fmt);
|
dispc_enable_am65x_oldi(dispc, hw_videoport, fmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1229,7 +1250,7 @@ void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
|
||||||
align = true;
|
align = true;
|
||||||
|
|
||||||
/* always use DE_HIGH for OLDI */
|
/* always use DE_HIGH for OLDI */
|
||||||
if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI)
|
if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X)
|
||||||
ieo = false;
|
ieo = false;
|
||||||
|
|
||||||
dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ,
|
dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ,
|
||||||
|
@ -1255,10 +1276,10 @@ void dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport)
|
||||||
|
|
||||||
void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport)
|
void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport)
|
||||||
{
|
{
|
||||||
if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
|
if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X) {
|
||||||
dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0);
|
dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0);
|
||||||
|
|
||||||
dispc_oldi_tx_power(dispc, false);
|
dispc_am65x_oldi_tx_power(dispc, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1420,7 +1441,6 @@ void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport)
|
||||||
* Calculate the percentage difference between the requested pixel clock rate
|
* Calculate the percentage difference between the requested pixel clock rate
|
||||||
* and the effective rate resulting from calculating the clock divider value.
|
* and the effective rate resulting from calculating the clock divider value.
|
||||||
*/
|
*/
|
||||||
static
|
|
||||||
unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
|
unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
|
||||||
{
|
{
|
||||||
int r = rate / 100, rr = real_rate / 100;
|
int r = rate / 100, rr = real_rate / 100;
|
||||||
|
@ -2852,15 +2872,15 @@ static int dispc_iomap_resource(struct platform_device *pdev, const char *name,
|
||||||
static int dispc_init_am65x_oldi_io_ctrl(struct device *dev,
|
static int dispc_init_am65x_oldi_io_ctrl(struct device *dev,
|
||||||
struct dispc_device *dispc)
|
struct dispc_device *dispc)
|
||||||
{
|
{
|
||||||
dispc->oldi_io_ctrl =
|
dispc->am65x_oldi_io_ctrl =
|
||||||
syscon_regmap_lookup_by_phandle(dev->of_node,
|
syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||||
"ti,am65x-oldi-io-ctrl");
|
"ti,am65x-oldi-io-ctrl");
|
||||||
if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) {
|
if (PTR_ERR(dispc->am65x_oldi_io_ctrl) == -ENODEV) {
|
||||||
dispc->oldi_io_ctrl = NULL;
|
dispc->am65x_oldi_io_ctrl = NULL;
|
||||||
} else if (IS_ERR(dispc->oldi_io_ctrl)) {
|
} else if (IS_ERR(dispc->am65x_oldi_io_ctrl)) {
|
||||||
dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n",
|
dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n",
|
||||||
__func__, PTR_ERR(dispc->oldi_io_ctrl));
|
__func__, PTR_ERR(dispc->am65x_oldi_io_ctrl));
|
||||||
return PTR_ERR(dispc->oldi_io_ctrl);
|
return PTR_ERR(dispc->am65x_oldi_io_ctrl);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ struct dispc_errata {
|
||||||
|
|
||||||
enum dispc_vp_bus_type {
|
enum dispc_vp_bus_type {
|
||||||
DISPC_VP_DPI, /* DPI output */
|
DISPC_VP_DPI, /* DPI output */
|
||||||
DISPC_VP_OLDI, /* OLDI (LVDS) output */
|
DISPC_VP_OLDI_AM65X, /* OLDI (LVDS) output for AM65x DSS */
|
||||||
DISPC_VP_INTERNAL, /* SoC internal routing */
|
DISPC_VP_INTERNAL, /* SoC internal routing */
|
||||||
DISPC_VP_TIED_OFF, /* Tied off / Unavailable */
|
DISPC_VP_TIED_OFF, /* Tied off / Unavailable */
|
||||||
DISPC_VP_MAX_BUS_TYPE,
|
DISPC_VP_MAX_BUS_TYPE,
|
||||||
|
@ -101,6 +101,11 @@ extern const struct dispc_features dispc_am62l_feats;
|
||||||
extern const struct dispc_features dispc_am65x_feats;
|
extern const struct dispc_features dispc_am65x_feats;
|
||||||
extern const struct dispc_features dispc_j721e_feats;
|
extern const struct dispc_features dispc_j721e_feats;
|
||||||
|
|
||||||
|
int tidss_configure_oldi(struct tidss_device *tidss, u32 hw_videoport,
|
||||||
|
u32 oldi_cfg);
|
||||||
|
void tidss_disable_oldi(struct tidss_device *tidss, u32 hw_videoport);
|
||||||
|
unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate);
|
||||||
|
|
||||||
void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask);
|
void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask);
|
||||||
dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc);
|
dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc);
|
||||||
|
|
||||||
|
|
|
@ -226,18 +226,35 @@ enum dispc_common_regs {
|
||||||
#define DISPC_VP_DSS_DMA_THREADSIZE 0x170 /* J721E */
|
#define DISPC_VP_DSS_DMA_THREADSIZE 0x170 /* J721E */
|
||||||
#define DISPC_VP_DSS_DMA_THREADSIZE_STATUS 0x174 /* J721E */
|
#define DISPC_VP_DSS_DMA_THREADSIZE_STATUS 0x174 /* J721E */
|
||||||
|
|
||||||
|
/* OLDI Config Bits (DISPC_VP_DSS_OLDI_CFG) */
|
||||||
|
#define OLDI_ENABLE BIT(0)
|
||||||
|
#define OLDI_MAP (BIT(1) | BIT(2) | BIT(3))
|
||||||
|
#define OLDI_SRC BIT(4)
|
||||||
|
#define OLDI_CLONE_MODE BIT(5)
|
||||||
|
#define OLDI_MASTERSLAVE BIT(6)
|
||||||
|
#define OLDI_DEPOL BIT(7)
|
||||||
|
#define OLDI_MSB BIT(8)
|
||||||
|
#define OLDI_LBEN BIT(9)
|
||||||
|
#define OLDI_LBDATA BIT(10)
|
||||||
|
#define OLDI_DUALMODESYNC BIT(11)
|
||||||
|
#define OLDI_SOFTRST BIT(12)
|
||||||
|
#define OLDI_TPATCFG BIT(13)
|
||||||
|
|
||||||
|
/* LVDS Format values for OLDI_MAP field in DISPC_VP_OLDI_CFG register */
|
||||||
|
enum oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OLDI IO_CTRL register offsets. On AM654 the registers are found
|
* OLDI IO_CTRL register offsets. On AM654 the registers are found
|
||||||
* from CTRL_MMR0, there the syscon regmap should map 0x14 bytes from
|
* from CTRL_MMR0, there the syscon regmap should map 0x14 bytes from
|
||||||
* CTRLMMR0P1_OLDI_DAT0_IO_CTRL to CTRLMMR0P1_OLDI_CLK_IO_CTRL
|
* CTRLMMR0P1_OLDI_DAT0_IO_CTRL to CTRLMMR0P1_OLDI_CLK_IO_CTRL
|
||||||
* register range.
|
* register range.
|
||||||
*/
|
*/
|
||||||
#define OLDI_DAT0_IO_CTRL 0x00
|
#define AM65X_OLDI_DAT0_IO_CTRL 0x00
|
||||||
#define OLDI_DAT1_IO_CTRL 0x04
|
#define AM65X_OLDI_DAT1_IO_CTRL 0x04
|
||||||
#define OLDI_DAT2_IO_CTRL 0x08
|
#define AM65X_OLDI_DAT2_IO_CTRL 0x08
|
||||||
#define OLDI_DAT3_IO_CTRL 0x0C
|
#define AM65X_OLDI_DAT3_IO_CTRL 0x0C
|
||||||
#define OLDI_CLK_IO_CTRL 0x10
|
#define AM65X_OLDI_CLK_IO_CTRL 0x10
|
||||||
|
|
||||||
#define OLDI_PWRDN_TX BIT(8)
|
#define AM65X_OLDI_PWRDN_TX BIT(8)
|
||||||
|
|
||||||
#endif /* __TIDSS_DISPC_REGS_H */
|
#endif /* __TIDSS_DISPC_REGS_H */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "tidss_drv.h"
|
#include "tidss_drv.h"
|
||||||
#include "tidss_kms.h"
|
#include "tidss_kms.h"
|
||||||
#include "tidss_irq.h"
|
#include "tidss_irq.h"
|
||||||
|
#include "tidss_oldi.h"
|
||||||
|
|
||||||
/* Power management */
|
/* Power management */
|
||||||
|
|
||||||
|
@ -147,6 +148,10 @@ static int tidss_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = tidss_oldi_init(tidss);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "failed to init OLDI\n");
|
||||||
|
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
pm_runtime_set_autosuspend_delay(dev, 1000);
|
pm_runtime_set_autosuspend_delay(dev, 1000);
|
||||||
|
@ -203,6 +208,8 @@ err_runtime_suspend:
|
||||||
pm_runtime_dont_use_autosuspend(dev);
|
pm_runtime_dont_use_autosuspend(dev);
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
tidss_oldi_deinit(tidss);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +234,8 @@ static void tidss_remove(struct platform_device *pdev)
|
||||||
pm_runtime_dont_use_autosuspend(dev);
|
pm_runtime_dont_use_autosuspend(dev);
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
tidss_oldi_deinit(tidss);
|
||||||
|
|
||||||
/* devm allocated dispc goes away with the dev so mark it NULL */
|
/* devm allocated dispc goes away with the dev so mark it NULL */
|
||||||
dispc_remove(tidss);
|
dispc_remove(tidss);
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,10 @@
|
||||||
|
|
||||||
#define TIDSS_MAX_PORTS 4
|
#define TIDSS_MAX_PORTS 4
|
||||||
#define TIDSS_MAX_PLANES 4
|
#define TIDSS_MAX_PLANES 4
|
||||||
|
#define TIDSS_MAX_OLDI_TXES 2
|
||||||
|
|
||||||
typedef u32 dispc_irq_t;
|
typedef u32 dispc_irq_t;
|
||||||
|
struct tidss_oldi;
|
||||||
|
|
||||||
struct tidss_device {
|
struct tidss_device {
|
||||||
struct drm_device ddev; /* DRM device for DSS */
|
struct drm_device ddev; /* DRM device for DSS */
|
||||||
|
@ -27,6 +29,9 @@ struct tidss_device {
|
||||||
unsigned int num_planes;
|
unsigned int num_planes;
|
||||||
struct drm_plane *planes[TIDSS_MAX_PLANES];
|
struct drm_plane *planes[TIDSS_MAX_PLANES];
|
||||||
|
|
||||||
|
unsigned int num_oldis;
|
||||||
|
struct tidss_oldi *oldis[TIDSS_MAX_OLDI_TXES];
|
||||||
|
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
|
|
||||||
/* protects the irq masks field and irqenable/irqstatus registers */
|
/* protects the irq masks field and irqenable/irqstatus registers */
|
||||||
|
|
|
@ -144,7 +144,7 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
|
||||||
dev_dbg(dev, "Setting up panel for port %d\n", i);
|
dev_dbg(dev, "Setting up panel for port %d\n", i);
|
||||||
|
|
||||||
switch (feat->vp_bus_type[i]) {
|
switch (feat->vp_bus_type[i]) {
|
||||||
case DISPC_VP_OLDI:
|
case DISPC_VP_OLDI_AM65X:
|
||||||
enc_type = DRM_MODE_ENCODER_LVDS;
|
enc_type = DRM_MODE_ENCODER_LVDS;
|
||||||
conn_type = DRM_MODE_CONNECTOR_LVDS;
|
conn_type = DRM_MODE_CONNECTOR_LVDS;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,598 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 - Texas Instruments Incorporated
|
||||||
|
*
|
||||||
|
* Aradhya Bhatia <a-bhatia1@ti.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_graph.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/media-bus-format.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic_helper.h>
|
||||||
|
#include <drm/drm_bridge.h>
|
||||||
|
#include <drm/drm_of.h>
|
||||||
|
|
||||||
|
#include "tidss_dispc.h"
|
||||||
|
#include "tidss_dispc_regs.h"
|
||||||
|
#include "tidss_oldi.h"
|
||||||
|
|
||||||
|
struct tidss_oldi {
|
||||||
|
struct tidss_device *tidss;
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
struct drm_bridge bridge;
|
||||||
|
struct drm_bridge *next_bridge;
|
||||||
|
|
||||||
|
enum tidss_oldi_link_type link_type;
|
||||||
|
const struct oldi_bus_format *bus_format;
|
||||||
|
u32 oldi_instance;
|
||||||
|
int companion_instance; /* -1 when OLDI TX operates in Single-Link */
|
||||||
|
u32 parent_vp;
|
||||||
|
|
||||||
|
struct clk *serial;
|
||||||
|
struct regmap *io_ctrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct oldi_bus_format {
|
||||||
|
u32 bus_fmt;
|
||||||
|
u32 data_width;
|
||||||
|
enum oldi_mode_reg_val oldi_mode_reg_val;
|
||||||
|
u32 input_bus_fmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct oldi_bus_format oldi_bus_formats[] = {
|
||||||
|
{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, SPWG_18, MEDIA_BUS_FMT_RGB666_1X18 },
|
||||||
|
{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, SPWG_24, MEDIA_BUS_FMT_RGB888_1X24 },
|
||||||
|
{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, JEIDA_24, MEDIA_BUS_FMT_RGB888_1X24 },
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OLDI_IDLE_CLK_HZ 25000000 /*25 MHz */
|
||||||
|
|
||||||
|
static inline struct tidss_oldi *
|
||||||
|
drm_bridge_to_tidss_oldi(struct drm_bridge *bridge)
|
||||||
|
{
|
||||||
|
return container_of(bridge, struct tidss_oldi, bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tidss_oldi_bridge_attach(struct drm_bridge *bridge,
|
||||||
|
struct drm_encoder *encoder,
|
||||||
|
enum drm_bridge_attach_flags flags)
|
||||||
|
{
|
||||||
|
struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge);
|
||||||
|
|
||||||
|
if (!oldi->next_bridge) {
|
||||||
|
dev_err(oldi->dev,
|
||||||
|
"%s: OLDI%u Failure attach next bridge\n",
|
||||||
|
__func__, oldi->oldi_instance);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
|
||||||
|
dev_err(oldi->dev,
|
||||||
|
"%s: OLDI%u DRM_BRIDGE_ATTACH_NO_CONNECTOR is mandatory.\n",
|
||||||
|
__func__, oldi->oldi_instance);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drm_bridge_attach(encoder, oldi->next_bridge, bridge, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tidss_oldi_set_serial_clk(struct tidss_oldi *oldi, unsigned long rate)
|
||||||
|
{
|
||||||
|
unsigned long new_rate;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_set_rate(oldi->serial, rate);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(oldi->dev,
|
||||||
|
"OLDI%u: failed to set serial clk rate to %lu Hz\n",
|
||||||
|
oldi->oldi_instance, rate);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_rate = clk_get_rate(oldi->serial);
|
||||||
|
|
||||||
|
if (dispc_pclk_diff(rate, new_rate) > 5)
|
||||||
|
dev_warn(oldi->dev,
|
||||||
|
"OLDI%u Clock rate %lu differs over 5%% from requested %lu\n",
|
||||||
|
oldi->oldi_instance, new_rate, rate);
|
||||||
|
|
||||||
|
dev_dbg(oldi->dev, "OLDI%u: new rate %lu Hz (requested %lu Hz)\n",
|
||||||
|
oldi->oldi_instance, clk_get_rate(oldi->serial), rate);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tidss_oldi_tx_power(struct tidss_oldi *oldi, bool enable)
|
||||||
|
{
|
||||||
|
u32 mask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The power control bits are Active Low, and remain powered off by
|
||||||
|
* default. That is, the bits are set to 1. To power on the OLDI TXes,
|
||||||
|
* the bits must be cleared to 0. Since there are cases where not all
|
||||||
|
* OLDI TXes are being used, the power logic selectively powers them
|
||||||
|
* on.
|
||||||
|
* Setting the variable 'val' to particular bit masks, makes sure that
|
||||||
|
* the undesired OLDI TXes remain powered off.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
switch (oldi->link_type) {
|
||||||
|
case OLDI_MODE_SINGLE_LINK:
|
||||||
|
/* Power-on only the required OLDI TX's IO*/
|
||||||
|
mask = OLDI_PWRDOWN_TX(oldi->oldi_instance) | OLDI_PWRDN_BG;
|
||||||
|
break;
|
||||||
|
case OLDI_MODE_CLONE_SINGLE_LINK:
|
||||||
|
case OLDI_MODE_DUAL_LINK:
|
||||||
|
/* Power-on both the OLDI TXes' IOs */
|
||||||
|
mask = OLDI_PWRDOWN_TX(oldi->oldi_instance) |
|
||||||
|
OLDI_PWRDOWN_TX(oldi->companion_instance) |
|
||||||
|
OLDI_PWRDN_BG;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* This code execution should never reach here as any
|
||||||
|
* OLDI with an unsupported OLDI mode would never get
|
||||||
|
* registered in the first place.
|
||||||
|
* However, power-off the OLDI in concern just in case.
|
||||||
|
*/
|
||||||
|
mask = OLDI_PWRDOWN_TX(oldi->oldi_instance);
|
||||||
|
enable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (oldi->link_type) {
|
||||||
|
case OLDI_MODE_CLONE_SINGLE_LINK:
|
||||||
|
case OLDI_MODE_DUAL_LINK:
|
||||||
|
mask = OLDI_PWRDOWN_TX(oldi->oldi_instance) |
|
||||||
|
OLDI_PWRDOWN_TX(oldi->companion_instance) |
|
||||||
|
OLDI_PWRDN_BG;
|
||||||
|
break;
|
||||||
|
case OLDI_MODE_SINGLE_LINK:
|
||||||
|
default:
|
||||||
|
mask = OLDI_PWRDOWN_TX(oldi->oldi_instance);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regmap_update_bits(oldi->io_ctrl, OLDI_PD_CTRL, mask, enable ? 0 : mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tidss_oldi_config(struct tidss_oldi *oldi)
|
||||||
|
{
|
||||||
|
const struct oldi_bus_format *bus_fmt = NULL;
|
||||||
|
u32 oldi_cfg = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bus_fmt = oldi->bus_format;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MASTERSLAVE and SRC bits of OLDI Config are always set to 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (bus_fmt->data_width == 24)
|
||||||
|
oldi_cfg |= OLDI_MSB;
|
||||||
|
else if (bus_fmt->data_width != 18)
|
||||||
|
dev_warn(oldi->dev,
|
||||||
|
"OLDI%u: DSS port width %d not supported\n",
|
||||||
|
oldi->oldi_instance, bus_fmt->data_width);
|
||||||
|
|
||||||
|
oldi_cfg |= OLDI_DEPOL;
|
||||||
|
|
||||||
|
oldi_cfg = (oldi_cfg & (~OLDI_MAP)) | (bus_fmt->oldi_mode_reg_val << 1);
|
||||||
|
|
||||||
|
oldi_cfg |= OLDI_SOFTRST;
|
||||||
|
|
||||||
|
oldi_cfg |= OLDI_ENABLE;
|
||||||
|
|
||||||
|
switch (oldi->link_type) {
|
||||||
|
case OLDI_MODE_SINGLE_LINK:
|
||||||
|
/* All configuration is done for this mode. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OLDI_MODE_CLONE_SINGLE_LINK:
|
||||||
|
oldi_cfg |= OLDI_CLONE_MODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OLDI_MODE_DUAL_LINK:
|
||||||
|
/* data-mapping field also indicates dual-link mode */
|
||||||
|
oldi_cfg |= BIT(3);
|
||||||
|
oldi_cfg |= OLDI_DUALMODESYNC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(oldi->dev, "OLDI%u: Unsupported mode.\n",
|
||||||
|
oldi->oldi_instance);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tidss_configure_oldi(oldi->tidss, oldi->parent_vp, oldi_cfg);
|
||||||
|
if (ret == -ETIMEDOUT)
|
||||||
|
dev_warn(oldi->dev, "OLDI%u: timeout waiting for OLDI reset done.\n",
|
||||||
|
oldi->oldi_instance);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tidss_oldi_atomic_pre_enable(struct drm_bridge *bridge,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge);
|
||||||
|
struct drm_connector *connector;
|
||||||
|
struct drm_connector_state *conn_state;
|
||||||
|
struct drm_crtc_state *crtc_state;
|
||||||
|
struct drm_display_mode *mode;
|
||||||
|
|
||||||
|
if (oldi->link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
connector = drm_atomic_get_new_connector_for_encoder(state,
|
||||||
|
bridge->encoder);
|
||||||
|
if (WARN_ON(!connector))
|
||||||
|
return;
|
||||||
|
|
||||||
|
conn_state = drm_atomic_get_new_connector_state(state, connector);
|
||||||
|
if (WARN_ON(!conn_state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
|
||||||
|
if (WARN_ON(!crtc_state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mode = &crtc_state->adjusted_mode;
|
||||||
|
|
||||||
|
/* Configure the OLDI params*/
|
||||||
|
tidss_oldi_config(oldi);
|
||||||
|
|
||||||
|
/* Set the OLDI serial clock (7 times the pixel clock) */
|
||||||
|
tidss_oldi_set_serial_clk(oldi, mode->clock * 7 * 1000);
|
||||||
|
|
||||||
|
/* Enable OLDI IO power */
|
||||||
|
tidss_oldi_tx_power(oldi, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tidss_oldi_atomic_post_disable(struct drm_bridge *bridge,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge);
|
||||||
|
|
||||||
|
if (oldi->link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Disable OLDI IO power */
|
||||||
|
tidss_oldi_tx_power(oldi, false);
|
||||||
|
|
||||||
|
/* Set the OLDI serial clock to IDLE Frequency */
|
||||||
|
tidss_oldi_set_serial_clk(oldi, OLDI_IDLE_CLK_HZ);
|
||||||
|
|
||||||
|
/* Clear OLDI Config */
|
||||||
|
tidss_disable_oldi(oldi->tidss, oldi->parent_vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_INPUT_SEL_FORMATS 1
|
||||||
|
|
||||||
|
static u32 *tidss_oldi_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
||||||
|
struct drm_bridge_state *bridge_state,
|
||||||
|
struct drm_crtc_state *crtc_state,
|
||||||
|
struct drm_connector_state *conn_state,
|
||||||
|
u32 output_fmt,
|
||||||
|
unsigned int *num_input_fmts)
|
||||||
|
{
|
||||||
|
struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge);
|
||||||
|
u32 *input_fmts;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*num_input_fmts = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(oldi_bus_formats); i++)
|
||||||
|
if (oldi_bus_formats[i].bus_fmt == output_fmt)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == ARRAY_SIZE(oldi_bus_formats))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!input_fmts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*num_input_fmts = 1;
|
||||||
|
input_fmts[0] = oldi_bus_formats[i].input_bus_fmt;
|
||||||
|
oldi->bus_format = &oldi_bus_formats[i];
|
||||||
|
|
||||||
|
return input_fmts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_bridge_funcs tidss_oldi_bridge_funcs = {
|
||||||
|
.attach = tidss_oldi_bridge_attach,
|
||||||
|
.atomic_pre_enable = tidss_oldi_atomic_pre_enable,
|
||||||
|
.atomic_post_disable = tidss_oldi_atomic_post_disable,
|
||||||
|
.atomic_get_input_bus_fmts = tidss_oldi_atomic_get_input_bus_fmts,
|
||||||
|
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||||
|
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||||
|
.atomic_reset = drm_atomic_helper_bridge_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_oldi_mode(struct device_node *oldi_tx, int *companion_instance)
|
||||||
|
{
|
||||||
|
struct device_node *companion;
|
||||||
|
struct device_node *port0, *port1;
|
||||||
|
u32 companion_reg;
|
||||||
|
bool secondary_oldi = false;
|
||||||
|
int pixel_order;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find if the OLDI is paired with another OLDI for combined OLDI
|
||||||
|
* operation (dual-link or clone).
|
||||||
|
*/
|
||||||
|
companion = of_parse_phandle(oldi_tx, "ti,companion-oldi", 0);
|
||||||
|
if (!companion)
|
||||||
|
/*
|
||||||
|
* The OLDI TX does not have a companion, nor is it a
|
||||||
|
* secondary OLDI. It will operate independently.
|
||||||
|
*/
|
||||||
|
return OLDI_MODE_SINGLE_LINK;
|
||||||
|
|
||||||
|
if (of_property_read_u32(companion, "reg", &companion_reg))
|
||||||
|
return OLDI_MODE_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (companion_reg > (TIDSS_MAX_OLDI_TXES - 1))
|
||||||
|
/* Invalid companion OLDI reg value. */
|
||||||
|
return OLDI_MODE_UNSUPPORTED;
|
||||||
|
|
||||||
|
*companion_instance = (int)companion_reg;
|
||||||
|
|
||||||
|
if (of_property_read_bool(oldi_tx, "ti,secondary-oldi"))
|
||||||
|
secondary_oldi = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to work out if the sink is expecting us to function in
|
||||||
|
* dual-link mode. We do this by looking at the DT port nodes, the
|
||||||
|
* OLDI TX ports are connected to. If they are marked as expecting
|
||||||
|
* even pixels and odd pixels, then we need to enable dual-link.
|
||||||
|
*/
|
||||||
|
port0 = of_graph_get_port_by_id(oldi_tx, 1);
|
||||||
|
port1 = of_graph_get_port_by_id(companion, 1);
|
||||||
|
pixel_order = drm_of_lvds_get_dual_link_pixel_order(port0, port1);
|
||||||
|
of_node_put(port0);
|
||||||
|
of_node_put(port1);
|
||||||
|
of_node_put(companion);
|
||||||
|
|
||||||
|
switch (pixel_order) {
|
||||||
|
case -EINVAL:
|
||||||
|
/*
|
||||||
|
* The dual-link properties were not found in at least
|
||||||
|
* one of the sink nodes. Since 2 OLDI ports are present
|
||||||
|
* in the DT, it can be safely assumed that the required
|
||||||
|
* configuration is Clone Mode.
|
||||||
|
*/
|
||||||
|
return (secondary_oldi ? OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK :
|
||||||
|
OLDI_MODE_CLONE_SINGLE_LINK);
|
||||||
|
|
||||||
|
case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
|
||||||
|
/*
|
||||||
|
* Primary OLDI can only support "ODD" pixels. So, from its
|
||||||
|
* perspective, the pixel order has to be ODD-EVEN.
|
||||||
|
*/
|
||||||
|
return (secondary_oldi ? OLDI_MODE_UNSUPPORTED :
|
||||||
|
OLDI_MODE_DUAL_LINK);
|
||||||
|
|
||||||
|
case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
|
||||||
|
/*
|
||||||
|
* Secondary OLDI can only support "EVEN" pixels. So, from its
|
||||||
|
* perspective, the pixel order has to be EVEN-ODD.
|
||||||
|
*/
|
||||||
|
return (secondary_oldi ? OLDI_MODE_SECONDARY_DUAL_LINK :
|
||||||
|
OLDI_MODE_UNSUPPORTED);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return OLDI_MODE_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_parent_dss_vp(struct device_node *oldi_tx, u32 *parent_vp)
|
||||||
|
{
|
||||||
|
struct device_node *ep, *dss_port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ep = of_graph_get_endpoint_by_regs(oldi_tx, OLDI_INPUT_PORT, -1);
|
||||||
|
if (ep) {
|
||||||
|
dss_port = of_graph_get_remote_port(ep);
|
||||||
|
if (!dss_port) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto err_return_ep_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = of_property_read_u32(dss_port, "reg", parent_vp);
|
||||||
|
|
||||||
|
of_node_put(dss_port);
|
||||||
|
err_return_ep_port:
|
||||||
|
of_node_put(ep);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_bridge_timings default_tidss_oldi_timings = {
|
||||||
|
.input_bus_flags = DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE
|
||||||
|
| DRM_BUS_FLAG_DE_HIGH,
|
||||||
|
};
|
||||||
|
|
||||||
|
void tidss_oldi_deinit(struct tidss_device *tidss)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tidss->num_oldis; i++) {
|
||||||
|
if (tidss->oldis[i]) {
|
||||||
|
drm_bridge_remove(&tidss->oldis[i]->bridge);
|
||||||
|
tidss->oldis[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tidss_oldi_init(struct tidss_device *tidss)
|
||||||
|
{
|
||||||
|
struct tidss_oldi *oldi;
|
||||||
|
struct device_node *child;
|
||||||
|
struct drm_bridge *bridge;
|
||||||
|
u32 parent_vp, oldi_instance;
|
||||||
|
int companion_instance = -1;
|
||||||
|
enum tidss_oldi_link_type link_type = OLDI_MODE_UNSUPPORTED;
|
||||||
|
struct device_node *oldi_parent;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
tidss->num_oldis = 0;
|
||||||
|
|
||||||
|
oldi_parent = of_get_child_by_name(tidss->dev->of_node, "oldi-transmitters");
|
||||||
|
if (!oldi_parent)
|
||||||
|
/* Return gracefully */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for_each_available_child_of_node(oldi_parent, child) {
|
||||||
|
ret = get_parent_dss_vp(child, &parent_vp);
|
||||||
|
if (ret) {
|
||||||
|
if (ret == -ENODEV) {
|
||||||
|
/*
|
||||||
|
* ENODEV means that this particular OLDI node
|
||||||
|
* is not connected with the DSS, which is not
|
||||||
|
* a harmful case. There could be another OLDI
|
||||||
|
* which may still be connected.
|
||||||
|
* Continue to search for that.
|
||||||
|
*/
|
||||||
|
ret = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto err_put_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = of_property_read_u32(child, "reg", &oldi_instance);
|
||||||
|
if (ret)
|
||||||
|
goto err_put_node;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that it's confirmed that OLDI is connected with DSS,
|
||||||
|
* let's continue getting the OLDI sinks ahead and other OLDI
|
||||||
|
* properties.
|
||||||
|
*/
|
||||||
|
bridge = devm_drm_of_get_bridge(tidss->dev, child,
|
||||||
|
OLDI_OUTPUT_PORT, 0);
|
||||||
|
if (IS_ERR(bridge)) {
|
||||||
|
/*
|
||||||
|
* Either there was no OLDI sink in the devicetree, or
|
||||||
|
* the OLDI sink has not been added yet. In any case,
|
||||||
|
* return.
|
||||||
|
* We don't want to have an OLDI node connected to DSS
|
||||||
|
* but not to any sink.
|
||||||
|
*/
|
||||||
|
ret = dev_err_probe(tidss->dev, PTR_ERR(bridge),
|
||||||
|
"no panel/bridge for OLDI%u.\n",
|
||||||
|
oldi_instance);
|
||||||
|
goto err_put_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
link_type = get_oldi_mode(child, &companion_instance);
|
||||||
|
if (link_type == OLDI_MODE_UNSUPPORTED) {
|
||||||
|
ret = dev_err_probe(tidss->dev, -EINVAL,
|
||||||
|
"OLDI%u: Unsupported OLDI connection.\n",
|
||||||
|
oldi_instance);
|
||||||
|
goto err_put_node;
|
||||||
|
} else if ((link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) ||
|
||||||
|
(link_type == OLDI_MODE_CLONE_SINGLE_LINK)) {
|
||||||
|
/*
|
||||||
|
* The OLDI driver cannot support OLDI clone mode
|
||||||
|
* properly at present.
|
||||||
|
* The clone mode requires 2 working encoder-bridge
|
||||||
|
* pipelines, generating from the same crtc. The DRM
|
||||||
|
* framework does not support this at present. If
|
||||||
|
* there were to be, say, 2 OLDI sink bridges each
|
||||||
|
* connected to an OLDI TXes, they couldn't both be
|
||||||
|
* supported simultaneously.
|
||||||
|
* This driver still has some code pertaining to OLDI
|
||||||
|
* clone mode configuration in DSS hardware for future,
|
||||||
|
* when there is a better infrastructure in the DRM
|
||||||
|
* framework to support 2 encoder-bridge pipelines
|
||||||
|
* simultaneously.
|
||||||
|
* Till that time, this driver shall error out if it
|
||||||
|
* detects a clone mode configuration.
|
||||||
|
*/
|
||||||
|
ret = dev_err_probe(tidss->dev, -EOPNOTSUPP,
|
||||||
|
"The OLDI driver does not support Clone Mode at present.\n");
|
||||||
|
goto err_put_node;
|
||||||
|
} else if (link_type == OLDI_MODE_SECONDARY_DUAL_LINK) {
|
||||||
|
/*
|
||||||
|
* This is the secondary OLDI node, which serves as a
|
||||||
|
* companion to the primary OLDI, when it is configured
|
||||||
|
* for the dual-link mode. Since the primary OLDI will
|
||||||
|
* be a part of bridge chain, no need to put this one
|
||||||
|
* too. Continue onto the next OLDI node.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldi = devm_kzalloc(tidss->dev, sizeof(*oldi), GFP_KERNEL);
|
||||||
|
if (!oldi) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_put_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldi->parent_vp = parent_vp;
|
||||||
|
oldi->oldi_instance = oldi_instance;
|
||||||
|
oldi->companion_instance = companion_instance;
|
||||||
|
oldi->link_type = link_type;
|
||||||
|
oldi->dev = tidss->dev;
|
||||||
|
oldi->next_bridge = bridge;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only the primary OLDI needs to reference the io-ctrl system
|
||||||
|
* registers, and the serial clock.
|
||||||
|
* We don't require a check for secondary OLDI in dual-link mode
|
||||||
|
* because the driver will not create a drm_bridge instance.
|
||||||
|
* But the driver will need to create a drm_bridge instance,
|
||||||
|
* for secondary OLDI in clone mode (once it is supported).
|
||||||
|
*/
|
||||||
|
if (link_type != OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) {
|
||||||
|
oldi->io_ctrl = syscon_regmap_lookup_by_phandle(child,
|
||||||
|
"ti,oldi-io-ctrl");
|
||||||
|
if (IS_ERR(oldi->io_ctrl)) {
|
||||||
|
ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->io_ctrl),
|
||||||
|
"OLDI%u: syscon_regmap_lookup_by_phandle failed.\n",
|
||||||
|
oldi_instance);
|
||||||
|
goto err_put_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldi->serial = of_clk_get_by_name(child, "serial");
|
||||||
|
if (IS_ERR(oldi->serial)) {
|
||||||
|
ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->serial),
|
||||||
|
"OLDI%u: Failed to get serial clock.\n",
|
||||||
|
oldi_instance);
|
||||||
|
goto err_put_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register the bridge. */
|
||||||
|
oldi->bridge.of_node = child;
|
||||||
|
oldi->bridge.driver_private = oldi;
|
||||||
|
oldi->bridge.funcs = &tidss_oldi_bridge_funcs;
|
||||||
|
oldi->bridge.timings = &default_tidss_oldi_timings;
|
||||||
|
|
||||||
|
tidss->oldis[tidss->num_oldis++] = oldi;
|
||||||
|
oldi->tidss = tidss;
|
||||||
|
|
||||||
|
drm_bridge_add(&oldi->bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(child);
|
||||||
|
of_node_put(oldi_parent);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_put_node:
|
||||||
|
of_node_put(child);
|
||||||
|
of_node_put(oldi_parent);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 - Texas Instruments Incorporated
|
||||||
|
*
|
||||||
|
* Aradhya Bhatia <a-bhatia1@ti.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TIDSS_OLDI_H__
|
||||||
|
#define __TIDSS_OLDI_H__
|
||||||
|
|
||||||
|
#include "tidss_drv.h"
|
||||||
|
|
||||||
|
struct tidss_oldi;
|
||||||
|
|
||||||
|
/* OLDI PORTS */
|
||||||
|
#define OLDI_INPUT_PORT 0
|
||||||
|
#define OLDI_OUTPUT_PORT 1
|
||||||
|
|
||||||
|
/* Control MMR Registers */
|
||||||
|
|
||||||
|
/* Register offsets */
|
||||||
|
#define OLDI_PD_CTRL 0x100
|
||||||
|
#define OLDI_LB_CTRL 0x104
|
||||||
|
|
||||||
|
/* Power control bits */
|
||||||
|
#define OLDI_PWRDOWN_TX(n) BIT(n)
|
||||||
|
|
||||||
|
/* LVDS Bandgap reference Enable/Disable */
|
||||||
|
#define OLDI_PWRDN_BG BIT(8)
|
||||||
|
|
||||||
|
enum tidss_oldi_link_type {
|
||||||
|
OLDI_MODE_UNSUPPORTED,
|
||||||
|
OLDI_MODE_SINGLE_LINK,
|
||||||
|
OLDI_MODE_CLONE_SINGLE_LINK,
|
||||||
|
OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK,
|
||||||
|
OLDI_MODE_DUAL_LINK,
|
||||||
|
OLDI_MODE_SECONDARY_DUAL_LINK,
|
||||||
|
};
|
||||||
|
|
||||||
|
int tidss_oldi_init(struct tidss_device *tidss);
|
||||||
|
void tidss_oldi_deinit(struct tidss_device *tidss);
|
||||||
|
|
||||||
|
#endif /* __TIDSS_OLDI_H__ */
|
|
@ -526,11 +526,11 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (bo->deleted) {
|
if (bo->deleted) {
|
||||||
lret = ttm_bo_wait_ctx(bo, walk->ctx);
|
lret = ttm_bo_wait_ctx(bo, walk->arg.ctx);
|
||||||
if (!lret)
|
if (!lret)
|
||||||
ttm_bo_cleanup_memtype_use(bo);
|
ttm_bo_cleanup_memtype_use(bo);
|
||||||
} else {
|
} else {
|
||||||
lret = ttm_bo_evict(bo, walk->ctx);
|
lret = ttm_bo_evict(bo, walk->arg.ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lret)
|
if (lret)
|
||||||
|
@ -566,8 +566,10 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
|
||||||
struct ttm_bo_evict_walk evict_walk = {
|
struct ttm_bo_evict_walk evict_walk = {
|
||||||
.walk = {
|
.walk = {
|
||||||
.ops = &ttm_evict_walk_ops,
|
.ops = &ttm_evict_walk_ops,
|
||||||
.ctx = ctx,
|
.arg = {
|
||||||
.ticket = ticket,
|
.ctx = ctx,
|
||||||
|
.ticket = ticket,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.place = place,
|
.place = place,
|
||||||
.evictor = evictor,
|
.evictor = evictor,
|
||||||
|
@ -576,7 +578,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
|
||||||
};
|
};
|
||||||
s64 lret;
|
s64 lret;
|
||||||
|
|
||||||
evict_walk.walk.trylock_only = true;
|
evict_walk.walk.arg.trylock_only = true;
|
||||||
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
|
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
|
||||||
|
|
||||||
/* One more attempt if we hit low limit? */
|
/* One more attempt if we hit low limit? */
|
||||||
|
@ -590,12 +592,12 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
|
||||||
/* Reset low limit */
|
/* Reset low limit */
|
||||||
evict_walk.try_low = evict_walk.hit_low = false;
|
evict_walk.try_low = evict_walk.hit_low = false;
|
||||||
/* If ticket-locking, repeat while making progress. */
|
/* If ticket-locking, repeat while making progress. */
|
||||||
evict_walk.walk.trylock_only = false;
|
evict_walk.walk.arg.trylock_only = false;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
do {
|
do {
|
||||||
/* The walk may clear the evict_walk.walk.ticket field */
|
/* The walk may clear the evict_walk.walk.ticket field */
|
||||||
evict_walk.walk.ticket = ticket;
|
evict_walk.walk.arg.ticket = ticket;
|
||||||
evict_walk.evicted = 0;
|
evict_walk.evicted = 0;
|
||||||
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
|
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
|
||||||
} while (!lret && evict_walk.evicted);
|
} while (!lret && evict_walk.evicted);
|
||||||
|
@ -1106,7 +1108,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
|
||||||
struct ttm_place place = {.mem_type = bo->resource->mem_type};
|
struct ttm_place place = {.mem_type = bo->resource->mem_type};
|
||||||
struct ttm_bo_swapout_walk *swapout_walk =
|
struct ttm_bo_swapout_walk *swapout_walk =
|
||||||
container_of(walk, typeof(*swapout_walk), walk);
|
container_of(walk, typeof(*swapout_walk), walk);
|
||||||
struct ttm_operation_ctx *ctx = walk->ctx;
|
struct ttm_operation_ctx *ctx = walk->arg.ctx;
|
||||||
s64 ret;
|
s64 ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1217,8 +1219,10 @@ s64 ttm_bo_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx,
|
||||||
struct ttm_bo_swapout_walk swapout_walk = {
|
struct ttm_bo_swapout_walk swapout_walk = {
|
||||||
.walk = {
|
.walk = {
|
||||||
.ops = &ttm_swap_ops,
|
.ops = &ttm_swap_ops,
|
||||||
.ctx = ctx,
|
.arg = {
|
||||||
.trylock_only = true,
|
.ctx = ctx,
|
||||||
|
.trylock_only = true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.gfp_flags = gfp_flags,
|
.gfp_flags = gfp_flags,
|
||||||
};
|
};
|
||||||
|
|
|
@ -773,14 +773,15 @@ error_destroy_tt:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ttm_lru_walk_trylock(struct ttm_operation_ctx *ctx,
|
static bool ttm_lru_walk_trylock(struct ttm_bo_lru_cursor *curs,
|
||||||
struct ttm_buffer_object *bo,
|
struct ttm_buffer_object *bo)
|
||||||
bool *needs_unlock)
|
|
||||||
{
|
{
|
||||||
*needs_unlock = false;
|
struct ttm_operation_ctx *ctx = curs->arg->ctx;
|
||||||
|
|
||||||
|
curs->needs_unlock = false;
|
||||||
|
|
||||||
if (dma_resv_trylock(bo->base.resv)) {
|
if (dma_resv_trylock(bo->base.resv)) {
|
||||||
*needs_unlock = true;
|
curs->needs_unlock = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,27 +793,27 @@ static bool ttm_lru_walk_trylock(struct ttm_operation_ctx *ctx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ttm_lru_walk_ticketlock(struct ttm_lru_walk *walk,
|
static int ttm_lru_walk_ticketlock(struct ttm_bo_lru_cursor *curs,
|
||||||
struct ttm_buffer_object *bo,
|
struct ttm_buffer_object *bo)
|
||||||
bool *needs_unlock)
|
|
||||||
{
|
{
|
||||||
|
struct ttm_lru_walk_arg *arg = curs->arg;
|
||||||
struct dma_resv *resv = bo->base.resv;
|
struct dma_resv *resv = bo->base.resv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (walk->ctx->interruptible)
|
if (arg->ctx->interruptible)
|
||||||
ret = dma_resv_lock_interruptible(resv, walk->ticket);
|
ret = dma_resv_lock_interruptible(resv, arg->ticket);
|
||||||
else
|
else
|
||||||
ret = dma_resv_lock(resv, walk->ticket);
|
ret = dma_resv_lock(resv, arg->ticket);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
*needs_unlock = true;
|
curs->needs_unlock = true;
|
||||||
/*
|
/*
|
||||||
* Only a single ticketlock per loop. Ticketlocks are prone
|
* Only a single ticketlock per loop. Ticketlocks are prone
|
||||||
* to return -EDEADLK causing the eviction to fail, so
|
* to return -EDEADLK causing the eviction to fail, so
|
||||||
* after waiting for the ticketlock, revert back to
|
* after waiting for the ticketlock, revert back to
|
||||||
* trylocking for this walk.
|
* trylocking for this walk.
|
||||||
*/
|
*/
|
||||||
walk->ticket = NULL;
|
arg->ticket = NULL;
|
||||||
} else if (ret == -EDEADLK) {
|
} else if (ret == -EDEADLK) {
|
||||||
/* Caller needs to exit the ww transaction. */
|
/* Caller needs to exit the ww transaction. */
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
|
@ -821,12 +822,6 @@ static int ttm_lru_walk_ticketlock(struct ttm_lru_walk *walk,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ttm_lru_walk_unlock(struct ttm_buffer_object *bo, bool locked)
|
|
||||||
{
|
|
||||||
if (locked)
|
|
||||||
dma_resv_unlock(bo->base.resv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ttm_lru_walk_for_evict() - Perform a LRU list walk, with actions taken on
|
* ttm_lru_walk_for_evict() - Perform a LRU list walk, with actions taken on
|
||||||
* valid items.
|
* valid items.
|
||||||
|
@ -861,64 +856,21 @@ static void ttm_lru_walk_unlock(struct ttm_buffer_object *bo, bool locked)
|
||||||
s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev,
|
s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev,
|
||||||
struct ttm_resource_manager *man, s64 target)
|
struct ttm_resource_manager *man, s64 target)
|
||||||
{
|
{
|
||||||
struct ttm_resource_cursor cursor;
|
struct ttm_bo_lru_cursor cursor;
|
||||||
struct ttm_resource *res;
|
struct ttm_buffer_object *bo;
|
||||||
s64 progress = 0;
|
s64 progress = 0;
|
||||||
s64 lret;
|
s64 lret;
|
||||||
|
|
||||||
spin_lock(&bdev->lru_lock);
|
ttm_bo_lru_for_each_reserved_guarded(&cursor, man, &walk->arg, bo) {
|
||||||
ttm_resource_cursor_init(&cursor, man);
|
lret = walk->ops->process_bo(walk, bo);
|
||||||
ttm_resource_manager_for_each_res(&cursor, res) {
|
|
||||||
struct ttm_buffer_object *bo = res->bo;
|
|
||||||
bool bo_needs_unlock = false;
|
|
||||||
bool bo_locked = false;
|
|
||||||
int mem_type;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Attempt a trylock before taking a reference on the bo,
|
|
||||||
* since if we do it the other way around, and the trylock fails,
|
|
||||||
* we need to drop the lru lock to put the bo.
|
|
||||||
*/
|
|
||||||
if (ttm_lru_walk_trylock(walk->ctx, bo, &bo_needs_unlock))
|
|
||||||
bo_locked = true;
|
|
||||||
else if (!walk->ticket || walk->ctx->no_wait_gpu ||
|
|
||||||
walk->trylock_only)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!ttm_bo_get_unless_zero(bo)) {
|
|
||||||
ttm_lru_walk_unlock(bo, bo_needs_unlock);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_type = res->mem_type;
|
|
||||||
spin_unlock(&bdev->lru_lock);
|
|
||||||
|
|
||||||
lret = 0;
|
|
||||||
if (!bo_locked)
|
|
||||||
lret = ttm_lru_walk_ticketlock(walk, bo, &bo_needs_unlock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that in between the release of the lru lock and the
|
|
||||||
* ticketlock, the bo may have switched resource,
|
|
||||||
* and also memory type, since the resource may have been
|
|
||||||
* freed and allocated again with a different memory type.
|
|
||||||
* In that case, just skip it.
|
|
||||||
*/
|
|
||||||
if (!lret && bo->resource && bo->resource->mem_type == mem_type)
|
|
||||||
lret = walk->ops->process_bo(walk, bo);
|
|
||||||
|
|
||||||
ttm_lru_walk_unlock(bo, bo_needs_unlock);
|
|
||||||
ttm_bo_put(bo);
|
|
||||||
if (lret == -EBUSY || lret == -EALREADY)
|
if (lret == -EBUSY || lret == -EALREADY)
|
||||||
lret = 0;
|
lret = 0;
|
||||||
progress = (lret < 0) ? lret : progress + lret;
|
progress = (lret < 0) ? lret : progress + lret;
|
||||||
|
|
||||||
spin_lock(&bdev->lru_lock);
|
|
||||||
if (progress < 0 || progress >= target)
|
if (progress < 0 || progress >= target)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ttm_resource_cursor_fini(&cursor);
|
if (IS_ERR(bo))
|
||||||
spin_unlock(&bdev->lru_lock);
|
return PTR_ERR(bo);
|
||||||
|
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
@ -956,44 +908,87 @@ EXPORT_SYMBOL(ttm_bo_lru_cursor_fini);
|
||||||
* ttm_bo_lru_cursor_init() - Initialize a struct ttm_bo_lru_cursor
|
* ttm_bo_lru_cursor_init() - Initialize a struct ttm_bo_lru_cursor
|
||||||
* @curs: The ttm_bo_lru_cursor to initialize.
|
* @curs: The ttm_bo_lru_cursor to initialize.
|
||||||
* @man: The ttm resource_manager whose LRU lists to iterate over.
|
* @man: The ttm resource_manager whose LRU lists to iterate over.
|
||||||
* @ctx: The ttm_operation_ctx to govern the locking.
|
* @arg: The ttm_lru_walk_arg to govern the walk.
|
||||||
*
|
*
|
||||||
* Initialize a struct ttm_bo_lru_cursor. Currently only trylocking
|
* Initialize a struct ttm_bo_lru_cursor.
|
||||||
* or prelocked buffer objects are available as detailed by
|
|
||||||
* @ctx::resv and @ctx::allow_res_evict. Ticketlocking is not
|
|
||||||
* supported.
|
|
||||||
*
|
*
|
||||||
* Return: Pointer to @curs. The function does not fail.
|
* Return: Pointer to @curs. The function does not fail.
|
||||||
*/
|
*/
|
||||||
struct ttm_bo_lru_cursor *
|
struct ttm_bo_lru_cursor *
|
||||||
ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs,
|
ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs,
|
||||||
struct ttm_resource_manager *man,
|
struct ttm_resource_manager *man,
|
||||||
struct ttm_operation_ctx *ctx)
|
struct ttm_lru_walk_arg *arg)
|
||||||
{
|
{
|
||||||
memset(curs, 0, sizeof(*curs));
|
memset(curs, 0, sizeof(*curs));
|
||||||
ttm_resource_cursor_init(&curs->res_curs, man);
|
ttm_resource_cursor_init(&curs->res_curs, man);
|
||||||
curs->ctx = ctx;
|
curs->arg = arg;
|
||||||
|
|
||||||
return curs;
|
return curs;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ttm_bo_lru_cursor_init);
|
EXPORT_SYMBOL(ttm_bo_lru_cursor_init);
|
||||||
|
|
||||||
static struct ttm_buffer_object *
|
static struct ttm_buffer_object *
|
||||||
ttm_bo_from_res_reserved(struct ttm_resource *res, struct ttm_bo_lru_cursor *curs)
|
__ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
|
||||||
{
|
{
|
||||||
struct ttm_buffer_object *bo = res->bo;
|
spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock;
|
||||||
|
struct ttm_resource *res = NULL;
|
||||||
|
struct ttm_buffer_object *bo;
|
||||||
|
struct ttm_lru_walk_arg *arg = curs->arg;
|
||||||
|
bool first = !curs->bo;
|
||||||
|
|
||||||
if (!ttm_lru_walk_trylock(curs->ctx, bo, &curs->needs_unlock))
|
ttm_bo_lru_cursor_cleanup_bo(curs);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!ttm_bo_get_unless_zero(bo)) {
|
spin_lock(lru_lock);
|
||||||
if (curs->needs_unlock)
|
for (;;) {
|
||||||
dma_resv_unlock(bo->base.resv);
|
int mem_type, ret = 0;
|
||||||
return NULL;
|
bool bo_locked = false;
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
res = ttm_resource_manager_first(&curs->res_curs);
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
res = ttm_resource_manager_next(&curs->res_curs);
|
||||||
|
}
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bo = res->bo;
|
||||||
|
if (ttm_lru_walk_trylock(curs, bo))
|
||||||
|
bo_locked = true;
|
||||||
|
else if (!arg->ticket || arg->ctx->no_wait_gpu || arg->trylock_only)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ttm_bo_get_unless_zero(bo)) {
|
||||||
|
if (curs->needs_unlock)
|
||||||
|
dma_resv_unlock(bo->base.resv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_type = res->mem_type;
|
||||||
|
spin_unlock(lru_lock);
|
||||||
|
if (!bo_locked)
|
||||||
|
ret = ttm_lru_walk_ticketlock(curs, bo);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that in between the release of the lru lock and the
|
||||||
|
* ticketlock, the bo may have switched resource,
|
||||||
|
* and also memory type, since the resource may have been
|
||||||
|
* freed and allocated again with a different memory type.
|
||||||
|
* In that case, just skip it.
|
||||||
|
*/
|
||||||
|
curs->bo = bo;
|
||||||
|
if (!ret && bo->resource && bo->resource->mem_type == mem_type)
|
||||||
|
return bo;
|
||||||
|
|
||||||
|
ttm_bo_lru_cursor_cleanup_bo(curs);
|
||||||
|
if (ret && ret != -EALREADY)
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
spin_lock(lru_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
curs->bo = bo;
|
spin_unlock(lru_lock);
|
||||||
return bo;
|
return res ? bo : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1007,25 +1002,7 @@ ttm_bo_from_res_reserved(struct ttm_resource *res, struct ttm_bo_lru_cursor *cur
|
||||||
*/
|
*/
|
||||||
struct ttm_buffer_object *ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
|
struct ttm_buffer_object *ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
|
||||||
{
|
{
|
||||||
spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock;
|
return __ttm_bo_lru_cursor_next(curs);
|
||||||
struct ttm_resource *res = NULL;
|
|
||||||
struct ttm_buffer_object *bo;
|
|
||||||
|
|
||||||
ttm_bo_lru_cursor_cleanup_bo(curs);
|
|
||||||
|
|
||||||
spin_lock(lru_lock);
|
|
||||||
for (;;) {
|
|
||||||
res = ttm_resource_manager_next(&curs->res_curs);
|
|
||||||
if (!res)
|
|
||||||
break;
|
|
||||||
|
|
||||||
bo = ttm_bo_from_res_reserved(res, curs);
|
|
||||||
if (bo)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(lru_lock);
|
|
||||||
return res ? bo : NULL;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ttm_bo_lru_cursor_next);
|
EXPORT_SYMBOL(ttm_bo_lru_cursor_next);
|
||||||
|
|
||||||
|
@ -1039,21 +1016,8 @@ EXPORT_SYMBOL(ttm_bo_lru_cursor_next);
|
||||||
*/
|
*/
|
||||||
struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs)
|
struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs)
|
||||||
{
|
{
|
||||||
spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock;
|
ttm_bo_lru_cursor_cleanup_bo(curs);
|
||||||
struct ttm_buffer_object *bo;
|
return __ttm_bo_lru_cursor_next(curs);
|
||||||
struct ttm_resource *res;
|
|
||||||
|
|
||||||
spin_lock(lru_lock);
|
|
||||||
res = ttm_resource_manager_first(&curs->res_curs);
|
|
||||||
if (!res) {
|
|
||||||
spin_unlock(lru_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bo = ttm_bo_from_res_reserved(res, curs);
|
|
||||||
spin_unlock(lru_lock);
|
|
||||||
|
|
||||||
return bo ? bo : ttm_bo_lru_cursor_next(curs);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ttm_bo_lru_cursor_first);
|
EXPORT_SYMBOL(ttm_bo_lru_cursor_first);
|
||||||
|
|
||||||
|
|
|
@ -284,11 +284,10 @@ static void vmw_bo_print_info(int id, struct vmw_bo *bo, struct seq_file *m)
|
||||||
|
|
||||||
seq_printf(m, "\t\t0x%08x: %12zu bytes %s, type = %s",
|
seq_printf(m, "\t\t0x%08x: %12zu bytes %s, type = %s",
|
||||||
id, bo->tbo.base.size, placement, type);
|
id, bo->tbo.base.size, placement, type);
|
||||||
seq_printf(m, ", priority = %u, pin_count = %u, GEM refs = %d, TTM refs = %d",
|
seq_printf(m, ", priority = %u, pin_count = %u, GEM refs = %d",
|
||||||
bo->tbo.priority,
|
bo->tbo.priority,
|
||||||
bo->tbo.pin_count,
|
bo->tbo.pin_count,
|
||||||
kref_read(&bo->tbo.base.refcount),
|
kref_read(&bo->tbo.base.refcount));
|
||||||
kref_read(&bo->tbo.kref));
|
|
||||||
seq_puts(m, "\n");
|
seq_puts(m, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,15 @@ static s64 xe_shrinker_walk(struct xe_device *xe,
|
||||||
struct ttm_resource_manager *man = ttm_manager_type(&xe->ttm, mem_type);
|
struct ttm_resource_manager *man = ttm_manager_type(&xe->ttm, mem_type);
|
||||||
struct ttm_bo_lru_cursor curs;
|
struct ttm_bo_lru_cursor curs;
|
||||||
struct ttm_buffer_object *ttm_bo;
|
struct ttm_buffer_object *ttm_bo;
|
||||||
|
struct ttm_lru_walk_arg arg = {
|
||||||
|
.ctx = ctx,
|
||||||
|
.trylock_only = true,
|
||||||
|
};
|
||||||
|
|
||||||
if (!man || !man->use_tt)
|
if (!man || !man->use_tt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ttm_bo_lru_for_each_reserved_guarded(&curs, man, ctx, ttm_bo) {
|
ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) {
|
||||||
if (!ttm_bo_shrink_suitable(ttm_bo, ctx))
|
if (!ttm_bo_shrink_suitable(ttm_bo, ctx))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -82,6 +86,8 @@ static s64 xe_shrinker_walk(struct xe_device *xe,
|
||||||
if (*scanned >= to_scan)
|
if (*scanned >= to_scan)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Trylocks should never error, just fail. */
|
||||||
|
xe_assert(xe, !IS_ERR(ttm_bo));
|
||||||
}
|
}
|
||||||
|
|
||||||
return freed;
|
return freed;
|
||||||
|
|
|
@ -843,6 +843,7 @@ drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk)
|
||||||
* @lsb_reg_used: Do we also write values to the DP_EDP_BACKLIGHT_BRIGHTNESS_LSB register?
|
* @lsb_reg_used: Do we also write values to the DP_EDP_BACKLIGHT_BRIGHTNESS_LSB register?
|
||||||
* @aux_enable: Does the panel support the AUX enable cap?
|
* @aux_enable: Does the panel support the AUX enable cap?
|
||||||
* @aux_set: Does the panel support setting the brightness through AUX?
|
* @aux_set: Does the panel support setting the brightness through AUX?
|
||||||
|
* @luminance_set: Does the panel support setting the brightness through AUX using luminance values?
|
||||||
*
|
*
|
||||||
* This structure contains various data about an eDP backlight, which can be populated by using
|
* This structure contains various data about an eDP backlight, which can be populated by using
|
||||||
* drm_edp_backlight_init().
|
* drm_edp_backlight_init().
|
||||||
|
@ -850,21 +851,23 @@ drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk)
|
||||||
struct drm_edp_backlight_info {
|
struct drm_edp_backlight_info {
|
||||||
u8 pwmgen_bit_count;
|
u8 pwmgen_bit_count;
|
||||||
u8 pwm_freq_pre_divider;
|
u8 pwm_freq_pre_divider;
|
||||||
u16 max;
|
u32 max;
|
||||||
|
|
||||||
bool lsb_reg_used : 1;
|
bool lsb_reg_used : 1;
|
||||||
bool aux_enable : 1;
|
bool aux_enable : 1;
|
||||||
bool aux_set : 1;
|
bool aux_set : 1;
|
||||||
|
bool luminance_set : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl,
|
drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl,
|
||||||
|
u32 max_luminance,
|
||||||
u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE],
|
u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE],
|
||||||
u16 *current_level, u8 *current_mode);
|
u32 *current_level, u8 *current_mode, bool need_luminance);
|
||||||
int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
||||||
u16 level);
|
u32 level);
|
||||||
int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl,
|
||||||
u16 level);
|
u32 level);
|
||||||
int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl);
|
int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_DRM_KMS_HELPER) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
|
#if IS_ENABLED(CONFIG_DRM_KMS_HELPER) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
|
||||||
|
|
|
@ -82,8 +82,10 @@ void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pi
|
||||||
const struct drm_rect *clip, struct drm_format_conv_state *state);
|
const struct drm_rect *clip, struct drm_format_conv_state *state);
|
||||||
void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
|
void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
|
||||||
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
||||||
const struct drm_rect *clip, struct drm_format_conv_state *state,
|
const struct drm_rect *clip, struct drm_format_conv_state *state);
|
||||||
bool swab);
|
void drm_fb_xrgb8888_to_rgb565be(struct iosys_map *dst, const unsigned int *dst_pitch,
|
||||||
|
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
||||||
|
const struct drm_rect *clip, struct drm_format_conv_state *state);
|
||||||
void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
|
void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
|
||||||
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
const struct iosys_map *src, const struct drm_framebuffer *fb,
|
||||||
const struct drm_rect *clip, struct drm_format_conv_state *state);
|
const struct drm_rect *clip, struct drm_format_conv_state *state);
|
||||||
|
|
|
@ -130,8 +130,6 @@ struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
|
||||||
#define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6)
|
#define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6)
|
||||||
/* disable hsync-active area */
|
/* disable hsync-active area */
|
||||||
#define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7)
|
#define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7)
|
||||||
/* flush display FIFO on vsync pulse */
|
|
||||||
#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
|
|
||||||
/* disable EoT packets in HS mode */
|
/* disable EoT packets in HS mode */
|
||||||
#define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9)
|
#define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9)
|
||||||
/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
||||||
|
|
|
@ -207,11 +207,9 @@ struct ttm_lru_walk_ops {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ttm_lru_walk - Structure describing a LRU walk.
|
* struct ttm_lru_walk_arg - Common part for the variants of BO LRU walk.
|
||||||
*/
|
*/
|
||||||
struct ttm_lru_walk {
|
struct ttm_lru_walk_arg {
|
||||||
/** @ops: Pointer to the ops structure. */
|
|
||||||
const struct ttm_lru_walk_ops *ops;
|
|
||||||
/** @ctx: Pointer to the struct ttm_operation_ctx. */
|
/** @ctx: Pointer to the struct ttm_operation_ctx. */
|
||||||
struct ttm_operation_ctx *ctx;
|
struct ttm_operation_ctx *ctx;
|
||||||
/** @ticket: The struct ww_acquire_ctx if any. */
|
/** @ticket: The struct ww_acquire_ctx if any. */
|
||||||
|
@ -220,6 +218,16 @@ struct ttm_lru_walk {
|
||||||
bool trylock_only;
|
bool trylock_only;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ttm_lru_walk - Structure describing a LRU walk.
|
||||||
|
*/
|
||||||
|
struct ttm_lru_walk {
|
||||||
|
/** @ops: Pointer to the ops structure. */
|
||||||
|
const struct ttm_lru_walk_ops *ops;
|
||||||
|
/** @arg: Common bo LRU walk arguments. */
|
||||||
|
struct ttm_lru_walk_arg arg;
|
||||||
|
};
|
||||||
|
|
||||||
s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev,
|
s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev,
|
||||||
struct ttm_resource_manager *man, s64 target);
|
struct ttm_resource_manager *man, s64 target);
|
||||||
|
|
||||||
|
@ -466,11 +474,6 @@ int ttm_bo_populate(struct ttm_buffer_object *bo,
|
||||||
struct ttm_bo_lru_cursor {
|
struct ttm_bo_lru_cursor {
|
||||||
/** @res_curs: Embedded struct ttm_resource_cursor. */
|
/** @res_curs: Embedded struct ttm_resource_cursor. */
|
||||||
struct ttm_resource_cursor res_curs;
|
struct ttm_resource_cursor res_curs;
|
||||||
/**
|
|
||||||
* @ctx: The struct ttm_operation_ctx used while looping.
|
|
||||||
* governs the locking mode.
|
|
||||||
*/
|
|
||||||
struct ttm_operation_ctx *ctx;
|
|
||||||
/**
|
/**
|
||||||
* @bo: Buffer object pointer if a buffer object is refcounted,
|
* @bo: Buffer object pointer if a buffer object is refcounted,
|
||||||
* NULL otherwise.
|
* NULL otherwise.
|
||||||
|
@ -481,6 +484,8 @@ struct ttm_bo_lru_cursor {
|
||||||
* unlock before the next iteration or after loop exit.
|
* unlock before the next iteration or after loop exit.
|
||||||
*/
|
*/
|
||||||
bool needs_unlock;
|
bool needs_unlock;
|
||||||
|
/** @arg: Pointer to common BO LRU walk arguments. */
|
||||||
|
struct ttm_lru_walk_arg *arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ttm_bo_lru_cursor_fini(struct ttm_bo_lru_cursor *curs);
|
void ttm_bo_lru_cursor_fini(struct ttm_bo_lru_cursor *curs);
|
||||||
|
@ -488,7 +493,7 @@ void ttm_bo_lru_cursor_fini(struct ttm_bo_lru_cursor *curs);
|
||||||
struct ttm_bo_lru_cursor *
|
struct ttm_bo_lru_cursor *
|
||||||
ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs,
|
ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs,
|
||||||
struct ttm_resource_manager *man,
|
struct ttm_resource_manager *man,
|
||||||
struct ttm_operation_ctx *ctx);
|
struct ttm_lru_walk_arg *arg);
|
||||||
|
|
||||||
struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs);
|
struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs);
|
||||||
|
|
||||||
|
@ -499,9 +504,9 @@ struct ttm_buffer_object *ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
|
||||||
*/
|
*/
|
||||||
DEFINE_CLASS(ttm_bo_lru_cursor, struct ttm_bo_lru_cursor *,
|
DEFINE_CLASS(ttm_bo_lru_cursor, struct ttm_bo_lru_cursor *,
|
||||||
if (_T) {ttm_bo_lru_cursor_fini(_T); },
|
if (_T) {ttm_bo_lru_cursor_fini(_T); },
|
||||||
ttm_bo_lru_cursor_init(curs, man, ctx),
|
ttm_bo_lru_cursor_init(curs, man, arg),
|
||||||
struct ttm_bo_lru_cursor *curs, struct ttm_resource_manager *man,
|
struct ttm_bo_lru_cursor *curs, struct ttm_resource_manager *man,
|
||||||
struct ttm_operation_ctx *ctx);
|
struct ttm_lru_walk_arg *arg);
|
||||||
static inline void *
|
static inline void *
|
||||||
class_ttm_bo_lru_cursor_lock_ptr(class_ttm_bo_lru_cursor_t *_T)
|
class_ttm_bo_lru_cursor_lock_ptr(class_ttm_bo_lru_cursor_t *_T)
|
||||||
{ return *_T; }
|
{ return *_T; }
|
||||||
|
@ -512,7 +517,7 @@ class_ttm_bo_lru_cursor_lock_ptr(class_ttm_bo_lru_cursor_t *_T)
|
||||||
* resources on LRU lists.
|
* resources on LRU lists.
|
||||||
* @_cursor: struct ttm_bo_lru_cursor to use for the iteration.
|
* @_cursor: struct ttm_bo_lru_cursor to use for the iteration.
|
||||||
* @_man: The resource manager whose LRU lists to iterate over.
|
* @_man: The resource manager whose LRU lists to iterate over.
|
||||||
* @_ctx: The struct ttm_operation_context to govern the @_bo locking.
|
* @_arg: The struct ttm_lru_walk_arg to govern the LRU walk.
|
||||||
* @_bo: The struct ttm_buffer_object pointer pointing to the buffer object
|
* @_bo: The struct ttm_buffer_object pointer pointing to the buffer object
|
||||||
* for the current iteration.
|
* for the current iteration.
|
||||||
*
|
*
|
||||||
|
@ -524,10 +529,15 @@ class_ttm_bo_lru_cursor_lock_ptr(class_ttm_bo_lru_cursor_t *_T)
|
||||||
* up at looping termination, even if terminated prematurely by, for
|
* up at looping termination, even if terminated prematurely by, for
|
||||||
* example a return or break statement. Exiting the loop will also unlock
|
* example a return or break statement. Exiting the loop will also unlock
|
||||||
* (if needed) and unreference @_bo.
|
* (if needed) and unreference @_bo.
|
||||||
|
*
|
||||||
|
* Return: If locking of a bo returns an error, then iteration is terminated
|
||||||
|
* and @_bo is set to a corresponding error pointer. It's illegal to
|
||||||
|
* dereference @_bo after loop exit.
|
||||||
*/
|
*/
|
||||||
#define ttm_bo_lru_for_each_reserved_guarded(_cursor, _man, _ctx, _bo) \
|
#define ttm_bo_lru_for_each_reserved_guarded(_cursor, _man, _arg, _bo) \
|
||||||
scoped_guard(ttm_bo_lru_cursor, _cursor, _man, _ctx) \
|
scoped_guard(ttm_bo_lru_cursor, _cursor, _man, _arg) \
|
||||||
for ((_bo) = ttm_bo_lru_cursor_first(_cursor); (_bo); \
|
for ((_bo) = ttm_bo_lru_cursor_first(_cursor); \
|
||||||
(_bo) = ttm_bo_lru_cursor_next(_cursor))
|
!IS_ERR_OR_NULL(_bo); \
|
||||||
|
(_bo) = ttm_bo_lru_cursor_next(_cursor))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,9 +7,13 @@
|
||||||
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
|
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include <linux/platform_data/simplefb.h>
|
#include <linux/platform_data/simplefb.h>
|
||||||
|
|
||||||
|
struct device;
|
||||||
|
struct platform_device;
|
||||||
struct screen_info;
|
struct screen_info;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -210,6 +210,10 @@ extern "C" {
|
||||||
#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */
|
#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */
|
||||||
#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
|
#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
|
||||||
|
|
||||||
|
/* 48 bpp RGB */
|
||||||
|
#define DRM_FORMAT_RGB161616 fourcc_code('R', 'G', '4', '8') /* [47:0] R:G:B 16:16:16 little endian */
|
||||||
|
#define DRM_FORMAT_BGR161616 fourcc_code('B', 'G', '4', '8') /* [47:0] B:G:R 16:16:16 little endian */
|
||||||
|
|
||||||
/* 64 bpp RGB */
|
/* 64 bpp RGB */
|
||||||
#define DRM_FORMAT_XRGB16161616 fourcc_code('X', 'R', '4', '8') /* [63:0] x:R:G:B 16:16:16:16 little endian */
|
#define DRM_FORMAT_XRGB16161616 fourcc_code('X', 'R', '4', '8') /* [63:0] x:R:G:B 16:16:16:16 little endian */
|
||||||
#define DRM_FORMAT_XBGR16161616 fourcc_code('X', 'B', '4', '8') /* [63:0] x:B:G:R 16:16:16:16 little endian */
|
#define DRM_FORMAT_XBGR16161616 fourcc_code('X', 'B', '4', '8') /* [63:0] x:B:G:R 16:16:16:16 little endian */
|
||||||
|
@ -218,7 +222,7 @@ extern "C" {
|
||||||
#define DRM_FORMAT_ABGR16161616 fourcc_code('A', 'B', '4', '8') /* [63:0] A:B:G:R 16:16:16:16 little endian */
|
#define DRM_FORMAT_ABGR16161616 fourcc_code('A', 'B', '4', '8') /* [63:0] A:B:G:R 16:16:16:16 little endian */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Floating point 64bpp RGB
|
* Half-Floating point - 16b/component
|
||||||
* IEEE 754-2008 binary16 half-precision float
|
* IEEE 754-2008 binary16 half-precision float
|
||||||
* [15:0] sign:exponent:mantissa 1:5:10
|
* [15:0] sign:exponent:mantissa 1:5:10
|
||||||
*/
|
*/
|
||||||
|
@ -228,6 +232,20 @@ extern "C" {
|
||||||
#define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */
|
#define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */
|
||||||
#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */
|
#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */
|
||||||
|
|
||||||
|
#define DRM_FORMAT_R16F fourcc_code('R', ' ', ' ', 'H') /* [15:0] R 16 little endian */
|
||||||
|
#define DRM_FORMAT_GR1616F fourcc_code('G', 'R', ' ', 'H') /* [31:0] G:R 16:16 little endian */
|
||||||
|
#define DRM_FORMAT_BGR161616F fourcc_code('B', 'G', 'R', 'H') /* [47:0] B:G:R 16:16:16 little endian */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Floating point - 32b/component
|
||||||
|
* IEEE 754-2008 binary32 float
|
||||||
|
* [31:0] sign:exponent:mantissa 1:8:23
|
||||||
|
*/
|
||||||
|
#define DRM_FORMAT_R32F fourcc_code('R', ' ', ' ', 'F') /* [31:0] R 32 little endian */
|
||||||
|
#define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] R:G 32:32 little endian */
|
||||||
|
#define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] R:G:B 32:32:32 little endian */
|
||||||
|
#define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] R:G:B:A 32:32:32:32 little endian */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits
|
* RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits
|
||||||
* of unused padding per component:
|
* of unused padding per component:
|
||||||
|
|
Loading…
Reference in New Issue