LCD is a commonly used peripheral, and semiconductor manufacturers typically provide pre-written LCD interface driver programs for their chips. Developers don’t need to modify the LCD driver section; they only need to adjust the device tree according to the specific LCD device they are using. While no modifications are necessary in the driver, it’s still essential to comprehend the LCD driver process.
1. Framebuffer Device
In the Linux operating system, applications ultimately interact with the video memory of RGB LCD to display characters, images, and other information on the LCD screen. Memory management in Linux is rigorous, and video memory needs to be allocated. Moreover, because of the presence of virtual memory, the video memory set by the driver and the video memory accessed by the application must correspond to the same physical memory. To address this issue, the Framebuffer (referred to as “fb”) was introduced. The Framebuffer represents a memory area that stores a frame of an image. Writing data to this memory is equivalent to writing data to the screen. In essence, the Framebuffer maps each point on the screen to a linear memory space, enabling programs to change the value of this memory segment to alter the color of a specific point on the screen.
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
.llseek = default_llseek,
};
The Framebuffer mechanism provides a unified interface for user space operations on display devices, abstracting away the differences between underlying hardware components. When the LCD driver is successfully loaded, it generates a device file named /dev/fbX
. Applications can access the LCD through this device file. /dev/fbX
is a character device, and it has its corresponding file_operations
operation set, which is defined in the drivers/video/fbdev/core/fbmem.c
file.
struct fb_info {
atomic_t count;
int node;
int flags;
struct mutex lock;
struct mutex mm_lock;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
struct fb_monspecs monspecs;
struct work_struct queue;
struct fb_pixmap pixmap;
struct fb_pixmap sprite;
struct fb_cmap cmap;
struct list_head modelist;
struct fb_videomode *mode;
#ifdef CONFIG_FB_BACKLIGHT
struct backlight_device *bl_dev;
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
struct fb_ops *fbops;
struct device *device;
struct device *dev;
int class_flag;
char __iomem *screen_base;
unsigned long screen_size;
void *pseudo_palette;
};
The Linux kernel abstracts all Framebuffers as fb_info
structures. The fb_info
structure contains the complete attributes and operation sets of the Framebuffer device. As a result, each Framebuffer device is associated with an fb_info
. The structure is defined in the include/linux/fb.h
file.
2. Analysis of the LCD Driver
For a given chip, the driver code for the eLCDIF controller for LCD screens with different resolutions remains the same. As an example, let’s consider the LCD driver for the NXP IMX6ULL chip in Linux and briefly outline the LCD driver’s process.
- Opening the Device Tree: Open the
imx6ull.dtsi
file and locate the content of thelcdif
LCDインターフェースコントローラの設定詳細を含むノード。
lcdif: lcdif@021c8000 {
compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";
reg = ;
interrupts = ;
clocks = ,
,
;
clock-names = "pix", "axi", "disp_axi";
status = "disabled";
};
- デバイスドライバのマッチング:
compatible
プロパティの値は、Linuxソースコード内のデバイスドライバと対応付けるために使用されます。mxsfb.c
ファイルには、MXSフレームバッファ用のプラットフォームドライバが含まれています。
static const struct of_device_id mxsfb_dt_ids[] = {
{ .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
{ .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
{ /* sentinel */ }
};
……
……
static struct platform_driver mxsfb_driver = {
.probe = mxsfb_probe,
.remove = mxsfb_remove,
.shutdown = mxsfb_shutdown,
.id_table = mxsfb_devtype,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxsfb_dt_ids,
.pm = &mxsfb_pm_ops,
},
};
module_platform_driver(mxsfb_driver);
- プローブ関数: ドライバがデバイスと一致すると、
mxsfb_probe
関数が実行されます。この関数は、フレームバッファデバイスの初期化、リソースの割り当て、メモリのマッピング、および割り込みハンドラの設定を行います。
static int mxsfb_probe(struct platform_device *pdev) {
const struct of_device_id *of_id = of_match_device(mxsfb_dt_ids, &pdev->dev);
struct resource *res;
struct mxsfb_info *host;
struct fb_info *fb_info;
struct pinctrl *pinctrl;
int irq = platform_get_irq(pdev, 0);
int gpio, ret;
……
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "メモリIOリソースを取得できません\n");
return -ENODEV;
}
host = devm_kzalloc(&pdev->dev, sizeof(struct mxsfb_info), GFP_KERNEL);
if (!host) {
dev_err(&pdev->dev, "IOリソースの割り当てに失敗しました\n");
return -ENOMEM;
}
fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev);
if (!fb_info) {
dev_err(&pdev->dev, "fbdevの割り当てに失敗しました\n");
devm_kfree(&pdev->dev, host);
return -ENOMEM;
}
host->fb_info = fb_info;
fb_info->par = host;
ret = devm_request_irq(&pdev->dev, irq, mxsfb_irq_handler, 0, dev_name(&pdev->dev), host);
if (ret) {
dev_err(&pdev->dev, "request_irq (%d) がエラー %d で失敗しました\n", irq, ret);
ret = -ENODEV;
goto fb_release;
}
host->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->base)) {
dev_err(&pdev->dev, "ioremapに失敗しました\n");
ret = PTR_ERR(host->base);
goto fb_release;
}
……
fb_info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16, GFP_KERNEL);
if (!fb_info->pseudo_palette) {
ret = -ENOMEM;
goto fb_release;
}
INIT_LIST_HEAD(&fb_info->modelist);
pm_runtime_enable(&host->pdev->dev);
ret = mxsfb_init_fbinfo(host);
if (ret != 0)
goto fb_pm_runtime_disable;
mxsfb_dispdrv_init(pdev, fb_info);
if (!host->dispdrv) {
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
goto fb_pm_runtime_disable;
}
}
if (!host->enabled) {
writel(0, host->base + LCDC_CTRL);
mxsfb_set_par(fb_info);
mxsfb_enable_controller(fb_info);
pm_runtime_get_sync(&host->pdev->dev);
}
ret = register_framebuffer(fb_info);
if (ret != 0) {
dev_err(&pdev->dev, "フレームバッファの登録に失敗しました\n");
goto fb_destroy;
}
……
return ret;
}
- フレームバッファ初期化: フレームバッファデバイスを初期化し、ドライバはLinuxカーネルに登録します。
主なタスクは、 mxsfb_probe
メモリの割り当て、 fb_info
疑似パレット用のメモリ割り当て、 pseudo_palette
、eLCDIFコントローラの初期化、および fb_info
をLinuxカーネルに登録することです。
実際、Linuxシステムの使用は、多くのLCDモジュールサプライヤーにとって常に挑戦的な技術的側面です。Linuxシステムを使用して製品を開発する場合、適切なLCDモジュールサプライヤーを選択することは容易ではありません。RJOYTEKは、LCDモジュールおよびボード開発に特化したテクノロジー企業です。さらに技術サポートが必要な場合は、お気軽にご連絡ください。 お問い合わせください!
- 製品リストはこちらでご確認いただけます TFT LCD表示モジュール
- LCDパネル動画はこちら LCDソリューション RJY
- エンジニアリングサポートが必要な場合は お問い合わせください