S3C2440 LCD驱动架构与优化实践详解
·
1. S3C2440 LCD驱动架构解析
S3C2440作为经典的ARM9处理器,其LCD控制器采用硬件加速设计,通过DMA通道直接操作显存。内核驱动代码主要分布在drivers/video/fbdev/s3c2410fb.c中,这个文件实现了帧缓冲设备的核心操作。
驱动采用标准的platform_driver架构,与设备树中的节点匹配后触发probe函数。关键数据结构包括:
struct s3c2410fb_info {
struct device *dev;
struct clk *clk;
void __iomem *io;
struct s3c2410fb_hw regs;
u32 palette_buffer[256];
u32 pseudo_pal[16];
};
注意:不同内核版本中寄存器定义可能变化,4.19内核后新增了alpha混合支持
2. 硬件接口配置详解
2.1 时序参数计算
LCD驱动需要配置的关键时序参数包括:
- VCLK:像素时钟频率 = (HCLK / (CLKVAL +1)) × 2
- VBPD:垂直后沿 = (tvb - 1) / (tv + 1)
- VFPD:垂直前沿 = tvf - 1
- VSPW:垂直同步脉宽 = tvp - 1
以800x480 LCD为例,典型配置如下:
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
.timing = {
.h_fp = 8,
.h_bp = 4,
.h_sw = 8,
.v_fp = 2,
.v_fpe = 1,
.v_bp = 2,
.v_bpe = 1,
.v_sw = 1,
},
.default_display = 0,
};
2.2 显存管理
驱动通过dma_alloc_writecombine()申请DMA内存:
fbi->screen_base = dma_alloc_writecombine(dev,
map_size, &map_dma, GFP_KERNEL);
显存布局采用双缓冲设计:
+-------------------+
| 主缓冲 (800x480x2) |
+-------------------+
| 副缓冲 (800x480x2) |
+-------------------+
| 调色板 (256x4) |
+-------------------+
3. 关键函数流程分析
3.1 初始化流程
-
s3c2410fb_probe()
- 获取平台资源(I/O映射、中断等)
- 配置GPIO为LCD功能
- 初始化时钟和PLL
- 注册framebuffer设备
-
s3c2410fb_set_par()
- 计算并设置时序参数
- 配置DMA缓冲区地址
- 更新调色板
3.2 中断处理
VSYNC中断服务程序完成:
static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
{
struct s3c2410fb_info *fbi = dev_id;
u32 irq_sts = readl(fbi->irq_base + S3C2410_LCDINTPND);
if (irq_sts & S3C2410_LCDINT_VSYNC) {
wake_up_interruptible(&fbi->vsync_wait);
writel(S3C2410_LCDINT_VSYNC,
fbi->irq_base + S3C2410_LCDINTPND);
}
return IRQ_HANDLED;
}
4. 性能优化实践
4.1 DMA传输优化
通过调整BURST_SIZE提升吞吐量:
#define S3C2410_LCDFIFO_BURST_4 (0x3 << 4)
#define S3C2410_LCDFIFO_BURST_8 (0x2 << 4)
#define S3C2410_LCDFIFO_BURST_16 (0x1 << 4)
4.2 双缓冲实现
在fb_ops中实现页面切换:
static int s3c2410fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
dma_addr_t dma_addr = fbi->screen_dma + var->yoffset * fbi->fix.line_length;
writel(dma_addr, fbi->regs + S3C2410_LCDSADDR1);
return 0;
}
5. 常见问题排查
5.1 花屏问题处理
- 检查时序参数是否匹配LCD规格书
- 确认HCLK频率是否稳定
- 测量VCLK信号质量
- 排查显存地址对齐问题
5.2 性能调优记录
通过ftrace测得各阶段耗时:
| 阶段 | 4.9内核(ms) | 5.10内核(ms) |
|---------------------|------------|-------------|
| DMA配置 | 1.2 | 0.8 |
| 调色板更新 | 3.5 | 1.2 |
| 垂直同步等待 | 16.7 | 8.9 |
6. 设备树配置实例
典型S3C2440 LCD节点配置:
lcd-controller@4D000000 {
compatible = "samsung,s3c2440-lcd";
reg = <0x4D000000 0x20>;
interrupts = <0 0 16>;
clocks = <&lcd CLK_LCD>;
clock-names = "lcd";
pinctrl-names = "default";
pinctrl-0 = <&lcd_pins>;
status = "okay";
display-timings {
native-mode = <&timing0>;
timing0: 800x480 {
clock-frequency = <33300000>;
hactive = <800>;
vactive = <480>;
hfront-porch = <40>;
hback-porch = <88>;
hsync-len = <48>;
vfront-porch = <13>;
vback-porch = <32>;
vsync-len = <3>;
hsync-active = <0>;
vsync-active = <0>;
};
};
};
7. 调试技巧汇编
- 寄存器检查命令:
adb shell cat /sys/kernel/debug/regmap/4d000000.lcd/registers
- 帧率测量方法:
static void measure_fps(struct fb_info *info)
{
struct timespec ts1, ts2;
getnstimeofday(&ts1);
for (int i = 0; i < 60; i++) {
fb_pan_display(info, &info->var);
}
getnstimeofday(&ts2);
pr_info("FPS: %ld\n", 60 * NSEC_PER_SEC / (ts2.tv_nsec - ts1.tv_nsec));
}
- 内存泄漏检测:
echo scan > /sys/kernel/debug/kmemleak
cat /sys/kernel/debug/kmemleak
更多推荐
所有评论(0)