📄 fr400cc_vdc.c
字号:
printk("VDC_RC:%08x\r\n", v);//gfliu 1125
}
}
static void
vdc_conf_to_prm(struct fr400vdc_config *src, struct vdc_prm *dst)
{
int *prm;
prm = src->prm;
dst->htc = prm[0];
dst->hdc = prm[1];
dst->hfp = prm[2];
dst->hsc = prm[3];
dst->hbp = prm[4];
dst->hip = prm[10];
dst->vtc = prm[5];
dst->vdc = prm[6];
dst->vfp = prm[7];
dst->vsc = prm[8];
dst->vbp = prm[9];
dst->vip = prm[11];
dst->rck = prm[12];
dst->rddl = src->rddl;
dst->hls = src->hls;
dst->pal = src->pal;
dst->cscv = src->cscv;
dst->dbls = src->dbls;
dst->r601 = src->r601;
dst->tfop = src->tfop;
dst->dsm = src->dsm;
dst->dfp = src->dfp;
dst->die = src->die;
dst->enop = src->enop;
dst->vsop = src->vsop;
dst->hsop = src->hsop;
dst->dsr = src->dsr;
dst->csron = src->csron;
dst->dpf = src->dpf;
dst->dms = src->dms;
}
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
static int
diff_check_without_dms(struct vdc_prm *p)
{
struct vdc_prm *s;
if(vdc_cur_prm_set == 0) return 1; /* diff */
s = &vdc_cur_prm;
return (p->htc != s->htc || p->hdc != s->hdc ||
p->hfp != s->hfp || p->hsc != s->hsc || p->hbp != s->hbp ||
p->vtc != s->vtc || p->vdc != s->vdc ||
p->vfp != s->vfp || p->vsc != s->vsc || p->vbp != s->vbp ||
p->hip != s->hip || p->vip != s->vip ||
p->rck != s->rck || p->rddl != s->rddl ||
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);
}
#endif /* CONFIG_FR400CC_VDC_VSYNC_REPORT */
static void
vdc_go(int type) /* type 0:vdc , 1:vsync */
{
struct vdc_prm prm;
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
struct vdc_prm tmp;
#endif
if(GO_STAT_CHK(type)) return; /* already */
vdc_conf_to_prm(&vdc_config, &prm);
switch(type){
case 0:
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
if(GO_STAT_CHK(GO_STAT_TYPE_VSYNC) &&
diff_check_without_dms(&prm)){
tmp = vdc_cur_prm;
tmp.dms = 1; /* stop stat */
vdc_prm_wrt(&tmp);
}
#endif
printk("now in vdc_go, before vdc_prm_wrt\r\n"); //gfliu 1125
vdc_prm_wrt(&prm);
printk("now in vdc_go, after vdc_prm_wrt\r\n"); //gfliu 1125
break;
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
case 1:
if(! GO_STAT_CHK(GO_STAT_TYPE_VDC)){
prm.dms = 2; /* free run stat */
vdc_prm_wrt(&prm);
}
break;
#endif
}
GO_STAT_SET(type);
}
/**/
static void
dma_stop(void)
{
unsigned v;
v = dmac_reg_read(VDC_DMA_CH, CCTR);
#if 1
v &= ~(CCTR_IE);
dmac_reg_write(VDC_DMA_CH, CCTR, v);
v &= ~(CCTR_ACT);
dmac_reg_write(VDC_DMA_CH, CCTR, v);
#else
v &= ~(CCTR_ACT | CCTR_IE);
dmac_reg_write(VDC_DMA_CH, CCTR, v);
#endif
/* fifo clear */
v = dmac_reg_read(VDC_DMA_CH, CCTR);
v |= CCTR_FC;
dmac_reg_write(VDC_DMA_CH, CCTR, v);
v &= ~CCTR_FC;
dmac_reg_write(VDC_DMA_CH, CCTR, v);
dmac_reg_write(VDC_DMA_CH, BCL, 0);
dmac_reg_write(VDC_DMA_CH, CSTR, 0);
}
static void
vdc_real_stop(void)
{
vdc_reset();
dma_stop();
}
static void
vdc_stop2(int type) /* type 0:vdc , 1:vsync */
{
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
struct vdc_prm prm;
#endif
if(! GO_STAT_CHK(type)) return; /* already */
switch(type){
case 0:
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
if(GO_STAT_CHK(GO_STAT_TYPE_VSYNC)){
prm = vdc_cur_prm;
prm.dms = 2; /* free run stat */
vdc_prm_wrt(&prm);
break;
}
#endif
vdc_real_stop();
break;
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
case 1:
if(! GO_STAT_CHK(GO_STAT_TYPE_VDC)){
vdc_real_stop();
}
break;
#endif
}
GO_STAT_RESET(type);
}
static int vdc_dma_intr_cnt;
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
static int vdc_intr_cnt;
static int vdc_intr_cnt_vsync;
static int vdc_intr_cnt_under;
#endif
static int vdc_dfi; /* 0: top , 1: bottom */
static void
vdc_dma_interrupt(int ch, void *dev_id)
{
int updt, ret_count;
#if 0
printk("vdc_dma_intr\n");
#endif
#if UNDERRUN_NORESET
#ifdef DDDN
ddd_add(in_blank ? ddd_DMA_I : ddd_DMA_H);
#endif
if(in_blank) return;
#endif
vdc_dma_intr_cnt++;
ret_count = play_idx;
updt = !Q_EMP;
if(vdc_config.skipbf == 1){ /* skipbf:1 only, not 0,2 */
updt = (updt && (vdc_dfi == 1));
}
if(updt){
play_idx = Q_RD;
Q_INC_R;
}
#if VDC_INTR_NEVER /* under flow err test */
if(vdc_dma_intr_cnt >= 30){
if(updt){
frm_count++;
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
wake_up_interruptible(&vdc_waitq);
#else
wake_up(&vdc_waitq);
#endif
}
return;
}
#endif
if(Q_TERM(play_idx)){
vdc_stop2(0);
Q_CLR;
}else{
vdc_dfi = 1 - vdc_dfi_get();
/* current --> set next field idx */
dma_set_2d(ch, area_get(play_idx));
}
if(updt){
if(! vdc_config.rd_count_buf_idx) ret_count = frm_count;
rbuf_que_put(&rbuf_vdc, FR400CC_VDC_RTYPE_FRAME_FIN, ret_count);
frm_count++;
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
wake_up_interruptible(&vdc_waitq);
#else
wake_up(&vdc_waitq);
#endif
}
}
#if UNDERRUN_NORESET
static void
vdc_underrun_dma(void)
{
int updt;
updt = !Q_EMP;
if(updt){
play_idx = Q_RD;
Q_INC_R;
}
if(Q_TERM(play_idx)){
vdc_stop2(0);
Q_CLR;
}else{
dma_set_2d(VDC_DMA_CH, area_get(play_idx));
}
}
#endif /* UNDERRUN_NORESET */
#ifdef DBG_Dec16
static void
dump_dma(int id)
{
static unsigned buf[10*8];
static int bufcnt = 0;
static int ch = VDC_DMA_CH;
buf[bufcnt++] = id;
buf[bufcnt++] = dmac_reg_read(ch, CCTR);
buf[bufcnt++] = dmac_reg_read(ch, CSTR);
buf[bufcnt++] = dmac_reg_read(ch, SBA);
buf[bufcnt++] = dmac_reg_read(ch, DBA);
buf[bufcnt++] = dmac_reg_read(ch, BCL);
buf[bufcnt++] = dmac_reg_read(ch, APR);
buf[bufcnt++] = dmac_reg_read(ch, PIX);
buf[bufcnt++] = dmac_reg_read(ch, SIX);
buf[bufcnt++] = 0; /* dummy */
if(bufcnt >= 10*8){
int i, j, k;
k = 0;
for(j=0; j<8; j++){
for(i=0; i<10; i++){
printk("%08x\n", buf[k++]);
}
printk("--\n");
}
printk("===\n");
bufcnt = 0;
}
}
#endif
static void
vdc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
extern void ack_mb93401(unsigned int irq);
unsigned iqsr, vdc_pat, v;
int vsync, underflow, dfi;
#if 0
printk("vdc_intr irq=%d\n", irq);
#endif
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
vdc_intr_cnt++;
#endif
if(irq != vdc_kirq){
printk("vdc: not vdc interrupt irq=%d\n", irq);
return;
}
iqsr = read_fr400cc_register(IQSRs[VDC_FR400CC_IRQ]);
vdc_pat = (1<<0); /* I0 */
if((iqsr & vdc_pat) == 0){
#if 0
printk("vdc: unknown interrupt IQSR=%08x\n", iqsr);
#endif
return;
}
v = read_fr400cc_register(VDC_RS);
#if 0
printk("RS=%08x\n", v);
#endif
vsync = (v >> 17) & 1;
underflow = (v >> 18) & 1;
dfi = (v >> 16) & 1;
#ifdef DDDN
if(underflow){
ddd_en = 1;
ddd_add(ddd_ERR);
}
if(vsync){
ddd_add(dfi==0 ? ddd_VT : ddd_VB);
}
#endif
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
if(GO_STAT_CHK(GO_STAT_TYPE_VSYNC) && vsync){
rbuf_que_put(&rbuf_vsync,
FR400CC_VDC_RTYPE_VSYNC,
dfi);
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
wake_up_interruptible(&vdc_vsync_waitq);
#else
wake_up(&vdc_vsync_waitq);
#endif
}
#endif
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
if(vsync){
vdc_intr_cnt_vsync++;
}
#endif
if(underflow){
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
vdc_intr_cnt_under++;
#endif
rbuf_que_put(&rbuf_vdc, FR400CC_VDC_RTYPE_ERR_UNDERFLOW, 0);
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
#if UNDERRUN_NORESET
if(underrun_reset){
vdc_start_inner(0, 1);
}else{
dma_stop();
#if 1 /* RGB */
vdc_underrun_dma();
if(vdc_config.dpf == 1){ /* RGB */
in_blank = 1;
}else{
if(dfi == 0) in_blank = 1;
}
#else /* RGB */
vdc_underrun_dma();
#ifdef DBG_Dec16
if(dfi == 0){
in_dbg16 = 1;
dump_dma(1);
}
#else
if(dfi == 0) in_blank = 1;
#endif
#endif /* ! RGB */
}
#else
vdc_start_inner(0, 1);
#endif
wake_up_interruptible(&vdc_waitq);
#else
wake_up(&vdc_waitq);
#endif
}
#if UNDERRUN_NORESET
#if 1 /* RGB */
if(vdc_config.dpf == 1){ /* RGB */
if(in_blank > 0){
vdc_underrun_dma();
in_blank--;
}
}else{
if(vsync && dfi == 0 && in_blank > 0){
vdc_underrun_dma();
in_blank--;
}
}
#else
if(vsync && dfi == 0 && in_blank > 0){
vdc_underrun_dma();
in_blank--;
}
#endif
#endif
#ifdef DBG_Dec16
if(vsync && dfi == 0 && in_dbg16 > 0){
dump_dma(2);
in_dbg16 = 0;
}
#endif
#ifdef DDDN
if(ddd_en && vsync && dfi == 0){
ddd_add(ddd_DIV);
ddd_en = 0;
}
#endif
/*
about RS
31..19 : reserved
18..17 : IT[1:0] IT[1] underflow , IT[0] vsync
16 : DFI TOP/BOTTOM
15..5 : reserved
4 : DCSR Cursor ON/OFF
3..2 : reserved
1..0 : DCM mode disable/stop/freerun/transfer
*/
v &= 0x10013; /* 16/4/1..0 --> keep */
write_fr400cc_register(VDC_RS, v);
do{
iqsr = read_fr400cc_register(IQSRs[VDC_FR400CC_IRQ]);
}while(iqsr & vdc_pat);
ack_mb93401(irq);
#if 0
printk("vdc intr fin.\n");
#endif
}
/**/
static int irq_open_cnt = 0;
static int
irq_open(void)
{
int retval;
if(irq_open_cnt++ > 0) return 0;
if((retval = request_irq(vdc_kirq,
vdc_interrupt,
SA_INTERRUPT | SA_SHIRQ,
"fr400cc_vdc",
&vdc_count)) != 0){
irq_open_cnt--;
}
return retval;
}
static void
irq_close(void)
{
if(irq_open_cnt <= 0) return;
if(--irq_open_cnt > 0) return;
free_irq(vdc_kirq, &vdc_count);
}
static int dma_open_cnt = 0;
static int
dma_open(void)
{
int retval;
if(dma_open_cnt++ > 0) return 0;
Q_CLR;
if((retval = mb93401_dma_register(VDC_DMA_CH,
"fr400cc_vdc_dma",
vdc_dma_interrupt,
NULL)) < 0){
dma_open_cnt--;
return retval;
}
vdc_dma_intr_cnt = 0;
#if defined(CONFIG_MB93091_CB30) || defined(CONFIG_FR400PDK2_BOARD)
vdc_intr_cnt = 0;
vdc_intr_cnt_vsync = 0;
vdc_intr_cnt_under = 0;
#endif
dma_stop();
return retval;
}
static int
dma_close(void)
{
int retval;
if(dma_open_cnt <= 0) return 0;
if(--dma_open_cnt > 0) return 0;
if((retval = mb93401_dma_unregister(VDC_DMA_CH)) < 0){
dma_open_cnt++;
}
return retval;
}
static int
vdc_open(struct inode *inode, struct file *file)
{
int retval;
lock_kernel();
if(vdc_count){
unlock_kernel();
return -EBUSY;
}
#ifdef CONFIG_FR400CC_VDC_VSYNC_REPORT
if(vdc_vsync_count <= 0){
vdc_config = default_config;
}
#else
vdc_config = default_config;
#endif
if((retval = dma_open()) < 0){
unlock_kernel();
return retval;
}
if((retval = irq_open()) != 0){
printk("vdc: open, request_irq NG.\n");
dma_close();
unlock_kernel();
return retval;
}
vdc_count++;
unlock_kernel();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -