LuckFox Pico Ultra 和 LuckFox Pico Ultra W 现在支持 RGB 屏幕,采用并行的 RGB LCD 接口。图像数据以 RGB666 格式传输,每个像素占用 6 位。目前的只适配分辨率有 720x720 和 480x480。为了帮助大家的理解工作原理,本节会从应用层到驱动层进行介绍,由于屏幕种类繁多,其它分辨率屏幕适配还需要自行研究。
刚到手可以使用开发板自带的程序测试屏幕,默认已经将测试程序打包到开发板上(/oem/usr/bin),如果想了解可执行程序的源码,在
/SDK目录//media/luckfox/examples 和 ./SDK目录/project/app/lvgl:
# luckfox_fb_test The mem is :921600 The line_length is :1920 The xres is :480 The yres is :480 bits_per_pixel is :32 # luckfox_lvgl_test fbdev_init
panel: panel { compatible = "simple-panel"; backlight = <&backlight>; reset-gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>; reset-delay-ms = <200>; status = "okay"; bus-format = <MEDIA_BUS_FMT_RGB666_1X18>; width-mm = <85>; height-mm = <85>; display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <16500000>; hactive = <480>; vactive = <480>; hback-porch = <43>; hfront-porch = <8>; vback-porch = <15>; vfront-porch = <12>; hsync-len = <4>; vsync-len = <10>; //value range <2~22> hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <1>; }; }; port { panel_in_rgb: endpoint { remote-endpoint = <&rgb_out_panel>; }; }; };
display_subsystem: display-subsystem { compatible = "rockchip,display-subsystem"; ports = <&vop_out>;
vop: vop@ff990000 { compatible = "rockchip,rv1106-vop"; reg = <0xff990000 0x200>; reg-names = "regs"; rockchip,grf = <&grf>; interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru ACLK_VOP>, <&cru DCLK_VOP>, <&cru HCLK_VOP>; clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; status = "disabled"; vop_out: port { #address-cells = <1>; #size-cells = <0>; vop_out_rgb: endpoint@0 { reg = <0>; remote-endpoint = <&rgb_in_vop>; }; }; };
cp ./arch/arm/configs/luckfox_rv1106_linux_defconfig .config make ARCH=arm menuconfig
Device Drivers ---> Graphics support ---> <*> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) ---> <*> DRM Support for Rockchip (DRM_ROCKCHIP [=y]) [ ] Support 3D cubic LUT [ ] Rockchip DRM debug [ ] Rockchip DRM direct show [*] Rockchip VOP driver [ ] Rockchip VOP2 driver [ ] Rockchip specific extensions for Analogix DP driver [ ] Rockchip cdn DP [ ] Rockchip TVE support [ ] Rockchip specific extensions for Synopsys DW HDMI [ ] Rockchip specific extensions for Synopsys DW MIPI DSI [ ] Rockchip specific extensions for Synopsys DW DPTX [ ] Rockchip specific extensions for Innosilicon HDMI [ ] Rockchip LVDS support [*] Rockchip RGB support [ ] Rockchip specific extensions for RK3066 HDMI [ ] Rockchip Virtual connector driver for HDMI/DP/DSI [ ] Rockchip virtual VOP drm driver< > Synopsis Designware HDCP2 interface
root@718974014fe6:/home/sysdrv/source/kernel/drivers/gpu/drm/rockchip# grep -rn "CONFIG_ROCKCHIP_RGB" ./ ./Makefile:27:rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o ./rockchip_drm_drv.c:2050: ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver, CONFIG_ROCKCHIP_RGB); ./rockchip_rgb.h:8:#ifdef CONFIG_ROCKCHIP_RGB
static struct platform_driver panel_simple_platform_driver = { .driver = { .name = "panel-simple", .of_match_table = platform_of_match, }, .probe = panel_simple_platform_probe, .remove = panel_simple_platform_remove, .shutdown = panel_simple_platform_shutdown, };
static int panel_simple_of_get_desc_data(struct device *dev, struct panel_desc *desc) { struct device_node *np = dev->of_node; u32 bus_flags; const void *data; int len; int err; if (of_child_node_is_present(np, "display-timings")) { struct drm_display_mode *mode; mode = devm_kzalloc(dev, sizeof(*mode), GFP_KERNEL); if (!mode) return -ENOMEM; if (!of_get_drm_display_mode(np, mode, &bus_flags, OF_USE_NATIVE_MODE)) { desc->modes = mode; desc->num_modes = 1; desc->bus_flags = bus_flags; }
static int panel_simple_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct of_device_id *id; const struct panel_desc *desc; struct panel_desc *d; int err; id = of_match_node(platform_of_match, pdev->dev.of_node); if (!id) return -ENODEV; if (!id->data) { d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM; err = panel_simple_of_get_desc_data(dev, d); if (err) { dev_err(dev, "failed to get desc data: %d\n", err); return err; } } desc = id->data ? id->data : d; return panel_simple_probe(&pdev->dev, desc); }
void drm_panel_init(struct drm_panel *panel, struct device *dev, const struct drm_panel_funcs *funcs, int connector_type) { INIT_LIST_HEAD(&panel->list); panel->dev = dev; panel->funcs = funcs; panel->connector_type = connector_type; } EXPORT_SYMBOL(drm_panel_init); /** * drm_panel_add - add a panel to the global registry * @panel: panel to add * * Add a panel to the global registry so that it can be looked up by display * drivers. */ void drm_panel_add(struct drm_panel *panel) { mutex_lock(&panel_lock); list_add_tail(&panel->list, &panel_list); mutex_unlock(&panel_lock); } EXPORT_SYMBOL(drm_panel_add);
#define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \ if (IS_ENABLED(cond) && \ !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \ rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \ } static int __init rockchip_drm_init(void) { int ret; num_rockchip_sub_drivers = 0; #if IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP) ADD_ROCKCHIP_SUB_DRIVER(vvop_platform_driver, CONFIG_DRM_ROCKCHIP_VVOP); #else ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); ... ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver, CONFIG_ROCKCHIP_RGB); ... #endif ret = platform_register_drivers(rockchip_sub_drivers, num_rockchip_sub_drivers); if (ret) return ret; ret = platform_driver_register(&rockchip_drm_platform_driver); if (ret) goto err_unreg_drivers; rockchip_gem_get_ddr_info(); return 0; err_unreg_drivers: platform_unregister_drivers(rockchip_sub_drivers, num_rockchip_sub_drivers); return ret; }
static struct platform_driver rockchip_drm_platform_driver = { .probe = rockchip_drm_platform_probe, .remove = rockchip_drm_platform_remove, .shutdown = rockchip_drm_platform_shutdown, .driver = { .name = "rockchip-drm", //此字段为device和driver匹配的最后一种方式 .of_match_table = rockchip_drm_dt_ids, .pm = &rockchip_drm_pm_ops, }, };
static const struct of_device_id rockchip_drm_dt_ids[] = { { .compatible = "rockchip,display-subsystem", }, { /* sentinel */ }, };
static int rockchip_drm_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct component_match *match = NULL; int ret; ret = rockchip_drm_platform_of_probe(dev); #if !IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP) if (ret) return ret; #endif match = rockchip_drm_match_add(dev); if (IS_ERR(match)) return PTR_ERR(match); ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) goto err; ret = component_master_add_with_match(dev, &rockchip_drm_ops, match); if (ret < 0) goto err; return 0; err: rockchip_drm_match_remove(dev); return ret; }
想了解更多具体内容,需自己进入源码目录(drivers/gpu/drm)阅读理解。