/*
**调了一天都调不通这个程序,终于发现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直接在用户态获取物理空间,值得研究。