drm/tidss: Add OLDI bridge support
Subsystems (5)
v7 cover drm/tidss: Add OLDI bridge support
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-v7_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. <[email protected]>. 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. <[email protected]>.
---
Change Log:
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/[email protected]/
V2: https://lore.kernel.org/all/[email protected]/
V3: https://lore.kernel.org/all/[email protected]/
V4: https://lore.kernel.org/all/[email protected]/
V5: https://lore.kernel.org/all/[email protected]/
V6: https://lore.kernel.org/all/[email protected]/
[0]: Dependency Patches:
("drm/atomic-helper: Refactor crtc & encoder-bridge op loops into separate functions")
https://lore.kernel.org/all/[email protected]/
("drm/atomic-helper: Separate out bridge pre_enable/post_disable from enable/disable)
https://lore.kernel.org/all/[email protected]/
("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")
https://lore.kernel.org/all/[email protected]/
[1]: AM62 OLDI Series - v7
https://lore.kernel.org/all/[email protected]/
[2]: AM62 DSS Series - v9
https://lore.kernel.org/all/[email protected]/
[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-v7_1-tests
[5]: ("ti,am65x-dss.yaml: oldi-txes: Missing additionalProperties/
unevaluatedProperties constraint")
https://lore.kernel.org/all/[email protected]/
[6]: Undo drop of OLDI clone mode support
https://gist.github.com/aradhya07/afb55761e64eb440d47d5de3ea2a3cb7
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 | 88 +++ .../bindings/display/ti/ti,am65x-dss.yaml | 196 +++++- 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 | 568 ++++++++++++++++++ drivers/gpu/drm/tidss/tidss_oldi.h | 42 ++ 12 files changed, 976 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: c8ba07caaecc622a9922cda49f24790821af8a71
Signature · 1 line
2.34.1
PATCH v7 1/4 dt-bindings: display: ti,am65x-dss: Re-indent the example
From: Aradhya Bhatia <[email protected]>
Reduce tab size from 8 spaces to 4 spaces to make the bindings consistent, and easy to expand.
--- .../bindings/display/ti/ti,am65x-dss.yaml | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-)
Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml +27 -27
@@ -142,32 +142,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>; + }; }; + }; };
Signature · 1 line
2.34.1
PATCH v7 2/4 dt-bindings: display: ti: Add schema for AM625 OLDI Transmitter
In reply to Aradhya BhatiaFrom: Aradhya Bhatia <[email protected]>
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.
--- .../bindings/display/ti/ti,am625-oldi.yaml | 88 ++++++++++ .../bindings/display/ti/ti,am65x-dss.yaml | 154 ++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 243 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml new file +88 -0
@@ -0,0 +1,88 @@ +# 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 <[email protected]> + - Aradhya Bhatia <[email protected]> + +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 mandatory for the + primarty OLDI TX if the OLDI TXes are expected to work either in dual-lvds + mode or in clone mode. This property should point to the secondary OLDI + TX. + + 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 + +allOf: + - if: + required: + - ti,secondary-oldi + then: + properties: + ti,companion-oldi: false + +required: + - reg + - clocks + - clock-names + - ti,oldi-io-ctrl + - ports + +additionalProperties: false + +...
Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml +154 -0
179 lines not on this page · raw message
MAINTAINERS +1 -0
@@ -7922,6 +7922,7 @@ M: Tomi Valkeinen <[email protected]> L: [email protected] 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
Signature · 1 line
2.34.1
PATCH v7 3/4 drm/tidss: Mark AM65x OLDI code separately
In reply to Aradhya BhatiaThe 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.
--- 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(-)
drivers/gpu/drm/tidss/tidss_dispc.c +33 -35
@@ -139,7 +139,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 = {
@@ -169,7 +169,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,
@@ -391,7 +391,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 ];
@@ -906,13 +906,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[] = {
@@ -956,7 +954,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]);
@@ -966,23 +964,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,
@@ -1011,8 +1009,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);
@@ -1031,7 +1029,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 */
@@ -1060,10 +1058,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); } }
@@ -1119,7 +1117,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,
@@ -1145,10 +1143,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); } }
@@ -2735,15 +2733,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 ; }
drivers/gpu/drm/tidss/tidss_dispc.h +1 -1
@@ -52,7 +52,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 ,
drivers/gpu/drm/tidss/tidss_dispc_regs.h +9 -6
@@ -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 */
drivers/gpu/drm/tidss/tidss_kms.c +1 -1
@@ -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 ;
Signature · 1 line
2.34.1
PATCH v7 4/4 drm/tidss: Add OLDI bridge support
In reply to Aradhya BhatiaFrom: Aradhya Bhatia <[email protected]>
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.
--- 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 | 568 +++++++++++++++++++++++ drivers/gpu/drm/tidss/tidss_oldi.h | 42 ++ 8 files changed, 668 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/tidss/tidss_oldi.c create mode 100644 drivers/gpu/drm/tidss/tidss_oldi.h
drivers/gpu/drm/tidss/Makefile +2 -1
@@ -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
drivers/gpu/drm/tidss/tidss_dispc.c +23 -1
@@ -466,6 +466,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
@@ -1308,7 +1331,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 ;
drivers/gpu/drm/tidss/tidss_dispc.h +5 -0
@@ -94,6 +94,11 @@ extern const struct dispc_features dispc_am62a7_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);
drivers/gpu/drm/tidss/tidss_dispc_regs.h +14 -0
@@ -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 };
drivers/gpu/drm/tidss/tidss_drv.c +9 -0
@@ -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);
drivers/gpu/drm/tidss/tidss_drv.h +5 -0
@@ -11,8 +11,10 @@#define TIDSS_MAX_PORTS 4#define TIDSS_MAX_PLANES 4 +#define TIDSS_MAX_OLDI_TXES 2typedef 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 */
drivers/gpu/drm/tidss/tidss_oldi.c new file +568 -0
568 lines not on this page · raw message
drivers/gpu/drm/tidss/tidss_oldi.h new file +42 -0
42 lines not on this page · raw message
Signature · 1 line
2.34.1
Quoted 16 lines · Aradhya Bhatia
From: Aradhya Bhatia <[email protected]>
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.ccan 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 intidss_dispc.calso 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.
Quoted 6 lines
For all these reasons, add support for the OLDI TXes as DRM bridges.
Reviewed-by Tomi Valkeinen <[email protected]>Tested-by Alexander Sverdlin <[email protected]>Signed-off-by Aradhya Bhatia <[email protected]>Signed-off-by Aradhya Bhatia <[email protected]>
FWIW, I have a few downstream patches to get the DSS on j722s running.
-michael