| .. | .. |
|---|
| 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: |
|---|