Chinaunix首页 | 论坛 | 博客
  • 博客访问: 196097
  • 博文数量: 30
  • 博客积分: 1571
  • 博客等级: 上尉
  • 技术积分: 363
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-28 11:42
文章分类

全部博文(30)

文章存档

2012年(6)

2011年(11)

2010年(13)

我的朋友

分类: LINUX

2010-03-22 09:32:06

开始将开发板带的三星的2.6.28的g2d驱动移植过来。结果在设置完命令寄存器以后,命令全都往FIFO里面放了,压根没有执行!
后来按照6410手册614页的寄存器设置,自己设置。结果设置完命令寄存器以后,命令运行了,但是没有看到任何输出。
问了几个开发板的技术支持,都说没用过linux下的2D,Wince下的倒是可以正常运行。
只好参考WinCE的2D驱动了,还好搞定了。

6410手册里面讲的太不清楚,有几个寄存器的设置他就没讲清楚甚至没讲!
    1、DST_BASE_ADDR和SRC_BASE_ADDR要设置物理地址。不能是内核的虚拟地址或者应用程序中的地址。对于FB,要使用 dma_alloc_writecombine 第三个参数返回的物理地址 fbi->fix.smem_start。
    2、在手册里bitblt没说要设置 clip 的寄存器,但是clip不设是不行的,感觉是使用默认值的0话就把图像全部剪掉了!我直接设为屏幕的分辨率了。
    3、使用透明模式要设置的是 BS_COLOR,而不是BG_COLOR。开始我还以为是代码写错了。后来试了一下,感觉是手册写错了。Blue Screen Mode咋设置我就没有试了。
    4、使用2D的画线和画点功能,也要设置DST_BASE_ADDR和clip的!手册里面都没说!
    5、设置COORDn_X_REG+COORDn_Y_REG和设置COORDn_REG好像是一样的,都能跑。

下面是主要部分的代码,s3c_g2d_transparent_copy()是bitblt的主要函数。
注:因为不知道如何将用户空间的虚拟地址转换为物理地址,只好在内核里面alloc了一块buffer s3c_g2d_userFB,每次都要用copy_from_user把图片先拷贝到s3c_g2d_userFB,再由2D搬到屏幕。
大概测试过一下,一张800*600的图片 copy_from_user 用了大概 4ms。2D搬到屏幕上用了大概5~6ms。还是想把copy_from_user给剩了!

static void s3c_g2d_wait_allcmd_finish(void)
{
    while (__raw_readl(s3c_g2d_base + S3C_G2D_FIFO_STAT_REG) != 0x600)
    {
    }
}

irqreturn_t s3c_g2d_irq(int irq, void *dev_id)
{
    if(__raw_readl(s3c_g2d_base + S3C_G2D_INTC_PEND_REG) & S3C_G2D_PEND_REG_INTP_CMD_FIN) {
         __raw_writel ( S3C_G2D_PEND_REG_INTP_CMD_FIN, s3c_g2d_base + S3C_G2D_INTC_PEND_REG );
        wake_up_interruptible(&waitq_g2d);
        s3c_g2d_poll_flag = 1;
    }

    return IRQ_HANDLED;
}

void s3c_g2d_enable_interrupt(void)
{
    s3c_g2d_debug_reg(S3C_G2D_INTEN_REG_CCF, s3c_g2d_base + S3C_G2D_INTEN_REG);   
}

void s3c_g2d_set_srcsurface(struct fb_info *info, u32 src_addr,
                            int src_width, int src_heigth)
{
    s3c_g2d_check_fifo(4);

    s3c_g2d_debug_reg(src_addr, s3c_g2d_base + S3C_G2D_SRC_BASE_ADDR);
    s3c_g2d_debug_reg(S3C_G2D_COLOR_RGB_565,
                      s3c_g2d_base + S3C_G2D_SRC_COLOR_MODE);
    s3c_g2d_debug_reg(src_width, s3c_g2d_base + S3C_G2D_HORI_RES_REG);
    s3c_g2d_debug_reg(src_heigth, s3c_g2d_base + S3C_G2D_VERT_RES_REG);
}

void s3c_g2d_set_dstsurface(struct fb_info *info, u32 dst_addr)
{
    s3c_g2d_check_fifo(4);

    s3c_g2d_debug_reg(dst_addr, s3c_g2d_base + S3C_G2D_DST_BASE_ADDR);
    s3c_g2d_debug_reg(S3C_G2D_COLOR_RGB_565,
                      s3c_g2d_base + S3C_G2D_SRC_COLOR_MODE);
    s3c_g2d_debug_reg(info->var.xres, s3c_g2d_base + S3C_G2D_SC_HORI_REG);
    s3c_g2d_debug_reg(info->var.yres, s3c_g2d_base + S3C_G2D_SC_VERT_REG);
}

void s3c_g2d_set_clipwindows(struct fb_info *info)
{
    s3c_g2d_check_fifo(4);

    s3c_g2d_debug_reg(0, s3c_g2d_base + S3C_G2D_CW_LT_X_REG);
    s3c_g2d_debug_reg(0, s3c_g2d_base + S3C_G2D_CW_LT_Y_REG);
    s3c_g2d_debug_reg(info->var.xres, s3c_g2d_base + S3C_G2D_CW_RB_X_REG);
    s3c_g2d_debug_reg(info->var.yres, s3c_g2d_base + S3C_G2D_CW_RB_Y_REG);
}

void s3c_g2d_set_transparentmode(struct fb_info *info, int is_transp, u32 color)
{
    u32 tmp;
    s3c_g2d_check_fifo(2);

    tmp = __raw_readl(s3c_g2d_base + S3C_G2D_ROP_REG);
    if (is_transp)
    {
        tmp |= S3C_G2D_ROP_REG_T_TRANSP_MODE;
    }
    else
    {
        tmp &= ~S3C_G2D_ROP_REG_T_TRANSP_MODE;
    }

    s3c_g2d_debug_reg(tmp, s3c_g2d_base + S3C_G2D_ROP_REG);
    s3c_g2d_debug_reg(color, s3c_g2d_base + S3C_G2D_BS_COLOR_REG);  //wy!Rev in wince set bs_color????
    //s3c_g2d_debug_reg(color, s3c_g2d_base + S3C_G2D_BG_COLOR_REG);      //wy ! rev!!!!
}

void s3c_g2d_set_rotationmode(struct fb_info *info, S3C_G2D_ROT_TYPE rot_type)
{
    u32 tmp;
    s3c_g2d_check_fifo(1);

    tmp = __raw_readl(s3c_g2d_base + S3C_G2D_ROTATE_REG);
    tmp = (tmp&~0x3f) | rot_type;
    s3c_g2d_debug_reg(tmp, s3c_g2d_base + S3C_G2D_ROTATE_REG);
}

void s3c_g2d_set_srccoordinate(struct fb_info *info,
        int start_x, int start_y, int end_x, int end_y)
{
    s3c_g2d_check_fifo(4);

    s3c_g2d_debug_reg(start_x, s3c_g2d_base + S3C_G2D_COORD0_X_REG);
    s3c_g2d_debug_reg(start_y, s3c_g2d_base + S3C_G2D_COORD0_Y_REG);
    s3c_g2d_debug_reg(end_x,   s3c_g2d_base + S3C_G2D_COORD1_X_REG);
    s3c_g2d_debug_reg(end_y,   s3c_g2d_base + S3C_G2D_COORD1_Y_REG);
}

void s3c_g2d_set_dstcoordinate(struct fb_info *info,
         int start_x, int start_y, int end_x, int end_y)
{
    s3c_g2d_check_fifo(4);

    s3c_g2d_debug_reg(start_x, s3c_g2d_base + S3C_G2D_COORD2_X_REG);
    s3c_g2d_debug_reg(start_y, s3c_g2d_base + S3C_G2D_COORD2_Y_REG);
    s3c_g2d_debug_reg(end_x,   s3c_g2d_base + S3C_G2D_COORD3_X_REG);
    s3c_g2d_debug_reg(end_y,   s3c_g2d_base + S3C_G2D_COORD3_Y_REG);
}

void s3c_g2d_set_rotationorg(struct fb_info *info, int x, int y)
{
    s3c_g2d_check_fifo(2);

    s3c_g2d_debug_reg(x, s3c_g2d_base + S3C_G2D_ROT_OC_X_REG);
    s3c_g2d_debug_reg(y, s3c_g2d_base + S3C_G2D_ROT_OC_Y_REG);
}

void s3c_g2d_transparent_copy(struct fb_info *info, S3CFB_COPY_INFO *copy_info)
{
    s3c_g2d_wait_allcmd_finish();
    if (copy_from_user(s3c_g2d_userFB, (unsigned short *)copy_info->src_base,
                copy_info->dst_width * copy_info->dst_height
                * (info->var.bits_per_pixel>>3) ) )
    {
        printk("G2D TransparentCopy copy from user error!\n");
        return ;
    }

    copy_info->src_base   = __pa(s3c_g2d_userFB);
    copy_info->dst_base   = info->fix.smem_start;


    s3c_g2d_enable_interrupt();

    s3c_g2d_set_srcsurface(info, copy_info->src_base,
            copy_info->dst_width, copy_info->dst_height);
    s3c_g2d_set_dstsurface(info, copy_info->dst_base);

    s3c_g2d_set_clipwindows(info);

    if (copy_info->transparent_enable)
    {
        s3c_g2d_set_transparentmode(info, 1, copy_info->transparent_color);
    }
    else
    {
        s3c_g2d_set_transparentmode(info, 0, 0);
    }

    s3c_g2d_set_rotationmode(info, G2D_ROT_0);
    s3c_g2d_set_srccoordinate(info, copy_info->src_X, copy_info->src_Y,
            copy_info->src_X+copy_info->dst_width-1,
            copy_info->src_Y+copy_info->dst_height-1);
    s3c_g2d_set_rotationorg(info, copy_info->dst_X, copy_info->dst_Y);
    s3c_g2d_set_dstcoordinate(info, copy_info->dst_X, copy_info->dst_Y,
            copy_info->dst_X+copy_info->dst_width-1,
            copy_info->dst_Y+copy_info->dst_height-1);

    s3c_g2d_debug_reg(1, s3c_g2d_base + S3C_G2D_CMD1_REG);
}

static void s3c_fb_g2d_init(void)  
{
    //DisableEffect
    s3c_g2d_debug_reg(__raw_readl(s3c_g2d_base+S3C_G2D_ROP_REG)&~(0x7<<10),
                      s3c_g2d_base + S3C_G2D_ROP_REG);   

    //SetColorKeyOff
    s3c_g2d_debug_reg(__raw_readl(s3c_g2d_base+S3C_G2D_ROP_REG)&(~(0x1<<9)),
                      s3c_g2d_base + S3C_G2D_ROP_REG);   
    s3c_g2d_debug_reg(__raw_readl(s3c_g2d_base+S3C_G2D_STENCIL_CNTL_REG)&(~(0x1U<<31)),
                      s3c_g2d_base + S3C_G2D_STENCIL_CNTL_REG);   

    s3c_g2d_debug_reg((FADING_OFFSET_DISABLE | ALPHA_VALUE_DISABLE),
                      s3c_g2d_base + S3C_G2D_ALPHA_REG);   
    s3c_g2d_debug_reg((G2D_OPERAND3_FG_BIT | G2D_NO_ALPHA_BIT | OPAQUE_ENABLE | G2D_ROP_SRC_ONLY),
                      s3c_g2d_base + S3C_G2D_ROP_REG);   

    //SetRotationOrg
    s3c_g2d_debug_reg((0&0x000007FF),
                      s3c_g2d_base + S3C_G2D_ROT_OC_X_REG);   
    s3c_g2d_debug_reg((0&0x000007FF),
                      s3c_g2d_base + S3C_G2D_ROT_OC_Y_REG);   

    s3c_g2d_debug_reg((0x1<<0),
                      s3c_g2d_base + S3C_G2D_ROTATE_REG);   
    s3c_g2d_debug_reg(0,
                      s3c_g2d_base + S3C_G2D_ALPHA_REG);   
}
阅读(3484) | 评论(4) | 转发(1) |
给主人留下些什么吧!~~

chinaunix网友2010-09-18 11:30:47

很好的文章。用户空间分配的内存经过了页表,在物理空间上可能并非连续,所以即使得到了首页的物理地址,也是无意义的。

chinaunix网友2010-06-21 10:08:17

你好,我要用到6410里面的DMA部分,规格书里写的方法从理论上好像有我有用的东西,可我在linux开发包中找不到一个规格书里写的寄存器名字,所以现在不知如何用代码来配置那些寄存器。希望能得到兄台的支援,不知你的邮箱是多少,我的Email: bellchen@sekaku.com 、QQ: 174646172

chinaunix网友2010-06-21 10:08:08

你好,我要用到6410里面的DMA部分,规格书里写的方法从理论上好像有我有用的东西,可我在linux开发包中找不到一个规格书里写的寄存器名字,所以现在不知如何用代码来配置那些寄存器。希望能得到兄台的支援,不知你的邮箱是多少,我的Email: bellchen@sekaku.com 、QQ: 174646172

chinaunix网友2010-05-24 11:50:01

我QQ 313132755 做6410 2d硬件画线时遇到一个问题,相应的寄存器配置好了,但画面却没显示。