/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtkfb_vsync.h" #include "primary_display.h" /* #include "extd_info.h" */ static size_t mtkfb_vsync_on; #define MTKFB_VSYNC_LOG(fmt, arg...) \ do { \ if (mtkfb_vsync_on) \ pr_debug(fmt, ##arg); \ } while (0) #define MTKFB_VSYNC_FUNC() \ do { \ if (mtkfb_vsync_on) \ pr_debug("[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) { pr_debug("driver open\n"); return 0; } static ssize_t mtkfb_vsync_read(struct file *file, char __user *data, size_t len, loff_t *ppos) { pr_debug("driver read\n"); return 0; } static int mtkfb_vsync_release(struct inode *inode, struct file *file) { pr_debug("driver release\n"); pr_debug("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; } #ifdef CONFIG_COMPAT static long compat_mtkfb_vsync_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { compat_uint_t __user *data32; unsigned long __user *data; compat_uint_t u; int err = 0; long ret = 0; if (!file->f_op || !file->f_op->unlocked_ioctl) return -ENOTTY; data32 = compat_ptr(arg); data = compat_alloc_user_space(sizeof(unsigned long)); err |= get_user(u, data32); err |= put_user(u, data); if (err) { pr_debug("compat_mtkfb_vsync_ioctl fail!\n"); return err; } ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)data); return ret; } #endif 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_info("[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_info("[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, #ifdef CONFIG_COMPAT .compat_ioctl = compat_mtkfb_vsync_unlocked_ioctl, #endif .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)) { pr_debug("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) { pr_debug("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); pr_debug("probe is done\n"); return 0; } static int mtkfb_vsync_remove(struct platform_device *pdev) { pr_debug("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) { pr_debug("initializeing driver...\n"); if (platform_device_register(&mtkfb_vsync_device)) { pr_debug("failed to register device\n"); return -ENODEV; } if (platform_driver_register(&mtkfb_vsync_driver)) { pr_debug("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); pr_debug("exit driver...\n"); } /* module_init(mtkfb_vsync_init); */ /* module_exit(mtkfb_vsync_exit); */ MODULE_DESCRIPTION("MediaTek FB VSYNC Driver"); MODULE_AUTHOR("Zaikuo Wang ");