Milestone/umts_sholes/OMAP3430 DSS(Display Sub-System) Go-Through
前世今生:
为什么又翻出了10年入手的Milestone,费时费力sync 了github 上的代码,编译umts_sholes 工程?
一个关于通过读写 fb0设备节点读写LCD屏的问题,现在高通的解决方案MSM8974/MSM8x26通过读写fb0 设备节点都
不能完成读写LCD屏操作。
完全弄清楚这个问题首先需要理解Tiny6410/Milestone 是如何通过读写fb0 设备节点完成读写LCD 屏的。
印象中 CM7 umts_sholes 采用 2ndboot 启动内核的ROM就是通过写 /dev/graphics/fb0 这个设备节点将2ndboot 的image 刷到LCD 上的。
因此,研究了一下 OMAP3430 DSS。废话不多说,用代码 TRM 说明问题。
/home/CORPUSERS/xxxx/projects/umts_sholes/out/target/product/umts_sholes/system/bin/sh_hijack.sh
通过 Omap3430-trm.pdf ( http://www.droid-developers.org/images/0/0b/Omap3430-trm.pdf),可以看到 OMAP3430 DSS主要的module: Display Controller Module(DISPC), Display Serial Interface(DSI),Serial Display Interface(SDI CONFIG_OMAP2_DSS_SDI
没有打开,因此umts_sholes 并没有使用SDI,使用的是DSI)。
# cat /dev/graphics/fb0 > /mnt/sdcard/umts_sholes.fb
//强制刷 LCD 之前需要将 update_mode 设置为1, auto update 模式,默认情况下update mode 是Manual update mode。
Manual update mode 下需要设置 dirty 才能真正写到 LCD 上。
# echo 1 > /sys/devices/omapdss/display0/update_mode
# cat /mnt/sdcard/umts_sholes.fb > /dev/graphics/fb0
这一节中提到的DSS.DISPC_GFX_BAj registers 就是要写 framebuffer SDRAM Address 的寄存器。
看下Driver 的结构
~/projects/umts_sholes/kernel/drivers/video/omap2$ tree
.
├── displays
│ ├── Kconfig
│ ├── Makefile
│ ├── omap-panel.c
│ ├── panel-mapphone.c
├── dss
│ ├── core.c
│ ├── dispc.c
│ ├── display.c
│ ├── dpi.c
│ ├── dsi.c
│ ├── dss.c
│ ├── dss.h
│ ├── Kconfig
│ ├── Makefile
│ ├── manager.c
│ ├── overlay.c
│ ├── rfbi.c
│ └── venc.c
├── Kconfig
├── Makefile
├── misc
│ ├── dispsw.c
│ ├── dispsw-mr.c
│ ├── dispsw-mr.h
│ ├── dispsw-rotate.c
│ ├── dispsw-rotate.h
│ ├── Kconfig
│ └── Makefile
├── omapfb
│ ├── Kconfig
│ ├── Makefile
│ ├── omapfb.h
│ ├── omapfb-ioctl.c
│ ├── omapfb-main.c
│ └── omapfb-sysfs.c
├── vram.c
└── vrfb.c
4 directories, 41 files
~/projects/umts_sholes/kernel/drivers/video/omap2$ grep -nr "DISPC_GFX" .
./dss/dispc.c:75:#define DISPC_GFX_BA0 DISPC_REG(0x0080)
./dss/dispc.c:76:#define DISPC_GFX_BA1 DISPC_REG(0x0084)
./dss/dispc.c:77:#define DISPC_GFX_POSITION DISPC_REG(0x0088)
./dss/dispc.c:78:#define DISPC_GFX_SIZE DISPC_REG(0x008C)
./dss/dispc.c:79:#define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0)
./dss/dispc.c:80:#define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4)
./dss/dispc.c:81:#define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8)
./dss/dispc.c:82:#define DISPC_GFX_ROW_INC DISPC_REG(0x00AC)
./dss/dispc.c:83:#define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0)
./dss/dispc.c:84:#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
./dss/dispc.c:85:#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
./dss/dispc.c:95:#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
//调用流程
dsi_update_thread
-> dss_setup_partial_planes
-> configure_dispc(void)
-> configure_overlay
-> _dispc_setup_plane
-> _dispc_set_plane_ba0(plane, paddr + offset0);
-> _dispc_set_plane_ba1(plane, paddr + offset1);
前世今生:
为什么又翻出了10年入手的Milestone,费时费力sync 了github 上的代码,编译umts_sholes 工程?
一个关于通过读写 fb0设备节点读写LCD屏的问题,现在高通的解决方案MSM8974/MSM8x26通过读写fb0 设备节点都
不能完成读写LCD屏操作。
完全弄清楚这个问题首先需要理解Tiny6410/Milestone 是如何通过读写fb0 设备节点完成读写LCD 屏的。
印象中 CM7 umts_sholes 采用 2ndboot 启动内核的ROM就是通过写 /dev/graphics/fb0 这个设备节点将2ndboot 的image 刷到LCD 上的。
因此,研究了一下 OMAP3430 DSS。废话不多说,用代码 TRM 说明问题。
/home/CORPUSERS/xxxx/projects/umts_sholes/out/target/product/umts_sholes/system/bin/sh_hijack.sh
#!/system/bin/sh
echo 32 > /sys/devices/platform/omapfb/graphics/fb0/bits_per_pixel
echo 1 > /sys/devices/omapdss/display0/update_mode
/system/bin/busybox_static gunzip -c /etc/2ndboot/2ndboot.fb.gz > /dev/graphics/fb0
/system/bin/busybox_static insmod /etc/2ndboot/hbootmod.ko > /cache/2ndboot.log 2>&1
/system/bin/busybox_static mknod /dev/hbootctrl c 245 0 >> /cache/2ndboot.log 2>&1
echo 255 > /sys/class/leds/green/brightness
/system/bin/hbootuser /etc/2ndboot/hboot.cfg >> /cache/2ndboot.log 2>&1
/system/bin/busybox_static sleep 10
通过 Omap3430-trm.pdf ( http://www.droid-developers.org/images/0/0b/Omap3430-trm.pdf),可以看到 OMAP3430 DSS主要的module: Display Controller Module(DISPC), Display Serial Interface(DSI),Serial Display Interface(SDI CONFIG_OMAP2_DSS_SDI
没有打开,因此umts_sholes 并没有使用SDI,使用的是DSI)。
The Big Picture
# cat /dev/graphics/fb0 > /mnt/sdcard/umts_sholes.fb
//强制刷 LCD 之前需要将 update_mode 设置为1, auto update 模式,默认情况下update mode 是Manual update mode。
Manual update mode 下需要设置 dirty 才能真正写到 LCD 上。
enum omapfb_update_mode {
OMAPFB_UPDATE_DISABLED = 0,
OMAPFB_AUTO_UPDATE,
OMAPFB_MANUAL_UPDATE
};
static int dsi_update_thread(void *data)
{
struct omap_dss_device *device;
u16 x, y, w, h;
u8 num_timeouts = 0;
u8 num_success = 0;
while (1) {
bool sched;
wait_event_interruptible(dsi.waitqueue,
dsi.update_mode == OMAP_DSS_UPDATE_AUTO ||
(dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
dsi.update_region.dirty == true) ||
kthread_should_stop());
if (kthread_should_stop())
break;
# echo 1 > /sys/devices/omapdss/display0/update_mode
# cat /mnt/sdcard/umts_sholes.fb > /dev/graphics/fb0
static const struct file_operations fb_fops = {
.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
};
static ssize_t
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
//这个函数指针是 NULL.
if (info->fbops->fb_write)
return info->fbops->fb_write(info, buf, count, ppos);
//真正完成写 LCD 的有效代码是这一段
//info->screen_base 保存的是 framebuffer SDRAM 中的Virtual Address,
//这块内存地址 在DSS driver 中会配到DISPC Display Controller 的一个寄存器中,
// Dispc 负责将 SDRAM 中的这段内存数据搬运通过数据线发给 LCD.
dst = (u32 __iomem *) (info->screen_base + p);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
src = buffer;
if (copy_from_user(src, buf, c)) {
err = -EFAULT;
break;
}
for (i = c >> 2; i--; )
fb_writel(*src++, dst++);
if (c & 3) {
u8 *src8 = (u8 *) src;
u8 __iomem *dst8 = (u8 __iomem *) dst;
for (i = c & 3; i--; )
fb_writeb(*src8++, dst8++);
dst = (u32 __iomem *) dst8;
}
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
Omap3430-trm.pdf <Display Subsystem Basic Programming Model>
这一节中提到的DSS.DISPC_GFX_BAj registers 就是要写 framebuffer SDRAM Address 的寄存器。
15.5.3.2 Graphics Layer Configuration
15.5.3.2.1 Graphics DMA Registers
15.5.3.3 Video Layer Configuration
15.5.3.3.1 Video DMA Registers
看下Driver 的结构
~/projects/umts_sholes/kernel/drivers/video/omap2$ tree
.
├── displays
│ ├── Kconfig
│ ├── Makefile
│ ├── omap-panel.c
│ ├── panel-mapphone.c
├── dss
│ ├── core.c
│ ├── dispc.c
│ ├── display.c
│ ├── dpi.c
│ ├── dsi.c
│ ├── dss.c
│ ├── dss.h
│ ├── Kconfig
│ ├── Makefile
│ ├── manager.c
│ ├── overlay.c
│ ├── rfbi.c
│ └── venc.c
├── Kconfig
├── Makefile
├── misc
│ ├── dispsw.c
│ ├── dispsw-mr.c
│ ├── dispsw-mr.h
│ ├── dispsw-rotate.c
│ ├── dispsw-rotate.h
│ ├── Kconfig
│ └── Makefile
├── omapfb
│ ├── Kconfig
│ ├── Makefile
│ ├── omapfb.h
│ ├── omapfb-ioctl.c
│ ├── omapfb-main.c
│ └── omapfb-sysfs.c
├── vram.c
└── vrfb.c
4 directories, 41 files
~/projects/umts_sholes/kernel/drivers/video/omap2$ grep -nr "DISPC_GFX" .
./dss/dispc.c:75:#define DISPC_GFX_BA0 DISPC_REG(0x0080)
./dss/dispc.c:76:#define DISPC_GFX_BA1 DISPC_REG(0x0084)
./dss/dispc.c:77:#define DISPC_GFX_POSITION DISPC_REG(0x0088)
./dss/dispc.c:78:#define DISPC_GFX_SIZE DISPC_REG(0x008C)
./dss/dispc.c:79:#define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0)
./dss/dispc.c:80:#define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4)
./dss/dispc.c:81:#define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8)
./dss/dispc.c:82:#define DISPC_GFX_ROW_INC DISPC_REG(0x00AC)
./dss/dispc.c:83:#define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0)
./dss/dispc.c:84:#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
./dss/dispc.c:85:#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
./dss/dispc.c:95:#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
{
const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
DISPC_VID_BA0(0),
DISPC_VID_BA0(1) };
dispc_write_reg(ba0_reg[plane], paddr);//paddr 就是framebuffer SDRAM中对应的物理地址
}
//调用流程
dsi_update_thread
-> dss_setup_partial_planes
-> configure_dispc(void)
-> configure_overlay
-> _dispc_setup_plane
-> _dispc_set_plane_ba0(plane, paddr + offset0);
-> _dispc_set_plane_ba1(plane, paddr + offset1);
关于 sync/build umts_sholes 源代码,请参考以下文章:
http://blog.csdn.net/fervor_heart/article/details/10060557
That's All ! Thanks !