.. | .. |
---|
15 | 15 | #include <linux/ctype.h> |
---|
16 | 16 | #include <linux/dma-mapping.h> |
---|
17 | 17 | #include <linux/delay.h> |
---|
| 18 | +#include <linux/fbcon.h> |
---|
18 | 19 | #include <linux/gpio.h> |
---|
19 | 20 | #include <linux/init.h> |
---|
20 | 21 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
213 | 214 | struct sh_mobile_lcdc_chan ch[2]; |
---|
214 | 215 | struct sh_mobile_lcdc_overlay overlays[4]; |
---|
215 | 216 | |
---|
216 | | - struct notifier_block notifier; |
---|
217 | 217 | int started; |
---|
218 | 218 | int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ |
---|
219 | 219 | }; |
---|
.. | .. |
---|
534 | 534 | ch->tx_dev->ops->display_off(ch->tx_dev); |
---|
535 | 535 | } |
---|
536 | 536 | |
---|
537 | | -static bool |
---|
538 | | -sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch, |
---|
539 | | - const struct fb_videomode *new_mode) |
---|
540 | | -{ |
---|
541 | | - dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n", |
---|
542 | | - ch->display.mode.xres, ch->display.mode.yres, |
---|
543 | | - new_mode->xres, new_mode->yres); |
---|
544 | | - |
---|
545 | | - /* It can be a different monitor with an equal video-mode */ |
---|
546 | | - if (fb_mode_is_equal(&ch->display.mode, new_mode)) |
---|
547 | | - return false; |
---|
548 | | - |
---|
549 | | - dev_dbg(ch->info->dev, "Switching %u -> %u lines\n", |
---|
550 | | - ch->display.mode.yres, new_mode->yres); |
---|
551 | | - ch->display.mode = *new_mode; |
---|
552 | | - |
---|
553 | | - return true; |
---|
554 | | -} |
---|
555 | | - |
---|
556 | 537 | static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var, |
---|
557 | 538 | struct fb_info *info); |
---|
558 | | - |
---|
559 | | -static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch, |
---|
560 | | - enum sh_mobile_lcdc_entity_event event, |
---|
561 | | - const struct fb_videomode *mode, |
---|
562 | | - const struct fb_monspecs *monspec) |
---|
563 | | -{ |
---|
564 | | - struct fb_info *info = ch->info; |
---|
565 | | - struct fb_var_screeninfo var; |
---|
566 | | - int ret = 0; |
---|
567 | | - |
---|
568 | | - switch (event) { |
---|
569 | | - case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT: |
---|
570 | | - /* HDMI plug in */ |
---|
571 | | - console_lock(); |
---|
572 | | - if (lock_fb_info(info)) { |
---|
573 | | - |
---|
574 | | - |
---|
575 | | - ch->display.width = monspec->max_x * 10; |
---|
576 | | - ch->display.height = monspec->max_y * 10; |
---|
577 | | - |
---|
578 | | - if (!sh_mobile_lcdc_must_reconfigure(ch, mode) && |
---|
579 | | - info->state == FBINFO_STATE_RUNNING) { |
---|
580 | | - /* First activation with the default monitor. |
---|
581 | | - * Just turn on, if we run a resume here, the |
---|
582 | | - * logo disappears. |
---|
583 | | - */ |
---|
584 | | - info->var.width = ch->display.width; |
---|
585 | | - info->var.height = ch->display.height; |
---|
586 | | - sh_mobile_lcdc_display_on(ch); |
---|
587 | | - } else { |
---|
588 | | - /* New monitor or have to wake up */ |
---|
589 | | - fb_set_suspend(info, 0); |
---|
590 | | - } |
---|
591 | | - |
---|
592 | | - |
---|
593 | | - unlock_fb_info(info); |
---|
594 | | - } |
---|
595 | | - console_unlock(); |
---|
596 | | - break; |
---|
597 | | - |
---|
598 | | - case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT: |
---|
599 | | - /* HDMI disconnect */ |
---|
600 | | - console_lock(); |
---|
601 | | - if (lock_fb_info(info)) { |
---|
602 | | - fb_set_suspend(info, 1); |
---|
603 | | - unlock_fb_info(info); |
---|
604 | | - } |
---|
605 | | - console_unlock(); |
---|
606 | | - break; |
---|
607 | | - |
---|
608 | | - case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: |
---|
609 | | - /* Validate a proposed new mode */ |
---|
610 | | - fb_videomode_to_var(&var, mode); |
---|
611 | | - var.bits_per_pixel = info->var.bits_per_pixel; |
---|
612 | | - var.grayscale = info->var.grayscale; |
---|
613 | | - ret = sh_mobile_lcdc_check_var(&var, info); |
---|
614 | | - break; |
---|
615 | | - } |
---|
616 | | - |
---|
617 | | - return ret; |
---|
618 | | -} |
---|
619 | 539 | |
---|
620 | 540 | /* ----------------------------------------------------------------------------- |
---|
621 | 541 | * Format helpers |
---|
.. | .. |
---|
1570 | 1490 | ovl->dma_handle, ovl->fb_size); |
---|
1571 | 1491 | } |
---|
1572 | 1492 | |
---|
1573 | | -static struct fb_ops sh_mobile_lcdc_overlay_ops = { |
---|
| 1493 | +static const struct fb_ops sh_mobile_lcdc_overlay_ops = { |
---|
1574 | 1494 | .owner = THIS_MODULE, |
---|
1575 | 1495 | .fb_read = fb_sys_read, |
---|
1576 | 1496 | .fb_write = fb_sys_write, |
---|
.. | .. |
---|
1644 | 1564 | |
---|
1645 | 1565 | /* Allocate and initialize the frame buffer device. */ |
---|
1646 | 1566 | info = framebuffer_alloc(0, priv->dev); |
---|
1647 | | - if (info == NULL) { |
---|
1648 | | - dev_err(priv->dev, "unable to allocate fb_info\n"); |
---|
| 1567 | + if (!info) |
---|
1649 | 1568 | return -ENOMEM; |
---|
1650 | | - } |
---|
1651 | 1569 | |
---|
1652 | 1570 | ovl->info = info; |
---|
1653 | 1571 | |
---|
1654 | 1572 | info->flags = FBINFO_FLAG_DEFAULT; |
---|
1655 | 1573 | info->fbops = &sh_mobile_lcdc_overlay_ops; |
---|
1656 | 1574 | info->device = priv->dev; |
---|
1657 | | - info->screen_base = ovl->fb_mem; |
---|
| 1575 | + info->screen_buffer = ovl->fb_mem; |
---|
1658 | 1576 | info->par = ovl; |
---|
1659 | 1577 | |
---|
1660 | 1578 | /* Initialize fixed screen information. Restrict pan to 2 lines steps |
---|
.. | .. |
---|
1676 | 1594 | case V4L2_PIX_FMT_NV12: |
---|
1677 | 1595 | case V4L2_PIX_FMT_NV21: |
---|
1678 | 1596 | info->fix.ypanstep = 2; |
---|
| 1597 | + fallthrough; |
---|
1679 | 1598 | case V4L2_PIX_FMT_NV16: |
---|
1680 | 1599 | case V4L2_PIX_FMT_NV61: |
---|
1681 | 1600 | info->fix.xpanstep = 2; |
---|
.. | .. |
---|
1838 | 1757 | struct sh_mobile_lcdc_chan *ch = info->par; |
---|
1839 | 1758 | struct fb_var_screeninfo var; |
---|
1840 | 1759 | struct fb_videomode mode; |
---|
1841 | | - struct fb_event event; |
---|
1842 | | - int evnt = FB_EVENT_MODE_CHANGE_ALL; |
---|
1843 | 1760 | |
---|
1844 | 1761 | if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) |
---|
1845 | 1762 | /* More framebuffer users are active */ |
---|
.. | .. |
---|
1861 | 1778 | /* Couldn't reconfigure, hopefully, can continue as before */ |
---|
1862 | 1779 | return; |
---|
1863 | 1780 | |
---|
1864 | | - /* |
---|
1865 | | - * fb_set_var() calls the notifier change internally, only if |
---|
1866 | | - * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a |
---|
1867 | | - * user event, we have to call the chain ourselves. |
---|
1868 | | - */ |
---|
1869 | | - event.info = info; |
---|
1870 | | - event.data = &ch->display.mode; |
---|
1871 | | - fb_notifier_call_chain(evnt, &event); |
---|
| 1781 | + fbcon_update_vcs(info, true); |
---|
1872 | 1782 | } |
---|
1873 | 1783 | |
---|
1874 | 1784 | /* |
---|
.. | .. |
---|
2054 | 1964 | ch->dma_handle, ch->fb_size); |
---|
2055 | 1965 | } |
---|
2056 | 1966 | |
---|
2057 | | -static struct fb_ops sh_mobile_lcdc_ops = { |
---|
| 1967 | +static const struct fb_ops sh_mobile_lcdc_ops = { |
---|
2058 | 1968 | .owner = THIS_MODULE, |
---|
2059 | 1969 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, |
---|
2060 | 1970 | .fb_read = fb_sys_read, |
---|
.. | .. |
---|
2138 | 2048 | * list and allocate the color map. |
---|
2139 | 2049 | */ |
---|
2140 | 2050 | info = framebuffer_alloc(0, priv->dev); |
---|
2141 | | - if (info == NULL) { |
---|
2142 | | - dev_err(priv->dev, "unable to allocate fb_info\n"); |
---|
| 2051 | + if (!info) |
---|
2143 | 2052 | return -ENOMEM; |
---|
2144 | | - } |
---|
2145 | 2053 | |
---|
2146 | 2054 | ch->info = info; |
---|
2147 | 2055 | |
---|
2148 | 2056 | info->flags = FBINFO_FLAG_DEFAULT; |
---|
2149 | 2057 | info->fbops = &sh_mobile_lcdc_ops; |
---|
2150 | 2058 | info->device = priv->dev; |
---|
2151 | | - info->screen_base = ch->fb_mem; |
---|
| 2059 | + info->screen_buffer = ch->fb_mem; |
---|
2152 | 2060 | info->pseudo_palette = &ch->pseudo_palette; |
---|
2153 | 2061 | info->par = ch; |
---|
2154 | 2062 | |
---|
.. | .. |
---|
2177 | 2085 | case V4L2_PIX_FMT_NV12: |
---|
2178 | 2086 | case V4L2_PIX_FMT_NV21: |
---|
2179 | 2087 | info->fix.ypanstep = 2; |
---|
| 2088 | + fallthrough; |
---|
2180 | 2089 | case V4L2_PIX_FMT_NV16: |
---|
2181 | 2090 | case V4L2_PIX_FMT_NV61: |
---|
2182 | 2091 | info->fix.xpanstep = 2; |
---|
.. | .. |
---|
2319 | 2228 | * Framebuffer notifier |
---|
2320 | 2229 | */ |
---|
2321 | 2230 | |
---|
2322 | | -/* locking: called with info->lock held */ |
---|
2323 | | -static int sh_mobile_lcdc_notify(struct notifier_block *nb, |
---|
2324 | | - unsigned long action, void *data) |
---|
2325 | | -{ |
---|
2326 | | - struct fb_event *event = data; |
---|
2327 | | - struct fb_info *info = event->info; |
---|
2328 | | - struct sh_mobile_lcdc_chan *ch = info->par; |
---|
2329 | | - |
---|
2330 | | - if (&ch->lcdc->notifier != nb) |
---|
2331 | | - return NOTIFY_DONE; |
---|
2332 | | - |
---|
2333 | | - dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", |
---|
2334 | | - __func__, action, event->data); |
---|
2335 | | - |
---|
2336 | | - switch(action) { |
---|
2337 | | - case FB_EVENT_SUSPEND: |
---|
2338 | | - sh_mobile_lcdc_display_off(ch); |
---|
2339 | | - sh_mobile_lcdc_stop(ch->lcdc); |
---|
2340 | | - break; |
---|
2341 | | - case FB_EVENT_RESUME: |
---|
2342 | | - mutex_lock(&ch->open_lock); |
---|
2343 | | - sh_mobile_fb_reconfig(info); |
---|
2344 | | - mutex_unlock(&ch->open_lock); |
---|
2345 | | - |
---|
2346 | | - sh_mobile_lcdc_display_on(ch); |
---|
2347 | | - sh_mobile_lcdc_start(ch->lcdc); |
---|
2348 | | - } |
---|
2349 | | - |
---|
2350 | | - return NOTIFY_OK; |
---|
2351 | | -} |
---|
2352 | | - |
---|
2353 | 2231 | /* ----------------------------------------------------------------------------- |
---|
2354 | 2232 | * Probe/remove and driver init/exit |
---|
2355 | 2233 | */ |
---|
.. | .. |
---|
2376 | 2254 | { |
---|
2377 | 2255 | struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); |
---|
2378 | 2256 | unsigned int i; |
---|
2379 | | - |
---|
2380 | | - fb_unregister_client(&priv->notifier); |
---|
2381 | 2257 | |
---|
2382 | 2258 | for (i = 0; i < ARRAY_SIZE(priv->overlays); i++) |
---|
2383 | 2259 | sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]); |
---|
.. | .. |
---|
2539 | 2415 | unsigned int num_modes; |
---|
2540 | 2416 | unsigned int max_size; |
---|
2541 | 2417 | unsigned int i; |
---|
2542 | | - |
---|
2543 | | - ch->notify = sh_mobile_lcdc_display_notify; |
---|
2544 | 2418 | |
---|
2545 | 2419 | /* Validate the format. */ |
---|
2546 | 2420 | format = sh_mobile_format_info(cfg->fourcc); |
---|
.. | .. |
---|
2714 | 2588 | if (num_channels == 2) |
---|
2715 | 2589 | priv->forced_fourcc = pdata->ch[0].fourcc; |
---|
2716 | 2590 | |
---|
2717 | | - priv->base = ioremap_nocache(res->start, resource_size(res)); |
---|
| 2591 | + priv->base = ioremap(res->start, resource_size(res)); |
---|
2718 | 2592 | if (!priv->base) { |
---|
2719 | 2593 | error = -ENOMEM; |
---|
2720 | 2594 | goto err1; |
---|
.. | .. |
---|
2769 | 2643 | if (error) |
---|
2770 | 2644 | goto err1; |
---|
2771 | 2645 | } |
---|
2772 | | - |
---|
2773 | | - /* Failure ignored */ |
---|
2774 | | - priv->notifier.notifier_call = sh_mobile_lcdc_notify; |
---|
2775 | | - fb_register_client(&priv->notifier); |
---|
2776 | 2646 | |
---|
2777 | 2647 | return 0; |
---|
2778 | 2648 | err1: |
---|