⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fr400cc_vdc.c

📁 一个linux内核编程文件
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/fr400cc_vdc.h>
#include <linux/poll.h>
#include <asm/semaphore.h>
#include <asm/frvirq.h>
#include <asm/uaccess.h>
#include <asm/smplock.h>
#include <asm/fr400cc.h>
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
#include <asm/io.h>
#endif
#include <asm/mb93401_dma.h>
#include <asm/frvcache.h>

#include "../../kernel/axmon.h"

#if 0
#define DBG_Dec16	1
#endif

#if 0
#define DDDN	20	/* for debug */
#endif

#define UNDERRUN_NORESET		1

#define VDC_CFG_MOD			1
/*
#define CONFIG_FR400CC_VDC_VSYNC_REPORT		1
#define CONFIG_FR400CC_VDC_VSYNC_AUTO		1
#define CONFIG_FR400CC_VDC_DMA_CH		2
	--> Config.in , linux/autoconf.h
*/
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
#define CONFIG_FR400CC_VDC_IRQ			26
#else
#define CONFIG_FR400CC_VDC_IRQ			10
#endif
#define CONFIG_FR400CC_VDC_READ_BUF_LEN		240

#define VDC_DMA_CH		CONFIG_FR400CC_VDC_DMA_CH
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
#define VDC_FR400CC_IRQ		(CONFIG_FR400CC_VDC_IRQ - FRV_K_IRQ_FR400CC0)
#else
#define VDC_FR400CC_IRQ		(CONFIG_FR400CC_VDC_IRQ - 10)
#endif

static const int kirqs[] = {
	FRV_K_IRQ_FR400CC0,
	FRV_K_IRQ_FR400CC1,
};
static const unsigned IQSRs[] = {
	LBUS_IQSR0,
	LBUS_IQSR1,
};
static const unsigned DQSRs[] = {
	LBUS_DQSR0,
	LBUS_DQSR1,
	LBUS_DQSR2,
	LBUS_DQSR3,
};
static const unsigned dmac_base[DMA_CH_MAX] = {
	FR400_DMAC_BASE0,
	FR400_DMAC_BASE1,
	FR400_DMAC_BASE2,
	FR400_DMAC_BASE3,
};

static int vdc_kirq; /* kernel IRQ */
static int dmasiz = 5; /* 32 byte */

#define VDC_PIX_X_NTSC	CONFIG_FR400CC_VDC_BUFWIDTH
#define VDC_PIX_Y_NTSC	CONFIG_FR400CC_VDC_BUFHEIGHT
#define VDC_PIX_X_VGA	640
#define VDC_PIX_Y_VGA	480
#define VDC_PIX_X_QVGA	(VDC_PIX_X_VGA/2)
#define VDC_PIX_Y_QVGA	(VDC_PIX_Y_VGA/2)

#define VDC_PIX_SZ	CONFIG_FR400CC_VDC_BUFPIXSZ
#define VDC_DEF_BUF_NUM	CONFIG_FR400CC_VDC_BUFNUM
#define VDC_BUF_ALL_SZ	(VDC_PIX_X_NTSC * VDC_PIX_Y_NTSC * VDC_PIX_SZ * VDC_DEF_BUF_NUM)
#define VDC_BUF_SZ_MIN	(VDC_PIX_X_VGA * VDC_PIX_Y_QVGA * 2)
#define VDC_BUF_N_MAX	(VDC_BUF_ALL_SZ / VDC_BUF_SZ_MIN)
#define DFL_BUF_UNIT_SZ	(VDC_PIX_X_NTSC * VDC_PIX_Y_NTSC * VDC_PIX_SZ)

static char mmap_area[VDC_BUF_ALL_SZ] __attribute__ ((aligned (FRV_CACHE_LINE_SIZE)));
static DECLARE_MUTEX(vdc_sem);
static spinlock_t fr400vdc_lock = SPIN_LOCK_UNLOCKED;
static wait_queue_head_t vdc_waitq;

static int vdc_count = 0;
static int play_idx;
static int frm_count;

#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
static DECLARE_MUTEX(vdc_vsync_sem);
static wait_queue_head_t vdc_vsync_waitq;
static int vdc_vsync_count = 0;
#endif

#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
static int vdc_start(unsigned long arg);
static int vdc_start_inner(unsigned long arg, int que_keep);
#endif

static const struct fr400vdc_config default_config = {
	VDC_PIX_X_NTSC, /* pix_x */
	VDC_PIX_Y_NTSC, /* pix_y */
#if VDC_CFG_MOD
	VDC_PIX_SZ,	/* pix_sz */
#endif
	0, /* skipbf */
	DFL_BUF_UNIT_SZ, /* buf_unit_sz */
	(VDC_BUF_ALL_SZ / DFL_BUF_UNIT_SZ), /* buf_num */
	1, /* stop_immidiate */
	0, /* rd_count_buf_idx */

	/* VDC param ... */

#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
	{0,  720, 4,  4,  130,  0,  240,  2, 4, 16,  0,  0,  4},
	1, /* RDDL */
	1, /* HLS */
#else
	{ 858,  720, 11,  67,  60,  262,  240,  2, 19, 1,  0,  0,  1}, /* ID=04:480:I BT656 */
	2, /* RDDL */
	0, /* HLS (def) */
#endif
	0, /* PAL (NTSC) */  
	0, /* CSCV */
	0, /* DBLS (def) */
	0, /* R601 (def) */
	0, /* TFOP (def) */
	1, /* DSM (interlace) */
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
	0, /* DFP */
#else
	1, /* DFP */
#endif
	1, /* DIE */
	0, /* ENOP (def) */
	0, /* VSOP (def) */
	0, /* HSOP (def) */
	0, /* DSR (no reset) */
	0, /* CSRON (no cursor) */
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
	0, /* DPF (YCbCr 4:2:2 16 bit) */
#else
	3, /* DPF (YCbCr 4:2:2  8 bit */
#endif
	3, /* DMS (transfer state) */
#if VDC_CFG_MOD
	CCFR_CM_2D,	/* dma_mode */
	2,		/* dma_ats */
	CCFR_RS_EXT,	/* dma_rs */
#endif
};
static struct fr400vdc_config vdc_config;

struct vdc_prm{
	int htc, hdc, hfp, hsc, hbp, hip;
	int vtc, vdc, vfp, vsc, vbp, vip;
	int rck, rddl;
	int hls, pal, cscv, dbls, r601, tfop, dsm;
  	int dfp, die, enop, vsop, hsop, dsr, csron, dpf, dms;
};
static int vdc_cur_prm_set = 0;
static struct vdc_prm vdc_cur_prm;

#if UNDERRUN_NORESET
static int underrun_reset = 0;
static int in_blank = 0;
#endif

#ifdef DBG_Dec16
static int in_dbg16 = 0;
#endif


/**/

static int que[VDC_BUF_N_MAX + 1];			/* +1 !!! */
#define QSZ		(vdc_config.buf_num + 1)	/* +1 !!! */
#define Q_RING(idx)	((idx) % QSZ)
#define Q_INC(idx)	{ (idx) = Q_RING((idx)+1); }
static int q_idx_r = 0;
static int q_idx_w = 0;
#define Q_CLR		{ q_idx_r = q_idx_w = 0; }
#define Q_INC_R		Q_INC(q_idx_r)
#define Q_INC_W		Q_INC(q_idx_w)
#define Q_EMP		(q_idx_r == q_idx_w)
#define Q_FULL		(Q_RING(q_idx_w + 1) == q_idx_r)
#define Q_WR(d)		que[q_idx_w] = (d)
#define Q_RD		que[q_idx_r]
#define Q_TERM_SET	{ Q_WR(-1); Q_INC_W; }
#define Q_TERM(d)	((d) == -1)


#ifdef DDDN
static char *ddd_ERR	= "Under Err";
static char *ddd_VT	= "Vsync Top";
static char *ddd_VB	= "Vsync Bottom";
static char *ddd_DMA_H	= "DMA Intr";
static char *ddd_DMA_I	= "DMA Intr ignore";
static char *ddd_DIV	= "--------";
static char *ddds[DDDN] = {NULL};
static int ddds_cnt = 0;
static int ddd_en = 0;

static void
ddd_dump(void)
{
	int i;
	printk("--> dump\n");
	for(i=0; i<ddds_cnt; i++){
		printk("%d '%s'\n", i, ddds[i]);
	}
	printk("<-- dump\n");
}

static void
ddd_add(char *msg)
{
	if(!ddd_en) return;
	if(ddds_cnt >= DDDN){
		ddd_dump();
		return;
	}
	ddds[ddds_cnt++] = msg;
}
#endif /*DDDN*/

/**/

static inline void dmac_reg_write(int ch, int reg, int v)
{
	write_frv_register(dmac_base[ch]+reg, v);
}

static inline unsigned dmac_reg_read(int ch, int reg)
{
	unsigned v;
	v = read_frv_register(dmac_base[ch]+reg);
	return v;
}

static inline int vdc_dfi_get(void)
{
	unsigned v;
	v = read_fr400cc_register(VDC_RS);
	return (v >> 16) & 1;
}

/**/

#define READ_BUF_LEN	CONFIG_FR400CC_VDC_READ_BUF_LEN
struct rbuf_que{
	int head, tail, num;
	struct fr400vdc_read rbuf[READ_BUF_LEN];
};

static struct rbuf_que rbuf_vdc;
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
static struct rbuf_que rbuf_vsync;
#endif

static void
rbuf_que_clear(struct rbuf_que *q)
{
	q->head = q->tail = q->num = 0;
}

static void
rbuf_que_put(struct rbuf_que *q, int type, int count)
{
	unsigned long flags;
	struct fr400vdc_read *p;
	spin_lock_irqsave(&fr400vdc_lock, flags);	
	p = &q->rbuf[q->head];
	p->type = type;
	p->count = count;
	q->head++;
	q->head %= READ_BUF_LEN;
	if(q->num == READ_BUF_LEN){
		/* buffer full */
		q->tail = q->head;
	}else{
		q->num++;
	}
	spin_unlock_irqrestore(&fr400vdc_lock, flags);
}

static int
rbuf_que_get(struct rbuf_que *q, struct fr400vdc_read *buf)
{
	unsigned long flags;
	spin_lock_irqsave(&fr400vdc_lock, flags);
	if(q->num == 0){
		spin_unlock_irqrestore(&fr400vdc_lock, flags);
		return 0; /* empty */
	}
	*buf = q->rbuf[q->tail];
	q->tail++;
	q->tail %= READ_BUF_LEN;
	q->num--;
	spin_unlock_irqrestore(&fr400vdc_lock, flags);
	return 1; /* OK */
}

/**/

static void
buf_size_adjust(void)
{
	vdc_config.buf_unit_sz =
		vdc_config.pix_x * vdc_config.pix_y
#if VDC_CFG_MOD
		* vdc_config.pix_sz;
#else
		* VDC_PIX_SZ;
#endif

	if(vdc_config.skipbf) vdc_config.buf_unit_sz /= 2;

	vdc_config.buf_num = VDC_BUF_ALL_SZ 
		/ vdc_config.buf_unit_sz;

	if(vdc_config.buf_num > VDC_BUF_N_MAX){
		printk("VDC: config buf_num %d --> %d\n",
		       vdc_config.buf_num, VDC_BUF_N_MAX);
		vdc_config.buf_num = VDC_BUF_N_MAX;
	}
	if(vdc_config.buf_num <= 0){
		printk("VDC: config buf_num=%d\n", 
		       vdc_config.buf_num);
	}
}

static unsigned char *
area_get(int buf_idx)
{
	return mmap_area + vdc_config.buf_unit_sz * buf_idx;
}

static void
dma_set_2d(int ch, unsigned char *src)
{
	unsigned sba,dba,pix,six,bcl,apr,cstr,cctr;
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
	unsigned trans_bytes;
#endif

	sba = (unsigned)src;
	dba = VDC_TPO;

	pix = 0;

#if VDC_CFG_MOD
	six = bcl = apr = trans_bytes = 0;
	switch(vdc_config.dma_mode){
	case CCFR_CM_2D:
		six = vdc_config.pix_y;
		if(vdc_config.skipbf) six >>= 1;
		bcl = vdc_config.pix_x * vdc_config.pix_sz;
		apr = bcl;
		trans_bytes = apr * six;
		break;

	case CCFR_CM_SCA:
		six = 0xffffffff;
		bcl = vdc_config.pix_x * vdc_config.pix_y * 
			vdc_config.pix_sz ;
		apr = 0;
		trans_bytes = bcl;
		break;

	case CCFR_CM_DA:
		six = 0;
		bcl = vdc_config.pix_x * vdc_config.pix_y * 
			vdc_config.pix_sz ;
		apr = 0;
		trans_bytes = bcl;
		break;
	default:
		printk("VDC: Not support DMA mode %d\n", 
			vdc_config.dma_mode);
		break;
	}
#else /* VDC_CFG_MOD */
	six = vdc_config.pix_y;
	if(vdc_config.skipbf) six >>= 1;
	bcl = vdc_config.pix_x * VDC_PIX_SZ;
	apr = bcl; /* ! */
#endif /* VDC_CFG_MOD */

	cstr = 0;

	cctr = CCTR_ACT | CCTR_IE |
		(CCTR_AU_INC << CCTR_SAU_SHIFT) |
		(dmasiz << CCTR_SSIZ_SHIFT) |
		(CCTR_AU_HOLD << CCTR_DAU_SHIFT) |
		(dmasiz << CCTR_DSIZ_SHIFT) ;

	dmac_reg_write(ch, SBA, sba);
	dmac_reg_write(ch, DBA, dba);
	dmac_reg_write(ch, BCL, bcl);
	dmac_reg_write(ch, APR, apr);
	dmac_reg_write(ch, PIX, pix);
	dmac_reg_write(ch, SIX, six);
	dmac_reg_write(ch, CSTR, cstr);
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
	dma_cache_wback((unsigned)src, trans_bytes);
#endif
	dmac_reg_write(ch, CCTR, cctr);
}

/**/

static int vdc_go_stat = 0; /* ref vdc_reset, vdc_go , vdc_stop2 */
#define GO_STAT_TYPE_VDC	0
#define GO_STAT_TYPE_VSYNC	1
#define GO_STAT_CLR		(vdc_go_stat = 0)
#define GO_STAT_SET(type)	(vdc_go_stat |= (1<<(type)))
#define GO_STAT_RESET(type)	(vdc_go_stat &= ~(1<<(type)))
#define GO_STAT_CHK(type)	(vdc_go_stat & (1<<(type)))

/**/

static void
vdc_reset(void)
{
	unsigned v;
	v = (1<<7); /* DSR */
	write_fr400cc_register(VDC_RC, v);
#ifdef NEVER
	while(read_fr400cc_register(VDC_RC) & v)
		;
#endif
	vdc_cur_prm_set = 0;
	GO_STAT_CLR;
}

static void
vdc_prm_wrt_all(struct vdc_prm *p)
{
	unsigned v;

	v = (p->htc<<16) | p->hdc;
	write_fr400cc_register(VDC_RHTC, v);

	v = (p->hfp<<24) | (p->hsc<<16) | p->hbp;
	write_fr400cc_register(VDC_RHFP, v);

	v = (p->vtc<<16) | p->vdc;
	write_fr400cc_register(VDC_RVTC, v);
	
	v = (p->vfp<<24) | (p->vsc<<16) | (p->vbp<<8);
	write_fr400cc_register(VDC_RVFP, v);

	v = (p->hip<<24) | (p->vip<<16);
	write_fr400cc_register(VDC_RHIP, v);

	v = (p->rck<<24) | (p->rddl<<16);
	write_fr400cc_register(VDC_RCK, v);
//	p->vsop = p->hsop = 1; //gfliu 1125
	v = (p->hls<<31) | (p->pal<<22) | (p->cscv<<21) | 
		(p->dbls<<20) | (p->r601<<19) | (p->tfop<<16) | 
		(p->dsm<<14) | (p->dfp<<12) | (p->die<<11) | 
		(p->enop<<10) | (p->vsop<<9) | (p->hsop<<8) |
		(p->dsr<<7) | (p->csron<<4) | (p->dpf<<2) | 
		p->dms;
	write_fr400cc_register(VDC_RC, v);
	printk("all VDC_RC:%08x\r\n", v);//gfliu 1125
}

static void
vdc_prm_wrt(struct vdc_prm *p)
{
	struct vdc_prm *s;
	unsigned v;

	if(vdc_cur_prm_set == 0){
		vdc_cur_prm = *p;
		vdc_cur_prm_set = 1;
		vdc_prm_wrt_all(p);
		return;
	}

	s = &vdc_cur_prm;

	if(p->htc != s->htc || p->hdc != s->hdc){
		s->htc = p->htc;
		s->hdc = p->hdc;
		v = (p->htc<<16) | p->hdc;
		write_fr400cc_register(VDC_RHTC, v);
	}
	if(p->hfp != s->hfp || p->hsc != s->hsc || p->hbp != s->hbp){
		s->hfp = p->hfp;
		s->hsc = p->hsc;
		s->hbp = p->hbp;
		v = (p->hfp<<24) | (p->hsc<<16) | p->hbp;
		write_fr400cc_register(VDC_RHFP, v);
	}
	if(p->vtc != s->vtc || p->vdc != s->vdc){
		s->vtc = p->vtc;
		s->vdc = p->vdc;
		v = (p->vtc<<16) | p->vdc;
		write_fr400cc_register(VDC_RVTC, v);
	}
	if(p->vfp != s->vfp || p->vsc != s->vsc || p->vbp != s->vbp){
		s->vfp = p->vfp;
		s->vsc = p->vsc;
		s->vbp = p->vbp;
		v = (p->vfp<<24) | (p->vsc<<16) | (p->vbp<<8);
		write_fr400cc_register(VDC_RVFP, v);
	}
	if(p->hip != s->hip || p->vip != s->vip){
		s->hip = p->hip;
		s->vip = p->vip;
		v = (p->hip<<24) | (p->vip<<16);
		write_fr400cc_register(VDC_RHIP, v);
	}
	if(p->rck != s->rck || p->rddl != s->rddl){
		s->rck = p->rck;
		s->rddl = p->rddl;
		v = (p->rck<<24) | (p->rddl<<16);
		write_fr400cc_register(VDC_RCK, v);
	}
	if(p->hls != s->hls ||
	   p->pal != s->pal ||
	   p->cscv != s->cscv ||
	   p->dbls != s->dbls ||
	   p->r601 != s->r601 ||
	   p->tfop != s->tfop ||
	   p->dsm != s->dsm ||
	   p->dfp != s->dfp ||
	   p->die != s->die ||
	   p->enop != s->enop ||
	   p->vsop != s->vsop ||
	   p->hsop != s->hsop ||
	   p->dsr != s->dsr ||
	   p->csron != s->csron ||
	   p->dpf != s->dpf ||
	   p->dms != s->dms){

		s->hls = p->hls;
		s->pal = p->pal;
		s->cscv = p->cscv;
		s->dbls = p->dbls;
		s->r601 = p->r601;
		s->tfop = p->tfop;
		s->dsm = p->dsm;
		s->dfp = p->dfp;
		s->die = p->die;
		s->enop = p->enop;
		s->vsop = p->vsop;
		s->hsop = p->hsop;
		s->dsr = p->dsr;
		s->csron = p->csron;
		s->dpf = p->dpf;
		s->dms = p->dms;
//		p->vsop = p->hsop = 1; //gfliu 1125

		v = (p->hls<<31) | (p->pal<<22) | (p->cscv<<21) | 
		  (p->dbls<<20) | (p->r601<<19) | (p->tfop<<16) | 
		  (p->dsm<<14) | (p->dfp<<12) | (p->die<<11) | 
		  (p->enop<<10) | (p->vsop<<9) | (p->hsop<<8) |
		  (p->dsr<<7) | (p->csron<<4) | (p->dpf<<2) | 
		  p->dms;

		write_fr400cc_register(VDC_RC, v);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -