S3C6410 2D Graphics Driver

S3C6410 2D Graphics Driver
2010-04-24 16:23

/*****************************************************
三星的2D驱动
主要实现功能有
bitBLT
rotate
Alpha Blending
transparent
color expansion
奇怪的是有两个功能没有实现?
stretch <--这个是可以修改简单代码实现的
draw line

*****************************************************/
//

typedef struct
{
u32 src_base_addr;    //Base address of the source image源图像基址
u32 src_full_width;    //source image full width源图像宽度
u32 src_full_height;   //source image full height源图像高度
u32 src_start_x;    //coordinate start x of source image源图像起始x坐标
u32 src_start_y;    //coordinate start y of source image源图像起始y坐标
u32 src_work_width;    //source image width for work源图像工作宽度?
u32 src_work_height;   //source image height for work源图像工作高度

u32 dst_base_addr;    //Base address of the destination image 目标图像基址
u32 dst_full_width;    //destination screen full width目标图像宽度
u32 dst_full_height;   //destination screen full width目标图像高度
u32 dst_start_x;    //coordinate start x of destination screen目标图像起始x坐标
u32 dst_start_y;    //coordinate start y of destination screen目标图像起始y坐标
u32 dst_work_width;    //destination screen width for work目标图像工作宽度
u32 dst_work_height;   //destination screen height for work目标图像工作高度

// Coordinate (X, Y) of clipping window裁剪窗口的X、Y坐标
u32 cw_x1, cw_y1;
u32 cw_x2, cw_y2;

u32 color_val[8]; //填充颜色值,前景、背景、蓝屏
G2D_COLOR_SPACE bpp;//颜色类型

u32 alpha_mode;    //true : enable, false : disable 是否使能alpha
u32 alpha_val;
u32 color_key_mode;    //treu : enable, false : disable透明使能?
u32 color_key_val;    //transparent color value透明度

}s3c_g2d_params;//该结构体比较重要

/**** function declearation初步看一下***************************/
static int s3c_g2d_init_regs(s3c_g2d_params *params);//初始化寄存器
void s3c_g2d_bitblt(u16 src_x1, u16 src_y1, u16 src_x2, u16 src_y2,
   u16 dst_x1, u16 dst_y1, u16 dst_x2, u16 dst_y2);//bilblit操作
static void s3c_g2d_rotate_with_bitblt(s3c_g2d_params *params, ROT_DEG rot_degree);//bitblit并rotate操作
static void s3c_g2d_get_rotation_origin(u16 src_x1, u16 src_y1,
      u16 src_x2, u16 src_y2,
      u16 dst_x1, u16 dst_y1,
      ROT_DEG rot_degree,
      u16* org_x, u16* org_y);//获取rotation的origin?
void s3c_g2d_set_xy_incr_format(u32 uDividend, u32 uDivisor, u32* uResult);//没有实现该功能
static void s3c_g2d_rotator_start(s3c_g2d_params *params,ROT_DEG rot_degree);//启动rotator
void s3c_g2d_check_fifo(int empty_fifo);//检查fifo
int s3c_g2d_open(struct inode *inode, struct file *file);//open
int s3c_g2d_release(struct inode *inode, struct file *file);//close
int s3c_g2d_mmap(struct file* filp, struct vm_area_struct *vma) ;//映射空间函数,值的一看
static int s3c_g2d_ioctl(struct inode *inode, struct file *file,
     unsigned int cmd, unsigned long arg);//ioctl
static unsigned int s3c_g2d_poll(struct file *file, poll_table *wait);//poll

///


/* linux/drivers/media/video/samsung/g2d/s3c_fimg2d2x.c
*
* Driver file for Samsung 2D Accelerator(FIMG-2D)
*
* Jonghun Han, Copyright (c) 2009 Samsung Electronics
*
http://www.samsungsemi.com/
*
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/irq.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <mach/map.h>
#include <plat/regs-g2d.h>

#include "s3c_fimg2d2x.h"

static struct clk *s3c_g2d_clock;
static struct clk *h_clk;

static int s3c_g2d_irq_num = NO_IRQ;
static struct resource *s3c_g2d_mem;
static void __iomem *s3c_g2d_base;
static wait_queue_head_t waitq_g2d;

static struct mutex *h_rot_mutex;

static u16 s3c_g2d_poll_flag = 0;
/*****************************************************
check fifo 检查fifo函数
参数
int empty_fifo
功能
读取S3C_G2D_FIFO_STAT_REG,读出其中的【6:1】fifo used
循环等待,直到fifo中有我们需要的empty fifo为止
******************************************************/
void s3c_g2d_check_fifo(int empty_fifo)
{
u32 val;

val = __raw_readl(s3c_g2d_base + S3C_G2D_FIFO_STAT_REG);
while( S3C_G2D_FIFO_USED(val) > (FIFO_NUM - empty_fifo));
}

/*****************************************************
s3c_g2d_init_regs 初始化函数
参数
s3c_g2d_params *params
功能
clip、alpha、transparent操作均在初始化时完成
******************************************************/
static int s3c_g2d_init_regs(s3c_g2d_params *params)
{
u32 bpp_mode;
u32 tmp_reg;
s3c_g2d_check_fifo(25);//fifo至少要有25以上的空间
//设置图像类型
switch(params->bpp) {
case ARGB8:
   bpp_mode = S3C_G2D_COLOR_MODE_REG_C0_15BPP;
   break;
case RGB16:
   bpp_mode = S3C_G2D_COLOR_RGB_565;
   break;
case RGB18:
   bpp_mode = S3C_G2D_COLOR_MODE_REG_C2_18BPP;
   break;
case RGB24:
   bpp_mode = S3C_G2D_COLOR_XRGB_8888;
   break;
default:
   bpp_mode = S3C_G2D_COLOR_MODE_REG_C3_24BPP;
   break;
}

/*set register for soruce image 设置源图像寄存器===============================*/
__raw_writel(params->src_base_addr, s3c_g2d_base + S3C_G2D_SRC_BASE_ADDR);
__raw_writel(params->src_full_width, s3c_g2d_base + S3C_G2D_HORI_RES_REG);
__raw_writel(params->src_full_height, s3c_g2d_base + S3C_G2D_VERT_RES_REG);
__raw_writel((S3C_G2D_FULL_V(params->src_full_height) |
    S3C_G2D_FULL_H(params->src_full_width)),
    s3c_g2d_base+S3C_G2D_SRC_RES_REG);
__raw_writel(bpp_mode, s3c_g2d_base + S3C_G2D_SRC_COLOR_MODE);

/*set register for destination image设置目的图像寄存器 =============================*/
__raw_writel(params->dst_base_addr, s3c_g2d_base + S3C_G2D_DST_BASE_ADDR);
__raw_writel(params->dst_full_width, s3c_g2d_base + S3C_G2D_SC_HORI_REG);
__raw_writel(params->dst_full_height, s3c_g2d_base + S3C_G2D_SC_VERT_REG);
__raw_writel((S3C_G2D_FULL_V(params->dst_full_height) |
    S3C_G2D_FULL_H(params->dst_full_width)),
    s3c_g2d_base+S3C_G2D_SC_RES_REG);
__raw_writel(bpp_mode, s3c_g2d_base + S3C_G2D_DST_COLOR_MODE);//mode和源一样

/*set register for clipping window设置剪裁窗口尺寸===============================*/
__raw_writel(params->cw_x1, s3c_g2d_base + S3C_G2D_CW_LT_X_REG);
__raw_writel(params->cw_y1, s3c_g2d_base + S3C_G2D_CW_LT_Y_REG);
__raw_writel(params->cw_x2, s3c_g2d_base + S3C_G2D_CW_RB_X_REG);
__raw_writel(params->cw_y2, s3c_g2d_base + S3C_G2D_CW_RB_Y_REG);

/*set register for colo设置颜色:前景、背景、blue screen=======================================*/
__raw_writel(params->color_val[G2D_WHITE], s3c_g2d_base + S3C_G2D_FG_COLOR_REG); /* set color to both font and foreground color */
__raw_writel(params->color_val[G2D_BLACK], s3c_g2d_base + S3C_G2D_BG_COLOR_REG);
__raw_writel(params->color_val[G2D_BLUE], s3c_g2d_base + S3C_G2D_BS_COLOR_REG);   /* Set blue color to blue screen color */

/*set register for ROP & Alpha设置光栅和alpha值==================================*/
if(params->alpha_mode == TRUE) {//如果打开了alpha模式,执行alpha操作
   if(params->alpha_val > ALPHA_VALUE_MAX) {
    printk(KERN_ALERT "s3c g2d dirver error: exceed alpha value range 0~255/n");
      return -ENOENT;
   }

   __raw_writel(S3C_G2D_ROP_REG_OS_FG_COLOR |
     S3C_G2D_ROP_REG_ABM_REGISTER |
     S3C_G2D_ROP_REG_T_OPAQUE_MODE |
     G2D_ROP_SRC_ONLY,
     s3c_g2d_base + S3C_G2D_ROP_REG);
   __raw_writel(S3C_G2D_ALPHA(params->alpha_val), s3c_g2d_base + S3C_G2D_ALPHA_REG);
} else {//如果没有打开aplha模式,不执行alpha blending操作,alpha寄存器写0
   __raw_writel(S3C_G2D_ROP_REG_OS_FG_COLOR |
     S3C_G2D_ROP_REG_ABM_NO_BLENDING |
     S3C_G2D_ROP_REG_T_OPAQUE_MODE |
     G2D_ROP_SRC_ONLY,
     s3c_g2d_base + S3C_G2D_ROP_REG);
   __raw_writel(S3C_G2D_ALPHA(0x00), s3c_g2d_base + S3C_G2D_ALPHA_REG);  
}

/*set register for color key注册color key====================================*/
if(params->color_key_mode == TRUE) {
   tmp_reg = __raw_readl(s3c_g2d_base + S3C_G2D_ROP_REG);
   tmp_reg |= S3C_G2D_ROP_REG_T_TRANSP_MODE ;
   __raw_writel(tmp_reg , s3c_g2d_base + S3C_G2D_ROP_REG);//设置透明度
   __raw_writel(params->color_key_val, s3c_g2d_base + S3C_G2D_BS_COLOR_REG); //写入透明值
}

/*set register for rotation设置rotation为0°=====================================*/
__raw_writel(S3C_G2D_ROTATRE_REG_R0_0, s3c_g2d_base + S3C_G2D_ROT_OC_X_REG);
__raw_writel(S3C_G2D_ROTATRE_REG_R0_0, s3c_g2d_base + S3C_G2D_ROT_OC_Y_REG);
__raw_writel(S3C_G2D_ROTATRE_REG_R0_0, s3c_g2d_base + S3C_G2D_ROTATE_REG);

return 0;
}

/*****************************************************
s3c_g2d_bitblt bilblt操作
参数
u16 src_x1, u16 src_y1, u16 src_x2, u16 src_y2,
   u16 dst_x1, u16 dst_y1, u16 dst_x2, u16 dst_y2
******************************************************/
void s3c_g2d_bitblt(u16 src_x1, u16 src_y1, u16 src_x2, u16 src_y2,
   u16 dst_x1, u16 dst_y1, u16 dst_x2, u16 dst_y2)
{
u32 cmd_reg_val;

s3c_g2d_check_fifo(25);//至少要有25个空间

   __raw_writel(src_x1, s3c_g2d_base + S3C_G2D_COORD0_X_REG);//设置源图像x y寄存器
__raw_writel(src_y1, s3c_g2d_base + S3C_G2D_COORD0_Y_REG);
   __raw_writel(src_x2, s3c_g2d_base + S3C_G2D_COORD1_X_REG);
__raw_writel(src_y2, s3c_g2d_base + S3C_G2D_COORD1_Y_REG);

   __raw_writel(dst_x1, s3c_g2d_base + S3C_G2D_COORD2_X_REG);//设置目标图像x y寄存器
   __raw_writel(dst_y1, s3c_g2d_base + S3C_G2D_COORD2_Y_REG);
   __raw_writel(dst_x2, s3c_g2d_base + S3C_G2D_COORD3_X_REG);
   __raw_writel(dst_y2, s3c_g2d_base + S3C_G2D_COORD3_Y_REG);

cmd_reg_val = readl(s3c_g2d_base + S3C_G2D_CMD1_REG);
cmd_reg_val = ~(S3C_G2D_CMD1_REG_S|S3C_G2D_CMD1_REG_N);
cmd_reg_val |= S3C_G2D_CMD1_REG_N;
__raw_writel(cmd_reg_val, s3c_g2d_base + S3C_G2D_CMD1_REG);//设置为normal BLT操作
}

/*****************************************************
s3c_g2d_rotate_with_bitblt操作
参数
s3c_g2d_params *params, ROT_DEG rot_degree
说明
bitblt操作为调用s3c_g2d_bitblt函数实现
******************************************************/
static void s3c_g2d_rotate_with_bitblt(s3c_g2d_params *params, ROT_DEG rot_degree)
{
u16 org_x=0, org_y=0;
u32 rot_reg_val = 0;
u32 src_x1, src_y1, src_x2, src_y2, dst_x1, dst_y1, dst_x2, dst_y2;

src_x1 = params->src_start_x;
src_y1 = params->src_start_y;
src_x2 = params->src_start_x + params->src_work_width;//是右下角的坐标吗?
src_y2 = params->src_start_y + params->src_work_height;
dst_x1 = params->dst_start_x;
dst_y1 = params->dst_start_y;
dst_x2 = params->dst_start_x + params->dst_work_width;
dst_y2 = params->dst_start_y + params->dst_work_height;

s3c_g2d_check_fifo(25);//检查空间
__raw_writel(S3C_G2D_INTEN_REG_CCF, s3c_g2d_base + S3C_G2D_INTEN_REG); //使能中断,执行完fifo所有指令后中断

s3c_g2d_get_rotation_origin(src_x1, src_y1, src_x2, src_y2,
      dst_x1, dst_y1, rot_degree, &org_x, &org_y);//计算rotate
if(rot_degree != (ROT_0||ROT_X_FLIP||ROT_Y_FLIP)){
   org_x += 1;
   org_y += 1;
}
__raw_writel(org_x, s3c_g2d_base + S3C_G2D_ROT_OC_X_REG);//写入旋转参考ocX和ocY值
__raw_writel(org_y, s3c_g2d_base + S3C_G2D_ROT_OC_Y_REG);

switch(rot_degree) {//判断旋转类型
case ROT_0:
   rot_reg_val = S3C_G2D_ROTATRE_REG_R0_0;
   break;
case ROT_90:
   rot_reg_val = S3C_G2D_ROTATRE_REG_R1_90;
   break;
case ROT_180:
   rot_reg_val = S3C_G2D_ROTATRE_REG_R2_180;
   break;
case ROT_270:
   rot_reg_val = S3C_G2D_ROTATRE_REG_R3_270;
   break;
case ROT_X_FLIP:
   rot_reg_val = S3C_G2D_ROTATRE_REG_FX;
   break;
case ROT_Y_FLIP:
   rot_reg_val = S3C_G2D_ROTATRE_REG_FY;
   break;
default:
   printk(KERN_ERR "[%s : %d] Wrong rotation degree/n", __FUNCTION__, __LINE__);
   break;
}
__raw_writel(rot_reg_val, s3c_g2d_base + S3C_G2D_ROTATE_REG);//写入rotate寄存器

switch(rot_degree) {//判断rotate类型,根据类型用相应的参数调用s3c_g2d_bitblt
case ROT_0:   /* fall through */
case ROT_X_FLIP: /* fall through */
case ROT_Y_FLIP:
   s3c_g2d_bitblt(src_x1, src_y1, src_x2, src_y2, dst_x1, dst_y1, dst_x2, dst_y2);
   break;
  
case ROT_90:
   s3c_g2d_bitblt(src_x1, src_y1, src_x2, src_y2, src_x1, src_y1+1, src_x2, src_y2+1);//参考值ocx ocy会自动叠加
   break;

case ROT_180:
   s3c_g2d_bitblt(src_x1, src_y1, src_x2, src_y2, src_x1+1, src_y1+1, src_x2+1, src_y2+1);
   break;

case ROT_270:
   s3c_g2d_bitblt(src_x1, src_y1, src_x2, src_y2, src_x1+1, src_y1, src_x2+1, src_y2);
   break;
  
default:
   break;
}
}

/*****************************************************
s3c_g2d_get_rotation_origin操作
参数
u16 src_x1, u16 src_y1,
      u16 src_x2, u16 src_y2,
      u16 dst_x1, u16 dst_y1,
      ROT_DEG rot_degree,
      u16* org_x, u16* org_y
输出数据
u16* org_x, u16* org_y

rotate操作可参照数据手册的对应表,函数作用为计算参考值
******************************************************/
static void s3c_g2d_get_rotation_origin(u16 src_x1, u16 src_y1,
      u16 src_x2, u16 src_y2,
      u16 dst_x1, u16 dst_y1,
      ROT_DEG rot_degree,
      u16* org_x, u16* org_y)
{
s3c_g2d_check_fifo(25);//为什么这儿都要check,前面不是检查过了么?

switch(rot_degree) {
case ROT_90:
   *org_x = ((dst_x1 - dst_y1 + src_x1 + src_y2)>>1);
   *org_y = ((dst_x1 + dst_y1 - src_x1 + src_y2)>>1);
   break;

case ROT_180:   /* fall through */
case ROT_X_FLIP: /* fall through */
case ROT_Y_FLIP:
   *org_x = ((dst_x1 + src_x2)>>1);
   *org_y = ((dst_y1 + src_y2)>>1);
   break;

case ROT_270:
   *org_x = ((dst_x1 + dst_y1 + src_x2 - src_y1)>>1);
   *org_y = ((dst_y1 - dst_x1 + src_x2 + src_y1)>>1);
   break;

case ROT_0:    /* fall through */
default:
   break;
}
}

/*****************************************************
s3c_g2d_rotator_start
参数
s3c_g2d_params *params, ROT_DEG rot_degree
功能
启动2d操作
******************************************************/
static void s3c_g2d_rotator_start(s3c_g2d_params *params, ROT_DEG rot_degree)
{
s3c_g2d_init_regs(params);
s3c_g2d_rotate_with_bitblt(params, rot_degree);
}

/*****************************************************
s3c_g2d_irq 中断

功能
读取结束标志位
清空结束标志位
唤醒等待队列
******************************************************/
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;
}

/*****************************************************
s3c_g2d_open

功能
分配空间
******************************************************/
int s3c_g2d_open(struct inode *inode, struct file *file)
{
s3c_g2d_params *params;
params = (s3c_g2d_params *)kmalloc(sizeof(s3c_g2d_params), GFP_KERNEL);//分配空间
if(params == NULL) {
   printk(KERN_ERR "Instance memory allocation was failed/n");
   return -1;
}
memset(params, 0, sizeof(s3c_g2d_params));
file->private_data = (s3c_g2d_params *)params;
printk("s3c_g2d_open() /n");
return 0;
}

/*****************************************************
s3c_g2d_release

功能
释放空间
******************************************************/
int s3c_g2d_release(struct inode *inode, struct file *file)
{
s3c_g2d_params *params;
params = (s3c_g2d_params *)file->private_data;
if (params == NULL) {
   printk(KERN_ERR "Can't release s3c_rotator!!/n");
   return -1;
}
kfree(params);
printk("s3c_g2d_release() /n");
return 0;
}

/*****************************************************
s3c_g2d_mmap

功能

******************************************************/
int s3c_g2d_mmap(struct file* filp, struct vm_area_struct *vma)
{
unsigned long pageFrameNo = 0;
unsigned long size;

size = vma->vm_end - vma->vm_start;

// page frame number of the address for a source G2D_SFR_SIZE to be stored at.
pageFrameNo = __phys_to_pfn(s3c_g2d_mem->start);

if(size > G2D_SFR_SIZE) {
   printk("The size of G2D_SFR_SIZE mapping is too big!/n");
   return -EINVAL;
}
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

if((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {
   printk("Writable G2D_SFR_SIZE mapping must be shared !/n");
   return -EINVAL;
}

if(remap_pfn_range(vma, vma->vm_start, pageFrameNo, size, vma->vm_page_prot))
   return -EINVAL;

return 0;
}

/*****************************************************
s3c_g2d_ioctl

功能
根据参数执行不同操作,主要调用s3c_g2d_rotator_start(params, rot_degree);
******************************************************/
static int s3c_g2d_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
s3c_g2d_params *params;
ROT_DEG rot_degree;

params = (s3c_g2d_params*)file->private_data;
if (copy_from_user(params, (s3c_g2d_params*)arg, sizeof(s3c_g2d_params)))//从用户空间复制s3c_g2d_params结构体
   return -EFAULT;

mutex_lock(h_rot_mutex);//上锁

switch(cmd) {//判断并执行相应操作,我觉得这IOCTRL没有啥意思
case S3C_G2D_ROTATOR_0:
   rot_degree = ROT_0;
   s3c_g2d_rotator_start(params, rot_degree);
   break;
  
case S3C_G2D_ROTATOR_90:
   rot_degree = ROT_90;
   s3c_g2d_rotator_start(params, rot_degree);
   break;

case S3C_G2D_ROTATOR_180:
   rot_degree = ROT_180;
   s3c_g2d_rotator_start(params, rot_degree);
   break;
  
case S3C_G2D_ROTATOR_270:
   rot_degree = ROT_270;
   s3c_g2d_rotator_start(params, rot_degree);
   break;

case S3C_G2D_ROTATOR_X_FLIP:
   rot_degree = ROT_X_FLIP;
   s3c_g2d_rotator_start(params, rot_degree);
   break;

case S3C_G2D_ROTATOR_Y_FLIP:
   rot_degree = ROT_Y_FLIP;
   s3c_g2d_rotator_start(params, rot_degree);
   break;

default:
   mutex_unlock(h_rot_mutex);
   return -EINVAL;
}

if(!(file->f_flags & O_NONBLOCK)) {
   if (interruptible_sleep_on_timeout(&waitq_g2d, G2D_TIMEOUT) == 0) {
    printk(KERN_ERR "/n%s: Waiting for interrupt is timeout/n", __FUNCTION__);
   }
}

mutex_unlock(h_rot_mutex);//解锁

return 0;

}

/*****************************************************
s3c_g2d_poll
参数
struct file *file, poll_table *wait
功能
poll等待
******************************************************/
static unsigned int s3c_g2d_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;

poll_wait(file, &waitq_g2d, wait);
if(s3c_g2d_poll_flag == 1) {
   mask = POLLOUT|POLLWRNORM;
   s3c_g2d_poll_flag = 0;
}
return mask;
}

//注册结构体
struct file_operations s3c_g2d_fops = {
.owner    = THIS_MODULE,
.open    = s3c_g2d_open,
.release = s3c_g2d_release,
.mmap    = s3c_g2d_mmap,
.ioctl   = s3c_g2d_ioctl,
.poll   = s3c_g2d_poll,
};


static struct miscdevice s3c_g2d_dev = {
.minor   = G2D_MINOR,
.name   = "s3c-g2d",
.fops   = &s3c_g2d_fops,
};

/*****************************************************
s3c_g2d_probe
参数
struct platform_device *pdev
功能
初始化
******************************************************/
int s3c_g2d_probe(struct platform_device *pdev)
{
struct resource *res;
int ret;
printk(KERN_ALERT"s3c_g2d_probe called/n");

/* find the IRQs获取并注册中断 */
s3c_g2d_irq_num = platform_get_irq(pdev, 0);
if(s3c_g2d_irq_num <= 0) {
   printk(KERN_ERR "failed to get irq resouce/n");
    return -ENOENT;
}
ret = request_irq(s3c_g2d_irq_num, s3c_g2d_irq, IRQF_DISABLED, pdev->name, NULL);
if (ret) {
   printk("request_irq(g2d) failed./n");
   return ret;
}


/* get the memory region 获取内存空间 */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(res == NULL) {
   printk(KERN_ERR "failed to get memory region resouce/n");
   return -ENOENT;
}

s3c_g2d_mem = request_mem_region(res->start, res->end-res->start+1, pdev->name);
if(s3c_g2d_mem == NULL) {
   printk(KERN_ERR "failed to reserve memory region/n");
   return -ENOENT;
}

//映射IO空间
s3c_g2d_base = ioremap(s3c_g2d_mem->start, s3c_g2d_mem->end - res->start + 1);
if(s3c_g2d_base == NULL) {
   printk(KERN_ERR "failed ioremap/n");
   return -ENOENT;
}
//获取时钟资源
s3c_g2d_clock = clk_get(&pdev->dev, "g2d");
if(s3c_g2d_clock == NULL) {
   printk(KERN_ERR "failed to find g2d clock source/n");
   return -ENOENT;
}

clk_enable(s3c_g2d_clock);
h_clk = clk_get(&pdev->dev, "hclk");
if(h_clk == NULL) {
   printk(KERN_ERR "failed to find h_clk clock source/n");
   return -ENOENT;
}
//初始化等待队列
init_waitqueue_head(&waitq_g2d);
//杂项注册
ret = misc_register(&s3c_g2d_dev);
if (ret) {
   printk (KERN_ERR "cannot register miscdev on minor=%d (%d)/n",
    G2D_MINOR, ret);
   return ret;
}
//为信号量分配空间
h_rot_mutex = (struct mutex *)kmalloc(sizeof(struct mutex), GFP_KERNEL);
if (h_rot_mutex == NULL)
   return -1;
//初始化信号量
mutex_init(h_rot_mutex);
printk(KERN_ALERT" s3c_g2d_probe Success/n");
return 0;
}


static int s3c_g2d_remove(struct platform_device *dev)
{
printk(KERN_INFO "s3c_g2d_remove called !/n");

free_irq(s3c_g2d_irq_num, NULL);

if (s3c_g2d_mem != NULL) {
   printk(KERN_INFO "S3C Rotator Driver, releasing resource/n");
   iounmap(s3c_g2d_base);
   release_resource(s3c_g2d_mem);
   kfree(s3c_g2d_mem);
}

misc_deregister(&s3c_g2d_dev);
printk(KERN_INFO "s3c_g2d_remove Success !/n");
return 0;
}

static int s3c_g2d_suspend(struct platform_device *dev, pm_message_t state)
{
clk_disable(s3c_g2d_clock);
return 0;
}

static int s3c_g2d_resume(struct platform_device *pdev)
{
clk_enable(s3c_g2d_clock);
return 0;
}

static struct platform_driver s3c_g2d_driver = {
.probe   = s3c_g2d_probe,
.remove   = s3c_g2d_remove,
.suspend = s3c_g2d_suspend,
.resume   = s3c_g2d_resume,
.driver   = {
   .owner = THIS_MODULE,
   .name = "s3c-g2d",
},
};


int __init s3c_g2d_init(void)
{
   if(platform_driver_register(&s3c_g2d_driver) != 0) {
    printk("platform device register Failed /n");
    return -1;
   }
printk(" S3C G2D Init : Done/n");
   return 0;
}


void s3c_g2d_exit(void)
{
platform_driver_unregister(&s3c_g2d_driver);
mutex_destroy(h_rot_mutex);
}

module_init(s3c_g2d_init);
module_exit(s3c_g2d_exit);

MODULE_AUTHOR("Jonghun Han <jonghun.han@samsung.com>");
MODULE_DESCRIPTION("S3C FIMG-2D Device Driver");
MODULE_LICENSE("GPL");

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值