* [PATCH v9 0/4] drm/tidss: Add OLDI bridge support
@ 2025-05-28 12:25 Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 1/4] dt-bindings: display: ti, am65x-dss: Re-indent the example Aradhya Bhatia
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Aradhya Bhatia @ 2025-05-28 12:25 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tomi Valkeinen,
Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, Michael Walle, DRI Development List,
Devicetree List, Linux Kernel List, Aradhya Bhatia
Hello all,
This patch series adds support for the dual OLDI TXes supported in Texas
Instruments' AM62x and AM62Px family of SoCs. The OLDI TX hardware supports
single-lvds, lvds-clone, and dual-lvds modes. These TXes have now been
represented through DRM bridges within TI-DSS.
* Some history and hardware description for this patch series *
This patch series is a complete re-vamp from the previously posted series[1] and
hence, the version index has been reset to v1. The OLDI support from that series
was dropped and only the base support for AM62x DSS was kept (and eventually
merged)[2].
The OLDI display that the tidss driver today supports, could not be extended for
the newer SoCs. The OLDI display in tidss is modelled after the DSS and OLDI
hardware in the AM65x SoC. The DSS in AM65x SoC, has two video-ports. Both these
video-ports (VP) output DPI video signals. One of the DPI output (from VP1) from
the DSS connects to a singular OLDI TX present inside the SoC. There is no other
way for the DPI from VP1 to be taken out of the SoC. The other DPI output
however - the one from VP2 - is taken out of the SoC as is. Hence we have an
OLDI bus output and a DPI bus output from the SoC. Since the VP1 and OLDI are
tightly coupled, the tidss driver considers them as a single entity. That is
why, any OLDI sink connects directly to the DSS ports in the OF graphs.
The newer SoCs have varying DSS and OLDI integrations.
The AM62x DSS also has 2 VPs. The 2nd VP, VP2, outputs DPI signals which are
taken out of the SoC - similar to the AM65x above. For the VP1, there are 2 OLDI
TXes. These OLDI TXes can only receive DPI signals from VP1, and don't connect
to VP2 at all.
The AM62Px SoC has 2 OLDI TXes like AM62x SoC. However, the AM62Px SoC also has
2 separate DSSes. The 2 OLDI TXes can now be shared between the 2 VPs of the 2
DSSes.
The addition of the 2nd OLDI TX (and a 2nd DSS in AM62Px) creates a need for
some major changes for a full feature experience.
1. The OF graph needs to be updated to accurately show the data flow.
2. The tidss and OLDI drivers now need to support the dual-link and the cloned
single-link OLDI video signals.
3. The drivers also need to support the case where 2 OLDI TXes are connected to
2 different VPs - thereby creating 2 independent streams of single-link OLDI
outputs.
Note that the OLDI does not have registers of its own. It is still dependent on
the parent VP. The VP that provides the DPI video signals to the OLDI TXes, also
gives the OLDI TXes all the config data. That is to say, the hardware doesn't
sit on the bus directly - but does so through the DSS.
In light of all of these hardware variations, it was decided to have a separate
OLDI driver (unlike AM65x) but not entirely separate so as to be a platform
device. The OLDI TXes are now being represented as DRM bridges under the tidss.
* Regarding the Dependency Patches *
Since the OLDI TXes have a hardware dependency with the parent VP(s), the OLDI
configuration needs to happen before that VP is enabled for streaming. VP stream
enable takes place in tidss_crtc_atomic_enable hook. I have posted patches[0]
allowing DRM bridges to get pre-enabled before the CRTC of that bridge is
enabled. Without those patches, some warnings or glitches may be observed.
* Regarding the Drop of Clone Mode support *
Another key point to note is that the support for clone mode has been dropped
from the tidss OLDI driver, from v5 onwards. If the DT is configured for a clone
mode, the driver will report an error and exit. This has been done because the
driver was not supporting a specific case of clone mode where 2 OLDI sink
bridges connected to the 2 OLDI TXes require active programming (unlike the
simple-panels which do not). The driver does not support creation of two
encoder-bridge pipelines (along with the parent tidss driver) to allow program
any subsequent bridges (OLDI sinks and bridges thereafter).
The code fragments that write the OLDI config to enable clone mode have been
kept as they are, for future, but the driver will not continue to probe if it
detects a clone mode configuration, for the time being.
This drop of clone mode support can be undone by applying this _soft-tested_
patch[6] on top of this series. This patch will revert the driver to previous
revisions and will allow OLDI sinks that don't require active programming (for
example: simple-panels) to work with the driver. Note that this isn't the ideal
way to run clone mode, but it just works for any bridge pipeline after OLDT TX
that does not require additional configuration after the OLDI (for example: a
couple of simple lvds panels connected directly to the OLDI TXes in clone mode).
These patches have been tested on AM625 based Beagleplay[3] platform with a
Lincolntech LCD185 dual-lvds panel. The patches with complete support including
the expected devicetree configuration of the OLDI TXes can be found in the
"next_oldi-v9_1_tests" branch of my github fork[4]. This branch also has support
for Microtips dual-lvds panel (SK-LCD1) which is compatible with the SK-AM625
EVM platform.
I'd appreciate it if somebody can test it, and report back if they observe any
issues.
Thanks,
Aradhya
* Important note about the authorship of patches *
All the patches in the of this series were authored when I owned a "ti.com"
based email id, i.e. <a-bhatia1@ti.com>. This email id is not in use anymore,
and all the work done later has been part of my personal work. Since the
original patches were authored using TI's email id, I have maintained the
original authorships as they are, as well as their sign offs.
I have further added another sign off that uses my current (and personal) email
id, the one that is being used to send this revision, i.e.
<aradhya.bhatia@linux.dev>.
---
Change Log:
V9:
- Fixes and improvements over V8, in patches 2/4 and 4/4.
* Reword the "ti,companion-oldi" property description. (Michael)
* Fix the missing "ti,companion-oldi" property in the dt-schema example. (Michael)
* Fix the get_oldi_mode() logic, for secondary-oldi in dual-link mode.
* Allow secondary-oldi to skip getting serial-clk and io-ctrl syscon regs.
* Rename enum "OLDI_MODE_CLONE_SECONDARY_SINGLE_LINK" to
"OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK".
- Rebase to latest drm-misc-next.
V8:
- V8 brings some additional changes that are required to properly set up Clone
Mode in future:
* Allow for secondary OLDIs to have the "companion-oldi" devicetree property.
* Have separate Secondary OLDI enums for Dual-link and Clone Mode.
* Change get_oldi_mode() logic to distinguish between the 2 different types
of secondary OLDIs (dual-link and clone-mode). This is required because
the secondary OLDI of clone-mode needs to get registered as a drm_bridge
device (when we have the full support in future). The secondary OLDI of
dual-link mode does not need to be set up as a drm_bridge.
- Add "ti,am62l-dss" to the list of compatibles that cannot have the
"oldi-transmitter" property or multiple endpoints on port@0.
- Fix some typos and the one wrong variable type in the tidss_oldi driver.
- Drop Tomi Valkeinen's R-b from patches 2/4 and 4/4 because the logic has
fairly changed, and requires another pass at a review. Also drop
Rob Herring's R-b tag from patch 2/4.
- Drop T-b tags from Alexander Sverdlin and Michael Walle, from patch 4/4.
V7:
- Use for_each_available_child_of_node() instead of for_each_child_of_node()
to parse through the OLDI TX device nodes, as recommended by Alexander
Sverdlin.
- Rebase to drm-misc-next.
As part of this, update the bridge attach part of the code, as encoders are
now passed as a parameter in the drm_bridge_attach() call after Maxime
Ripard's change in commit 98007a0d56b0
("drm/bridge: Add encoder parameter to drm_bridge_funcs.attach").
- Add Alexander Sverdlin's T-b tag in patch 4/4, and Tomi Valkeinen's R-b in
patch 3/4.
V6:
- Add patch 3/4: ("drm/tidss: Add 'AM65X_' prefix to OLDI identifiers"),
to segregate the pre-existing OLDI code intended for AM65x, from the
new-coming OLDI bridge driver related code.
- Cosmetic changes suggested by Tomi Valkeinen in patch 4.
- Rebase to latest linux-next (next-20250226).
- Add Rob Herring's R-b in patch-2, and Tomi Valkeinen's R-b tags in
patches 2 and 4.
V5:
- Implement fixes suggested by Rob Herring in patch-2.
* Drop the example from OLDI schema.
* Fix the DSS schema conditions.
- Drop the OLDI clone mode support from the driver as it was incomplete and
could not account for cases where OLDI TXes were connected to another pair
of bridges that would require additional programming, instead of a pair of
simple-panels which wouldn't.
V4:
- Implement fixes suggested by Krzysztof Kozlowski:
* Squash patches v3:2/4 and v3:3/4 to v4:2/3, and add more hardware details
in commit description.
* Change the serial clock name for OLDI, from "s_clk" to "serial".
* Fix the required condition in the OLDI schema.
* Other minor fixes.
- Change "oldi-txes" OLDI DT node name to "oldi-transmitters".
- Update secondary-OLDI property requirements to be more relaxing for AM62P
DSS configuration.
V3:
- Fix the dt_binding_check warning in patch 3/4[5] by adding
"additionalProperties" constraint.
V2:
- Add all the R-b and A-b tags from Laurent Pinchart, Rob Herring, and
Tomi Valkeinen.
- Reword the subject for patch 1/4.
- Reword the commit descriptions to add proper hardware detail.
- Drop the change in schema reference for port@0 in patch 3/4.
- Lots of improvements for patch 4/4.
* Refactor OLDI selection logic in tidss_oldi_tx_power().
* Add "companion_instance" support to identify the OLDI index in
dual-link or cloned sinle-link modes.
* De-initialize tidss_oldi during tidss removal.
* Use dev_err_probe() instead of dev_err().
* Drop OLDI(n) macro.
* Move OLDI Config register bits to tidss_dispc_regs.h.
* Drop oldi bridge atomic_check().
* s/%d/%u for all print instances of "oldi_instance".
* Move OLDI init after DISPC init in tidss_probe.
* Use devm_drm_of_get_bridge() instead of
drm_of_find_panel_or_bridge() to find the next bridge and drop all
the drm_panel support from tidss_oldi.
Previous revisions:
V1: https://lore.kernel.org/all/20240511193055.1686149-1-a-bhatia1@ti.com/
V2: https://lore.kernel.org/all/20240715200953.1213284-1-a-bhatia1@ti.com/
V3: https://lore.kernel.org/all/20240716084248.1393666-1-a-bhatia1@ti.com/
V4: https://lore.kernel.org/all/20241124143649.686995-1-aradhya.bhatia@linux.dev/
V5: https://lore.kernel.org/all/20250209160925.380348-1-aradhya.bhatia@linux.dev/
V6: https://lore.kernel.org/all/20250226181300.756610-1-aradhya.bhatia@linux.dev/
V7: https://lore.kernel.org/all/20250329133943.110698-1-aradhya.bhatia@linux.dev/
V8: https://lore.kernel.org/all/20250525151721.567042-1-aradhya.bhatia@linux.dev/
[0]: Dependency Patches:
("drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions")
https://lore.kernel.org/all/20250406131642.171240-2-aradhya.bhatia@linux.dev/
("drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable")
https://lore.kernel.org/all/20250406131642.171240-3-aradhya.bhatia@linux.dev/
("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
https://lore.kernel.org/all/20250406131642.171240-4-aradhya.bhatia@linux.dev/
[1]: AM62 OLDI Series - v7
https://lore.kernel.org/all/20230125113529.13952-1-a-bhatia1@ti.com/
[2]: AM62 DSS Series - v9
https://lore.kernel.org/all/20230616150900.6617-1-a-bhatia1@ti.com/
[3]: TI AM625 SoC based Beagleplay platform
https://www.beagleboard.org/boards/beagleplay
[4]: GitHub Fork for OLDI tests
https://github.com/aradhya07/linux-ab/tree/next_oldi-v9_1_tests
[5]: ("ti,am65x-dss.yaml: oldi-txes: Missing additionalProperties/
unevaluatedProperties constraint")
https://lore.kernel.org/all/172107979988.1595945.9666141982402158422.robh@kernel.org/
[6]: Undo drop of OLDI clone mode support
https://gist.github.com/aradhya07/383b4679453025ba515d58858bd813ca
Aradhya Bhatia (4):
dt-bindings: display: ti,am65x-dss: Re-indent the example
dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter
drm/tidss: Mark AM65x OLDI code separately
drm/tidss: Add OLDI bridge support
.../bindings/display/ti/ti,am625-oldi.yaml | 79 +++
.../bindings/display/ti/ti,am65x-dss.yaml | 199 +++++-
MAINTAINERS | 1 +
drivers/gpu/drm/tidss/Makefile | 3 +-
drivers/gpu/drm/tidss/tidss_dispc.c | 92 +--
drivers/gpu/drm/tidss/tidss_dispc.h | 7 +-
drivers/gpu/drm/tidss/tidss_dispc_regs.h | 29 +-
drivers/gpu/drm/tidss/tidss_drv.c | 9 +
drivers/gpu/drm/tidss/tidss_drv.h | 5 +
drivers/gpu/drm/tidss/tidss_kms.c | 2 +-
drivers/gpu/drm/tidss/tidss_oldi.c | 598 ++++++++++++++++++
drivers/gpu/drm/tidss/tidss_oldi.h | 43 ++
12 files changed, 1001 insertions(+), 66 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
create mode 100644 drivers/gpu/drm/tidss/tidss_oldi.c
create mode 100644 drivers/gpu/drm/tidss/tidss_oldi.h
base-commit: 126bf397bf58485cdd631824190cdcfeb86f5d9b
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v9 1/4] dt-bindings: display: ti, am65x-dss: Re-indent the example
2025-05-28 12:25 [PATCH v9 0/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
@ 2025-05-28 12:25 ` Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 2/4] dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter Aradhya Bhatia
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Aradhya Bhatia @ 2025-05-28 12:25 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tomi Valkeinen,
Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, Michael Walle, DRI Development List,
Devicetree List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
Reduce tab size from 8 spaces to 4 spaces to make the bindings
consistent, and easy to expand.
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
.../bindings/display/ti/ti,am65x-dss.yaml | 54 +++++++++----------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
index a5b13cb7bc73..9cebe237bd4e 100644
--- a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
+++ b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
@@ -161,32 +161,32 @@ examples:
#include <dt-bindings/soc/ti,sci_pm_domain.h>
dss: dss@4a00000 {
- compatible = "ti,am65x-dss";
- reg = <0x04a00000 0x1000>, /* common */
- <0x04a02000 0x1000>, /* vidl1 */
- <0x04a06000 0x1000>, /* vid */
- <0x04a07000 0x1000>, /* ovr1 */
- <0x04a08000 0x1000>, /* ovr2 */
- <0x04a0a000 0x1000>, /* vp1 */
- <0x04a0b000 0x1000>, /* vp2 */
- <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>;
- };
- };
+ compatible = "ti,am65x-dss";
+ reg = <0x04a00000 0x1000>, /* common */
+ <0x04a02000 0x1000>, /* vidl1 */
+ <0x04a06000 0x1000>, /* vid */
+ <0x04a07000 0x1000>, /* ovr1 */
+ <0x04a08000 0x1000>, /* ovr2 */
+ <0x04a0a000 0x1000>, /* vp1 */
+ <0x04a0b000 0x1000>, /* vp2 */
+ <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>;
+ };
};
+ };
};
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v9 2/4] dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter
2025-05-28 12:25 [PATCH v9 0/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 1/4] dt-bindings: display: ti, am65x-dss: Re-indent the example Aradhya Bhatia
@ 2025-05-28 12:25 ` Aradhya Bhatia
2025-06-05 14:41 ` Rob Herring (Arm)
2025-05-28 12:25 ` [PATCH v9 3/4] drm/tidss: Mark AM65x OLDI code separately Aradhya Bhatia
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Aradhya Bhatia @ 2025-05-28 12:25 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tomi Valkeinen,
Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, Michael Walle, DRI Development List,
Devicetree List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
The OLDI transmitters (TXes) do not have registers of their own, and are
dependent on the source video-ports (VPs) from the DSS to provide
configuration data. This hardware doesn't directly sit on the internal
bus of the SoC, but does so via the DSS. Hence, the OLDI TXes are
supposed to be child nodes under the DSS, and not independent devices.
Two of the OLDI TXes can function in tandem to output dual-link OLDI
output, or cloned single-link outputs. In these cases, one OLDI will be
the primary OLDI, and the other one, a companion. The following diagram
represents such a configuration.
+-----+-----+ +-------+
| | | | |
| | VP1 +----+--->+ OLDI0 | (Primary - may need companion)
| | | | | |
| DSS +-----+ | +-------+
| | | |
| | VP2 | | +-------+
| | | | | |
+-----+-----+ +--->+ OLDI1 | (Companion OLDI)
| |
+-------+
The DSS in AM625 SoC has a configuration like the one above. The AM625
DSS VP1 (port@0) can connect and control 2 OLDI TXes, to use them in
dual-link or cloned single-link OLDI modes. It is only the VP1 that can
connect to either OLDI TXes for the AM625 DSS, and not the VP2.
Alternatively, on some future TI SoCs, along with the above
configuration, the OLDI TX can _also_ connect to separate video sources,
making them work entirely independent of each other. In this case,
neither of the OLDIs are "companion" or "secondary" OLDIs, and nor do
they require one. They both are independent and primary OLDIs. The
following diagram represents such a configuration.
+-----+-----+ +-------+
| | | | |
| | VP1 +--+----------->+ OLDI0 | (Primary - may need companion)
| | | | | |
| +-----+ | +-------+
| | | |
| | VP2 | |
| | | |
| DSS +-----+ | +---+ +-------+
| | | +-->+ M | | |
| | VP3 +----->+ U +--->+ OLDI1 | (Companion or Primary)
| | | | X | | |
| +-----+ +---+ +-------+
| | |
| | VP4 |
| | |
+-----+-----+
Note that depending on the mux configuration, the OLDIs can either be
working together in tandem - sourced by VP1, OR, they could be working
independently sourced by VP1 and VP3 respectively.
The idea is to support all the configurations with this OLDI TX schema.
The OLDI functionality is further supported by a system-control module,
which contains a few registers to control OLDI IO power and other
electrical characteristics of the IO lanes.
Add devicetree binding schema for the OLDI TXes to support various
configurations, and extend their support to the AM625 DSS.
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
Changes Log:
V9:
- Reword the "ti,companion-oldi" property description.
- Fix the missing "ti,companion-oldi" property in the schema example.
- v8 of this patch: https://lore.kernel.org/all/20250525151721.567042-3-aradhya.bhatia@linux.dev/
V8:
- Drop the condition that made the "secondary-oldi" and "companion-oldi"
properties mutually exclusive.
- Add "ti,am62l-dss" compatible to the list of compatibles that cannot
use the multiple endpoints or have "oldi-transmitters", on port@0.
- Because of above, drop R-b tags from Tomi Valkeinen, and Rob Herring.
- v7 of this patch: https://lore.kernel.org/all/20250329133943.110698-3-aradhya.bhatia@linux.dev/
---
.../bindings/display/ti/ti,am625-oldi.yaml | 79 +++++++++
.../bindings/display/ti/ti,am65x-dss.yaml | 157 ++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 237 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
diff --git a/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml b/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
new file mode 100644
index 000000000000..8203ec5e5bb3
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
@@ -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
+
+...
diff --git a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
index 9cebe237bd4e..361e9cae6896 100644
--- a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
+++ b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
@@ -100,6 +100,24 @@ properties:
For AM62A7 DSS, the port is tied off inside the SoC.
For AM62L DSS, the DSS DPI output port node from 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:
$ref: /schemas/graph.yaml#/properties/port
@@ -121,6 +139,25 @@ properties:
Input memory (from main memory to dispc) bandwidth limit in
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:
- if:
properties:
@@ -129,6 +166,7 @@ allOf:
const: ti,am62a7-dss
then:
properties:
+ oldi-transmitters: false
ports:
properties:
port@0: false
@@ -143,6 +181,22 @@ allOf:
properties:
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:
- compatible
- reg
@@ -190,3 +244,106 @@ examples:
};
};
};
+
+ - |
+ #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",
+ "ovr1", "ovr2", "vp1", "vp2", "common1";
+ power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 186 6>,
+ <&vp1_clock>,
+ <&k3_clks 186 2>;
+ clock-names = "fck", "vp1", "vp2";
+ 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 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ dpi0_out0: endpoint@0 {
+ reg = <0>;
+ 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>;
+ };
+ };
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 88b17f23ed4f..1836434ef5fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8097,6 +8097,7 @@ M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
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,j721e-dss.yaml
F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v9 3/4] drm/tidss: Mark AM65x OLDI code separately
2025-05-28 12:25 [PATCH v9 0/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 1/4] dt-bindings: display: ti, am65x-dss: Re-indent the example Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 2/4] dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter Aradhya Bhatia
@ 2025-05-28 12:25 ` Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 4/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
2025-06-26 9:40 ` [PATCH v9 0/4] " Tomi Valkeinen
4 siblings, 0 replies; 9+ messages in thread
From: Aradhya Bhatia @ 2025-05-28 12:25 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tomi Valkeinen,
Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, Michael Walle, DRI Development List,
Devicetree List, Linux Kernel List, Aradhya Bhatia
The dss dt schema and the tidss driver have kept the single-link OLDI in
AM65x integrated with the parent video-port (VP) from DSS (as the OLDI
configuration happens from the source VP only).
To help configure the dual-lvds modes that the OLDI has to offer in
devices AM62x and later, a new OLDI bridge driver will be introduced.
Mark the existing OLDI code separately by renaming all the current OLDI
identifiers with the 'AM65X_' prefix in tidss driver, to help
distinguish from the upcoming OLDI bridge driver.
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
drivers/gpu/drm/tidss/tidss_dispc.c | 68 ++++++++++++------------
drivers/gpu/drm/tidss/tidss_dispc.h | 2 +-
drivers/gpu/drm/tidss/tidss_dispc_regs.h | 15 +++---
drivers/gpu/drm/tidss/tidss_kms.c | 2 +-
4 files changed, 44 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 21363ccbd763..befa5ae1c246 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -146,7 +146,7 @@ static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
const struct dispc_features dispc_am65x_feats = {
.max_pclk_khz = {
[DISPC_VP_DPI] = 165000,
- [DISPC_VP_OLDI] = 165000,
+ [DISPC_VP_OLDI_AM65X] = 165000,
},
.scaling = {
@@ -176,7 +176,7 @@ const struct dispc_features dispc_am65x_feats = {
.vp_name = { "vp1", "vp2" },
.ovr_name = { "ovr1", "ovr2" },
.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 = {
.has_ctm = true,
@@ -491,7 +491,7 @@ struct dispc_device {
void __iomem *base_ovr[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];
@@ -1016,13 +1016,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 {
u32 bus_fmt;
u32 data_width;
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[] = {
@@ -1066,7 +1064,7 @@ int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
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) {
dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
__func__, dispc->feat->vp_name[hw_videoport]);
@@ -1076,23 +1074,23 @@ int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
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;
- regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL,
- OLDI_PWRDN_TX, val);
- regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL,
- OLDI_PWRDN_TX, val);
- regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL,
- OLDI_PWRDN_TX, val);
- regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL,
- OLDI_PWRDN_TX, val);
- regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL,
- OLDI_PWRDN_TX, val);
+ regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT0_IO_CTRL,
+ AM65X_OLDI_PWRDN_TX, val);
+ regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT1_IO_CTRL,
+ AM65X_OLDI_PWRDN_TX, val);
+ regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT2_IO_CTRL,
+ AM65X_OLDI_PWRDN_TX, val);
+ regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT3_IO_CTRL,
+ AM65X_OLDI_PWRDN_TX, val);
+ regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_CLK_IO_CTRL,
+ AM65X_OLDI_PWRDN_TX, val);
}
static void dispc_set_num_datalines(struct dispc_device *dispc,
@@ -1121,8 +1119,8 @@ static void dispc_set_num_datalines(struct dispc_device *dispc,
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,
- const struct dispc_bus_format *fmt)
+static void dispc_enable_am65x_oldi(struct dispc_device *dispc, u32 hw_videoport,
+ const struct dispc_bus_format *fmt)
{
u32 oldi_cfg = 0;
u32 oldi_reset_bit = BIT(5 + hw_videoport);
@@ -1141,7 +1139,7 @@ static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport,
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 */
@@ -1170,10 +1168,10 @@ void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
if (WARN_ON(!fmt))
return;
- if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
- dispc_oldi_tx_power(dispc, true);
+ if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X) {
+ dispc_am65x_oldi_tx_power(dispc, true);
- dispc_enable_oldi(dispc, hw_videoport, fmt);
+ dispc_enable_am65x_oldi(dispc, hw_videoport, fmt);
}
}
@@ -1229,7 +1227,7 @@ void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
align = true;
/* 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;
dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ,
@@ -1255,10 +1253,10 @@ void dispc_vp_disable(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_oldi_tx_power(dispc, false);
+ dispc_am65x_oldi_tx_power(dispc, false);
}
}
@@ -2852,15 +2850,15 @@ static int dispc_iomap_resource(struct platform_device *pdev, const char *name,
static int dispc_init_am65x_oldi_io_ctrl(struct device *dev,
struct dispc_device *dispc)
{
- dispc->oldi_io_ctrl =
+ dispc->am65x_oldi_io_ctrl =
syscon_regmap_lookup_by_phandle(dev->of_node,
"ti,am65x-oldi-io-ctrl");
- if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) {
- dispc->oldi_io_ctrl = NULL;
- } else if (IS_ERR(dispc->oldi_io_ctrl)) {
+ if (PTR_ERR(dispc->am65x_oldi_io_ctrl) == -ENODEV) {
+ dispc->am65x_oldi_io_ctrl = NULL;
+ } else if (IS_ERR(dispc->am65x_oldi_io_ctrl)) {
dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n",
- __func__, PTR_ERR(dispc->oldi_io_ctrl));
- return PTR_ERR(dispc->oldi_io_ctrl);
+ __func__, PTR_ERR(dispc->am65x_oldi_io_ctrl));
+ return PTR_ERR(dispc->am65x_oldi_io_ctrl);
}
return 0;
}
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index 28958514b8f5..8f1cd0b75629 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -58,7 +58,7 @@ struct dispc_errata {
enum dispc_vp_bus_type {
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_TIED_OFF, /* Tied off / Unavailable */
DISPC_VP_MAX_BUS_TYPE,
diff --git a/drivers/gpu/drm/tidss/tidss_dispc_regs.h b/drivers/gpu/drm/tidss/tidss_dispc_regs.h
index e88148e44937..30ce5ee40e1e 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc_regs.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc_regs.h
@@ -226,18 +226,21 @@ enum dispc_common_regs {
#define DISPC_VP_DSS_DMA_THREADSIZE 0x170 /* J721E */
#define DISPC_VP_DSS_DMA_THREADSIZE_STATUS 0x174 /* J721E */
+/* 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
* from CTRL_MMR0, there the syscon regmap should map 0x14 bytes from
* CTRLMMR0P1_OLDI_DAT0_IO_CTRL to CTRLMMR0P1_OLDI_CLK_IO_CTRL
* register range.
*/
-#define OLDI_DAT0_IO_CTRL 0x00
-#define OLDI_DAT1_IO_CTRL 0x04
-#define OLDI_DAT2_IO_CTRL 0x08
-#define OLDI_DAT3_IO_CTRL 0x0C
-#define OLDI_CLK_IO_CTRL 0x10
+#define AM65X_OLDI_DAT0_IO_CTRL 0x00
+#define AM65X_OLDI_DAT1_IO_CTRL 0x04
+#define AM65X_OLDI_DAT2_IO_CTRL 0x08
+#define AM65X_OLDI_DAT3_IO_CTRL 0x0C
+#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 */
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 19432c08ec6b..c34eb90cddbe 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -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);
switch (feat->vp_bus_type[i]) {
- case DISPC_VP_OLDI:
+ case DISPC_VP_OLDI_AM65X:
enc_type = DRM_MODE_ENCODER_LVDS;
conn_type = DRM_MODE_CONNECTOR_LVDS;
break;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v9 4/4] drm/tidss: Add OLDI bridge support
2025-05-28 12:25 [PATCH v9 0/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
` (2 preceding siblings ...)
2025-05-28 12:25 ` [PATCH v9 3/4] drm/tidss: Mark AM65x OLDI code separately Aradhya Bhatia
@ 2025-05-28 12:25 ` Aradhya Bhatia
2025-05-28 13:35 ` Michael Walle
2025-06-30 10:56 ` Jayesh Choudhary
2025-06-26 9:40 ` [PATCH v9 0/4] " Tomi Valkeinen
4 siblings, 2 replies; 9+ messages in thread
From: Aradhya Bhatia @ 2025-05-28 12:25 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Tomi Valkeinen,
Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, Michael Walle, DRI Development List,
Devicetree List, Linux Kernel List, Aradhya Bhatia
From: Aradhya Bhatia <a-bhatia1@ti.com>
The AM62x and AM62Px SoCs feature 2 OLDI TXes each, which makes it
possible to connect them in dual-link or cloned single-link OLDI display
modes. The current OLDI support in tidss_dispc.c can only support for
a single OLDI TX, connected to a VP and doesn't really support
configuration of OLDIs in the other modes. The current OLDI support in
tidss_dispc.c also works on the principle that the OLDI output can only
be served by one, and only one, DSS video-port. This isn't the case in
the AM62Px SoC, where there are 2 DSS controllers present that share the
OLDI TXes.
Having their own devicetree and their own bridge entity will help
support the various display modes and sharing possiblilities of the OLDI
hardware.
For all these reasons, add support for the OLDI TXes as DRM bridges.
Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
---
Change Log:
V9:
- Fix the get_oldi_mode() logic, for secondary-oldi in dual-link mode.
- Allow secondary-oldi to skip getting serial-clk and io-ctrl syscon regs.
- Rename enum "OLDI_MODE_CLONE_SECONDARY_SINGLE_LINK" to
"OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK".
- v8 of this patch: https://lore.kernel.org/all/20250525151721.567042-5-aradhya.bhatia@linux.dev/
V8:
- Change get_oldi_mode() logic to distinguish between the 2 different types
of secondary OLDIs (dual-link and clone-mode). This is required because
the secondary OLDI of clone-mode needs to get registered as a drm_bridge
device (when we have the full support in future). The secondary OLDI of
dual-link mode does not need to be set up as a drm_bridge.
- Fix some typos and the one wrong variable type in the tidss_oldi driver.
- Drop Tomi Valkeinen's R-b tag, and T-b tags by Alexander Sverdlin, and
Michael Walle.
- v7 of this patch: https://lore.kernel.org/all/20250329133943.110698-5-aradhya.bhatia@linux.dev/
---
drivers/gpu/drm/tidss/Makefile | 3 +-
drivers/gpu/drm/tidss/tidss_dispc.c | 24 +-
drivers/gpu/drm/tidss/tidss_dispc.h | 5 +
drivers/gpu/drm/tidss/tidss_dispc_regs.h | 14 +
drivers/gpu/drm/tidss/tidss_drv.c | 9 +
drivers/gpu/drm/tidss/tidss_drv.h | 5 +
drivers/gpu/drm/tidss/tidss_oldi.c | 598 +++++++++++++++++++++++
drivers/gpu/drm/tidss/tidss_oldi.h | 43 ++
8 files changed, 699 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/tidss/tidss_oldi.c
create mode 100644 drivers/gpu/drm/tidss/tidss_oldi.h
diff --git a/drivers/gpu/drm/tidss/Makefile b/drivers/gpu/drm/tidss/Makefile
index 312645271014..b6d6becf1683 100644
--- a/drivers/gpu/drm/tidss/Makefile
+++ b/drivers/gpu/drm/tidss/Makefile
@@ -7,6 +7,7 @@ tidss-y := tidss_crtc.o \
tidss_irq.o \
tidss_plane.o \
tidss_scale_coefs.o \
- tidss_dispc.o
+ tidss_dispc.o \
+ tidss_oldi.o
obj-$(CONFIG_DRM_TIDSS) += tidss.o
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index befa5ae1c246..c0277fa36425 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -566,6 +566,29 @@ static u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 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
* number. For example 7:0
@@ -1418,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
* and the effective rate resulting from calculating the clock divider value.
*/
-static
unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
{
int r = rate / 100, rr = real_rate / 100;
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index 8f1cd0b75629..b8614f62186c 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -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_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);
dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc);
diff --git a/drivers/gpu/drm/tidss/tidss_dispc_regs.h b/drivers/gpu/drm/tidss/tidss_dispc_regs.h
index 30ce5ee40e1e..50a3f28250ef 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc_regs.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc_regs.h
@@ -226,6 +226,20 @@ enum dispc_common_regs {
#define DISPC_VP_DSS_DMA_THREADSIZE 0x170 /* 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 };
diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
index f2a4f659f574..a1b12e52aca4 100644
--- a/drivers/gpu/drm/tidss/tidss_drv.c
+++ b/drivers/gpu/drm/tidss/tidss_drv.c
@@ -24,6 +24,7 @@
#include "tidss_drv.h"
#include "tidss_kms.h"
#include "tidss_irq.h"
+#include "tidss_oldi.h"
/* Power management */
@@ -147,6 +148,10 @@ static int tidss_probe(struct platform_device *pdev)
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_set_autosuspend_delay(dev, 1000);
@@ -203,6 +208,8 @@ static int tidss_probe(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
+ tidss_oldi_deinit(tidss);
+
return ret;
}
@@ -227,6 +234,8 @@ static void tidss_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
+ tidss_oldi_deinit(tidss);
+
/* devm allocated dispc goes away with the dev so mark it NULL */
dispc_remove(tidss);
diff --git a/drivers/gpu/drm/tidss/tidss_drv.h b/drivers/gpu/drm/tidss/tidss_drv.h
index 7f4f4282bc04..d14d5d28f0a3 100644
--- a/drivers/gpu/drm/tidss/tidss_drv.h
+++ b/drivers/gpu/drm/tidss/tidss_drv.h
@@ -11,8 +11,10 @@
#define TIDSS_MAX_PORTS 4
#define TIDSS_MAX_PLANES 4
+#define TIDSS_MAX_OLDI_TXES 2
typedef u32 dispc_irq_t;
+struct tidss_oldi;
struct tidss_device {
struct drm_device ddev; /* DRM device for DSS */
@@ -27,6 +29,9 @@ struct tidss_device {
unsigned int num_planes;
struct drm_plane *planes[TIDSS_MAX_PLANES];
+ unsigned int num_oldis;
+ struct tidss_oldi *oldis[TIDSS_MAX_OLDI_TXES];
+
unsigned int irq;
/* protects the irq masks field and irqenable/irqstatus registers */
diff --git a/drivers/gpu/drm/tidss/tidss_oldi.c b/drivers/gpu/drm/tidss/tidss_oldi.c
new file mode 100644
index 000000000000..8223b8fec8ce
--- /dev/null
+++ b/drivers/gpu/drm/tidss/tidss_oldi.c
@@ -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;
+}
diff --git a/drivers/gpu/drm/tidss/tidss_oldi.h b/drivers/gpu/drm/tidss/tidss_oldi.h
new file mode 100644
index 000000000000..8cd535c5ee65
--- /dev/null
+++ b/drivers/gpu/drm/tidss/tidss_oldi.h
@@ -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__ */
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v9 4/4] drm/tidss: Add OLDI bridge support
2025-05-28 12:25 ` [PATCH v9 4/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
@ 2025-05-28 13:35 ` Michael Walle
2025-06-30 10:56 ` Jayesh Choudhary
1 sibling, 0 replies; 9+ messages in thread
From: Michael Walle @ 2025-05-28 13:35 UTC (permalink / raw)
To: Aradhya Bhatia, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Tomi Valkeinen, Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, DRI Development List, Devicetree List,
Linux Kernel List
[-- Attachment #1: Type: text/plain, Size: 1191 bytes --]
On Wed May 28, 2025 at 2:25 PM CEST, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The AM62x and AM62Px SoCs feature 2 OLDI TXes each, which makes it
> possible to connect them in dual-link or cloned single-link OLDI display
> modes. The current OLDI support in tidss_dispc.c can only support for
> a single OLDI TX, connected to a VP and doesn't really support
> configuration of OLDIs in the other modes. The current OLDI support in
> tidss_dispc.c also works on the principle that the OLDI output can only
> be served by one, and only one, DSS video-port. This isn't the case in
> the AM62Px SoC, where there are 2 DSS controllers present that share the
> OLDI TXes.
>
> Having their own devicetree and their own bridge entity will help
> support the various display modes and sharing possiblilities of the OLDI
> hardware.
>
> For all these reasons, add support for the OLDI TXes as DRM bridges.
>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
Tested-by: Michael Walle <mwalle@kernel.org> # on am67a
(with local patches from downstream for DSS support)
Thanks,
-michael
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v9 2/4] dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter
2025-05-28 12:25 ` [PATCH v9 2/4] dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter Aradhya Bhatia
@ 2025-06-05 14:41 ` Rob Herring (Arm)
0 siblings, 0 replies; 9+ messages in thread
From: Rob Herring (Arm) @ 2025-06-05 14:41 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Devarsh Thakkar, Alexander Sverdlin, Devicetree List,
Simona Vetter, Tomi Valkeinen, Thomas Zimmermann, Maxime Ripard,
Michael Walle, Laurent Pinchart, Jyri Sarha, Vignesh Raghavendra,
Conor Dooley, Francesco Dolcini, David Airlie, Maarten Lankhorst,
Praneeth Bajjuri, Udit Kumar, Linux Kernel List, Jayesh Choudhary,
Nishanth Menon, DRI Development List, Krzysztof Kozlowski
On Wed, 28 May 2025 17:55:42 +0530, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The OLDI transmitters (TXes) do not have registers of their own, and are
> dependent on the source video-ports (VPs) from the DSS to provide
> configuration data. This hardware doesn't directly sit on the internal
> bus of the SoC, but does so via the DSS. Hence, the OLDI TXes are
> supposed to be child nodes under the DSS, and not independent devices.
>
> Two of the OLDI TXes can function in tandem to output dual-link OLDI
> output, or cloned single-link outputs. In these cases, one OLDI will be
> the primary OLDI, and the other one, a companion. The following diagram
> represents such a configuration.
>
> +-----+-----+ +-------+
> | | | | |
> | | VP1 +----+--->+ OLDI0 | (Primary - may need companion)
> | | | | | |
> | DSS +-----+ | +-------+
> | | | |
> | | VP2 | | +-------+
> | | | | | |
> +-----+-----+ +--->+ OLDI1 | (Companion OLDI)
> | |
> +-------+
>
> The DSS in AM625 SoC has a configuration like the one above. The AM625
> DSS VP1 (port@0) can connect and control 2 OLDI TXes, to use them in
> dual-link or cloned single-link OLDI modes. It is only the VP1 that can
> connect to either OLDI TXes for the AM625 DSS, and not the VP2.
>
> Alternatively, on some future TI SoCs, along with the above
> configuration, the OLDI TX can _also_ connect to separate video sources,
> making them work entirely independent of each other. In this case,
> neither of the OLDIs are "companion" or "secondary" OLDIs, and nor do
> they require one. They both are independent and primary OLDIs. The
> following diagram represents such a configuration.
>
> +-----+-----+ +-------+
> | | | | |
> | | VP1 +--+----------->+ OLDI0 | (Primary - may need companion)
> | | | | | |
> | +-----+ | +-------+
> | | | |
> | | VP2 | |
> | | | |
> | DSS +-----+ | +---+ +-------+
> | | | +-->+ M | | |
> | | VP3 +----->+ U +--->+ OLDI1 | (Companion or Primary)
> | | | | X | | |
> | +-----+ +---+ +-------+
> | | |
> | | VP4 |
> | | |
> +-----+-----+
>
> Note that depending on the mux configuration, the OLDIs can either be
> working together in tandem - sourced by VP1, OR, they could be working
> independently sourced by VP1 and VP3 respectively.
> The idea is to support all the configurations with this OLDI TX schema.
>
> The OLDI functionality is further supported by a system-control module,
> which contains a few registers to control OLDI IO power and other
> electrical characteristics of the IO lanes.
>
> Add devicetree binding schema for the OLDI TXes to support various
> configurations, and extend their support to the AM625 DSS.
>
> Signed-off-by: Aradhya Bhatia <a-bhatia1@ti.com>
> Signed-off-by: Aradhya Bhatia <aradhya.bhatia@linux.dev>
> ---
> Changes Log:
> V9:
> - Reword the "ti,companion-oldi" property description.
> - Fix the missing "ti,companion-oldi" property in the schema example.
> - v8 of this patch: https://lore.kernel.org/all/20250525151721.567042-3-aradhya.bhatia@linux.dev/
>
> V8:
> - Drop the condition that made the "secondary-oldi" and "companion-oldi"
> properties mutually exclusive.
> - Add "ti,am62l-dss" compatible to the list of compatibles that cannot
> use the multiple endpoints or have "oldi-transmitters", on port@0.
> - Because of above, drop R-b tags from Tomi Valkeinen, and Rob Herring.
> - v7 of this patch: https://lore.kernel.org/all/20250329133943.110698-3-aradhya.bhatia@linux.dev/
>
> ---
> .../bindings/display/ti/ti,am625-oldi.yaml | 79 +++++++++
> .../bindings/display/ti/ti,am65x-dss.yaml | 157 ++++++++++++++++++
> MAINTAINERS | 1 +
> 3 files changed, 237 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v9 0/4] drm/tidss: Add OLDI bridge support
2025-05-28 12:25 [PATCH v9 0/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
` (3 preceding siblings ...)
2025-05-28 12:25 ` [PATCH v9 4/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
@ 2025-06-26 9:40 ` Tomi Valkeinen
4 siblings, 0 replies; 9+ messages in thread
From: Tomi Valkeinen @ 2025-06-26 9:40 UTC (permalink / raw)
To: Aradhya Bhatia
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Jayesh Choudhary, Francesco Dolcini,
Alexander Sverdlin, Michael Walle, DRI Development List,
Devicetree List, Linux Kernel List, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Jyri Sarha
Hi,
On 28/05/2025 15:25, Aradhya Bhatia wrote:
> Hello all,
>
> This patch series adds support for the dual OLDI TXes supported in Texas
> Instruments' AM62x and AM62Px family of SoCs. The OLDI TX hardware supports
> single-lvds, lvds-clone, and dual-lvds modes. These TXes have now been
> represented through DRM bridges within TI-DSS.
>
> * Some history and hardware description for this patch series *
>
> This patch series is a complete re-vamp from the previously posted series[1] and
> hence, the version index has been reset to v1. The OLDI support from that series
> was dropped and only the base support for AM62x DSS was kept (and eventually
> merged)[2].
>
> The OLDI display that the tidss driver today supports, could not be extended for
> the newer SoCs. The OLDI display in tidss is modelled after the DSS and OLDI
> hardware in the AM65x SoC. The DSS in AM65x SoC, has two video-ports. Both these
> video-ports (VP) output DPI video signals. One of the DPI output (from VP1) from
> the DSS connects to a singular OLDI TX present inside the SoC. There is no other
> way for the DPI from VP1 to be taken out of the SoC. The other DPI output
> however - the one from VP2 - is taken out of the SoC as is. Hence we have an
> OLDI bus output and a DPI bus output from the SoC. Since the VP1 and OLDI are
> tightly coupled, the tidss driver considers them as a single entity. That is
> why, any OLDI sink connects directly to the DSS ports in the OF graphs.
>
> The newer SoCs have varying DSS and OLDI integrations.
>
> The AM62x DSS also has 2 VPs. The 2nd VP, VP2, outputs DPI signals which are
> taken out of the SoC - similar to the AM65x above. For the VP1, there are 2 OLDI
> TXes. These OLDI TXes can only receive DPI signals from VP1, and don't connect
> to VP2 at all.
>
> The AM62Px SoC has 2 OLDI TXes like AM62x SoC. However, the AM62Px SoC also has
> 2 separate DSSes. The 2 OLDI TXes can now be shared between the 2 VPs of the 2
> DSSes.
>
> The addition of the 2nd OLDI TX (and a 2nd DSS in AM62Px) creates a need for
> some major changes for a full feature experience.
>
> 1. The OF graph needs to be updated to accurately show the data flow.
> 2. The tidss and OLDI drivers now need to support the dual-link and the cloned
> single-link OLDI video signals.
> 3. The drivers also need to support the case where 2 OLDI TXes are connected to
> 2 different VPs - thereby creating 2 independent streams of single-link OLDI
> outputs.
>
> Note that the OLDI does not have registers of its own. It is still dependent on
> the parent VP. The VP that provides the DPI video signals to the OLDI TXes, also
> gives the OLDI TXes all the config data. That is to say, the hardware doesn't
> sit on the bus directly - but does so through the DSS.
>
> In light of all of these hardware variations, it was decided to have a separate
> OLDI driver (unlike AM65x) but not entirely separate so as to be a platform
> device. The OLDI TXes are now being represented as DRM bridges under the tidss.
>
>
> * Regarding the Dependency Patches *
> Since the OLDI TXes have a hardware dependency with the parent VP(s), the OLDI
> configuration needs to happen before that VP is enabled for streaming. VP stream
> enable takes place in tidss_crtc_atomic_enable hook. I have posted patches[0]
> allowing DRM bridges to get pre-enabled before the CRTC of that bridge is
> enabled. Without those patches, some warnings or glitches may be observed.
>
>
> * Regarding the Drop of Clone Mode support *
> Another key point to note is that the support for clone mode has been dropped
> from the tidss OLDI driver, from v5 onwards. If the DT is configured for a clone
> mode, the driver will report an error and exit. This has been done because the
> driver was not supporting a specific case of clone mode where 2 OLDI sink
> bridges connected to the 2 OLDI TXes require active programming (unlike the
> simple-panels which do not). The driver does not support creation of two
> encoder-bridge pipelines (along with the parent tidss driver) to allow program
> any subsequent bridges (OLDI sinks and bridges thereafter).
> The code fragments that write the OLDI config to enable clone mode have been
> kept as they are, for future, but the driver will not continue to probe if it
> detects a clone mode configuration, for the time being.
> This drop of clone mode support can be undone by applying this _soft-tested_
> patch[6] on top of this series. This patch will revert the driver to previous
> revisions and will allow OLDI sinks that don't require active programming (for
> example: simple-panels) to work with the driver. Note that this isn't the ideal
> way to run clone mode, but it just works for any bridge pipeline after OLDT TX
> that does not require additional configuration after the OLDI (for example: a
> couple of simple lvds panels connected directly to the OLDI TXes in clone mode).
>
>
> These patches have been tested on AM625 based Beagleplay[3] platform with a
> Lincolntech LCD185 dual-lvds panel. The patches with complete support including
> the expected devicetree configuration of the OLDI TXes can be found in the
> "next_oldi-v9_1_tests" branch of my github fork[4]. This branch also has support
> for Microtips dual-lvds panel (SK-LCD1) which is compatible with the SK-AM625
> EVM platform.
>
> I'd appreciate it if somebody can test it, and report back if they observe any
> issues.
>
> Thanks,
> Aradhya
>
> * Important note about the authorship of patches *
> All the patches in the of this series were authored when I owned a "ti.com"
> based email id, i.e. <a-bhatia1@ti.com>. This email id is not in use anymore,
> and all the work done later has been part of my personal work. Since the
> original patches were authored using TI's email id, I have maintained the
> original authorships as they are, as well as their sign offs.
>
> I have further added another sign off that uses my current (and personal) email
> id, the one that is being used to send this revision, i.e.
> <aradhya.bhatia@linux.dev>.
Thanks! I will pick these up to drm-misc-next.
Tomi
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v9 4/4] drm/tidss: Add OLDI bridge support
2025-05-28 12:25 ` [PATCH v9 4/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
2025-05-28 13:35 ` Michael Walle
@ 2025-06-30 10:56 ` Jayesh Choudhary
1 sibling, 0 replies; 9+ messages in thread
From: Jayesh Choudhary @ 2025-06-30 10:56 UTC (permalink / raw)
To: Aradhya Bhatia, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Tomi Valkeinen, Michael Walle, Jyri Sarha
Cc: Maarten Lankhorst, Thomas Zimmermann, Maxime Ripard, David Airlie,
Laurent Pinchart, Simona Vetter, Nishanth Menon,
Vignesh Raghavendra, Devarsh Thakkar, Praneeth Bajjuri,
Udit Kumar, Francesco Dolcini, Alexander Sverdlin,
DRI Development List, Devicetree List, Linux Kernel List
Hello Aradhya, Tomi,
On 28/05/25 17:55, Aradhya Bhatia wrote:
> From: Aradhya Bhatia <a-bhatia1@ti.com>
>
> The AM62x and AM62Px SoCs feature 2 OLDI TXes each, which makes it
> possible to connect them in dual-link or cloned single-link OLDI display
> modes. The current OLDI support in tidss_dispc.c can only support for
> a single OLDI TX, connected to a VP and doesn't really support
> configuration of OLDIs in the other modes. The current OLDI support in
> tidss_dispc.c also works on the principle that the OLDI output can only
> be served by one, and only one, DSS video-port. This isn't the case in
> the AM62Px SoC, where there are 2 DSS controllers present that share the
> OLDI TXes.
>
[...]
> +}
> +
> +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);
I think this needs to be changed to devm_drm_bridge_alloc() to get rid
of the kernel warning. I am seeing WARNING in OLDI like:
[ 10.198109] WARNING: lib/refcount.c:25 at
refcount_warn_saturate+0x120/0x144, CPU#0: kworker/u16:0/12
[ 10.198140] Modules linked in: snd_soc_simple_card mux_gpio
snd_soc_simple_card_utils panel_simple cdns3_ti display_connector
snd_soc_davinci_mcasp phy_can_transceiver k3_j72xx_bandgap tps6594_i2c tps6
[ 10.198310] CPU: 0 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted
6.16.0-rc3-next-20250627-00046-ga876218600d6 #197 PREEMPT
[ 10.198321] Hardware name: Texas Instruments J722S EVM (DT)
[ 10.198327] Workqueue: events_unbound deferred_probe_work_func
[ 10.198344] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS
BTYPE=--)
[ 10.198352] pc : refcount_warn_saturate+0x120/0x144
[ 10.198359] lr : refcount_warn_saturate+0x120/0x144
[ 10.198365] sp : ffff800082fa3a30
[ 10.198368] x29: ffff800082fa3a30 x28: 0000000000000000 x27:
0000000000000000
[ 10.198377] x26: 0000000000000004 x25: 0000000000000001 x24:
ffff80007b1edf48
[ 10.198386] x23: ffff000806fa0000 x22: ffff00080c466800 x21:
ffff00094701ec20
[ 10.198395] x20: ffff00080f9cec80 x19: ffff00080f9cec90 x18:
fffffffffffe99f8
[ 10.198404] x17: ffff8008c4f5e000 x16: ffff800080000000 x15:
0000000000000002
[ 10.198414] x14: ffff0008001dc680 x13: 0000000000000021 x12:
0000000013cbce01
[ 10.198423] x11: 00000005cc209839 x10: ffff000946f68a40 x9 :
ffff0008001dc680
[ 10.198433] x8 : 0000000000000000 x7 : ffff0008001dc680 x6 :
0000000000000002
[ 10.198441] x5 : 0000000000000400 x4 : 0000000000000400 x3 :
0000000013cbce01
[ 10.198450] x2 : 0000000000000000 x1 : 0000000000000000 x0 :
ffff0008001dc600
[ 10.198459] Call trace:
[ 10.198464] refcount_warn_saturate+0x120/0x144 (P)
[ 10.198473] drm_bridge_add+0xec/0xf0 [drm]
[ 10.198733] tidss_oldi_init+0x2e0/0x434 [tidss]
[ 10.198759] tidss_probe+0x1a4/0x2e0 [tidss]
[ 10.198774] platform_probe+0x68/0xc4
[ 10.198786] really_probe+0xbc/0x29c
[ 10.198798] __driver_probe_device+0x78/0x12c
[ 10.198808] driver_probe_device+0xd8/0x15c
[ 10.198817] __device_attach_driver+0xb8/0x134
oldi = devm_drm_bridge_alloc(tidss->dev, struct tidss_oldi, bridge,
&tidss_oldi_bridge_funcs);
I am posting a fix patch for this since now its merged to linux-next.
Thanks,
Jayesh
[...]
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-06-30 10:57 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-28 12:25 [PATCH v9 0/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 1/4] dt-bindings: display: ti, am65x-dss: Re-indent the example Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 2/4] dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter Aradhya Bhatia
2025-06-05 14:41 ` Rob Herring (Arm)
2025-05-28 12:25 ` [PATCH v9 3/4] drm/tidss: Mark AM65x OLDI code separately Aradhya Bhatia
2025-05-28 12:25 ` [PATCH v9 4/4] drm/tidss: Add OLDI bridge support Aradhya Bhatia
2025-05-28 13:35 ` Michael Walle
2025-06-30 10:56 ` Jayesh Choudhary
2025-06-26 9:40 ` [PATCH v9 0/4] " Tomi Valkeinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).