unplugged-kernel/drivers/misc/mediatek/video/mt6785/videox/mtkfb_vsync.c

283 lines
6.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/module.h>
#include <generated/autoconf.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/param.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/sched/clock.h>
#include <linux/workqueue.h>
#include <linux/semaphore.h>
#include <linux/slab.h>
#include "mtkfb_vsync.h"
#include "primary_display.h"
/* #include "extd_info.h" */
#define VSYNC_DBG(...) pr_debug(__VA_ARGS__)
#define VSYNC_INF(...) pr_debug(__VA_ARGS__)
#define VSYNC_WRN(...) pr_debug(__VA_ARGS__)
#define VSYNC_ERR(...) pr_debug(__VA_ARGS__)
static size_t mtkfb_vsync_on;
#define MTKFB_VSYNC_LOG(fmt, arg...) \
do { \
if (mtkfb_vsync_on) \
VSYNC_WRN(fmt, ##arg); \
} while (0)
#define MTKFB_VSYNC_FUNC() \
do { \
if (mtkfb_vsync_on) \
VSYNC_WRN("[Func]%s\n", __func__); \
} while (0)
#undef CONFIG_MTK_HDMI_SUPPORT
#ifdef CONFIG_MTK_HDMI_SUPPORT
static EXTD_DRIVER * extd_driver[DEV_MAX_NUM - 1];
#endif
static dev_t mtkfb_vsync_devno;
static struct cdev *mtkfb_vsync_cdev;
static struct class *mtkfb_vsync_class;
DEFINE_SEMAPHORE(mtkfb_vsync_sem);
void mtkfb_vsync_log_enable(int enable)
{
mtkfb_vsync_on = enable;
MTKFB_VSYNC_LOG("mtkfb_vsync log %s\n",
enable ? "enabled" : "disabled");
}
static int mtkfb_vsync_open(struct inode *inode, struct file *file)
{
VSYNC_DBG("driver open\n");
return 0;
}
static ssize_t mtkfb_vsync_read(struct file *file, char __user *data,
size_t len, loff_t *ppos)
{
VSYNC_DBG("driver read\n");
return 0;
}
static int mtkfb_vsync_release(struct inode *inode, struct file *file)
{
VSYNC_DBG("driver release\n");
VSYNC_DBG("reset overlay engine\n");
return 0;
}
static int mtkfb_vsync_flush(struct file *a_pstFile, fl_owner_t a_id)
{
/* To Do : error handling here */
return 0;
}
static long mtkfb_vsync_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = 0;
MTKFB_VSYNC_FUNC();
switch (cmd) {
case MTKFB_VSYNC_IOCTL:
{
MTKFB_VSYNC_LOG("[MTKFB_VSYNC]: enter MTKFB_VSYNC_IOCTL\n");
#ifdef CONFIG_MTK_HDMI_SUPPORT
extd_driver[DEV_MHL] = EXTD_HDMI_Driver();
extd_driver[DEV_EINK] = EXTD_EPD_Driver();
if (arg == MTKFB_VSYNC_SOURCE_HDMI ||
arg == MTKFB_VSYNC_SOURCE_EPD) {
if (down_interruptible(&mtkfb_vsync_sem)) {
pr_err("[mtkfb_vsync_ioctl] can't get semaphore,%d\n",
__LINE__);
msleep(20);
return ret;
}
if (extd_driver[arg-1]->wait_vsync)
ret = extd_driver[arg-1]->wait_vsync();
else
ret = -EFAULT;
up(&mtkfb_vsync_sem);
pr_debug("[MTKFB_VSYNC]: leave MTKFB_VSYNC_IOCTL, %d, ret:%d\n",
__LINE__, ret);
return ret;
}
#endif
if (down_interruptible(&mtkfb_vsync_sem)) {
pr_err("[mtkfb_vsync_ioctl] can't get semaphore,%d\n",
__LINE__);
msleep(20);
return ret;
}
primary_display_wait_for_vsync(NULL);
up(&mtkfb_vsync_sem);
MTKFB_VSYNC_LOG("[MTKFB_VSYNC]: leave MTKFB_VSYNC_IOCTL\n");
}
break;
}
return ret;
}
static const struct file_operations mtkfb_vsync_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = mtkfb_vsync_unlocked_ioctl,
.open = mtkfb_vsync_open,
.release = mtkfb_vsync_release,
.flush = mtkfb_vsync_flush,
.read = mtkfb_vsync_read,
};
static int mtkfb_vsync_probe(struct platform_device *pdev)
{
struct class_device;
struct class_device *class_dev = NULL;
int ret = -1;
pr_info("\n=== MTKFB_VSYNC probe ===\n");
if (alloc_chrdev_region(&mtkfb_vsync_devno, 0,
1, MTKFB_VSYNC_DEVNAME)) {
VSYNC_ERR("can't get device major number...\n");
return -EFAULT;
}
pr_info("get device major number (%d)\n", mtkfb_vsync_devno);
mtkfb_vsync_cdev = cdev_alloc();
mtkfb_vsync_cdev->owner = THIS_MODULE;
mtkfb_vsync_cdev->ops = &mtkfb_vsync_fops;
ret = cdev_add(mtkfb_vsync_cdev, mtkfb_vsync_devno, 1);
if (ret != 0) {
VSYNC_ERR("cdev_add Failed!\n");
return -EFAULT;
}
mtkfb_vsync_class = class_create(THIS_MODULE, MTKFB_VSYNC_DEVNAME);
class_dev = (struct class_device *)device_create(mtkfb_vsync_class,
NULL, mtkfb_vsync_devno, NULL,
MTKFB_VSYNC_DEVNAME);
VSYNC_INF("probe is done\n");
return 0;
}
static int mtkfb_vsync_remove(struct platform_device *pdev)
{
VSYNC_INF("device remove\n");
return 0;
}
static void mtkfb_vsync_shutdown(struct platform_device *pdev)
{
pr_info("mtkfb_vsync device shutdown\n");
}
static int mtkfb_vsync_suspend(struct platform_device *pdev, pm_message_t mesg)
{
return 0;
}
static int mtkfb_vsync_resume(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver mtkfb_vsync_driver = {
.probe = mtkfb_vsync_probe,
.remove = mtkfb_vsync_remove,
.shutdown = mtkfb_vsync_shutdown,
.suspend = mtkfb_vsync_suspend,
.resume = mtkfb_vsync_resume,
.driver = {
.name = MTKFB_VSYNC_DEVNAME,
},
};
static void mtkfb_vsync_device_release(struct device *dev)
{
}
static u64 mtkfb_vsync_dmamask = ~(u32) 0;
static struct platform_device mtkfb_vsync_device = {
.name = MTKFB_VSYNC_DEVNAME,
.id = 0,
.dev = {
.release = mtkfb_vsync_device_release,
.dma_mask = &mtkfb_vsync_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = 0,
};
#if 0 /* defined but not used */
static int __init mtkfb_vsync_init(void)
{
VSYNC_INF("initializeing driver...\n");
if (platform_device_register(&mtkfb_vsync_device)) {
VSYNC_ERR("failed to register device\n");
return -ENODEV;
}
if (platform_driver_register(&mtkfb_vsync_driver)) {
VSYNC_ERR("failed to register driver\n");
platform_device_unregister(&mtkfb_vsync_device);
return -ENODEV;
}
return 0;
}
#endif
static void __exit mtkfb_vsync_exit(void)
{
cdev_del(mtkfb_vsync_cdev);
unregister_chrdev_region(mtkfb_vsync_devno, 1);
platform_driver_unregister(&mtkfb_vsync_driver);
platform_device_unregister(&mtkfb_vsync_device);
device_destroy(mtkfb_vsync_class, mtkfb_vsync_devno);
class_destroy(mtkfb_vsync_class);
VSYNC_INF("exit driver...\n");
}
/* module_init(mtkfb_vsync_init); */
/* module_exit(mtkfb_vsync_exit); */
MODULE_DESCRIPTION("MediaTek FB VSYNC Driver");
MODULE_AUTHOR("Zaikuo Wang <Zaikuo.Wang@mediatek.com>");