📄 fr400cc_vdc.c
字号:
#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 + -