S3C6410 Linux 2D Test Program

S3C6410 Linux 2D Test Program V0.01
2010-04-27 18:54

/*
**调了一天都调不通这个程序,终于发现2D硬件要提高物理地址。
**Linux用户态要如何才能获取图片和LCD的物理地址呢?HELP
**
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>

#include "s3c_g2d.h"
#include "fb.h"

//#define S3C_G2D_DEV_NAME "/dev/s3c-g2d"
#define S3C_FB_DEV_NAME "/dev/fb0"

int g2d_fd;
int fb_fd;
FILE *file_fd;
int file_len;

static unsigned char *file_name;
unsigned int *pic_buffer;

int width = 480;
int height = 272;

int main(int argc, char *argv[])
{
printf("This is a S3C6410 2d test program/n");

///////////////////////////////////////////////////////////
//file operaton
//////////////////////////////////////////////////////////

file_name = argv[1];

file_fd = fopen(file_name, "r");
fseek(file_fd,0,SEEK_END);     //定位到文件末
file_len = ftell(file_fd);     //文件长度

fclose(file_fd);
file_fd = fopen(file_name, "r");

pic_buffer = malloc(file_len);

fread(pic_buffer, file_len, 1, file_fd);

//memcpy(buffer,pic_buffer,file_len);

/////////////////////////////////////////////////////////////////////////////

g2d_fd = open(S3C_G2D_DEV_NAME, O_RDWR);//open g2d
if( g2d_fd < 0 )
   printf("open g2d device error!/n ");

fb_fd = open(S3C_FB_DEV_NAME, O_RDWR, 0);//open fb0
if( fb_fd < 0 )
   printf("open framebuffer device error!/n ");

struct fb_fix_screeninfo finfo;
   
if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        printf("get fix info error!/n");

struct fb_var_screeninfo info;

if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &info) == -1)
        printf("get var info error!/n");

   printf(   "using (fd=%d)/n"
            "id           = %s/n"
            "xres         = %d px/n"
            "yres         = %d px/n"
            "xres_virtual = %d px/n"
            "yres_virtual = %d px/n"
            "bpp          = %d/n"
            "r            = %2u:%u/n"
            "g            = %2u:%u/n"
            "b            = %2u:%u/n",
            fb_fd,
            finfo.id,
            info.xres,
            info.yres,
            info.xres_virtual,
            info.yres_virtual,
            info.bits_per_pixel,
            info.red.offset, info.red.length,
            info.green.offset, info.green.length,
            info.blue.offset, info.blue.length
    );
//mmap
void* lcd_buffer = (unsigned short*) mmap(
   0, finfo.smem_len,
   PROT_READ | PROT_WRITE,
   MAP_SHARED,
   fb_fd, 0);

if (lcd_buffer == MAP_FAILED)
        printf("mmap fb error!/n");

//test
//u32* test_buffer;
//test_buffer = (u32*)malloc(480*272*2);
//memset(test_buffer,0xaa,480*272*2);
// at least for now, always clear the fb
    memset(buffer, 0, finfo.smem_len);

////////////////////////////////////////////////////////////////
//g2d operation
///////////////////////////////////////////////////////////////

s3c_g2d_params *params;

params = (s3c_g2d_params *)malloc(sizeof(s3c_g2d_params));

params->bpp        = G2D_RGB16;
//params->bpp_dst        = G2D_RGB16;

params->alpha_mode     = 0;
params->alpha_val      = 0;
params->color_key_mode = 0;
params->color_key_val = 0;

params->src_base_addr   = (u32)pic_buffer;
params->src_full_width = width;
params->src_full_height = height;

params->src_start_x     = 0;
params->src_start_y     = 0;
params->src_work_width = width-1;
params->src_work_height = height-1;

params->dst_base_addr   =(u32)lcd_buffer;
params->dst_full_width = width;
params->dst_full_height = height;

params->dst_start_x     = 0;
params->dst_start_y     = 0;
params->dst_work_width = width-1;
params->dst_work_height = height-1;

//initialize clipping window
params->cw_x1 = 0;
params->cw_y1 = 0;
params->cw_x2 = width-1;
params->cw_y2 = width-1;

if(ioctl(g2d_fd, S3C_G2D_ROTATOR_0, params) < 0)
{
   printf("%s::S3C_G2D_ROTATOR fail/n", __func__);
   return -1;
}

end:
close(g2d_fd);
close(fb_fd);
fclose(file_fd);
return 0;
}

经过一天努力,首先要高兴2D驱动终于可以正常工作,可惜采用的方法并不好。

目的地址解决方案:

经过摸索,发现(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1)获取的finfo.smem_start就是Framebuffer的物理地址,可以将这个地址作为目的地址传入G2D。

源地址解决方案:

参考了msm7k的copybit,并没有在用户态获取图像物理地址,而是在内核驱动中通过copy_from_user获取图像数据。于是我修改了部分G2D驱动,大致添加如下代码:

1)声明一个虚拟和一个物理指针

static unsigned char * g2d_vaddr = NULL;
static unsigned char * g2d_phyaddr = NULL;

2)probe函数中预先分配空间

g2d_vaddr = (unsigned char *) dma_alloc_coherent(NULL,800*480*2, (dma_addr_t *) &g2d_phyaddr, GFP_KERNEL);

3)blit时调用copy form user,目前还只支持RGB565

copy_from_user(g2d_vaddr, (unsigned short*)params->src_base_addr,
        params->src_full_width * params->src_full_height * 2 )

4)最后是src add用g2d_phyaddr填充

 

 

虽然MSM也是这样做的,但感觉这样数据还是要从用户态至内核态倒一遍,不是很没有效率吗?

另外MSM的做法比较好,集合了链表中的12个元素一次性传输过去,效率高,值得学习。

此外似乎可以用Android的PMEM直接在用户态获取物理空间,值得研究。

你可能感兴趣的:(S3C6410 Linux 2D Test Program)