Advertisement
Guest User

s3cfb-main.c

a guest
Aug 16th, 2013
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 31.46 KB | None | 0 0
  1. /* linux/drivers/video/samsung/s3cfb-main.c
  2.  *
  3.  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  4.  *      http://www.samsung.com
  5.  *
  6.  * Core file for Samsung Display Controller (FIMD) driver
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License version 2 as
  10.  * published by the Free Software Foundation.
  11.  */
  12.  
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/errno.h>
  16. #include <linux/clk.h>
  17. #include <linux/mutex.h>
  18. #include <linux/poll.h>
  19. #include <linux/wait.h>
  20. #include <linux/fs.h>
  21. #include <linux/irq.h>
  22. #include <linux/mm.h>
  23. #include <linux/fb.h>
  24. #include <linux/ctype.h>
  25. #include <linux/dma-mapping.h>
  26. #include <linux/interrupt.h>
  27. #include <linux/platform_device.h>
  28. #include <linux/io.h>
  29. #include <linux/memory.h>
  30. #include <linux/pm_runtime.h>
  31. #include <linux/delay.h>
  32. #include <linux/sw_sync.h>
  33. #include <plat/clock.h>
  34. #include <plat/media.h>
  35. #include <mach/media.h>
  36. #include <mach/map.h>
  37. #include "s3cfb.h"
  38.  
  39. #ifdef CONFIG_BUSFREQ_OPP
  40. #include <mach/dev.h>
  41. #endif
  42.  
  43. #ifdef CONFIG_FB_S5P_MDNIE
  44. #include "s3cfb_mdnie.h"
  45. #include "mdnie.h"
  46. #endif
  47. #ifdef CONFIG_HAS_WAKELOCK
  48. #include <linux/wakelock.h>
  49. #include <linux/earlysuspend.h>
  50. #include <linux/suspend.h>
  51. #endif
  52.  
  53. #if defined(CONFIG_MACH_U1_BD) && defined(CONFIG_TARGET_LOCALE_KOR)
  54. #include <mach/regs-clock.h>
  55. #include "boot_progressbar.h"
  56. #define DISPLAY_BOOT_PROGRESS
  57. #endif
  58. #include <mach/regs-pmu.h>
  59. #include <plat/regs-fb-s5p.h>
  60.  
  61. #ifdef CONFIG_FB_S5P_SYSMMU
  62. #include <plat/s5p-sysmmu.h>
  63. #endif
  64.  
  65. #if defined(CONFIG_CPU_EXYNOS4210)
  66. #define FEATURE_VSYNC_EVENT_VIA_SYSFS
  67. #endif
  68.  
  69. struct s3cfb_fimd_desc      *fbfimd;
  70.  
  71. struct s3cfb_global *get_fimd_global(int id)
  72. {
  73.     struct s3cfb_global *fbdev;
  74.  
  75.     if (id < 5)
  76.         fbdev = fbfimd->fbdev[0];
  77.     else
  78.         fbdev = fbfimd->fbdev[1];
  79.  
  80.     return fbdev;
  81. }
  82.  
  83. int s3cfb_vsync_status_check(void)
  84. {
  85.     struct s3cfb_global *fbdev[2];
  86.     fbdev[0] = fbfimd->fbdev[0];
  87.  
  88.     if (fbdev[0]->regs != 0 && fbdev[0]->system_state == POWER_ON)
  89.         return s3cfb_check_vsync_status(fbdev[0]);
  90.     else
  91.         return 0;
  92. }
  93.  
  94. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  95. static void s3cfb_activate_vsync(struct s3cfb_global *fbdev)
  96. {
  97.     int prev_refcount;
  98.  
  99.     mutex_lock(&fbdev->vsync_info.irq_lock);
  100.     prev_refcount = fbdev->vsync_info.irq_refcount++;
  101.     if (!prev_refcount) {
  102.         s3cfb_set_global_interrupt(fbdev, 1);
  103.         s3cfb_set_vsync_interrupt(fbdev, 1);
  104.     }
  105.  
  106.     mutex_unlock(&fbdev->vsync_info.irq_lock);
  107. }
  108.  
  109. static void s3cfb_deactivate_vsync(struct s3cfb_global *fbdev)
  110. {
  111.     int new_refcount;
  112.  
  113.     mutex_lock(&fbdev->vsync_info.irq_lock);
  114.  
  115.     if (fbdev->vsync_info.irq_refcount <= 0) {
  116.         mutex_unlock(&fbdev->vsync_info.irq_lock);
  117.         return;
  118.     }
  119.  
  120.     new_refcount = --fbdev->vsync_info.irq_refcount;
  121.     WARN_ON(new_refcount < 0);
  122.     if (!new_refcount) {
  123.         s3cfb_set_global_interrupt(fbdev, 0);
  124.         s3cfb_set_vsync_interrupt(fbdev, 0);
  125.     }
  126.  
  127.     mutex_unlock(&fbdev->vsync_info.irq_lock);
  128. }
  129. #endif
  130.  
  131. static irqreturn_t s3cfb_irq_frame(int irq, void *dev_id)
  132. {
  133.     struct s3cfb_global *fbdev[2];
  134.     fbdev[0] = fbfimd->fbdev[0];
  135.  
  136.     spin_lock(&fbdev[0]->vsync_slock);
  137.  
  138.     if (fbdev[0]->regs != 0)
  139.         s3cfb_clear_interrupt(fbdev[0]);
  140.  
  141. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  142.     fbdev[0]->vsync_info.timestamp = ktime_get();
  143.     wake_up_interruptible_all(&fbdev[0]->vsync_info.wait);
  144. #endif
  145.  
  146.     fbdev[0]->wq_count++;
  147.     wake_up(&fbdev[0]->wq);
  148.  
  149.     spin_unlock(&fbdev[0]->vsync_slock);
  150.  
  151.     return IRQ_HANDLED;
  152. }
  153.  
  154. #ifdef CONFIG_FB_S5P_TRACE_UNDERRUN
  155. static irqreturn_t s3cfb_irq_fifo(int irq, void *dev_id)
  156. {
  157.     struct s3cfb_global *fbdev[2];
  158.     fbdev[0] = fbfimd->fbdev[0];
  159.  
  160.     if (fbdev[0]->regs != 0)
  161.         s3cfb_clear_interrupt(fbdev[0]);
  162.  
  163.     return IRQ_HANDLED;
  164. }
  165. #endif
  166.  
  167. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  168. int s3cfb_set_vsync_int(struct fb_info *info, bool active)
  169. {
  170.     struct s3cfb_global *fbdev = fbfimd->fbdev[0];
  171.     bool prev_active = fbdev->vsync_info.active;
  172.  
  173.     fbdev->vsync_info.active = active;
  174.  
  175.     if (active && !prev_active)
  176.         s3cfb_activate_vsync(fbdev);
  177.     else if (!active && prev_active)
  178.         s3cfb_deactivate_vsync(fbdev);
  179.  
  180.     return 0;
  181. }
  182.  
  183. /**
  184.  * s3cfb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
  185.  * @sfb: main hardware state
  186.  * @timeout: timeout in msecs, or 0 to wait indefinitely.
  187.  */
  188. int s3cfb_wait_for_vsync(struct s3cfb_global *fbdev, u32 timeout)
  189. {
  190.     ktime_t timestamp;
  191.     int ret;
  192.  
  193.     pm_runtime_get_sync(fbdev->dev);
  194.  
  195.     timestamp = fbdev->vsync_info.timestamp;
  196.     s3cfb_activate_vsync(fbdev);
  197.     if (timeout) {
  198.         ret = wait_event_interruptible_timeout(fbdev->vsync_info.wait,
  199.                         !ktime_equal(timestamp,
  200.                         fbdev->vsync_info.timestamp),
  201.                         msecs_to_jiffies(timeout));
  202.     } else {
  203.         ret = wait_event_interruptible(fbdev->vsync_info.wait,
  204.                         !ktime_equal(timestamp,
  205.                         fbdev->vsync_info.timestamp));
  206.     }
  207.     s3cfb_deactivate_vsync(fbdev);
  208.  
  209.     pm_runtime_put_sync(fbdev->dev);
  210.  
  211.     if (timeout && ret == 0)
  212.         return -ETIMEDOUT;
  213.  
  214.     return 0;
  215. }
  216. #endif
  217.  
  218. int s3cfb_register_framebuffer(struct s3cfb_global *fbdev)
  219. {
  220.     struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
  221.     int ret, i, j;
  222.  
  223.     /* on registering framebuffer, framebuffer of default window is registered at first. */
  224.     for (i = pdata->default_win; i < pdata->nr_wins + pdata->default_win; i++) {
  225.         j = i % pdata->nr_wins;
  226.         ret = register_framebuffer(fbdev->fb[j]);
  227.         if (ret) {
  228.             dev_err(fbdev->dev, "failed to register \
  229.                 framebuffer device\n");
  230.             goto err;
  231.         }
  232. #ifndef CONFIG_FRAMEBUFFER_CONSOLE
  233.         if (j == pdata->default_win) {
  234.             s3cfb_check_var_window(fbdev, &fbdev->fb[j]->var,
  235.                     fbdev->fb[j]);
  236.             ret = s3cfb_set_par_window(fbdev, fbdev->fb[j]);
  237.             if (ret != 0)
  238.                 BUG();
  239.             s3cfb_draw_logo(fbdev->fb[j]);
  240.         }
  241. #endif
  242.     }
  243.     return 0;
  244.  
  245. err:
  246.     while (--i >= pdata->default_win) {
  247.         j = i % pdata->nr_wins;
  248.         unregister_framebuffer(fbdev->fb[j]);
  249.     }
  250.     return -EINVAL;
  251. }
  252.  
  253. void read_lcd_register(void)
  254. {
  255.     struct s3cfb_global *fbdev[1];
  256.     u32 reg_val[156] = {0,};
  257.     u32 reg;
  258.     u32 i;
  259.  
  260.     fbdev[0] = fbfimd->fbdev[0];
  261.  
  262.     if (fbdev[0]->system_state == POWER_OFF) {
  263.         dev_err(fbdev[0]->dev, "%s::system_state is POWER_OFF\n", __func__);
  264.         return;
  265.     }
  266.  
  267.     /*11C00000 ~ 11C00260*/
  268.     reg = readl(fbdev[0]->regs_org + S3C_VIDCON1);
  269.     dev_info(fbdev[0]->dev, "11C000%02X| %08X", S3C_VIDCON1, reg);
  270.     for (i = 0; i < 156; i++)
  271.         reg_val[i] = readl(fbdev[0]->regs_org + (i*4));
  272.  
  273.     for (i = 0; i < 39; i++)
  274.         dev_info(fbdev[0]->dev, "11C0%04X| %08X %08X %08X %08X",
  275.         (i*16), reg_val[i*4], reg_val[i*4+1], reg_val[i*4+2], reg_val[i*4+3]);
  276.  
  277.     /*11C040A0 ~ 11C04110*/
  278.     for (i = 0; i < 32; i++)
  279.         reg_val[i] = readl(fbdev[0]->regs_org + (0x40A0)+(i*4));
  280.  
  281.     for (i = 0; i < 8; i++)
  282.         dev_info(fbdev[0]->dev, "11C0%04X| %08X %08X %08X %08X",
  283.         (0x40A0)+(i*16), reg_val[i*4], reg_val[i*4+1], reg_val[i*4+2], reg_val[i*4+3]);
  284. #ifdef CONFIG_FB_S5P_MDNIE
  285.     reg = readl(fbdev[0]->ielcd_regs + S3C_VIDCON1);
  286.     dev_info(fbdev[0]->dev, "11C400%02X| %08X", S3C_VIDCON1, reg);
  287.  
  288.     for (i = 0; i < 4; i++)
  289.         reg_val[i] = readl(fbdev[0]->ielcd_regs + (i*4));
  290.  
  291.     for (i = 0; i < 1; i++)
  292.         dev_info(fbdev[0]->dev, "11C400%02X| %08X %08X %08X %08X",
  293.         (i*16), reg_val[i*4], reg_val[i*4+1], reg_val[i*4+2], reg_val[i*4+3]);
  294. #endif
  295. #ifdef CONFIG_FB_S5P_MIPI_DSIM
  296.     reg = read_dsim_register(0);
  297.     dev_info(fbdev[0]->dev, "11C80000| %08X", reg);
  298.     for (i = 0; i < 4; i++)
  299.         reg_val[i] = read_dsim_register(i);
  300.  
  301.     for (i = 0; i < 1; i++)
  302.         dev_info(fbdev[0]->dev, "11C800%02X| %08X %08X %08X %08X",
  303.         (i*16), reg_val[i*4], reg_val[i*4+1], reg_val[i*4+2], reg_val[i*4+3]);
  304. #endif
  305. }
  306.  
  307. static int s3cfb_sysfs_show_win_power(struct device *dev,
  308.                 struct device_attribute *attr, char *buf)
  309. {
  310.     struct s3c_platform_fb *pdata = to_fb_plat(dev);
  311.     struct s3cfb_window *win;
  312.     char temp[16];
  313.     int i;
  314.     struct s3cfb_global *fbdev[1];
  315.     fbdev[0] = fbfimd->fbdev[0];
  316.  
  317.     for (i = 0; i < pdata->nr_wins; i++) {
  318.         win = fbdev[0]->fb[i]->par;
  319.         sprintf(temp, "[fb%d] %s\n", i, win->enabled ? "on" : "off");
  320.         strcat(buf, temp);
  321.     }
  322.  
  323.     return strlen(buf);
  324. }
  325.  
  326. static int s3cfb_sysfs_store_win_power(struct device *dev,
  327.                 struct device_attribute *attr,
  328.                 const char *buf, size_t len)
  329. {
  330.     struct s3c_platform_fb *pdata = to_fb_plat(dev);
  331.     char temp[4] = { 0, };
  332.     const char *p = buf;
  333.     int id, to;
  334.     struct s3cfb_global *fbdev[1];
  335.     fbdev[0] = fbfimd->fbdev[0];
  336.  
  337.     while (*p != '\0') {
  338.         if (!isspace(*p))
  339.             strncat(temp, p, 1);
  340.         p++;
  341.     }
  342.  
  343.     if (strlen(temp) != 2)
  344.         return -EINVAL;
  345.  
  346.     id = simple_strtoul(temp, NULL, 10) / 10;
  347.     to = simple_strtoul(temp, NULL, 10) % 10;
  348.  
  349.     if (id < 0 || id > pdata->nr_wins)
  350.         return -EINVAL;
  351.  
  352.     if (to != 0 && to != 1)
  353.         return -EINVAL;
  354.  
  355.     if (to == 0)
  356.         s3cfb_disable_window(fbdev[0], id);
  357.     else
  358.         s3cfb_enable_window(fbdev[0], id);
  359.  
  360.     return len;
  361. }
  362.  
  363. static DEVICE_ATTR(win_power, 0644,
  364.     s3cfb_sysfs_show_win_power, s3cfb_sysfs_store_win_power);
  365.  
  366. static ssize_t ielcd_dump_show(struct device *dev,
  367.     struct device_attribute *attr, char *buf)
  368. {
  369.     int reg_val, i;
  370.     char temp[50];
  371.     struct s3cfb_global *fbdev[1];
  372.  
  373.     fbdev[0] = fbfimd->fbdev[0];
  374.  
  375.     for (i = 0; i < 25; i++) {
  376.         reg_val = readl(fbdev[0]->ielcd_regs + i*4);
  377.         sprintf(temp, "[IELCD]0x11C4_00%02X = 0x%08X\n", (i*4), reg_val);
  378.         strcat(buf, temp);
  379.     }
  380.  
  381.     return strlen(buf);
  382. }
  383. static DEVICE_ATTR(ielcd_dump, 0444, ielcd_dump_show, NULL);
  384.  
  385. static ssize_t fimd_dump_show(struct device *dev,
  386.     struct device_attribute *attr, char *buf)
  387. {
  388.     int reg_val, i;
  389.     char temp[50];
  390.     struct s3cfb_global *fbdev[1];
  391.  
  392.     fbdev[0] = fbfimd->fbdev[0];
  393.  
  394.     for (i = 0; i < 25; i++) {
  395.         reg_val = readl(fbdev[0]->regs_org + i*4);
  396.         sprintf(temp, "[FIMD]0x11C0_00%02X = 0x%08X\n", (i*4), reg_val);
  397.         strcat(buf, temp);
  398.     }
  399.  
  400.     return strlen(buf);
  401. }
  402. static DEVICE_ATTR(fimd_dump, 0444, fimd_dump_show, NULL);
  403.  
  404. #if 0 /* def CONFIG_FB_S5P_MIPI_DSIM */
  405. void s3cfb_display_on_remote(void)
  406. {
  407.     struct s3cfb_global *fbdev = fbfimd->fbdev[0];
  408.     struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
  409.  
  410.     if (pdata == NULL) {
  411.         dev_err(fbdev->dev, "failed to get defualt window number.\n");
  412.         return;
  413.     }
  414.     s3cfb_display_on(fbdev);
  415. }
  416. EXPORT_SYMBOL(s3cfb_display_on_remote);
  417.  
  418. void s3cfb_trigger(void)
  419. {
  420.     struct s3cfb_global *fbdev = fbfimd->fbdev[0];
  421.     struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
  422.  
  423.     if (pdata == NULL) {
  424.         dev_err(fbdev->dev, "failed to get defualt window number.\n");
  425.         return;
  426.     }
  427.     s3cfb_set_trigger(fbdev);
  428. }
  429. EXPORT_SYMBOL(s3cfb_trigger);
  430. #endif
  431.  
  432. #ifdef FEATURE_VSYNC_EVENT_VIA_SYSFS
  433. static ssize_t vsync_event_show(struct device *dev,
  434.     struct device_attribute *attr, char *buf)
  435. {
  436.     struct s3cfb_global *fbdev[1];
  437.     fbdev[0] = fbfimd->fbdev[0];
  438.  
  439.     return snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
  440.             ((fbdev[0] != 0) ?
  441.             ktime_to_ns(fbdev[0]->vsync_info.timestamp) : 0));
  442. }
  443.  
  444. static DEVICE_ATTR(vsync_event, 0444, vsync_event_show, NULL);
  445. #endif
  446.  
  447. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  448. static int s3cfb_wait_for_vsync_thread(void *data)
  449. {
  450.     struct s3cfb_global *fbdev = data;
  451.  
  452.     while (!kthread_should_stop()) {
  453.         ktime_t timestamp = fbdev->vsync_info.timestamp;
  454.         int ret = wait_event_interruptible_timeout(
  455.                         fbdev->vsync_info.wait,
  456.                         !ktime_equal(timestamp,
  457.                         fbdev->vsync_info.timestamp) &&
  458.                         fbdev->vsync_info.active,
  459.                         msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
  460.  
  461.         if (ret > 0) {
  462. #ifdef FEATURE_VSYNC_EVENT_VIA_SYSFS
  463.             struct s3c_platform_fb *pdata = to_fb_plat(fbdev->dev);
  464.             sysfs_notify(&fbdev->fb[pdata->default_win]->dev->kobj,
  465.                 NULL, "vsync_event");
  466. #else
  467.             char *envp[2];
  468.             char buf[64];
  469.             snprintf(buf, sizeof(buf), "VSYNC=%llu",
  470.                     ktime_to_ns(fbdev->vsync_info.timestamp));
  471.             envp[0] = buf;
  472.             envp[1] = NULL;
  473.             kobject_uevent_env(&fbdev->dev->kobj, KOBJ_CHANGE,
  474.                             envp);
  475. #endif
  476.         }
  477.     }
  478.  
  479.     return 0;
  480. }
  481. #endif
  482.  
  483. static void s3c_fb_update_regs_handler(struct kthread_work *work)
  484. {
  485.     struct s3cfb_global *fbdev =
  486.         container_of(work, struct s3cfb_global, update_regs_work);
  487.     struct s3c_reg_data *data, *next;
  488.     struct list_head saved_list;
  489.  
  490.     mutex_lock(&fbdev->update_regs_list_lock);
  491.     saved_list = fbdev->update_regs_list;
  492.     list_replace_init(&fbdev->update_regs_list, &saved_list);
  493.     mutex_unlock(&fbdev->update_regs_list_lock);
  494.  
  495.     list_for_each_entry_safe(data, next, &saved_list, list) {
  496.         s3c_fb_update_regs(fbdev, data);
  497.         list_del(&data->list);
  498.         kfree(data);
  499.     }
  500. }
  501.  
  502. static int s3cfb_probe(struct platform_device *pdev)
  503. {
  504.     struct s3c_platform_fb *pdata = NULL;
  505.     struct resource *res = NULL;
  506.     struct s3cfb_global *fbdev[2];
  507.     int ret = 0;
  508.     int i = 0;
  509.  
  510. #ifdef CONFIG_EXYNOS_DEV_PD
  511.     /* to use the runtime PM helper functions */
  512.     pm_runtime_enable(&pdev->dev);
  513.     /* enable the power domain */
  514.     pm_runtime_get_sync(&pdev->dev);
  515. #endif
  516.  
  517.     fbfimd = kzalloc(sizeof(struct s3cfb_fimd_desc), GFP_KERNEL);
  518.     if (!fbfimd) {
  519.         printk(KERN_ERR "failed to allocate for fimd fb descriptor\n");
  520.         ret = -ENOMEM;
  521.         goto err_fimd_desc;
  522.     }
  523.  
  524.     if (FIMD_MAX == 2)
  525.         fbfimd->dual = 1;
  526.     else
  527.         fbfimd->dual = 0;
  528.  
  529.     for (i = 0; i < FIMD_MAX; i++) {
  530.         /* global structure */
  531.         fbfimd->fbdev[i] = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);
  532.         fbdev[i] = fbfimd->fbdev[i];
  533.         if (!fbdev[i]) {
  534.             dev_err(fbdev[i]->dev, "failed to allocate for  \
  535.                 global fb structure fimd[%d]!\n", i);
  536.                 ret = -ENOMEM;
  537.             goto err0;
  538.         }
  539.  
  540.         fbdev[i]->dev = &pdev->dev;
  541.  
  542. #if defined(CONFIG_MACH_SMDK4X12) || defined(CONFIG_FB_S5P_AMS369FG06)
  543.         s3cfb_set_lcd_info(fbdev[i]);
  544. #endif
  545.         /* platform_data*/
  546.         pdata = to_fb_plat(&pdev->dev);
  547.  
  548.         if (pdata->lcd)
  549.             fbdev[i]->lcd = (struct s3cfb_lcd *)pdata->lcd;
  550.  
  551.         if (pdata->cfg_gpio)
  552.             pdata->cfg_gpio(pdev);
  553.  
  554.         if (pdata->clk_on)
  555.             pdata->clk_on(pdev, &fbdev[i]->clock);
  556.  
  557.         /* io memory */
  558.         res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  559.         if (!res) {
  560.             dev_err(fbdev[i]->dev,
  561.                 "failed to get io memory region\n");
  562.             ret = -EINVAL;
  563.             goto err1;
  564.         }
  565.         res = request_mem_region(res->start,
  566.                     res->end - res->start + 1, pdev->name);
  567.         if (!res) {
  568.             dev_err(fbdev[i]->dev,
  569.                 "failed to request io memory region\n");
  570.             ret = -EINVAL;
  571.             goto err1;
  572.         }
  573.         fbdev[i]->regs = ioremap(res->start, res->end - res->start + 1);
  574.         fbdev[i]->regs_org = fbdev[i]->regs;
  575.         if (!fbdev[i]->regs) {
  576.             dev_err(fbdev[i]->dev, "failed to remap io region\n");
  577.             ret = -EINVAL;
  578.             goto err_ioremap;
  579.         }
  580.  
  581.         spin_lock_init(&fbdev[i]->vsync_slock);
  582.  
  583. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  584.         INIT_LIST_HEAD(&fbdev[i]->update_regs_list);
  585.         mutex_init(&fbdev[i]->update_regs_list_lock);
  586.         init_kthread_worker(&fbdev[i]->update_regs_worker);
  587.  
  588.         fbdev[i]->update_regs_thread = kthread_run(kthread_worker_fn,
  589.                 &fbdev[i]->update_regs_worker, "s3c-fb");
  590.         if (IS_ERR(fbdev[i]->update_regs_thread)) {
  591.             int err = PTR_ERR(fbdev[i]->update_regs_thread);
  592.             fbdev[i]->update_regs_thread = NULL;
  593.  
  594.             dev_err(fbdev[i]->dev, "failed to run update_regs thread\n");
  595.             return err;
  596.         }
  597.         init_kthread_work(&fbdev[i]->update_regs_work, s3c_fb_update_regs_handler);
  598.         fbdev[i]->timeline = sw_sync_timeline_create("s3c-fb");
  599.         fbdev[i]->timeline_max = 0;
  600. #endif
  601.  
  602.         /* irq */
  603.         fbdev[i]->irq = platform_get_irq(pdev, 0);
  604.         if (request_irq(fbdev[i]->irq, s3cfb_irq_frame, IRQF_SHARED,
  605.                 pdev->name, fbdev[i])) {
  606.             dev_err(fbdev[i]->dev, "request_irq failed\n");
  607.             ret = -EINVAL;
  608.             goto err2;
  609.         }
  610.  
  611. #ifdef CONFIG_FB_S5P_TRACE_UNDERRUN
  612.         if (request_irq(platform_get_irq(pdev, 1), s3cfb_irq_fifo,
  613.                 IRQF_DISABLED, pdev->name, fbdev[i])) {
  614.             dev_err(fbdev[i]->dev, "request_irq failed\n");
  615.             ret = -EINVAL;
  616.             goto err2;
  617.         }
  618.  
  619.         s3cfb_set_fifo_interrupt(fbdev[i], 1);
  620.         dev_info(fbdev[i]->dev, "fifo underrun trace\n");
  621. #endif
  622. #ifdef CONFIG_FB_S5P_MDNIE
  623.         /*  only FIMD0 is supported */
  624.         if (i == 0)
  625.             s3c_mdnie_setup();
  626. #endif
  627.         /* hw setting */
  628.         s3cfb_init_global(fbdev[i]);
  629.  
  630.         fbdev[i]->system_state = POWER_ON;
  631.  
  632.         spin_lock_init(&fbdev[i]->slock);
  633.  
  634.         /* alloc fb_info */
  635.         if (s3cfb_alloc_framebuffer(fbdev[i], i)) {
  636.             dev_err(fbdev[i]->dev, "alloc error fimd[%d]\n", i);
  637.             ret = -ENOMEM;
  638.             goto err3;
  639.         }
  640.  
  641.         /* register fb_info */
  642.         if (s3cfb_register_framebuffer(fbdev[i])) {
  643.             dev_err(fbdev[i]->dev, "register error fimd[%d]\n", i);
  644.             ret = -EINVAL;
  645.             goto err3;
  646.         }
  647.  
  648.         /* enable display */
  649.         s3cfb_set_clock(fbdev[i]);
  650. #ifdef CONFIG_FB_S5P_MDNIE
  651.         /*  only FIMD0 is supported */
  652.         if (i == 0) {
  653.             if (pdata->set_display_path)
  654.                 pdata->set_display_path();
  655.  
  656.             s3cfb_set_dualrgb(fbdev[i], S3C_DUALRGB_MDNIE);
  657.             s3c_mdnie_init_global(fbdev[i]);
  658.             s3c_mdnie_display_on(fbdev[i]);
  659.         }
  660. #endif
  661.         s3cfb_enable_window(fbdev[0], pdata->default_win);
  662.  
  663.         s3cfb_update_power_state(fbdev[i], pdata->default_win,
  664.                     FB_BLANK_UNBLANK);
  665.  
  666.         /* Set alpha value width to 8-bit */
  667.         s3cfb_set_alpha_value_width(fbdev[i], i);
  668.  
  669.         s3cfb_display_on(fbdev[i]);
  670.  
  671. #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412)
  672. #ifdef CONFIG_BUSFREQ_OPP
  673.         /* To lock bus frequency in OPP mode */
  674.         fbdev[i]->bus_dev = dev_get("exynos-busfreq");
  675. #endif
  676. #endif
  677.  
  678. #ifdef CONFIG_HAS_WAKELOCK
  679. #ifdef CONFIG_HAS_EARLYSUSPEND
  680.         fbdev[i]->early_suspend.suspend = s3cfb_early_suspend;
  681.         fbdev[i]->early_suspend.resume = s3cfb_late_resume;
  682.         fbdev[i]->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
  683.  
  684.         register_early_suspend(&fbdev[i]->early_suspend);
  685. #endif
  686. #endif
  687. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  688.         init_waitqueue_head(&fbdev[i]->vsync_info.wait);
  689.  
  690.         /* Create vsync thread */
  691.         mutex_init(&fbdev[i]->vsync_info.irq_lock);
  692.  
  693.         fbdev[i]->vsync_info.thread = kthread_run(
  694.                         s3cfb_wait_for_vsync_thread,
  695.                         fbdev[i], "s3c-fb-vsync");
  696.         if (fbdev[i]->vsync_info.thread == ERR_PTR(-ENOMEM)) {
  697.             dev_err(fbdev[i]->dev, "failed to run vsync thread\n");
  698.             fbdev[i]->vsync_info.thread = NULL;
  699.         }
  700. #endif
  701.         ret = device_create_file(fbdev[i]->dev, &dev_attr_fimd_dump);
  702.         if (ret < 0)
  703.             dev_err(fbdev[0]->dev, "failed to add sysfs entries\n");
  704.  
  705.         ret = device_create_file(fbdev[i]->dev, &dev_attr_ielcd_dump);
  706.         if (ret < 0)
  707.             dev_err(fbdev[0]->dev, "failed to add sysfs entries\n");
  708.  
  709. #ifdef FEATURE_VSYNC_EVENT_VIA_SYSFS
  710.         ret = device_create_file(fbdev[i]->fb[pdata->default_win]->dev,
  711.                     &dev_attr_vsync_event);
  712.         if (ret < 0)
  713.             dev_err(fbdev[0]->dev, "failed to add sysfs entries\n");
  714. #endif
  715.     }
  716.  
  717. #ifdef CONFIG_FB_S5P_LCD_INIT
  718.     /* panel control */
  719.     if (pdata->backlight_on)
  720.         pdata->backlight_on(pdev);
  721.  
  722.     if (pdata->lcd_on)
  723.         pdata->lcd_on(pdev);
  724. #endif
  725.  
  726.     ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
  727.     if (ret < 0)
  728.         dev_err(fbdev[0]->dev, "failed to add sysfs entries\n");
  729.  
  730. #ifdef DISPLAY_BOOT_PROGRESS
  731.     if (!(readl(S5P_INFORM2)))
  732.         s3cfb_start_progress(fbdev[0]->fb[pdata->default_win]);
  733. #endif
  734.  
  735. #ifdef FEATURE_BUSFREQ_LOCK
  736.     atomic_set(&fbdev[0]->busfreq_lock_cnt, 0);
  737. #endif
  738.  
  739. #if defined(CONFIG_LCD_FREQ_SWITCH)
  740.     lcdfreq_init(fbdev[0]->fb[pdata->default_win]);
  741. #endif
  742.  
  743.     dev_info(fbdev[0]->dev, "registered successfully\n");
  744.  
  745.     return 0;
  746.  
  747. err3:
  748.     for (i = 0; i < FIMD_MAX; i++)
  749.         free_irq(fbdev[i]->irq, fbdev[i]);
  750. err2:
  751.     for (i = 0; i < FIMD_MAX; i++)
  752.         iounmap(fbdev[i]->regs);
  753.  
  754. err_ioremap:
  755.     release_mem_region(res->start, res->end - res->start + 1);
  756.  
  757. err1:
  758.     for (i = 0; i < FIMD_MAX; i++) {
  759.         pdata->clk_off(pdev, &fbdev[i]->clock);
  760.         kfree(fbfimd->fbdev[i]);
  761.     }
  762. err0:
  763.     kfree(fbfimd);
  764. err_fimd_desc:
  765.     return ret;
  766. }
  767.  
  768. static int s3cfb_remove(struct platform_device *pdev)
  769. {
  770.     struct s3c_platform_fb *pdata = to_fb_plat(&pdev->dev);
  771.     struct s3cfb_window *win;
  772.     struct fb_info *fb;
  773.     struct s3cfb_global *fbdev[2];
  774.     int i;
  775.     int j;
  776.  
  777.     for (i = 0; i < FIMD_MAX; i++) {
  778.         fbdev[i] = fbfimd->fbdev[i];
  779.  
  780. #ifdef CONFIG_HAS_WAKELOCK
  781. #ifdef CONFIG_HAS_EARLYSUSPEND
  782.         unregister_early_suspend(&fbdev[i]->early_suspend);
  783. #endif
  784. #endif
  785.         free_irq(fbdev[i]->irq, fbdev[i]);
  786.         iounmap(fbdev[i]->regs);
  787.         pdata->clk_off(pdev, &fbdev[i]->clock);
  788.  
  789.         for (j = 0; j < pdata->nr_wins; j++) {
  790.             fb = fbdev[i]->fb[j];
  791.  
  792.             /* free if exists */
  793.             if (fb) {
  794.                 win = fb->par;
  795.                 if (win->id == pdata->default_win)
  796.                     s3cfb_unmap_default_video_memory(fbdev[i], fb);
  797.                 else
  798.                     s3cfb_unmap_video_memory(fbdev[i], fb);
  799.  
  800.                 s3cfb_set_buffer_address(fbdev[i], j);
  801.                 framebuffer_release(fb);
  802.             }
  803.         }
  804. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  805.         if (fbdev[i]->vsync_info.thread)
  806.             kthread_stop(fbdev[i]->vsync_info.thread);
  807. #endif
  808.  
  809.         kfree(fbdev[i]->fb);
  810.         kfree(fbdev[i]);
  811.     }
  812. #ifdef CONFIG_EXYNOS_DEV_PD
  813.     /* disable the power domain */
  814.     pm_runtime_put(&pdev->dev);
  815.     pm_runtime_disable(&pdev->dev);
  816. #endif
  817.     return 0;
  818. }
  819.  
  820. void s3cfb_lcd0_power_domain_start(void)
  821. {
  822.     int timeout;
  823.     writel(S5P_INT_LOCAL_PWR_EN, S5P_PMU_LCD0_CONF);
  824.  
  825.     /* Wait max 1ms */
  826.     timeout = 1000;
  827.     while ((readl(S5P_PMU_LCD0_CONF + 0x4) & S5P_INT_LOCAL_PWR_EN)\
  828.         != S5P_INT_LOCAL_PWR_EN) {
  829.         if (timeout == 0) {
  830.             printk(KERN_ERR "Power domain lcd0 enable failed.\n");
  831.             break;
  832.         }
  833.         timeout--;
  834.         udelay(1);
  835.     }
  836.  
  837.     if (timeout == 0) {
  838.         timeout = 1000;
  839.         writel(0x1, S5P_PMU_LCD0_CONF + 0x8);
  840.         writel(S5P_INT_LOCAL_PWR_EN, S5P_PMU_LCD0_CONF);
  841.         while ((readl(S5P_PMU_LCD0_CONF + 0x4) & S5P_INT_LOCAL_PWR_EN)\
  842.             != S5P_INT_LOCAL_PWR_EN) {
  843.  
  844.             if (timeout == 0) {
  845.                 printk(KERN_ERR "Power domain lcd0 enable failed 2nd.\n");
  846.                 break;
  847.             }
  848.  
  849.             timeout--;
  850.             udelay(1);
  851.         }
  852.         writel(0x2, S5P_PMU_LCD0_CONF + 0x8);
  853.     }
  854. }
  855.  
  856. void s3cfb_lcd0_power_domain_stop(void)
  857. {
  858.     int timeout;
  859.  
  860.     writel(0, S5P_PMU_LCD0_CONF);
  861.  
  862.     /* Wait max 1ms */
  863.     timeout = 1000;
  864.     while (readl(S5P_PMU_LCD0_CONF + 0x4) & S5P_INT_LOCAL_PWR_EN) {
  865.         if (timeout == 0) {
  866.             printk(KERN_ERR "Power domain lcd0 disable failed.\n");
  867.             break;
  868.         }
  869.         timeout--;
  870.         udelay(1);
  871.     }
  872.  
  873.     if (timeout == 0) {
  874.         timeout = 1000;
  875.         writel(0x1, S5P_PMU_LCD0_CONF + 0x8);
  876.         writel(0, S5P_PMU_LCD0_CONF);
  877.         while (readl(S5P_PMU_LCD0_CONF + 0x4) & S5P_INT_LOCAL_PWR_EN) {
  878.             if (timeout == 0) {
  879.                 printk(KERN_ERR "Power domain lcd0 disable failed 2nd.\n");
  880.                 break;
  881.             }
  882.             timeout--;
  883.             udelay(1);
  884.         }
  885.         writel(0x2, S5P_PMU_LCD0_CONF + 0x8);
  886.     }
  887. }
  888.  
  889. void s3cfb_lcd0_pmu_off(void)
  890. {
  891.     s3cfb_lcd0_power_domain_stop();
  892.     usleep_range(5000, 5000);
  893.     s3cfb_lcd0_power_domain_start();
  894.     printk(KERN_WARNING "lcd0 pmu re_start!!!\n");
  895. }
  896.  
  897. #ifdef CONFIG_PM
  898. #ifdef CONFIG_HAS_EARLYSUSPEND
  899. void (*lcd_early_suspend)(void);
  900. void (*lcd_late_resume)(void);
  901.  
  902. void s3cfb_early_suspend(struct early_suspend *h)
  903. {
  904.     struct s3cfb_global *info = container_of(h, struct s3cfb_global, early_suspend);
  905.     struct s3c_platform_fb *pdata = to_fb_plat(info->dev);
  906.     struct platform_device *pdev = to_platform_device(info->dev);
  907.     struct s3cfb_global *fbdev[2];
  908.     int i, ret;
  909.  
  910.     printk(KERN_INFO "+%s\n", __func__);
  911.  
  912. #ifdef CONFIG_FB_S5P_MIPI_DSIM
  913.     if (lcd_early_suspend)
  914.         lcd_early_suspend();
  915. #endif
  916.  
  917.     for (i = 0; i < FIMD_MAX; i++) {
  918.         fbdev[i] = fbfimd->fbdev[i];
  919.  
  920.         if (pdata->backlight_off)
  921.             pdata->backlight_off(pdev);
  922.  
  923.         if (pdata->lcd_off)
  924.             pdata->lcd_off(pdev);
  925.  
  926.         /* Disable Vsync */
  927.         s3cfb_set_global_interrupt(fbdev[i], 0);
  928.         s3cfb_set_vsync_interrupt(fbdev[i], 0);
  929.  
  930. #ifdef CONFIG_FB_S5P_AMS369FG06
  931.         ams369fg06_ldi_disable();
  932. #elif defined(CONFIG_FB_S5P_LMS501KF03)
  933.         lms501kf03_ldi_disable();
  934. #endif
  935.         ret = s3cfb_display_off(fbdev[i]);
  936.  
  937. #ifdef CONFIG_FB_S5P_MDNIE
  938.         ret += s3c_mdnie_display_off();
  939. #endif
  940.  
  941.         if (ret > 0)
  942.             s3cfb_lcd0_pmu_off();
  943.  
  944.         info->system_state = POWER_OFF;
  945.  
  946.         if (fbdev[i]->regs) {
  947.             fbdev[i]->regs_org = fbdev[i]->regs;
  948.             spin_lock(&fbdev[i]->slock);
  949.             fbdev[i]->regs = 0;
  950.             spin_unlock(&fbdev[i]->slock);
  951.         }
  952.  
  953.         if (pdata->clk_off)
  954.             pdata->clk_off(pdev, &fbdev[i]->clock);
  955.     }
  956.  
  957. #if defined(CONFIG_FB_S5P_S6C1372) || defined(CONFIG_FB_S5P_S6F1202A)
  958.     s5c1372_ldi_disable();
  959. #endif
  960.  
  961. #ifdef CONFIG_FB_S5P_MIPI_DSIM
  962.     s5p_dsim_early_suspend();
  963. #endif
  964. #ifdef CONFIG_EXYNOS_DEV_PD
  965.     /* disable the power domain */
  966.     printk(KERN_DEBUG "s3cfb - disable power domain\n");
  967.     pm_runtime_put_sync(&pdev->dev);
  968. #endif
  969.  
  970. #ifdef CONFIG_FB_S5P_SYSMMU
  971.     if (fbdev[0]->sysmmu.enabled == true) {
  972.         fbdev[0]->sysmmu.enabled = false;
  973.         fbdev[0]->sysmmu.pgd = 0;
  974.         s5p_sysmmu_disable(fbdev[0]->dev);
  975.     }
  976. #endif
  977.  
  978.     printk(KERN_INFO "-%s\n", __func__);
  979.     return ;
  980. }
  981.  
  982. void s3cfb_late_resume(struct early_suspend *h)
  983. {
  984.     struct s3cfb_global *info = container_of(h, struct s3cfb_global, early_suspend);
  985.     struct s3c_platform_fb *pdata = to_fb_plat(info->dev);
  986.     struct fb_info *fb;
  987.     struct s3cfb_window *win;
  988.     struct s3cfb_global *fbdev[2];
  989.     int i, j;
  990.     struct platform_device *pdev = to_platform_device(info->dev);
  991.  
  992.     dev_info(info->dev, "+%s\n", __func__);
  993.  
  994.     dev_dbg(info->dev, "wake up from suspend\n");
  995.  
  996. #ifdef CONFIG_EXYNOS_DEV_PD
  997.     /* enable the power domain */
  998.     dev_dbg(info->dev, "s3cfb - enable power domain\n");
  999.     pm_runtime_get_sync(&pdev->dev);
  1000. #endif
  1001.  
  1002. #ifdef CONFIG_FB_S5P_MIPI_DSIM
  1003.     s5p_dsim_late_resume();
  1004. #endif
  1005.  
  1006. #if defined(CONFIG_FB_S5P_DUMMYLCD)
  1007.         max8698_ldo_enable_direct(MAX8698_LDO4);
  1008. #endif
  1009.     for (i = 0; i < FIMD_MAX; i++) {
  1010.         fbdev[i] = fbfimd->fbdev[i];
  1011.  
  1012.         if (pdata->clk_on)
  1013.             pdata->clk_on(pdev, &fbdev[i]->clock);
  1014.  
  1015.         if (fbdev[i]->regs_org)
  1016.             fbdev[i]->regs = fbdev[i]->regs_org;
  1017.         else
  1018.             /* fbdev[i]->regs_org should be non-zero value */
  1019.             BUG();
  1020.  
  1021. #if defined(CONFIG_FB_MDNIE_PWM)
  1022.         set_mdnie_pwm_value(g_mdnie, 0);
  1023. #endif
  1024.  
  1025.         if (pdata->set_display_path)
  1026.             pdata->set_display_path();
  1027.  
  1028. #ifdef CONFIG_FB_S5P_MDNIE
  1029.         s3cfb_set_dualrgb(fbdev[i], S3C_DUALRGB_MDNIE);
  1030. #endif
  1031.  
  1032.         info->system_state = POWER_ON;
  1033.  
  1034.         s3cfb_init_global(fbdev[i]);
  1035.         s3cfb_set_clock(fbdev[i]);
  1036.         /* Set Alpha value width to 8-bit alpha value
  1037.          * 1 : 8bit mode
  1038.          * 2 : 4bit mode
  1039.          */
  1040.         s3cfb_set_alpha_value(fbdev[i], 1);
  1041. #ifdef CONFIG_FB_S5P_MDNIE
  1042. #if defined(CONFIG_FB_S5P_S6C1372) || defined(CONFIG_FB_S5P_S6F1202A)
  1043.         s5c1372_ldi_enable();
  1044. #endif
  1045.         s3c_mdnie_init_global(fbdev[i]);
  1046.         s3c_mdnie_display_on(fbdev[i]);
  1047. #endif
  1048.         s3cfb_display_on(fbdev[i]);
  1049.  
  1050.         /* Set alpha value width to 8-bit */
  1051.         s3cfb_set_alpha_value_width(fbdev[i], i);
  1052.  
  1053. #if defined(CONFIG_FB_RGBA_ORDER)
  1054.         s3cfb_set_output(fbdev[i]);
  1055. #else
  1056.         for (j = 0; j < pdata->nr_wins; j++) {
  1057.             fb = fbdev[i]->fb[j];
  1058.             win = fb->par;
  1059.             if ((win->path == DATA_PATH_DMA) && (win->enabled)) {
  1060.                 s3cfb_set_par(fb);
  1061.                 s3cfb_set_buffer_address(fbdev[i], win->id);
  1062.                 s3cfb_enable_window(fbdev[i], win->id);
  1063.             }
  1064.         }
  1065. #endif
  1066.  
  1067.         if (pdata->cfg_gpio)
  1068.             pdata->cfg_gpio(pdev);
  1069.  
  1070.         if (pdata->lcd_on)
  1071.             pdata->lcd_on(pdev);
  1072.  
  1073.         if (info->lcd->init_ldi)
  1074.             fbdev[i]->lcd->init_ldi();
  1075.  
  1076.         if (pdata->backlight_on)
  1077.             pdata->backlight_on(pdev);
  1078.  
  1079. #if defined(CONFIG_FB_S5P_VSYNC_THREAD)
  1080.         mutex_lock(&fbdev[i]->vsync_info.irq_lock);
  1081.         if (fbdev[i]->vsync_info.irq_refcount) {
  1082.             s3cfb_set_global_interrupt(fbdev[i], 1);
  1083.             s3cfb_set_vsync_interrupt(fbdev[i], 1);
  1084.         }
  1085.         mutex_unlock(&fbdev[i]->vsync_info.irq_lock);
  1086. #endif
  1087.     }
  1088.  
  1089. #ifdef CONFIG_FB_S5P_MIPI_DSIM
  1090.     if (lcd_late_resume)
  1091.         lcd_late_resume();
  1092. #endif
  1093.  
  1094.     dev_info(info->dev, "-%s\n", __func__);
  1095.  
  1096.     return;
  1097. }
  1098. #else /* else !CONFIG_HAS_EARLYSUSPEND */
  1099.  
  1100. int s3cfb_suspend(struct platform_device *pdev, pm_message_t state)
  1101. {
  1102.     struct s3c_platform_fb *pdata = to_fb_plat(&pdev->dev);
  1103.     struct s3cfb_global *fbdev[2];
  1104.     int i;
  1105.     u32 reg;
  1106.  
  1107.     for (i = 0; i < FIMD_MAX; i++) {
  1108.         fbdev[i] = fbfimd->fbdev[i];
  1109.  
  1110. #ifdef CONFIG_FB_S5P_MDNIE
  1111.         writel(0, fbdev[i]->regs + 0x27c);
  1112.         msleep(20);
  1113.         reg = readl(S3C_VA_SYS + 0x0210);
  1114.         reg |= (1<<1);
  1115.         writel(reg, S3C_VA_SYS + 0x0210);
  1116.         s3c_mdnie_display_off();
  1117. #endif
  1118.         if (atomic_read(&fbdev[i]->enabled_win) > 0) {
  1119.             /* lcd_off and backlight_off isn't needed. */
  1120.             if (fbdev[i]->lcd->deinit_ldi)
  1121.                 fbdev[i]->lcd->deinit_ldi();
  1122.  
  1123.             s3cfb_display_off(fbdev[i]);
  1124.             if (fbdev[i]->regs) {
  1125.                 fbdev[i]->regs_org = fbdev[i]->regs;
  1126.                 fbdev[i]->regs = 0;
  1127.             } else
  1128.                 /* fbdev[i]->regs should be non-zero value */
  1129.                 BUG();
  1130.             pdata->clk_off(pdev, &fbdev[i]->clock);
  1131.         }
  1132. #ifdef CONFIG_FB_S5P_MDNIE
  1133.         s3c_mdnie_off();
  1134. #endif
  1135.     }
  1136.  
  1137.     return 0;
  1138. }
  1139.  
  1140. int s3cfb_resume(struct platform_device *pdev)
  1141. {
  1142.     struct s3c_platform_fb *pdata = to_fb_plat(&pdev->dev);
  1143.     struct fb_info *fb;
  1144.     struct s3cfb_window *win;
  1145.     struct s3cfb_global *fbdev[2];
  1146.     int i, j;
  1147.     u32 reg;
  1148.  
  1149.     for (i = 0; i < FIMD_MAX; i++) {
  1150.         fbdev[i] = fbfimd->fbdev[i];
  1151.         dev_dbg(fbdev[i]->dev, "wake up from suspend fimd[%d]\n", i);
  1152.  
  1153.         if (pdata->cfg_gpio)
  1154.             pdata->cfg_gpio(pdev);
  1155.  
  1156.         if (pdata->backlight_on)
  1157.             pdata->backlight_on(pdev);
  1158.         if (pdata->lcd_on)
  1159.             pdata->lcd_on(pdev);
  1160.         if (fbdev[i]->lcd->init_ldi)
  1161.             fbdev[i]->lcd->init_ldi();
  1162.  
  1163.         if (pdata->backlight_off)
  1164.             pdata->backlight_off(pdev);
  1165.         if (pdata->lcd_off)
  1166.             pdata->lcd_off(pdev);
  1167.         if (fbdev[i]->lcd->deinit_ldi)
  1168.             fbdev[i]->lcd->deinit_ldi();
  1169.  
  1170.         if (atomic_read(&fbdev[i]->enabled_win) > 0) {
  1171. #ifdef CONFIG_FB_S5P_MDNIE
  1172.             reg = readl(S3C_VA_SYS + 0x0210);
  1173.             reg &= ~(1<<13);
  1174.             reg &= ~(1<<12);
  1175.             reg &= ~(3<<10);
  1176.             reg |= (1<<0);
  1177.             reg &= ~(1<<1);
  1178.             writel(reg, S3C_VA_SYS + 0x0210);
  1179.             writel(3, fbdev[i]->regs + 0x27c);
  1180. #endif
  1181.             pdata->clk_on(pdev, &fbdev[i]->clock);
  1182.             if (fbdev[i]->regs_org)
  1183.                 fbdev[i]->regs = fbdev[i]->regs_org;
  1184.             else
  1185.                 /* fbdev[i]->regs should be non-zero value */
  1186.                 BUG();
  1187.  
  1188.             s3cfb_init_global(fbdev[i]);
  1189.             s3cfb_set_clock(fbdev[i]);
  1190. #ifdef CONFIG_FB_S5P_MDNIE
  1191.             s3c_mdnie_init_global(fbdev[i]);
  1192.             s3c_mdnie_display_on(fbdev[i]);
  1193. #endif
  1194.             for (j = 0; j < pdata->nr_wins; j++) {
  1195.                 fb = fbdev[i]->fb[j];
  1196.                 win = fb->par;
  1197.                 if (win->owner == DMA_MEM_FIMD) {
  1198.                     s3cfb_set_win_params(fbdev[i], win->id);
  1199.                     if (win->enabled) {
  1200.                         if (win->power_state == FB_BLANK_NORMAL)
  1201.                             s3cfb_win_map_on(fbdev[i], win->id, 0x0);
  1202.  
  1203.                         s3cfb_enable_window(fbdev[i], win->id);
  1204.                     }
  1205.                 }
  1206.             }
  1207.  
  1208.             s3cfb_set_alpha_value_width(fbdev[i], i);
  1209.  
  1210.             s3cfb_display_on(fbdev[i]);
  1211.  
  1212.             if (pdata->backlight_on)
  1213.                 pdata->backlight_on(pdev);
  1214.  
  1215.             if (pdata->lcd_on)
  1216.                 pdata->lcd_on(pdev);
  1217.  
  1218.             if (fbdev[i]->lcd->init_ldi)
  1219.                 fbdev[i]->lcd->init_ldi();
  1220.         }
  1221.     }
  1222.  
  1223.     return 0;
  1224. }
  1225. #endif
  1226. #else
  1227. #define s3cfb_suspend NULL
  1228. #define s3cfb_resume NULL
  1229. #endif
  1230.  
  1231. #ifdef CONFIG_EXYNOS_DEV_PD
  1232. static int s3cfb_runtime_suspend(struct device *dev)
  1233. {
  1234.     return 0;
  1235. }
  1236.  
  1237. static int s3cfb_runtime_resume(struct device *dev)
  1238. {
  1239.     return 0;
  1240. }
  1241.  
  1242. static const struct dev_pm_ops s3cfb_pm_ops = {
  1243.     .runtime_suspend = s3cfb_runtime_suspend,
  1244.     .runtime_resume = s3cfb_runtime_resume,
  1245. };
  1246. #endif
  1247.  
  1248. static struct platform_driver s3cfb_driver = {
  1249.     .probe      = s3cfb_probe,
  1250.     .remove     = s3cfb_remove,
  1251. #ifndef CONFIG_HAS_EARLYSUSPEND
  1252.     .suspend    = s3cfb_suspend,
  1253.     .resume     = s3cfb_resume,
  1254. #endif
  1255.     .driver     = {
  1256.         .name   = S3CFB_NAME,
  1257.         .owner  = THIS_MODULE,
  1258. #ifdef CONFIG_EXYNOS_DEV_PD
  1259.         .pm = &s3cfb_pm_ops,
  1260. #endif
  1261.     },
  1262. };
  1263.  
  1264. struct fb_ops s3cfb_ops = {
  1265.     .owner      = THIS_MODULE,
  1266.     .fb_open    = s3cfb_open,
  1267.     .fb_release = s3cfb_release,
  1268.     .fb_check_var   = s3cfb_check_var,
  1269.     .fb_set_par = s3cfb_set_par,
  1270.     .fb_setcolreg   = s3cfb_setcolreg,
  1271.     .fb_blank   = s3cfb_blank,
  1272.     .fb_pan_display = s3cfb_pan_display,
  1273.     .fb_fillrect    = cfb_fillrect,
  1274.     .fb_copyarea    = cfb_copyarea,
  1275.     .fb_imageblit   = cfb_imageblit,
  1276.     .fb_cursor  = s3cfb_cursor,
  1277.     .fb_ioctl   = s3cfb_ioctl,
  1278. };
  1279.  
  1280. static int s3cfb_register(void)
  1281. {
  1282.     return platform_driver_register(&s3cfb_driver);
  1283. }
  1284.  
  1285. static void s3cfb_unregister(void)
  1286. {
  1287.     platform_driver_unregister(&s3cfb_driver);
  1288. }
  1289.  
  1290. module_init(s3cfb_register);
  1291. module_exit(s3cfb_unregister);
  1292.  
  1293. MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
  1294. MODULE_AUTHOR("Jonghun, Han <jonghun.han@samsung.com>");
  1295. MODULE_AUTHOR("Jinsung, Yang <jsgood.yang@samsung.com>");
  1296. MODULE_DESCRIPTION("Samsung Display Controller (FIMD) driver");
  1297. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement