From 611097d5daea95688e9187a53f36a8c743eaa0b8 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Jul 2019 15:44:18 +0200 Subject: fbdev: da8xx: add support for a regulator We want to remove the hacky platform data callback for power control. Add a regulator to the driver data and enable/disable it next to the current panel_power_ctrl() calls. We will use it in subsequent patch on da850-evm. Signed-off-by: Bartosz Golaszewski Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sekhar Nori --- drivers/video/fbdev/da8xx-fb.c | 54 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index b1cf248f3291..02dfe9e32eed 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -165,6 +166,7 @@ struct da8xx_fb_par { #endif unsigned int lcdc_clk_rate; void (*panel_power_ctrl)(int); + struct regulator *lcd_supply; u32 pseudo_palette[16]; struct fb_videomode mode; struct lcd_ctrl_config cfg; @@ -1066,6 +1068,7 @@ static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) static int fb_remove(struct platform_device *dev) { struct fb_info *info = dev_get_drvdata(&dev->dev); + int ret; if (info) { struct da8xx_fb_par *par = info->par; @@ -1073,8 +1076,13 @@ static int fb_remove(struct platform_device *dev) #ifdef CONFIG_CPU_FREQ lcd_da8xx_cpufreq_deregister(par); #endif - if (par->panel_power_ctrl) + if (par->panel_power_ctrl) { par->panel_power_ctrl(0); + } else if (par->lcd_supply) { + ret = regulator_disable(par->lcd_supply); + if (ret) + return ret; + } lcd_disable_raster(DA8XX_FRAME_WAIT); lcdc_write(0, LCD_RASTER_CTRL_REG); @@ -1179,15 +1187,25 @@ static int cfb_blank(int blank, struct fb_info *info) case FB_BLANK_UNBLANK: lcd_enable_raster(); - if (par->panel_power_ctrl) + if (par->panel_power_ctrl) { par->panel_power_ctrl(1); + } else if (par->lcd_supply) { + ret = regulator_enable(par->lcd_supply); + if (ret) + return ret; + } break; case FB_BLANK_NORMAL: case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: - if (par->panel_power_ctrl) + if (par->panel_power_ctrl) { par->panel_power_ctrl(0); + } else if (par->lcd_supply) { + ret = regulator_disable(par->lcd_supply); + if (ret) + return ret; + } lcd_disable_raster(DA8XX_FRAME_WAIT); break; @@ -1400,6 +1418,20 @@ static int fb_probe(struct platform_device *device) par->panel_power_ctrl(1); } + par->lcd_supply = devm_regulator_get_optional(&device->dev, "lcd"); + if (IS_ERR(par->lcd_supply)) { + if (PTR_ERR(par->lcd_supply) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_pm_runtime_disable; + } + + par->lcd_supply = NULL; + } else { + ret = regulator_enable(par->lcd_supply); + if (ret) + goto err_pm_runtime_disable; + } + fb_videomode_to_var(&da8xx_fb_var, lcdc_info); par->cfg = *lcd_cfg; @@ -1603,10 +1635,16 @@ static int fb_suspend(struct device *dev) { struct fb_info *info = dev_get_drvdata(dev); struct da8xx_fb_par *par = info->par; + int ret; console_lock(); - if (par->panel_power_ctrl) + if (par->panel_power_ctrl) { par->panel_power_ctrl(0); + } else if (par->lcd_supply) { + ret = regulator_disable(par->lcd_supply); + if (ret) + return ret; + } fb_set_suspend(info, 1); lcd_disable_raster(DA8XX_FRAME_WAIT); @@ -1620,6 +1658,7 @@ static int fb_resume(struct device *dev) { struct fb_info *info = dev_get_drvdata(dev); struct da8xx_fb_par *par = info->par; + int ret; console_lock(); pm_runtime_get_sync(dev); @@ -1627,8 +1666,13 @@ static int fb_resume(struct device *dev) if (par->blank == FB_BLANK_UNBLANK) { lcd_enable_raster(); - if (par->panel_power_ctrl) + if (par->panel_power_ctrl) { par->panel_power_ctrl(1); + } else if (par->lcd_supply) { + ret = regulator_enable(par->lcd_supply); + if (ret) + return ret; + } } fb_set_suspend(info, 0); -- cgit From 3fca9e0be9b5b7f4ccd5f71941143d9719047a05 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Jul 2019 15:44:20 +0200 Subject: fbdev: da8xx: remove panel_power_ctrl() callback from platform data There are no more users of panel_power_ctrl(). Remove it from the driver. Signed-off-by: Bartosz Golaszewski Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sekhar Nori --- drivers/video/fbdev/da8xx-fb.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index 02dfe9e32eed..19ed9889c8f8 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -165,7 +165,6 @@ struct da8xx_fb_par { struct notifier_block freq_transition; #endif unsigned int lcdc_clk_rate; - void (*panel_power_ctrl)(int); struct regulator *lcd_supply; u32 pseudo_palette[16]; struct fb_videomode mode; @@ -1076,9 +1075,7 @@ static int fb_remove(struct platform_device *dev) #ifdef CONFIG_CPU_FREQ lcd_da8xx_cpufreq_deregister(par); #endif - if (par->panel_power_ctrl) { - par->panel_power_ctrl(0); - } else if (par->lcd_supply) { + if (par->lcd_supply) { ret = regulator_disable(par->lcd_supply); if (ret) return ret; @@ -1187,9 +1184,7 @@ static int cfb_blank(int blank, struct fb_info *info) case FB_BLANK_UNBLANK: lcd_enable_raster(); - if (par->panel_power_ctrl) { - par->panel_power_ctrl(1); - } else if (par->lcd_supply) { + if (par->lcd_supply) { ret = regulator_enable(par->lcd_supply); if (ret) return ret; @@ -1199,9 +1194,7 @@ static int cfb_blank(int blank, struct fb_info *info) case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: - if (par->panel_power_ctrl) { - par->panel_power_ctrl(0); - } else if (par->lcd_supply) { + if (par->lcd_supply) { ret = regulator_disable(par->lcd_supply); if (ret) return ret; @@ -1413,10 +1406,6 @@ static int fb_probe(struct platform_device *device) par->dev = &device->dev; par->lcdc_clk = tmp_lcdc_clk; par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); - if (fb_pdata->panel_power_ctrl) { - par->panel_power_ctrl = fb_pdata->panel_power_ctrl; - par->panel_power_ctrl(1); - } par->lcd_supply = devm_regulator_get_optional(&device->dev, "lcd"); if (IS_ERR(par->lcd_supply)) { @@ -1638,9 +1627,7 @@ static int fb_suspend(struct device *dev) int ret; console_lock(); - if (par->panel_power_ctrl) { - par->panel_power_ctrl(0); - } else if (par->lcd_supply) { + if (par->lcd_supply) { ret = regulator_disable(par->lcd_supply); if (ret) return ret; @@ -1666,9 +1653,7 @@ static int fb_resume(struct device *dev) if (par->blank == FB_BLANK_UNBLANK) { lcd_enable_raster(); - if (par->panel_power_ctrl) { - par->panel_power_ctrl(1); - } else if (par->lcd_supply) { + if (par->lcd_supply) { ret = regulator_enable(par->lcd_supply); if (ret) return ret; -- cgit From c957c88f7be109a14294289f013b03bbe94e8af5 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Jul 2019 15:44:21 +0200 Subject: fbdev: da8xx-fb: use devm_platform_ioremap_resource() Shrink the code a bit by using the new helper wrapping the calls to platform_get_resource() and devm_ioremap_resource() together. Signed-off-by: Bartosz Golaszewski Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sekhar Nori --- drivers/video/fbdev/da8xx-fb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index 19ed9889c8f8..f2f66605e8fb 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -1339,7 +1339,6 @@ static int fb_probe(struct platform_device *device) { struct da8xx_lcdc_platform_data *fb_pdata = dev_get_platdata(&device->dev); - struct resource *lcdc_regs; struct lcd_ctrl_config *lcd_cfg; struct fb_videomode *lcdc_info; struct fb_info *da8xx_fb_info; @@ -1357,8 +1356,7 @@ static int fb_probe(struct platform_device *device) if (lcdc_info == NULL) return -ENODEV; - lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); - da8xx_fb_reg_base = devm_ioremap_resource(&device->dev, lcdc_regs); + da8xx_fb_reg_base = devm_platform_ioremap_resource(device, 0); if (IS_ERR(da8xx_fb_reg_base)) return PTR_ERR(da8xx_fb_reg_base); -- cgit From 8a3665f72d77867745099178a40200dd548161e5 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Jul 2019 15:44:22 +0200 Subject: fbdev: da8xx-fb: drop a redundant if The driver data is always set in probe. The remove() callback won't be called if probe failed which is the only way for it to be NULL. Remove the redundant if. Signed-off-by: Bartosz Golaszewski Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sekhar Nori --- drivers/video/fbdev/da8xx-fb.c | 43 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index f2f66605e8fb..d14ea6f91371 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -1067,37 +1067,34 @@ static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) static int fb_remove(struct platform_device *dev) { struct fb_info *info = dev_get_drvdata(&dev->dev); + struct da8xx_fb_par *par = info->par; int ret; - if (info) { - struct da8xx_fb_par *par = info->par; - #ifdef CONFIG_CPU_FREQ - lcd_da8xx_cpufreq_deregister(par); + lcd_da8xx_cpufreq_deregister(par); #endif - if (par->lcd_supply) { - ret = regulator_disable(par->lcd_supply); - if (ret) - return ret; - } + if (par->lcd_supply) { + ret = regulator_disable(par->lcd_supply); + if (ret) + return ret; + } - lcd_disable_raster(DA8XX_FRAME_WAIT); - lcdc_write(0, LCD_RASTER_CTRL_REG); + lcd_disable_raster(DA8XX_FRAME_WAIT); + lcdc_write(0, LCD_RASTER_CTRL_REG); - /* disable DMA */ - lcdc_write(0, LCD_DMA_CTRL_REG); + /* disable DMA */ + lcdc_write(0, LCD_DMA_CTRL_REG); - unregister_framebuffer(info); - fb_dealloc_cmap(&info->cmap); - dma_free_coherent(par->dev, PALETTE_SIZE, par->v_palette_base, - par->p_palette_base); - dma_free_coherent(par->dev, par->vram_size, par->vram_virt, - par->vram_phys); - pm_runtime_put_sync(&dev->dev); - pm_runtime_disable(&dev->dev); - framebuffer_release(info); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + dma_free_coherent(par->dev, PALETTE_SIZE, par->v_palette_base, + par->p_palette_base); + dma_free_coherent(par->dev, par->vram_size, par->vram_virt, + par->vram_phys); + pm_runtime_put_sync(&dev->dev); + pm_runtime_disable(&dev->dev); + framebuffer_release(info); - } return 0; } -- cgit From 671da5f3444b09779f108d28cc69414c57deab8c Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Jul 2019 15:44:23 +0200 Subject: fbdev: da8xx: use resource management for dma Use managed variants of dma alloc functions in the da8xx fbdev driver. Signed-off-by: Bartosz Golaszewski Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sekhar Nori --- drivers/video/fbdev/da8xx-fb.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index d14ea6f91371..2d3dcc52fcf3 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -1087,10 +1087,6 @@ static int fb_remove(struct platform_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); - dma_free_coherent(par->dev, PALETTE_SIZE, par->v_palette_base, - par->p_palette_base); - dma_free_coherent(par->dev, par->vram_size, par->vram_virt, - par->vram_phys); pm_runtime_put_sync(&dev->dev); pm_runtime_disable(&dev->dev); framebuffer_release(info); @@ -1427,10 +1423,10 @@ static int fb_probe(struct platform_device *device) par->vram_size = roundup(par->vram_size/8, ulcm); par->vram_size = par->vram_size * LCD_NUM_BUFFERS; - par->vram_virt = dma_alloc_coherent(par->dev, - par->vram_size, - &par->vram_phys, - GFP_KERNEL | GFP_DMA); + par->vram_virt = dmam_alloc_coherent(par->dev, + par->vram_size, + &par->vram_phys, + GFP_KERNEL | GFP_DMA); if (!par->vram_virt) { dev_err(&device->dev, "GLCD: kmalloc for frame buffer failed\n"); @@ -1448,20 +1444,20 @@ static int fb_probe(struct platform_device *device) da8xx_fb_fix.line_length - 1; /* allocate palette buffer */ - par->v_palette_base = dma_alloc_coherent(par->dev, PALETTE_SIZE, - &par->p_palette_base, - GFP_KERNEL | GFP_DMA); + par->v_palette_base = dmam_alloc_coherent(par->dev, PALETTE_SIZE, + &par->p_palette_base, + GFP_KERNEL | GFP_DMA); if (!par->v_palette_base) { dev_err(&device->dev, "GLCD: kmalloc for palette buffer failed\n"); ret = -EINVAL; - goto err_release_fb_mem; + goto err_release_fb; } par->irq = platform_get_irq(device, 0); if (par->irq < 0) { ret = -ENOENT; - goto err_release_pl_mem; + goto err_release_fb; } da8xx_fb_var.grayscale = @@ -1479,7 +1475,7 @@ static int fb_probe(struct platform_device *device) ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); if (ret) - goto err_release_pl_mem; + goto err_release_fb; da8xx_fb_info->cmap.len = par->palette_sz; /* initialize var_screeninfo */ @@ -1533,14 +1529,6 @@ err_cpu_freq: err_dealloc_cmap: fb_dealloc_cmap(&da8xx_fb_info->cmap); -err_release_pl_mem: - dma_free_coherent(par->dev, PALETTE_SIZE, par->v_palette_base, - par->p_palette_base); - -err_release_fb_mem: - dma_free_coherent(par->dev, par->vram_size, par->vram_virt, - par->vram_phys); - err_release_fb: framebuffer_release(da8xx_fb_info); -- cgit From c7b46e0c33c594623a279db4e1725d7ae477280f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Aug 2019 22:27:37 +0200 Subject: fbdev: remove w90x900/nuc900 platform drivers The ARM w90x900 platform is getting removed, so this driver is obsolete. Link: https://lore.kernel.org/r/20190809202749.742267-10-arnd@arndb.de Signed-off-by: Arnd Bergmann Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Arnd Bergmann --- drivers/video/fbdev/Kconfig | 14 - drivers/video/fbdev/Makefile | 1 - drivers/video/fbdev/nuc900fb.c | 760 ----------------------------------------- drivers/video/fbdev/nuc900fb.h | 51 --- 4 files changed, 826 deletions(-) delete mode 100644 drivers/video/fbdev/nuc900fb.c delete mode 100644 drivers/video/fbdev/nuc900fb.h (limited to 'drivers/video') diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 6b2de93bd302..5f83cd715387 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1924,20 +1924,6 @@ config FB_S3C2410_DEBUG Turn on debugging messages. Note that you can set/unset at run time through sysfs -config FB_NUC900 - tristate "NUC900 LCD framebuffer support" - depends on FB && ARCH_W90X900 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Nuvoton - NUC900 processor - -config GPM1040A0_320X240 - bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD" - depends on FB_NUC900 - config FB_SM501 tristate "Silicon Motion SM501 framebuffer support" depends on FB && MFD_SM501 diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 7dc4861a93e6..aab7155884ea 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -116,7 +116,6 @@ obj-y += omap2/ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ -obj-$(CONFIG_FB_NUC900) += nuc900fb.o obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o diff --git a/drivers/video/fbdev/nuc900fb.c b/drivers/video/fbdev/nuc900fb.c deleted file mode 100644 index 4fd851598584..000000000000 --- a/drivers/video/fbdev/nuc900fb.c +++ /dev/null @@ -1,760 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * Copyright (c) 2009 Nuvoton technology corporation - * All rights reserved. - * - * Description: - * Nuvoton LCD Controller Driver - * Author: - * Wang Qiang (rurality.linux@gmail.com) 2009/12/11 - */ -#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 - -#include "nuc900fb.h" - - -/* - * Initialize the nuc900 video (dual) buffer address - */ -static void nuc900fb_set_lcdaddr(struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - void __iomem *regs = fbi->io; - unsigned long vbaddr1, vbaddr2; - - vbaddr1 = info->fix.smem_start; - vbaddr2 = info->fix.smem_start; - vbaddr2 += info->fix.line_length * info->var.yres; - - /* set frambuffer start phy addr*/ - writel(vbaddr1, regs + REG_LCM_VA_BADDR0); - writel(vbaddr2, regs + REG_LCM_VA_BADDR1); - - writel(fbi->regs.lcd_va_fbctrl, regs + REG_LCM_VA_FBCTRL); - writel(fbi->regs.lcd_va_scale, regs + REG_LCM_VA_SCALE); -} - -/* - * calculate divider for lcd div - */ -static unsigned int nuc900fb_calc_pixclk(struct nuc900fb_info *fbi, - unsigned long pixclk) -{ - unsigned long clk = fbi->clk_rate; - unsigned long long div; - - /* pixclk is in picseconds. our clock is in Hz*/ - /* div = (clk * pixclk)/10^12 */ - div = (unsigned long long)clk * pixclk; - div >>= 12; - do_div(div, 625 * 625UL * 625); - - dev_dbg(fbi->dev, "pixclk %ld, divisor is %lld\n", pixclk, div); - - return div; -} - -/* - * Check the video params of 'var'. - */ -static int nuc900fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - struct nuc900fb_mach_info *mach_info = dev_get_platdata(fbi->dev); - struct nuc900fb_display *display = NULL; - struct nuc900fb_display *default_display = mach_info->displays + - mach_info->default_display; - int i; - - dev_dbg(fbi->dev, "check_var(var=%p, info=%p)\n", var, info); - - /* validate x/y resolution */ - /* choose default mode if possible */ - if (var->xres == default_display->xres && - var->yres == default_display->yres && - var->bits_per_pixel == default_display->bpp) - display = default_display; - else - for (i = 0; i < mach_info->num_displays; i++) - if (var->xres == mach_info->displays[i].xres && - var->yres == mach_info->displays[i].yres && - var->bits_per_pixel == mach_info->displays[i].bpp) { - display = mach_info->displays + i; - break; - } - - if (display == NULL) { - printk(KERN_ERR "wrong resolution or depth %dx%d at %d bit per pixel\n", - var->xres, var->yres, var->bits_per_pixel); - return -EINVAL; - } - - /* it should be the same size as the display */ - var->xres_virtual = display->xres; - var->yres_virtual = display->yres; - var->height = display->height; - var->width = display->width; - - /* copy lcd settings */ - var->pixclock = display->pixclock; - var->left_margin = display->left_margin; - var->right_margin = display->right_margin; - var->upper_margin = display->upper_margin; - var->lower_margin = display->lower_margin; - var->vsync_len = display->vsync_len; - var->hsync_len = display->hsync_len; - - var->transp.offset = 0; - var->transp.length = 0; - - fbi->regs.lcd_dccs = display->dccs; - fbi->regs.lcd_device_ctrl = display->devctl; - fbi->regs.lcd_va_fbctrl = display->fbctrl; - fbi->regs.lcd_va_scale = display->scale; - - /* set R/G/B possions */ - switch (var->bits_per_pixel) { - case 1: - case 2: - case 4: - case 8: - default: - var->red.offset = 0; - var->red.length = var->bits_per_pixel; - var->green = var->red; - var->blue = var->red; - break; - case 12: - var->red.length = 4; - var->green.length = 4; - var->blue.length = 4; - var->red.offset = 8; - var->green.offset = 4; - var->blue.offset = 0; - break; - case 16: - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - break; - case 18: - var->red.length = 6; - var->green.length = 6; - var->blue.length = 6; - var->red.offset = 12; - var->green.offset = 6; - var->blue.offset = 0; - break; - case 32: - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - break; - } - - return 0; -} - -/* - * Calculate lcd register values from var setting & save into hw - */ -static void nuc900fb_calculate_lcd_regs(const struct fb_info *info, - struct nuc900fb_hw *regs) -{ - const struct fb_var_screeninfo *var = &info->var; - int vtt = var->height + var->upper_margin + var->lower_margin; - int htt = var->width + var->left_margin + var->right_margin; - int hsync = var->width + var->right_margin; - int vsync = var->height + var->lower_margin; - - regs->lcd_crtc_size = LCM_CRTC_SIZE_VTTVAL(vtt) | - LCM_CRTC_SIZE_HTTVAL(htt); - regs->lcd_crtc_dend = LCM_CRTC_DEND_VDENDVAL(var->height) | - LCM_CRTC_DEND_HDENDVAL(var->width); - regs->lcd_crtc_hr = LCM_CRTC_HR_EVAL(var->width + 5) | - LCM_CRTC_HR_SVAL(var->width + 1); - regs->lcd_crtc_hsync = LCM_CRTC_HSYNC_EVAL(hsync + var->hsync_len) | - LCM_CRTC_HSYNC_SVAL(hsync); - regs->lcd_crtc_vr = LCM_CRTC_VR_EVAL(vsync + var->vsync_len) | - LCM_CRTC_VR_SVAL(vsync); - -} - -/* - * Activate (set) the controller from the given framebuffer - * information - */ -static void nuc900fb_activate_var(struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - void __iomem *regs = fbi->io; - struct fb_var_screeninfo *var = &info->var; - int clkdiv; - - clkdiv = nuc900fb_calc_pixclk(fbi, var->pixclock) - 1; - if (clkdiv < 0) - clkdiv = 0; - - nuc900fb_calculate_lcd_regs(info, &fbi->regs); - - /* set the new lcd registers*/ - - dev_dbg(fbi->dev, "new lcd register set:\n"); - dev_dbg(fbi->dev, "dccs = 0x%08x\n", fbi->regs.lcd_dccs); - dev_dbg(fbi->dev, "dev_ctl = 0x%08x\n", fbi->regs.lcd_device_ctrl); - dev_dbg(fbi->dev, "crtc_size = 0x%08x\n", fbi->regs.lcd_crtc_size); - dev_dbg(fbi->dev, "crtc_dend = 0x%08x\n", fbi->regs.lcd_crtc_dend); - dev_dbg(fbi->dev, "crtc_hr = 0x%08x\n", fbi->regs.lcd_crtc_hr); - dev_dbg(fbi->dev, "crtc_hsync = 0x%08x\n", fbi->regs.lcd_crtc_hsync); - dev_dbg(fbi->dev, "crtc_vr = 0x%08x\n", fbi->regs.lcd_crtc_vr); - - writel(fbi->regs.lcd_device_ctrl, regs + REG_LCM_DEV_CTRL); - writel(fbi->regs.lcd_crtc_size, regs + REG_LCM_CRTC_SIZE); - writel(fbi->regs.lcd_crtc_dend, regs + REG_LCM_CRTC_DEND); - writel(fbi->regs.lcd_crtc_hr, regs + REG_LCM_CRTC_HR); - writel(fbi->regs.lcd_crtc_hsync, regs + REG_LCM_CRTC_HSYNC); - writel(fbi->regs.lcd_crtc_vr, regs + REG_LCM_CRTC_VR); - - /* set lcd address pointers */ - nuc900fb_set_lcdaddr(info); - - writel(fbi->regs.lcd_dccs, regs + REG_LCM_DCCS); -} - -/* - * Alters the hardware state. - * - */ -static int nuc900fb_set_par(struct fb_info *info) -{ - struct fb_var_screeninfo *var = &info->var; - - switch (var->bits_per_pixel) { - case 32: - case 24: - case 18: - case 16: - case 12: - info->fix.visual = FB_VISUAL_TRUECOLOR; - break; - case 1: - info->fix.visual = FB_VISUAL_MONO01; - break; - default: - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - } - - info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; - - /* activate this new configuration */ - nuc900fb_activate_var(info); - return 0; -} - -static inline unsigned int chan_to_field(unsigned int chan, - struct fb_bitfield *bf) -{ - chan &= 0xffff; - chan >>= 16 - bf->length; - return chan << bf->offset; -} - -static int nuc900fb_setcolreg(unsigned regno, - unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) -{ - unsigned int val; - - switch (info->fix.visual) { - case FB_VISUAL_TRUECOLOR: - /* true-colour, use pseuo-palette */ - if (regno < 16) { - u32 *pal = info->pseudo_palette; - - val = chan_to_field(red, &info->var.red); - val |= chan_to_field(green, &info->var.green); - val |= chan_to_field(blue, &info->var.blue); - pal[regno] = val; - } - break; - - default: - return 1; /* unknown type */ - } - return 0; -} - -/** - * nuc900fb_blank - * - */ -static int nuc900fb_blank(int blank_mode, struct fb_info *info) -{ - - return 0; -} - -static struct fb_ops nuc900fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = nuc900fb_check_var, - .fb_set_par = nuc900fb_set_par, - .fb_blank = nuc900fb_blank, - .fb_setcolreg = nuc900fb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - - -static inline void modify_gpio(void __iomem *reg, - unsigned long set, unsigned long mask) -{ - unsigned long tmp; - tmp = readl(reg) & ~mask; - writel(tmp | set, reg); -} - -/* - * Initialise LCD-related registers - */ -static int nuc900fb_init_registers(struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - struct nuc900fb_mach_info *mach_info = dev_get_platdata(fbi->dev); - void __iomem *regs = fbi->io; - - /*reset the display engine*/ - writel(0, regs + REG_LCM_DCCS); - writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_ENG_RST, - regs + REG_LCM_DCCS); - ndelay(100); - writel(readl(regs + REG_LCM_DCCS) & (~LCM_DCCS_ENG_RST), - regs + REG_LCM_DCCS); - ndelay(100); - - writel(0, regs + REG_LCM_DEV_CTRL); - - /* config gpio output */ - modify_gpio(W90X900_VA_GPIO + 0x54, mach_info->gpio_dir, - mach_info->gpio_dir_mask); - modify_gpio(W90X900_VA_GPIO + 0x58, mach_info->gpio_data, - mach_info->gpio_data_mask); - - return 0; -} - - -/* - * Alloc the SDRAM region of NUC900 for the frame buffer. - * The buffer should be a non-cached, non-buffered, memory region - * to allow palette and pixel writes without flushing the cache. - */ -static int nuc900fb_map_video_memory(struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - dma_addr_t map_dma; - unsigned long map_size = PAGE_ALIGN(info->fix.smem_len); - - dev_dbg(fbi->dev, "nuc900fb_map_video_memory(fbi=%p) map_size %lu\n", - fbi, map_size); - - info->screen_base = dma_alloc_wc(fbi->dev, map_size, &map_dma, - GFP_KERNEL); - - if (!info->screen_base) - return -ENOMEM; - - memset(info->screen_base, 0x00, map_size); - info->fix.smem_start = map_dma; - - return 0; -} - -static inline void nuc900fb_unmap_video_memory(struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len), - info->screen_base, info->fix.smem_start); -} - -static irqreturn_t nuc900fb_irqhandler(int irq, void *dev_id) -{ - struct nuc900fb_info *fbi = dev_id; - void __iomem *regs = fbi->io; - void __iomem *irq_base = fbi->irq_base; - unsigned long lcdirq = readl(regs + REG_LCM_INT_CS); - - if (lcdirq & LCM_INT_CS_DISP_F_STATUS) { - writel(readl(irq_base) | 1<<30, irq_base); - - /* wait VA_EN low */ - if ((readl(regs + REG_LCM_DCCS) & - LCM_DCCS_SINGLE) == LCM_DCCS_SINGLE) - while ((readl(regs + REG_LCM_DCCS) & - LCM_DCCS_VA_EN) == LCM_DCCS_VA_EN) - ; - /* display_out-enable */ - writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_DISP_OUT_EN, - regs + REG_LCM_DCCS); - /* va-enable*/ - writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_VA_EN, - regs + REG_LCM_DCCS); - } else if (lcdirq & LCM_INT_CS_UNDERRUN_INT) { - writel(readl(irq_base) | LCM_INT_CS_UNDERRUN_INT, irq_base); - } else if (lcdirq & LCM_INT_CS_BUS_ERROR_INT) { - writel(readl(irq_base) | LCM_INT_CS_BUS_ERROR_INT, irq_base); - } - - return IRQ_HANDLED; -} - -#ifdef CONFIG_CPU_FREQ - -static int nuc900fb_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct nuc900fb_info *info; - struct fb_info *fbinfo; - long delta_f; - info = container_of(nb, struct nuc900fb_info, freq_transition); - fbinfo = dev_get_drvdata(info->dev); - - delta_f = info->clk_rate - clk_get_rate(info->clk); - - if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) || - (val == CPUFREQ_PRECHANGE && delta_f < 0)) { - info->clk_rate = clk_get_rate(info->clk); - nuc900fb_activate_var(fbinfo); - } - - return 0; -} - -static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi) -{ - fbi->freq_transition.notifier_call = nuc900fb_cpufreq_transition; - return cpufreq_register_notifier(&fbi->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *fbi) -{ - cpufreq_unregister_notifier(&fbi->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} -#else -static inline int nuc900fb_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - return 0; -} - -static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi) -{ - return 0; -} - -static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *info) -{ -} -#endif - -static char driver_name[] = "nuc900fb"; - -static int nuc900fb_probe(struct platform_device *pdev) -{ - struct nuc900fb_info *fbi; - struct nuc900fb_display *display; - struct fb_info *fbinfo; - struct nuc900fb_mach_info *mach_info; - struct resource *res; - int ret; - int irq; - int i; - int size; - - dev_dbg(&pdev->dev, "devinit\n"); - mach_info = dev_get_platdata(&pdev->dev); - if (mach_info == NULL) { - dev_err(&pdev->dev, - "no platform data for lcd, cannot attach\n"); - return -EINVAL; - } - - if (mach_info->default_display > mach_info->num_displays) { - dev_err(&pdev->dev, - "default display No. is %d but only %d displays \n", - mach_info->default_display, mach_info->num_displays); - return -EINVAL; - } - - - display = mach_info->displays + mach_info->default_display; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for device\n"); - return -ENOENT; - } - - fbinfo = framebuffer_alloc(sizeof(struct nuc900fb_info), &pdev->dev); - if (!fbinfo) - return -ENOMEM; - - platform_set_drvdata(pdev, fbinfo); - - fbi = fbinfo->par; - fbi->dev = &pdev->dev; - -#ifdef CONFIG_CPU_NUC950 - fbi->drv_type = LCDDRV_NUC950; -#endif - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - size = resource_size(res); - fbi->mem = request_mem_region(res->start, size, pdev->name); - if (fbi->mem == NULL) { - dev_err(&pdev->dev, "failed to alloc memory region\n"); - ret = -ENOENT; - goto free_fb; - } - - fbi->io = ioremap(res->start, size); - if (fbi->io == NULL) { - dev_err(&pdev->dev, "ioremap() of lcd registers failed\n"); - ret = -ENXIO; - goto release_mem_region; - } - - fbi->irq_base = fbi->io + REG_LCM_INT_CS; - - - /* Stop the LCD */ - writel(0, fbi->io + REG_LCM_DCCS); - - /* fill the fbinfo*/ - strcpy(fbinfo->fix.id, driver_name); - fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; - fbinfo->fix.type_aux = 0; - fbinfo->fix.xpanstep = 0; - fbinfo->fix.ypanstep = 0; - fbinfo->fix.ywrapstep = 0; - fbinfo->fix.accel = FB_ACCEL_NONE; - fbinfo->var.nonstd = 0; - fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.accel_flags = 0; - fbinfo->var.vmode = FB_VMODE_NONINTERLACED; - fbinfo->fbops = &nuc900fb_ops; - fbinfo->flags = FBINFO_FLAG_DEFAULT; - fbinfo->pseudo_palette = &fbi->pseudo_pal; - - ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi); - if (ret) { - dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n", - irq, ret); - ret = -EBUSY; - goto release_regs; - } - - fbi->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(fbi->clk)) { - printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n"); - ret = PTR_ERR(fbi->clk); - goto release_irq; - } - - clk_enable(fbi->clk); - dev_dbg(&pdev->dev, "got and enabled clock\n"); - - fbi->clk_rate = clk_get_rate(fbi->clk); - - /* calutate the video buffer size */ - for (i = 0; i < mach_info->num_displays; i++) { - unsigned long smem_len = mach_info->displays[i].xres; - smem_len *= mach_info->displays[i].yres; - smem_len *= mach_info->displays[i].bpp; - smem_len >>= 3; - if (fbinfo->fix.smem_len < smem_len) - fbinfo->fix.smem_len = smem_len; - } - - /* Initialize Video Memory */ - ret = nuc900fb_map_video_memory(fbinfo); - if (ret) { - printk(KERN_ERR "Failed to allocate video RAM: %x\n", ret); - goto release_clock; - } - - dev_dbg(&pdev->dev, "got video memory\n"); - - fbinfo->var.xres = display->xres; - fbinfo->var.yres = display->yres; - fbinfo->var.bits_per_pixel = display->bpp; - - nuc900fb_init_registers(fbinfo); - - nuc900fb_check_var(&fbinfo->var, fbinfo); - - ret = nuc900fb_cpufreq_register(fbi); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register cpufreq\n"); - goto free_video_memory; - } - - ret = register_framebuffer(fbinfo); - if (ret) { - printk(KERN_ERR "failed to register framebuffer device: %d\n", - ret); - goto free_cpufreq; - } - - fb_info(fbinfo, "%s frame buffer device\n", fbinfo->fix.id); - - return 0; - -free_cpufreq: - nuc900fb_cpufreq_deregister(fbi); -free_video_memory: - nuc900fb_unmap_video_memory(fbinfo); -release_clock: - clk_disable(fbi->clk); - clk_put(fbi->clk); -release_irq: - free_irq(irq, fbi); -release_regs: - iounmap(fbi->io); -release_mem_region: - release_mem_region(res->start, size); -free_fb: - framebuffer_release(fbinfo); - return ret; -} - -/* - * shutdown the lcd controller - */ -static void nuc900fb_stop_lcd(struct fb_info *info) -{ - struct nuc900fb_info *fbi = info->par; - void __iomem *regs = fbi->io; - - writel((~LCM_DCCS_DISP_INT_EN) | (~LCM_DCCS_VA_EN) | (~LCM_DCCS_OSD_EN), - regs + REG_LCM_DCCS); -} - -/* - * Cleanup - */ -static int nuc900fb_remove(struct platform_device *pdev) -{ - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct nuc900fb_info *fbi = fbinfo->par; - int irq; - - nuc900fb_stop_lcd(fbinfo); - msleep(1); - - unregister_framebuffer(fbinfo); - nuc900fb_cpufreq_deregister(fbi); - nuc900fb_unmap_video_memory(fbinfo); - - iounmap(fbi->io); - - irq = platform_get_irq(pdev, 0); - free_irq(irq, fbi); - - release_resource(fbi->mem); - kfree(fbi->mem); - - framebuffer_release(fbinfo); - - return 0; -} - -#ifdef CONFIG_PM - -/* - * suspend and resume support for the lcd controller - */ - -static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct fb_info *fbinfo = platform_get_drvdata(dev); - struct nuc900fb_info *info = fbinfo->par; - - nuc900fb_stop_lcd(fbinfo); - msleep(1); - clk_disable(info->clk); - return 0; -} - -static int nuc900fb_resume(struct platform_device *dev) -{ - struct fb_info *fbinfo = platform_get_drvdata(dev); - struct nuc900fb_info *fbi = fbinfo->par; - - printk(KERN_INFO "nuc900fb resume\n"); - - clk_enable(fbi->clk); - msleep(1); - - nuc900fb_init_registers(fbinfo); - nuc900fb_activate_var(fbinfo); - - return 0; -} - -#else -#define nuc900fb_suspend NULL -#define nuc900fb_resume NULL -#endif - -static struct platform_driver nuc900fb_driver = { - .probe = nuc900fb_probe, - .remove = nuc900fb_remove, - .suspend = nuc900fb_suspend, - .resume = nuc900fb_resume, - .driver = { - .name = "nuc900-lcd", - }, -}; - -module_platform_driver(nuc900fb_driver); - -MODULE_DESCRIPTION("Framebuffer driver for the NUC900"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/nuc900fb.h b/drivers/video/fbdev/nuc900fb.h deleted file mode 100644 index 055ae9297931..000000000000 --- a/drivers/video/fbdev/nuc900fb.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * - * Copyright (c) 2009 Nuvoton technology corporation - * All rights reserved. - * - * Author: - * Wang Qiang(rurality.linux@gmail.com) 2009/12/16 - */ - -#ifndef __NUC900FB_H -#define __NUC900FB_H - -#include -#include - -enum nuc900_lcddrv_type { - LCDDRV_NUC910, - LCDDRV_NUC930, - LCDDRV_NUC932, - LCDDRV_NUC950, - LCDDRV_NUC960, -}; - - -#define PALETTE_BUFFER_SIZE 256 -#define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */ - -struct nuc900fb_info { - struct device *dev; - struct clk *clk; - - struct resource *mem; - void __iomem *io; - void __iomem *irq_base; - int drv_type; - struct nuc900fb_hw regs; - unsigned long clk_rate; - -#ifdef CONFIG_CPU_FREQ - struct notifier_block freq_transition; -#endif - - /* keep these registers in case we need to re-write palette */ - u32 palette_buffer[PALETTE_BUFFER_SIZE]; - u32 pseudo_pal[16]; -}; - -int nuc900fb_init(void); - -#endif /* __NUC900FB_H */ -- cgit