📄 s3c-mfc.c
字号:
MFC_Mutex_Release();
return -EFAULT;
}
// FRAM_BUF address is calculated differently for Encoder and Decoder.
switch (pMfcInst->codec_mode) {
case MP4_DEC:
case AVC_DEC:
case VC1_DEC:
case H263_DEC:
// Decoder case
args.get_buf_addr.out_buf_size = (pMfcInst->width * pMfcInst->height * 3) >> 1;
tmp = (unsigned int)args.get_buf_addr.in_usr_data + ( ((unsigned int) pMfcInst->pFramBuf) \
+ (pMfcInst->idx) * (args.get_buf_addr.out_buf_size) - (unsigned int)GetDataBufVirAddr() );
#if (MFC_ROTATE_ENABLE == 1)
if ( (pMfcInst->codec_mode != VC1_DEC) && (pMfcInst->PostRotMode & 0x0010) ) {
tmp = (unsigned int)args.get_buf_addr.in_usr_data + ( ((unsigned int) pMfcInst->pFramBuf) \
+ (pMfcInst->frambufCnt) * (args.get_buf_addr.out_buf_size) - (unsigned int)GetDataBufVirAddr() );
}
#endif
args.get_buf_addr.out_buf_addr = tmp;
break;
case MP4_ENC:
case AVC_ENC:
case H263_ENC:
// Encoder case
tmp = (pMfcInst->width * pMfcInst->height * 3) >> 1;
args.get_buf_addr.out_buf_addr = args.get_buf_addr.in_usr_data + (pMfcInst->idx * tmp) + (int)(pMfcInst->pFramBuf - GetDataBufVirAddr());
break;
}
args.get_buf_addr.ret_code = MFCINST_RET_OK;
Copy_To_User((MFC_GET_BUF_ADDR_ARG *)arg, &args.get_buf_addr, sizeof(MFC_GET_BUF_ADDR_ARG));
MFC_Mutex_Release();
break;
case IOCTL_MFC_GET_PHY_FRAM_BUF_ADDR:
MFC_Mutex_Lock();
Copy_From_User(&args.get_buf_addr, (MFC_GET_BUF_ADDR_ARG *)arg, sizeof(MFC_GET_BUF_ADDR_ARG));
args.get_buf_addr.out_buf_size = (pMfcInst->width * pMfcInst->height * 3) >> 1;
tmp = (unsigned int)S3C6400_BASEADDR_MFC_DATA_BUF + ( ((unsigned int) pMfcInst->pFramBuf) \
+ (pMfcInst->idx) * (args.get_buf_addr.out_buf_size) - (unsigned int)GetDataBufVirAddr() );
args.get_buf_addr.out_buf_addr = tmp;
args.get_buf_addr.ret_code = MFCINST_RET_OK;
Copy_To_User((MFC_GET_BUF_ADDR_ARG *)arg, &args.get_buf_addr, sizeof(MFC_GET_BUF_ADDR_ARG));
MFC_Mutex_Release();
break;
case IOCTL_MFC_GET_CONFIG:
MFC_Mutex_Lock();
Copy_From_User(&args, (MFC_ARGS *)arg, sizeof(MFC_ARGS));
ret = MFC_GetConfigParams(pMfcInst, &args);
Copy_To_User((MFC_ARGS *)arg, &args, sizeof(MFC_ARGS));
MFC_Mutex_Release();
break;
case IOCTL_MFC_SET_CONFIG:
MFC_Mutex_Lock();
Copy_From_User(&args, (MFC_ARGS *)arg, sizeof(MFC_ARGS));
ret = MFC_SetConfigParams(pMfcInst, &args);
Copy_To_User((MFC_ARGS *)arg, &args, sizeof(MFC_ARGS));
MFC_Mutex_Release();
break;
case IOCTL_MFC_SET_H263_MULTIPLE_SLICE:
MFC_Mutex_Lock();
pMfcInst->multiple_slice = 1;
MFC_Mutex_Release();
break;
default:
MFC_Mutex_Lock();
LOG_MSG(LOG_TRACE, "s3c_mfc_ioctl", "Requested ioctl command is not defined. (ioctl cmd=0x%X)\n", cmd);
MFC_Mutex_Release();
return -EINVAL;
}
switch(ret) {
case MFCINST_RET_OK:
return TRUE;
default:
return -1;
}
return -1;
}
int s3c_mfc_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long maxSize;
unsigned long pageFrameNo;
pageFrameNo = __phys_to_pfn(S3C6400_BASEADDR_MFC_DATA_BUF);
maxSize = MFC_DATA_BUF_SIZE + PAGE_SIZE - (MFC_DATA_BUF_SIZE % PAGE_SIZE);
if(size > maxSize) {
return -EINVAL;
}
vma->vm_flags |= VM_RESERVED | VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if( remap_pfn_range(vma, vma->vm_start, pageFrameNo, size, \
vma->vm_page_prot) ) {
LOG_MSG(LOG_TRACE, "mfc_mmap", "remap error");
return -EAGAIN;
}
return 0;
}
static struct file_operations s3c_mfc_fops = {
owner: THIS_MODULE,
open: s3c_mfc_open,
release: s3c_mfc_release,
ioctl: s3c_mfc_ioctl,
read: s3c_mfc_read,
write: s3c_mfc_write,
mmap: s3c_mfc_mmap,
};
static struct miscdevice s3c_mfc_miscdev = {
minor: 252,
name: "s3c-mfc",
fops: &s3c_mfc_fops
};
static int s3c_mfc_probe(struct platform_device *pdev)
{
struct resource *res;
int size;
int ret;
unsigned int mfc_clk;
// mfc clock enable
mfc_hclk = clk_get(NULL, "hclk_mfc");
if (!mfc_hclk) {
printk(KERN_ERR "failed to get mfc hclk source\n");
return -ENOENT;
}
clk_enable(mfc_hclk);
mfc_sclk = clk_get(NULL, "sclk_mfc");
if (!mfc_sclk) {
printk(KERN_ERR "failed to get mfc sclk source\n");
return -ENOENT;
}
clk_enable(mfc_sclk);
mfc_pclk = clk_get(NULL, "pclk_mfc");
if (!mfc_pclk) {
printk(KERN_ERR "failed to get mfc pclk source\n");
return -ENOENT;
}
clk_enable(mfc_pclk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
printk(KERN_INFO "failed to get memory region resouce\n");
return -ENOENT;
}
size = (res->end-res->start)+1;
mfc_mem = request_mem_region(res->start, size, pdev->name);
if (mfc_mem == NULL) {
printk(KERN_INFO "failed to get memory region\n");
return -ENOENT;
}
mfc_base = ioremap(res->start, size);
if (mfc_base == 0) {
printk(KERN_INFO "failed to ioremap() region\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
printk(KERN_INFO "failed to get irq resource\n");
return -ENOENT;
}
ret = request_irq(res->start, s3c_mfc_irq, 0, pdev->name, pdev);
if (ret != 0) {
printk(KERN_INFO "failed to install irq (%d)\n", ret);
return ret;
}
if (MFC_Mutex_Create() == FALSE)
return -ENOMEM;
// mfc clock set 133 Mhz
mfc_clk = readl(S3C_CLK_DIV0);
mfc_clk |= (1<<28);
__raw_writel(mfc_clk, S3C_CLK_DIV0);
//////////////////////////////////
// 2. MFC Memory Setup //
//////////////////////////////////
if (MFC_MemorySetup() == FALSE)
return -ENOMEM;
//////////////////////////////////////
// 3. MFC Hardware Initialization //
//////////////////////////////////////
if (MFC_HW_Init() == FALSE)
return -ENODEV;
ret = misc_register(&s3c_mfc_miscdev);
clk_disable(mfc_hclk);
clk_disable(mfc_sclk);
clk_disable(mfc_pclk);
return 0;
}
static int s3c_mfc_remove(struct platform_device *dev)
{
if (mfc_mem != NULL) {
release_resource(mfc_mem);
kfree(mfc_mem);
mfc_mem = NULL;
}
free_irq(IRQ_MFC, dev);
misc_deregister(&s3c_mfc_miscdev);
return 0;
}
static int s3c_mfc_suspend(struct platform_device *dev, pm_message_t state)
{
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,21)
MFCInstCtx *mfcinst_ctx;
int inst_no;
int is_mfc_on = 0;
int i, index = 0;
unsigned int dwMfcBase;
MFC_Mutex_Lock();
is_mfc_on = 0;
// 1. Power Off state
// Invalidate all the MFC Instances
for (inst_no = 0; inst_no < MFC_NUM_INSTANCES_MAX; inst_no++) {
mfcinst_ctx = MFCInst_GetCtx(inst_no);
if (mfcinst_ctx) {
is_mfc_on = 1;
// On Power Down, the MFC instance is invalidated.
// Then the MFC operations (DEC_EXE, ENC_EXE, etc.) will not be performed
// until it is validated by entering Power up state transition
MFCInst_PowerOffState(mfcinst_ctx);
printk(KERN_INFO "MFC_Suspend %d-th instance is invalidated\n", inst_no);
}
}
// 2. Command MFC sleep and save MFC SFR
if (is_mfc_on) {
dwMfcBase = (unsigned int)GetMfcSfrVirAddr();
for(i=SAVE_START_ADDR; i <= SAVE_END_ADDR; i+=4)
{
mfc_save[index] = (unsigned int)MFC_READ_REG(dwMfcBase + i);
index++;
}
MFC_Sleep();
}
// 3. Disable MFC clock
clk_disable(mfc_hclk);
clk_disable(mfc_sclk);
clk_disable(mfc_pclk);
/*
// 4. MFC Power Off(Domain V)
mfc_pwr = readl(S3C_NORMAL_CFG);
mfc_pwr &= ~(1<<9);
printk("mfc_pwr : 0x%X\n", mfc_pwr);
__raw_writel(mfc_pwr, S3C_NORMAL_CFG);
*/
MFC_Mutex_Release();
#endif
return 0;
}
static int s3c_mfc_resume(struct platform_device *pdev)
{
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,21)
unsigned int mfc_pwr, dwMfcBase;
int i, index = 0;
MFCInstCtx *mfcinst_ctx;
int inst_no;
unsigned int domain_v_ready;
int is_mfc_on = 0;
MFC_Mutex_Lock();
clk_enable(mfc_hclk);
clk_enable(mfc_sclk);
clk_enable(mfc_pclk);
// 1. MFC Power On(Domain V)
mfc_pwr = readl(S3C_NORMAL_CFG);
mfc_pwr |= (1<<9);
__raw_writel(mfc_pwr, S3C_NORMAL_CFG);
// 2. Check MFC power on
do {
domain_v_ready = readl(S3C_BLK_PWR_STAT);
printk("domain v ready : 0x%X\n", domain_v_ready);
msleep(1);
}while(!(domain_v_ready & (1<<1)));
// 3. Firmware download
MfcFirmwareIntoCodeDownReg();
// 4. Power On state
// Validate all the MFC Instances
for (inst_no = 0; inst_no < MFC_NUM_INSTANCES_MAX; inst_no++) {
mfcinst_ctx = MFCInst_GetCtx(inst_no);
if (mfcinst_ctx) {
is_mfc_on = 1;
// When MFC Power On, the MFC instance is validated.
// Then the MFC operations (DEC_EXE, ENC_EXE, etc.) will be performed again
MFCInst_PowerOnState(mfcinst_ctx);
printk(KERN_INFO "MFC_Resume %d-th instance is validated\n", inst_no);
}
}
if (is_mfc_on) {
// 5. Restore MFC SFR
dwMfcBase = (unsigned int)GetMfcSfrVirAddr();
for( i=SAVE_START_ADDR; i<= SAVE_END_ADDR; i+=4 )
{
MFC_WRITE_REG( ( dwMfcBase + i ), mfc_save[index] );
index++;
}
// 6. Command MFC wakeup
MFC_Wakeup();
}
MFC_Mutex_Release();
#endif
return 0;
}
static struct platform_driver s3c_mfc_driver = {
.probe = s3c_mfc_probe,
.remove = s3c_mfc_remove,
.shutdown = NULL,
.suspend = s3c_mfc_suspend,
.resume = s3c_mfc_resume,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-mfc",
},
};
static char banner[] __initdata = KERN_INFO "S3C6400 MFC Driver, (c) 2007 Samsung Electronics\n";
static int __init s3c_mfc_init(void)
{
printk(banner);
#ifdef CONFIG_S3C6400_PDFW
pd_register_dev(&mfc_pmdev, "domain_v");
printk(KERN_INFO "pdfw: mfc devid = %d\n", mfc_pmdev.devid);
#endif
if(platform_driver_register(&s3c_mfc_driver)!=0)
{
printk("platform device register Failed \n");
return -1;
}
printk("S3C6400 MFC driver module init OK.\n");
return 0;
}
static void __exit s3c_mfc_exit(void)
{
MFC_Mutex_Delete();
#ifdef CONFIG_S3C6400_PDFW
pd_unregister_dev(&mfc_pmdev);
#endif
platform_driver_unregister(&s3c_mfc_driver);
printk("S3C6400 MFC driver module exit\n");
}
module_init(s3c_mfc_init);
module_exit(s3c_mfc_exit);
MODULE_AUTHOR("Jiun, Yu");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -