英文:
Add two TFT displays to device tree
问题
我正在处理一个带有Yocto Linux的嵌入式设备。最近更换了显示器类型。我已经成功在内核和设备树中进行了更改。但现在我正在努力在同一镜像中启用两种类型。
如何通过调用of_fixup_status()
在Barebox中添加两个带有status="disabled"
的panel-lcd
定义,并激活其中一个或另一个?
我的设备树文件(dtsi)如下所示:
/ {
panel-lcd-tn {
compatible = "powertip,ph320240t023_iha";
backlight = <&backlight_peb>;
status = "disabled";
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
panel-lcd-ips {
compatible = "powertip,ph320240t028_zha";
backlight = <&backlight_peb>;
status = "disabled";
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
...
...
...
};
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat>;
status = "disabled";
port {
display_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
编译器告诉我
重复标签'panel_in'
注意:唯一的区别是compatible字符串。
我尝试将panel_in
重命名为panel_in1
和panel_in2
,但然后对此标签的引用在&lcdif
中不再有效。所以我也将这个复制了一次。然后设备树就能编译了,但显示不再工作。在启动时出现错误
mxsfb 21c8000.lcdif: 无法连接桥接器:-19
有没有人知道如何解决这个问题?
英文:
I'm working on a embedded device with Yocto Linux. Recently the display type was replaced. I was able to make the changes in the kernel and device tree. But now I'm suffering to enable both types in the same image.
How can I add two panel-lcd definitions with status="disabled" and activate one OR the other by calling of_fixup_status()
in Barebox?
My dtsi looks like this:
/ {
panel-lcd-tn {
compatible = "powertip,ph320240t023_iha";
backlight = <&backlight_peb>;
status = "disabled";
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
panel-lcd-ips {
compatible = "powertip,ph320240t028_zha";
backlight = <&backlight_peb>;
status = "disabled";
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
...
...
...
};
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat>;
status = "disabled";
port {
display_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
The compiler tells me
Duplicate label 'panel_in'
Note: The only difference is the compatible string.
I've tried to rename panel_in
to panel_in1
and panel_in2
, but then the reference to this label is no longer valid at &lcdif
. So I've doubled this one a well. The DT compiles then, but the display does not work any more. On bootup the error
mxsfb 21c8000.lcdif: Cannot connect bridge: -19
appears. Does anybody have a clue how to solve it?
答案1
得分: 1
一般来说,具有两个设备树节点并启用其中一个是一个不错的方法。但面板有点特殊,因为它们使用设备树图绑定,其中面板指向显示控制器(或中间桥接器),而显示控制器也指向面板。因此,复制面板并选择其中一个意味着您还需要修复显示控制器节点中的链接。这是可行的,但更容易的方法是仅保留一个单一的面板节点,并仅动态修复兼容性。
假设您的内核设备树如下所示:
/ {
aliases {
display = &display;
};
display: panel-lcd {
compatible = "powertip,ph320240t023_iha";
backlight = <&backlight_peb>;
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
};
然后,在 barebox 中重新编写内核设备树非常简单:
#!/bin/sh
of_property -fs display compatible "powertip,ph320240t028_zha"
-f
注册一个修复,即更改将应用于内核设备树的引导,而不是 barebox 设备树。-s
表示设置属性。display
是我们选择的别名(我们也可以使用 /panel-lcd
)。
您可以将此脚本添加到 barebox 环境的 init
目录中,以便在启动时自动加载。
您也可以在 C 代码中实现相同的功能。当您需要在安全启动系统中禁用 shell 解释器、进行更复杂的修复或需要解析更复杂的 EEPROM 格式以确定您拥有的面板时,这可能比脚本更好。以下是一个示例:
#include <of.h>
#include <linux/printk.h>
#include <driver.h>
#include <init.h>
struct board_variant {
const char *panel_compatible;
};
static int my_board_display_fixup(struct device_node *root, void *_variant)
{
const struct board_variant *variant = _variant;
struct device_node *display;
display = of_find_node_by_alias(root, "display");
if (!display) {
pr_err("Cannot find node display\n");
return -EINVAL;
}
return of_property_write_string(display, "compatible",
variant->panel_compatible);
}
static int my_customboard_probe(struct device *dev)
{
/*
* will be used at device tree fixup time, so it needs to
* be either dynamically allocated or static storage
*/
static struct board_variant variant;
/* read EEPROM or something to decide dynamically */
variant.panel_compatible = "powertip,ph320240t028_zha";
return of_register_fixup(my_board_display_fixup, &variant);
}
static struct of_device_id board_dt_ids[] = {
{ .compatible = "my,imx6q-customboard", },
{ /* sentinel */ }
};
static struct driver my_customboard_driver = {
.name = "my-customboard",
.probe = my_customboard_probe,
.of_compatible = board_dt_ids,
};
coredevice_platform_driver(my_customboard_driver);
此代码通常放置在您的板代码目录中,例如 arch/arm/boards/my-customboard/board.c
。my,imx6q-customboard
是您的板的兼容性(如在 barebox 设备树中所写)。
最后,barebox 还支持应用设备树叠加,它会在底层将其转换为修复。对于您的简单情况,明确使用修复可能是更简单的方法。
英文:
In general, having two device tree nodes and enabling one or the other is a good approach. Panels are a bit special though, because they use the device tree graph binding, where the panel points at the display controller (or an in-between bridge) and the display points back. Duplicating the panel and choosing one or the other thus means that you also need to fix up the link in the display controller node. That's doable, but it's easier to just keep a single panel node and fix up only the compatible dynamically.
Provided your kernel device tree looks like this:
/ {
aliases {
display = &display;
};
display: panel-lcd {
compatible = "powertip,ph320240t023_iha";
backlight = <&backlight_peb>;
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
};
It's then quite trivial to rewrite the kernel device tree in barebox:
#!/bin/sh
of_property -fs display compatible "powertip,ph320240t028_zha"
-f
registers a fixup, i.e. the change is applied to the kernel device tree on boot and not to the barebox device tree. -s
means to set the property. display
is the alias we choose (We could also have used /panel-lcd
).
You can add this script into your barebox environment init
directory, so it's automatically sourced on startup.
You can also achieve the same in C board code. This can be better than a script, when you e.g. disable the shell interpreter in a secure booting system, if you do more complex fixups or if you need to parse some more complex EEPROM format to determine what panel you have. Here's an example:
#include <of.h>
#include <linux/printk.h>
#include <driver.h>
#include <init.h>
struct board_variant {
const char *panel_compatible;
};
static int my_board_display_fixup(struct device_node *root, void *_variant)
{
const struct board_variant *variant = _variant;
struct device_node *display;
display = of_find_node_by_alias(root, "display");
if (!display) {
pr_err("Cannot find node display\n");
return -EINVAL;
}
return of_property_write_string(display, "compatible",
variant->panel_compatible);
}
static int my_customboard_probe(struct device *dev)
{
/*
* will be used at device tree fixup time, so it needs to
* be either dynamically allocated or static storage
*/
static struct board_variant variant;
/* read EEPROM or something to decide dynamically */
variant.panel_compatible = "powertip,ph320240t028_zha";
return of_register_fixup(my_board_display_fixup, &variant);
}
static struct of_device_id board_dt_ids[] = {
{ .compatible = "my,imx6q-customboard", },
{ /* sentinel */ }
};
static struct driver my_customboard_driver = {
.name = "my-customboard",
.probe = my_customboard_probe,
.of_compatible = board_dt_ids,
};
coredevice_platform_driver(my_customboard_driver);
This code is usually placed in your board code directory, e.g. arch/arm/boards/my-customboard/board.c
. my,imx6q-customboard
is the compatible of your board (as written in the barebox device tree).
Finally, barebox also supports applying device tree overlays, which it will translate into fixups under the hood. For you simple case, explicitly using a fixup may be the easier way though.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论