diff options
-rw-r--r-- | arch/sandbox/Kconfig | 2 | ||||
-rw-r--r-- | arch/sandbox/dts/test.dts | 101 | ||||
-rw-r--r-- | common/Kconfig | 2 | ||||
-rw-r--r-- | configs/sandbox_defconfig | 2 | ||||
-rw-r--r-- | doc/arch/sandbox/sandbox.rst | 6 | ||||
-rw-r--r-- | drivers/core/Makefile | 2 | ||||
-rw-r--r-- | drivers/core/ofnode_graph.c | 217 | ||||
-rw-r--r-- | drivers/video/bridge/Kconfig | 7 | ||||
-rw-r--r-- | drivers/video/bridge/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/bridge/lvds-codec.c | 128 | ||||
-rw-r--r-- | drivers/video/bridge/video-bridge-uclass.c | 11 | ||||
-rw-r--r-- | include/configs/sandbox.h | 2 | ||||
-rw-r--r-- | include/dm/ofnode_graph.h | 90 | ||||
-rw-r--r-- | include/video_bridge.h | 54 | ||||
-rw-r--r-- | test/dm/Makefile | 1 | ||||
-rw-r--r-- | test/dm/ofnode.c | 54 | ||||
-rw-r--r-- | test/dm/video_bridge.c | 67 | ||||
-rw-r--r-- | test/lib/kconfig.c | 8 |
18 files changed, 744 insertions, 11 deletions
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig index 4c169034d9a..d61a327f151 100644 --- a/arch/sandbox/Kconfig +++ b/arch/sandbox/Kconfig @@ -77,7 +77,7 @@ config SANDBOX_BITS_PER_LONG config SYS_FDT_LOAD_ADDR hex "Address at which to load devicetree" - default 0x100 + default 0x1000 help With sandbox the devicetree is loaded into the emulated RAM. This sets the address that is used. There must be enough space at this address diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index b8f3012873e..52e9ddbf50f 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1047,6 +1047,31 @@ }; }; + lvds-encoder { + compatible = "lvds-encoder"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + bridge_input: endpoint { + /* link to output */ + }; + }; + + port@1 { + reg = <1>; + + bridge_output: endpoint { + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + wdt-gpio-toggle { gpios = <&gpio_a 8 0>; compatible = "linux,wdt-gpio"; @@ -1402,6 +1427,27 @@ panel { compatible = "simple-panel"; backlight = <&backlight 0 100>; + + display-timings { + timing@0 { + /* 1280x800@60Hz */ + clock-frequency = <68000000>; + hactive = <1280>; + hfront-porch = <48>; + hback-porch = <18>; + hsync-len = <30>; + vactive = <800>; + vfront-porch = <3>; + vback-porch = <12>; + vsync-len = <5>; + }; + }; + + port { + panel_input: endpoint { + remote-endpoint = <&bridge_output>; + }; + }; }; scsi { @@ -2048,6 +2094,61 @@ sandbox,err-step-size = <512>; }; }; + + graph1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <0>; + + endpoint@0 { + reg = <0>; + }; + + endpoint@1 { + reg = <1>; + }; + }; + + port@1 { + reg = <1>; + + endpoint { + test-property-0; + }; + }; + + port@2 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <2>; + + graph2_link: endpoint@0 { + reg = <0>; + test-property-1; + remote-endpoint = <&graph1_link>; + }; + + endpoint@1 { + reg = <1>; + }; + }; + }; + }; + + graph2 { + port { + graph1_link: endpoint { + remote-endpoint = <&graph2_link>; + }; + }; + }; }; #include "sandbox_pmic.dtsi" diff --git a/common/Kconfig b/common/Kconfig index 1d6de8badf7..a1f65559a1b 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1080,7 +1080,7 @@ endchoice config BLOBLIST_ADDR hex "Address of bloblist" - default 0xb000 if SANDBOX + default 0x100 if SANDBOX depends on BLOBLIST_FIXED help Sets the address of the bloblist, set up by the first part of U-Boot diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 861a1f4cd90..0b3c765389c 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -328,6 +328,8 @@ CONFIG_USB_ETH_CDC=y CONFIG_VIDEO=y CONFIG_VIDEO_FONT_SUN12X22=y CONFIG_VIDEO_COPY=y +CONFIG_VIDEO_BRIDGE=y +CONFIG_VIDEO_BRIDGE_LVDS_CODEC=y CONFIG_CONSOLE_ROTATION=y CONFIG_CONSOLE_TRUETYPE=y CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst index a8b0d7f0395..7e641306da2 100644 --- a/doc/arch/sandbox/sandbox.rst +++ b/doc/arch/sandbox/sandbox.rst @@ -658,10 +658,10 @@ that are mapped into that memory: ======== ======================== =============================== Addr Config Usage ======== ======================== =============================== - 100 CONFIG_SYS_FDT_LOAD_ADDR Device tree - b000 CONFIG_BLOBLIST_ADDR Blob list - 10000 CFG_MALLOC_F_ADDR Early memory allocation + 100 CONFIG_BLOBLIST_ADDR Blob list + 1000 CONFIG_SYS_FDT_LOAD_ADDR Device tree f0000 CONFIG_PRE_CON_BUF_ADDR Pre-console buffer + f4000 CFG_MALLOC_F_ADDR Early memory allocation 100000 TCG Event log TCG Event Log 200000 CONFIG_TRACE_EARLY_ADDR Early trace buffer (if enabled). Also used 400000 CONFIG_TEXT_BASE Load buffer for U-Boot (sandbox_spl only) diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 9ea57911f89..657e589c286 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -16,6 +16,6 @@ ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif obj-$(CONFIG_$(XPL_)OF_PLATDATA) += read.o -obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o +obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o ofnode_graph.o ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG diff --git a/drivers/core/ofnode_graph.c b/drivers/core/ofnode_graph.c new file mode 100644 index 00000000000..90c92af3258 --- /dev/null +++ b/drivers/core/ofnode_graph.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#define LOG_CATEGORY LOGC_DT + +#include <dm.h> +#include <log.h> +#include <dm/ofnode.h> +#include <linux/err.h> + +/** + * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device ofnode + * @parent: ofnode to the device containing ports and endpoints + * + * Return: count of endpoint of this device ofnode + */ +unsigned int ofnode_graph_get_endpoint_count(ofnode parent) +{ + ofnode ports, port, endpoint; + unsigned int num = 0; + + /* Check if ports node exists */ + ports = ofnode_find_subnode(parent, "ports"); + if (ofnode_valid(ports)) + parent = ports; + + ofnode_for_each_subnode(port, parent) { + if (!strncmp(ofnode_get_name(port), "port", 4)) { + /* Port node can only contain endpoints */ + ofnode_for_each_subnode(endpoint, port) + num++; + } + }; + + log_debug("%s: detected %d endpoints\n", __func__, num); + + return num++; +} + +/** + * ofnode_graph_get_port_count() - get the number of port in a device or ports ofnode + * @parent: ofnode to the device or ports node + * + * Return: count of port of this device or ports node + */ +unsigned int ofnode_graph_get_port_count(ofnode parent) +{ + ofnode ports, port; + unsigned int num = 0; + + /* Check if ports node exists */ + ports = ofnode_find_subnode(parent, "ports"); + if (ofnode_valid(ports)) + parent = ports; + + ofnode_for_each_subnode(port, parent) + if (!strncmp(ofnode_get_name(port), "port", 4)) + num++; + + log_debug("%s: detected %d ports\n", __func__, num); + + return num++; +} + +/** + * ofnode_graph_get_port_by_id() - get the port matching a given id + * @parent: parent ofnode + * @id: id of the port + * + * Return: ofnode in given port. + */ +ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id) +{ + ofnode ports, port; + u32 port_id; + + ports = ofnode_find_subnode(parent, "ports"); + if (!ofnode_valid(ports)) + return ofnode_null(); + + /* Check ports for node with desired id */ + ofnode_for_each_subnode(port, ports) { + ofnode_read_u32(port, "reg", &port_id); + log_debug("%s: detected port %d\n", __func__, port_id); + if (port_id == id) + return port; + } + + return ofnode_null(); +} + +/** + * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id + * @parent: parent ofnode + * @reg_id: id of the port + * @id: id for the endpoint + * + * Return: ofnode in given endpoint or ofnode_null() if not found. + * reg and port_reg are ignored when they are -1. + */ +ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id) +{ + ofnode port, endpoint; + u32 ep_id; + + /* get the port to work with */ + if (reg_id < 0) + port = ofnode_find_subnode(parent, "port"); + else + port = ofnode_graph_get_port_by_id(parent, reg_id); + + if (!ofnode_valid(port)) { + log_debug("%s: port node is not found\n", __func__); + return ofnode_null(); + } + + if (id < 0) + return ofnode_find_subnode(port, "endpoint"); + + /* Check endpoints for node with desired id */ + ofnode_for_each_subnode(endpoint, port) { + ofnode_read_u32(endpoint, "reg", &ep_id); + log_debug("%s: detected endpoint %d\n", __func__, ep_id); + if (ep_id == id) + return endpoint; + } + + return ofnode_null(); +} + +/** + * ofnode_graph_get_remote_endpoint() - get remote endpoint node + * @endpoint: ofnode of a local endpoint + * + * Return: Remote endpoint ofnode linked with local endpoint. + */ +ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint) +{ + /* Get remote endpoint node. */ + return ofnode_parse_phandle(endpoint, "remote-endpoint", 0); +} + +/** + * ofnode_graph_get_port_parent() - get port's parent node + * @endpoint: ofnode of a local endpoint + * + * Return: device ofnode associated with endpoint + */ +ofnode ofnode_graph_get_port_parent(ofnode endpoint) +{ + ofnode port = ofnode_get_parent(endpoint); + ofnode parent = ofnode_get_parent(port); + + /* check if we are on top level or in ports node */ + if (!strcmp(ofnode_get_name(parent), "ports")) + parent = ofnode_get_parent(parent); + + return parent; +} + +/** + * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode + * @endpoint: ofnode of a local endpoint + * + * Return: device ofnode associated with endpoint linked to local endpoint. + */ +ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint) +{ + ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint); + if (!ofnode_valid(remote_endpoint)) { + log_debug("%s: remote endpoint is not found\n", __func__); + return ofnode_null(); + } + + return ofnode_graph_get_port_parent(remote_endpoint); +} + +/** + * ofnode_graph_get_remote_port() - get remote port ofnode + * @endpoint: ofnode of a local endpoint + * + * Return: port ofnode associated with remote endpoint node linked + * to local endpoint. + */ +ofnode ofnode_graph_get_remote_port(ofnode endpoint) +{ + ofnode remote_endpoint = ofnode_graph_get_remote_endpoint(endpoint); + if (!ofnode_valid(remote_endpoint)) { + log_debug("%s: remote endpoint is not found\n", __func__); + return ofnode_null(); + } + + return ofnode_get_parent(remote_endpoint); +} + +/** + * ofnode_graph_get_remote_node() - get remote parent ofnode for given port/endpoint + * @parent: parent ofnode containing graph port/endpoint + * @port: identifier (value of reg property) of the parent port ofnode + * @endpoint: identifier (value of reg property) of the endpoint ofnode + * + * Return: device ofnode associated with endpoint linked to local endpoint. + */ +ofnode ofnode_graph_get_remote_node(ofnode parent, int port, int endpoint) +{ + ofnode endpoint_ofnode; + + endpoint_ofnode = ofnode_graph_get_endpoint_by_regs(parent, port, endpoint); + if (!ofnode_valid(endpoint_ofnode)) { + log_debug("%s: endpoint is not found\n", __func__); + return ofnode_null(); + } + + return ofnode_graph_get_remote_port_parent(endpoint_ofnode); +} diff --git a/drivers/video/bridge/Kconfig b/drivers/video/bridge/Kconfig index ab917273720..21c5a043e02 100644 --- a/drivers/video/bridge/Kconfig +++ b/drivers/video/bridge/Kconfig @@ -59,3 +59,10 @@ config VIDEO_BRIDGE_TOSHIBA_TC358768 help Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver. Found in Asus Transformer Infinity TF700T. + +config VIDEO_BRIDGE_LVDS_CODEC + bool "Transparent LVDS encoders and decoders support" + depends on VIDEO_BRIDGE && PANEL && DM_GPIO + help + Support for transparent LVDS encoders and decoders that don't + require any configuration. diff --git a/drivers/video/bridge/Makefile b/drivers/video/bridge/Makefile index 58697e3cbe9..63dc6e62c49 100644 --- a/drivers/video/bridge/Makefile +++ b/drivers/video/bridge/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o obj-$(CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345) += anx6345.o obj-$(CONFIG_VIDEO_BRIDGE_SOLOMON_SSD2825) += ssd2825.o obj-$(CONFIG_VIDEO_BRIDGE_TOSHIBA_TC358768) += tc358768.o +obj-$(CONFIG_VIDEO_BRIDGE_LVDS_CODEC) += lvds-codec.o diff --git a/drivers/video/bridge/lvds-codec.c b/drivers/video/bridge/lvds-codec.c new file mode 100644 index 00000000000..6cd8368a39e --- /dev/null +++ b/drivers/video/bridge/lvds-codec.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com> + * Loosely based on Linux lvds-codec.c driver + */ + +#include <dm.h> +#include <dm/ofnode_graph.h> +#include <log.h> +#include <panel.h> +#include <video_bridge.h> +#include <asm/gpio.h> +#include <power/regulator.h> + +struct lvds_codec_priv { + struct udevice *panel; + struct display_timing timing; + + struct gpio_desc powerdown_gpio; + struct udevice *power; +}; + +static int lvds_codec_attach(struct udevice *dev) +{ + struct lvds_codec_priv *priv = dev_get_priv(dev); + + regulator_set_enable_if_allowed(priv->power, 1); + dm_gpio_set_value(&priv->powerdown_gpio, 0); + + return panel_enable_backlight(priv->panel); +} + +static int lvds_codec_set_panel(struct udevice *dev, int percent) +{ + struct lvds_codec_priv *priv = dev_get_priv(dev); + + return panel_set_backlight(priv->panel, percent); +} + +static int lvds_codec_panel_timings(struct udevice *dev, + struct display_timing *timing) +{ + struct lvds_codec_priv *priv = dev_get_priv(dev); + + memcpy(timing, &priv->timing, sizeof(*timing)); + + return 0; +} + +/* Function is purely for sandbox testing */ +static int lvds_codec_read_edid(struct udevice *dev, u8 *buf, int buf_size) +{ + return 0; +} + +static int lvds_codec_get_panel(struct udevice *dev) +{ + struct lvds_codec_priv *priv = dev_get_priv(dev); + int i, ret; + + u32 num = ofnode_graph_get_port_count(dev_ofnode(dev)); + + for (i = 0; i < num; i++) { + ofnode remote = ofnode_graph_get_remote_node(dev_ofnode(dev), i, -1); + + ret = uclass_get_device_by_of_offset(UCLASS_PANEL, + ofnode_to_offset(remote), + &priv->panel); + if (!ret) + return 0; + } + + /* If this point is reached, no panels were found */ + return -ENODEV; +} + +static int lvds_codec_probe(struct udevice *dev) +{ + struct lvds_codec_priv *priv = dev_get_priv(dev); + int ret; + + ret = lvds_codec_get_panel(dev); + if (ret) { + log_debug("%s: cannot get panel: ret=%d\n", __func__, ret); + return log_ret(ret); + } + + panel_get_display_timing(priv->panel, &priv->timing); + + ret = gpio_request_by_name(dev, "powerdown-gpios", 0, + &priv->powerdown_gpio, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: could not get powerdown-gpios (%d)\n", __func__, ret); + if (ret != -ENOENT) + return log_ret(ret); + } + + ret = device_get_supply_regulator(dev, "power-supply", &priv->power); + if (ret) { + log_debug("%s: power regulator error: %d\n", __func__, ret); + if (ret != -ENOENT) + return log_ret(ret); + } + + return 0; +} + +static const struct video_bridge_ops lvds_codec_ops = { + .attach = lvds_codec_attach, + .set_backlight = lvds_codec_set_panel, + .get_display_timing = lvds_codec_panel_timings, + .read_edid = lvds_codec_read_edid, +}; + +static const struct udevice_id lvds_codec_ids[] = { + { .compatible = "lvds-decoder" }, + { .compatible = "lvds-encoder" }, + { } +}; + +U_BOOT_DRIVER(lvds_codec) = { + .name = "lvds_codec", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = lvds_codec_ids, + .ops = &lvds_codec_ops, + .probe = lvds_codec_probe, + .priv_auto = sizeof(struct lvds_codec_priv), +}; diff --git a/drivers/video/bridge/video-bridge-uclass.c b/drivers/video/bridge/video-bridge-uclass.c index 2084a2e03ee..1b8aa12b9e8 100644 --- a/drivers/video/bridge/video-bridge-uclass.c +++ b/drivers/video/bridge/video-bridge-uclass.c @@ -33,6 +33,17 @@ int video_bridge_attach(struct udevice *dev) return ops->attach(dev); } +int video_bridge_get_display_timing(struct udevice *dev, + struct display_timing *timings) +{ + struct video_bridge_ops *ops = video_bridge_get_ops(dev); + + if (!ops->get_display_timing) + return -ENOSYS; + + return ops->get_display_timing(dev, timings); +} + int video_bridge_check_attached(struct udevice *dev) { struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev); diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 2372485c84e..db2ac7f83bb 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -6,7 +6,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define CFG_MALLOC_F_ADDR 0x0010000 +#define CFG_MALLOC_F_ADDR 0x000f4000 /* Size of our emulated memory */ #define SB_CONCAT(x, y) x ## y diff --git a/include/dm/ofnode_graph.h b/include/dm/ofnode_graph.h new file mode 100644 index 00000000000..908c990a3f3 --- /dev/null +++ b/include/dm/ofnode_graph.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#ifndef _DM_OFNODE_GRAPH_H +#define _DM_OFNODE_GRAPH_H + +#include <dm/of.h> + +/** + * ofnode_graph_get_endpoint_count() - get the number of endpoints in a device ofnode + * @parent: ofnode to the device containing ports and endpoints + * + * Return: count of endpoint of this device ofnode + */ +unsigned int ofnode_graph_get_endpoint_count(ofnode parent); + +/** + * ofnode_graph_get_port_count() - get the number of port in a device or ports ofnode + * @parent: ofnode to the device or ports node + * + * Return: count of port of this device or ports node + */ +unsigned int ofnode_graph_get_port_count(ofnode parent); + +/** + * ofnode_graph_get_port_by_id() - get the port matching a given id + * @parent: parent ofnode + * @id: id of the port + * + * Return: ofnode in given port. + */ +ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id); + +/** + * ofnode_graph_get_endpoint_by_regs() - get the endpoint matching a given id + * @parent: parent ofnode + * @reg_id: id of the port + * @id: id for the endpoint + * + * Return: ofnode in given endpoint or NULL if not found. + * reg and port_reg are ignored when they are -1. + */ +ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, u32 reg_id, u32 id); + +/** + * ofnode_graph_get_remote_endpoint() - get remote endpoint node + * @endoint: ofnode of a local endpoint + * + * Return: Remote endpoint ofnode linked with local endpoint. + */ +ofnode ofnode_graph_get_remote_endpoint(ofnode endpoint); + +/** + * ofnode_graph_get_port_parent() - get port's parent node + * @endpoint: ofnode of a local endpoint + * + * Return: device ofnode associated with endpoint + */ +ofnode ofnode_graph_get_port_parent(ofnode endpoint); + +/** + * ofnode_graph_get_remote_port_parent() - get remote port's parent ofnode + * @endoint: ofnode of a local endpoint + * + * Return: device ofnode associated with endpoint linked to local endpoint. + */ +ofnode ofnode_graph_get_remote_port_parent(ofnode endpoint); + +/** + * ofnode_graph_get_remote_port() - get remote port ofnode + * @endoint: ofnode of a local endpoint + * + * Return: port ofnode associated with remote endpoint node linked + * to local endpoint. + */ +ofnode ofnode_graph_get_remote_port(ofnode endpoint); + +/** + * ofnode_graph_get_remote_node() - get remote parent ofnode for given port/endpoint + * @parent: parent ofnode containing graph port/endpoint + * @port: identifier (value of reg property) of the parent port ofnode + * @endpoint: identifier (value of reg property) of the endpoint ofnode + * + * Return: device ofnode associated with endpoint linked to local endpoint. + */ +ofnode ofnode_graph_get_remote_node(ofnode parent, u32 port, u32 endpoint); + +#endif diff --git a/include/video_bridge.h b/include/video_bridge.h index 3b429eac578..00e9804565c 100644 --- a/include/video_bridge.h +++ b/include/video_bridge.h @@ -54,6 +54,19 @@ struct video_bridge_ops { int (*set_backlight)(struct udevice *dev, int percent); /** + * get_display_timing() - Get display timings from bridge. + * + * @dev: Bridge device containing the linked display timings + * @tim: Place to put timings + * @return 0 if OK, -ve on error + * + * This call it totally optional and useful mainly for integrated + * bridges with fixed output device. + */ + int (*get_display_timing)(struct udevice *dev, + struct display_timing *timing); + + /** * read_edid() - Read information from EDID * * @dev: Device to read from @@ -67,6 +80,7 @@ struct video_bridge_ops { #define video_bridge_get_ops(dev) \ ((struct video_bridge_ops *)(dev)->driver->ops) +#if CONFIG_IS_ENABLED(VIDEO_BRIDGE) /** * video_bridge_attach() - attach a video bridge * @@ -99,6 +113,14 @@ int video_bridge_set_active(struct udevice *dev, bool active); int video_bridge_check_attached(struct udevice *dev); /** + * video_bridge_get_display_timing() - Get display timings from bridge. + * + * @dev: Bridge device containing the linked display timings + * Return: 0 if OK, -ve on error + */ +int video_bridge_get_display_timing(struct udevice *dev, + struct display_timing *timing); +/** * video_bridge_read_edid() - Read information from EDID * * @dev: Device to read from @@ -107,5 +129,37 @@ int video_bridge_check_attached(struct udevice *dev); * Return: number of bytes read, <=0 for error */ int video_bridge_read_edid(struct udevice *dev, u8 *buf, int buf_size); +#else +static inline int video_bridge_attach(struct udevice *dev) +{ + return -ENOSYS; +} + +static inline int video_bridge_set_backlight(struct udevice *dev, int percent) +{ + return -ENOSYS; +} + +static inline int video_bridge_set_active(struct udevice *dev, bool active) +{ + return -ENOSYS; +} + +static inline int video_bridge_check_attached(struct udevice *dev) +{ + return -ENOSYS; +} + +static inline int video_bridge_get_display_timing(struct udevice *dev, + struct display_timing *timing) +{ + return -ENOSYS; +} + +static inline int video_bridge_read_edid(struct udevice *dev, u8 *buf, int buf_size) +{ + return -ENOSYS; +} +#endif /* CONFIG_VIDEO_BRIDGE */ #endif diff --git a/test/dm/Makefile b/test/dm/Makefile index e44f3d89e77..3afcc26ca57 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_SOUND) += i2s.o obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o obj-$(CONFIG_IOMMU) += iommu.o obj-$(CONFIG_LED) += led.o +obj-$(CONFIG_VIDEO_BRIDGE_LVDS_CODEC) += video_bridge.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MDIO) += mdio.o obj-$(CONFIG_DM_MDIO_MUX) += mdio_mux.o diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index cc8b444ff9a..0f60c2a6281 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -23,6 +23,7 @@ #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/of_extra.h> +#include <dm/ofnode_graph.h> #include <dm/root.h> #include <dm/test.h> #include <dm/uclass-internal.h> @@ -1651,3 +1652,56 @@ static int dm_test_bool(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_bool, UTF_SCAN_FDT); + +/* test all helpers found in drivers/core/ofnode_graph.c */ +static int dm_test_ofnode_graph(struct unit_test_state *uts) +{ + /* 3 ports with 5 endpoints (2-1-2) */ + ofnode graph1 = ofnode_path("/graph1"); + /* 1 port with 1 endpoint */ + ofnode graph2 = ofnode_path("/graph2"); + ofnode node; + u32 id; + + ut_asserteq(ofnode_graph_get_endpoint_count(graph1), 5); + ut_asserteq(ofnode_graph_get_endpoint_count(graph2), 1); + + ut_asserteq(ofnode_graph_get_port_count(graph1), 3); + ut_asserteq(ofnode_graph_get_port_count(graph2), 1); + + /* Request port with reg 2 */ + node = ofnode_graph_get_port_by_id(graph1, 2); + ofnode_read_u32(node, "reg", &id); + ut_asserteq(id, 2); + + /* Reqest parent from prev requested endpoint */ + node = ofnode_graph_get_port_parent(node); + ut_asserteq_str(ofnode_get_name(node), "graph1"); + + /* Request endpoint under port 1 */ + node = ofnode_graph_get_endpoint_by_regs(graph1, 1, -1); + ut_assert(ofnode_has_property(node, "test-property-0")); + + /* Reqest remote endpoint from graph2 in graph1 */ + node = ofnode_graph_get_endpoint_by_regs(graph2, -1, -1); + node = ofnode_graph_get_remote_endpoint(node); + ut_assert(ofnode_has_property(node, "test-property-1")); + + /* Reqest remote parent from graph2 linked endpoint */ + node = ofnode_graph_get_endpoint_by_regs(graph2, -1, -1); + node = ofnode_graph_get_remote_port_parent(node); + ut_asserteq_str(ofnode_get_name(node), "graph1"); + + /* Reqest remote port from graph2 linked endpoint */ + node = ofnode_graph_get_endpoint_by_regs(graph2, -1, -1); + node = ofnode_graph_get_remote_port(node); + ofnode_read_u32(node, "reg", &id); + ut_asserteq(id, 2); + + /* Reqest remote parent from graph2 linked endpoint */ + node = ofnode_graph_get_remote_node(graph2, -1, -1); + ut_asserteq_str(ofnode_get_name(node), "graph1"); + + return 0; +} +DM_TEST(dm_test_ofnode_graph, UTF_SCAN_FDT); diff --git a/test/dm/video_bridge.c b/test/dm/video_bridge.c new file mode 100644 index 00000000000..f55a333c0b8 --- /dev/null +++ b/test/dm/video_bridge.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for video bridge uclass + * + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <backlight.h> +#include <dm.h> +#include <panel.h> +#include <video.h> +#include <video_bridge.h> +#include <asm/gpio.h> +#include <asm/test.h> +#include <dm/test.h> +#include <power/regulator.h> +#include <test/test.h> +#include <test/ut.h> + +/* Basic test of the video uclass, test is based on driven panel */ +static int dm_test_video_bridge(struct unit_test_state *uts) +{ + struct udevice *dev, *pwm, *gpio, *reg; + uint period_ns, duty_ns; + bool enable, polarity; + struct display_timing timing; + + ut_assertok(uclass_first_device_err(UCLASS_VIDEO_BRIDGE, &dev)); + ut_assertok(uclass_get_device_by_name(UCLASS_PWM, "pwm", &pwm)); + ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio)); + ut_assertok(regulator_get_by_platname("VDD_EMMC_1.8V", ®)); + ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, + &enable, &polarity)); + ut_asserteq(false, enable); + ut_asserteq(true, regulator_get_enable(reg)); + + /* bridge calls panel_enable_backlight() of panel */ + ut_assertok(video_bridge_attach(dev)); + ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, + &enable, &polarity)); + ut_asserteq(1000, period_ns); + ut_asserteq(170 * 1000 / 255, duty_ns); + ut_asserteq(true, enable); + ut_asserteq(false, polarity); + ut_asserteq(1, sandbox_gpio_get_value(gpio, 1)); + ut_asserteq(true, regulator_get_enable(reg)); + + /* bridge calls panel_set_backlight() of panel */ + ut_assertok(video_bridge_set_backlight(dev, BACKLIGHT_DEFAULT)); + ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns, + &enable, &polarity)); + ut_asserteq(true, enable); + ut_asserteq(170 * 1000 / 255, duty_ns); + + /* bridge should be active */ + ut_assertok(video_bridge_set_active(dev, true)); + + /* bridge is internal and has no hotplug gpio */ + ut_asserteq(-ENOENT, video_bridge_check_attached(dev)); + + /* check passing timings and EDID */ + ut_assertok(video_bridge_get_display_timing(dev, &timing)); + ut_assertok(video_bridge_read_edid(dev, NULL, 0)); + + return 0; +} +DM_TEST(dm_test_video_bridge, UTF_SCAN_PDATA | UTF_SCAN_FDT); diff --git a/test/lib/kconfig.c b/test/lib/kconfig.c index a3645abf946..2f47af9acf1 100644 --- a/test/lib/kconfig.c +++ b/test/lib/kconfig.c @@ -22,10 +22,10 @@ static int lib_test_is_enabled(struct unit_test_state *uts) ut_asserteq(0, CONFIG_IS_ENABLED(_UNDEFINED)); if (IS_ENABLED(CONFIG_BLOBLIST)) { - ut_asserteq(0xb000, IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, - CONFIG_BLOBLIST_ADDR)); - ut_asserteq(0xb000, CONFIG_IF_ENABLED_INT(BLOBLIST_FIXED, - BLOBLIST_ADDR)); + ut_asserteq(0x100, IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, + CONFIG_BLOBLIST_ADDR)); + ut_asserteq(0x100, CONFIG_IF_ENABLED_INT(BLOBLIST_FIXED, + BLOBLIST_ADDR)); } /* |