diff options
Diffstat (limited to 'drivers/video')
26 files changed, 950 insertions, 751 deletions
diff --git a/drivers/video/fbdev/68328fb.c b/drivers/video/fbdev/68328fb.c index 552258c8f99d..17f21cedff9b 100644 --- a/drivers/video/fbdev/68328fb.c +++ b/drivers/video/fbdev/68328fb.c @@ -49,12 +49,6 @@ #error wrong architecture for the MC68x328 frame buffer device #endif -#if defined(CONFIG_FB_68328_INVERT) -#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO01 -#else -#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO10 -#endif - static u_long videomemory; static u_long videomemorysize; @@ -462,7 +456,7 @@ int __init mc68x328fb_init(void) fb_info.fix.line_length = get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? - MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR; + FB_VISUAL_MONO10 : FB_VISUAL_PSEUDOCOLOR; if (fb_info.var.bits_per_pixel == 1) { fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index e05a58d759be..e911b9c96e19 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -280,6 +280,8 @@ config FB_ARMCLCD select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select FB_MODE_HELPERS if OF + select VIDEOMODE_HELPERS if OF help This framebuffer device driver is for the ARM PrimeCell PL110 Colour LCD controller. ARM PrimeCells provide the building @@ -307,15 +309,26 @@ config FB_ACORN hardware found in Acorn RISC PCs and other ARM-based machines. If unsure, say N. -config FB_CLPS711X - bool "CLPS711X LCD support" - depends on (FB = y) && ARM && ARCH_CLPS711X +config FB_CLPS711X_OLD + tristate select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + +config FB_CLPS711X + tristate "CLPS711X LCD support" + depends on FB && (ARCH_CLPS711X || COMPILE_TEST) + select FB_CLPS711X_OLD if ARCH_CLPS711X && !ARCH_MULTIPLATFORM + select BACKLIGHT_LCD_SUPPORT + select FB_MODE_HELPERS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select LCD_CLASS_DEVICE + select VIDEOMODE_HELPERS help - Say Y to enable the Framebuffer driver for the CLPS7111 and - EP7212 processors. + Say Y to enable the Framebuffer driver for the Cirrus Logic + CLPS711X CPUs. config FB_SA1100 bool "SA-1100 LCD support" diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 0b2090d2e52e..1979afffccfe 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -14,7 +14,8 @@ obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o # Hardware specific drivers go first obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o obj-$(CONFIG_FB_ARC) += arcfb.o -obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o +obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o +obj-$(CONFIG_FB_CLPS711X_OLD) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_GRVGA) += grvga.o obj-$(CONFIG_FB_PM2) += pm2fb.o diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index 14d6b3793e0a..beadd3edaa17 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -26,6 +26,13 @@ #include <linux/amba/clcd.h> #include <linux/clk.h> #include <linux/hardirq.h> +#include <linux/dma-mapping.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_graph.h> +#include <video/display_timing.h> +#include <video/of_display_timing.h> +#include <video/videomode.h> #include <asm/sizes.h> @@ -543,6 +550,259 @@ static int clcdfb_register(struct clcd_fb *fb) return ret; } +#ifdef CONFIG_OF +static int clcdfb_of_get_dpi_panel_mode(struct device_node *node, + struct fb_videomode *mode) +{ + int err; + struct display_timing timing; + struct videomode video; + + err = of_get_display_timing(node, "panel-timing", &timing); + if (err) + return err; + + videomode_from_timing(&timing, &video); + + err = fb_videomode_from_videomode(&video, mode); + if (err) + return err; + + return 0; +} + +static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode) +{ + return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres, + mode->refresh); +} + +static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint, + struct fb_videomode *mode) +{ + int err; + struct device_node *panel; + char *name; + int len; + + panel = of_graph_get_remote_port_parent(endpoint); + if (!panel) + return -ENODEV; + + /* Only directly connected DPI panels supported for now */ + if (of_device_is_compatible(panel, "panel-dpi")) + err = clcdfb_of_get_dpi_panel_mode(panel, mode); + else + err = -ENOENT; + if (err) + return err; + + len = clcdfb_snprintf_mode(NULL, 0, mode); + name = devm_kzalloc(dev, len + 1, GFP_KERNEL); + clcdfb_snprintf_mode(name, len + 1, mode); + mode->name = name; + + return 0; +} + +static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0) +{ + static struct { + unsigned int part; + u32 r0, g0, b0; + u32 caps; + } panels[] = { + { 0x110, 1, 7, 13, CLCD_CAP_5551 }, + { 0x110, 0, 8, 16, CLCD_CAP_888 }, + { 0x111, 4, 14, 20, CLCD_CAP_444 }, + { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 }, + { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 | + CLCD_CAP_565 }, + { 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 | + CLCD_CAP_565 | CLCD_CAP_888 }, + }; + int i; + + /* Bypass pixel clock divider, data output on the falling edge */ + fb->panel->tim2 = TIM2_BCD | TIM2_IPC; + + /* TFT display, vert. comp. interrupt at the start of the back porch */ + fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1); + + fb->panel->caps = 0; + + /* Match the setup with known variants */ + for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) { + if (amba_part(fb->dev) != panels[i].part) + continue; + if (g0 != panels[i].g0) + continue; + if (r0 == panels[i].r0 && b0 == panels[i].b0) + fb->panel->caps = panels[i].caps & CLCD_CAP_RGB; + if (r0 == panels[i].b0 && b0 == panels[i].r0) + fb->panel->caps = panels[i].caps & CLCD_CAP_BGR; + } + + return fb->panel->caps ? 0 : -EINVAL; +} + +static int clcdfb_of_init_display(struct clcd_fb *fb) +{ + struct device_node *endpoint; + int err; + u32 max_bandwidth; + u32 tft_r0b0g0[3]; + + fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL); + if (!fb->panel) + return -ENOMEM; + + endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL); + if (!endpoint) + return -ENODEV; + + err = clcdfb_of_get_mode(&fb->dev->dev, endpoint, &fb->panel->mode); + if (err) + return err; + + err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth", + &max_bandwidth); + if (!err) + fb->panel->bpp = 8 * max_bandwidth / (fb->panel->mode.xres * + fb->panel->mode.yres * fb->panel->mode.refresh); + else + fb->panel->bpp = 32; + +#ifdef CONFIG_CPU_BIG_ENDIAN + fb->panel->cntl |= CNTL_BEBO; +#endif + fb->panel->width = -1; + fb->panel->height = -1; + + if (of_property_read_u32_array(endpoint, + "arm,pl11x,tft-r0g0b0-pads", + tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) == 0) + return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0], + tft_r0b0g0[1], tft_r0b0g0[2]); + + return -ENOENT; +} + +static int clcdfb_of_vram_setup(struct clcd_fb *fb) +{ + int err; + struct device_node *memory; + u64 size; + + err = clcdfb_of_init_display(fb); + if (err) + return err; + + memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0); + if (!memory) + return -ENODEV; + + fb->fb.screen_base = of_iomap(memory, 0); + if (!fb->fb.screen_base) + return -ENOMEM; + + fb->fb.fix.smem_start = of_translate_address(memory, + of_get_address(memory, 0, &size, NULL)); + fb->fb.fix.smem_len = size; + + return 0; +} + +static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ + unsigned long off, user_size, kernel_size; + + + off = vma->vm_pgoff << PAGE_SHIFT; + user_size = vma->vm_end - vma->vm_start; + kernel_size = fb->fb.fix.smem_len; + + if (off >= kernel_size || user_size > (kernel_size - off)) + return -ENXIO; + + return remap_pfn_range(vma, vma->vm_start, + __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff, + user_size, + pgprot_writecombine(vma->vm_page_prot)); +} + +static void clcdfb_of_vram_remove(struct clcd_fb *fb) +{ + iounmap(fb->fb.screen_base); +} + +static int clcdfb_of_dma_setup(struct clcd_fb *fb) +{ + unsigned long framesize; + dma_addr_t dma; + int err; + + err = clcdfb_of_init_display(fb); + if (err) + return err; + + framesize = fb->panel->mode.xres * fb->panel->mode.yres * + fb->panel->bpp / 8; + fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize, + &dma, GFP_KERNEL); + if (!fb->fb.screen_base) + return -ENOMEM; + + fb->fb.fix.smem_start = dma; + fb->fb.fix.smem_len = framesize; + + return 0; +} + +static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ + return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base, + fb->fb.fix.smem_start, fb->fb.fix.smem_len); +} + +static void clcdfb_of_dma_remove(struct clcd_fb *fb) +{ + dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len, + fb->fb.screen_base, fb->fb.fix.smem_start); +} + +static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev) +{ + struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board), + GFP_KERNEL); + struct device_node *node = dev->dev.of_node; + + if (!board) + return NULL; + + board->name = of_node_full_name(node); + board->caps = CLCD_CAP_ALL; + board->check = clcdfb_check; + board->decode = clcdfb_decode; + if (of_find_property(node, "memory-region", NULL)) { + board->setup = clcdfb_of_vram_setup; + board->mmap = clcdfb_of_vram_mmap; + board->remove = clcdfb_of_vram_remove; + } else { + board->setup = clcdfb_of_dma_setup; + board->mmap = clcdfb_of_dma_mmap; + board->remove = clcdfb_of_dma_remove; + } + + return board; +} +#else +static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev) +{ + return NULL; +} +#endif + static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) { struct clcd_board *board = dev_get_platdata(&dev->dev); @@ -550,6 +810,9 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) int ret; if (!board) + board = clcdfb_of_get_board(dev); + + if (!board) return -EINVAL; ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index d36e830d6fc6..92640d46770a 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -290,7 +290,7 @@ static void init_contrast(struct atmel_lcdfb_info *sinfo) /* contrast pwm can be 'inverted' */ if (pdata->lcdcon_pol_negative) - contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); + contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); /* have some default contrast/backlight settings */ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); @@ -1097,6 +1097,7 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) pdata->lcd_wiring_mode = ret; pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight"); + pdata->lcdcon_pol_negative = of_property_read_bool(display_np, "atmel,lcdcon-backlight-inverted"); timings = of_get_display_timings(display_np); if (!timings) { diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c new file mode 100644 index 000000000000..49a7bb4ef02f --- /dev/null +++ b/drivers/video/fbdev/clps711x-fb.c @@ -0,0 +1,397 @@ +/* + * Cirrus Logic CLPS711X FB driver + * + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> + * Based on driver by Russell King <rmk@arm.linux.org.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/fb.h> +#include <linux/io.h> +#include <linux/lcd.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/clps711x.h> +#include <linux/regulator/consumer.h> +#include <video/of_display_timing.h> + +#define CLPS711X_FB_NAME "clps711x-fb" +#define CLPS711X_FB_BPP_MAX (4) + +/* Registers relative to LCDCON */ +#define CLPS711X_LCDCON (0x0000) +# define LCDCON_GSEN BIT(30) +# define LCDCON_GSMD BIT(31) +#define CLPS711X_PALLSW (0x0280) +#define CLPS711X_PALMSW (0x02c0) +#define CLPS711X_FBADDR (0x0d40) + +struct clps711x_fb_info { + struct clk *clk; + void __iomem *base; + struct regmap *syscon; + resource_size_t buffsize; + struct fb_videomode mode; + struct regulator *lcd_pwr; + u32 ac_prescale; + bool cmap_invert; +}; + +static int clps711x_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, struct fb_info *info) +{ + struct clps711x_fb_info *cfb = info->par; + u32 level, mask, shift; + + if (regno >= BIT(info->var.bits_per_pixel)) + return -EINVAL; + + shift = 4 * (regno & 7); + mask = 0xf << shift; + /* gray = 0.30*R + 0.58*G + 0.11*B */ + level = (((red * 77 + green * 151 + blue * 28) >> 20) << shift) & mask; + if (cfb->cmap_invert) + level = 0xf - level; + + regno = (regno < 8) ? CLPS711X_PALLSW : CLPS711X_PALMSW; + + writel((readl(cfb->base + regno) & ~mask) | level, cfb->base + regno); + + return 0; +} + +static int clps711x_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + u32 val; + + if (var->bits_per_pixel < 1 || + var->bits_per_pixel > CLPS711X_FB_BPP_MAX) + return -EINVAL; + + if (!var->pixclock) + return -EINVAL; + + val = DIV_ROUND_UP(var->xres, 16) - 1; + if (val < 0x01 || val > 0x3f) + return -EINVAL; + + val = DIV_ROUND_UP(var->yres * var->xres * var->bits_per_pixel, 128); + val--; + if (val < 0x001 || val > 0x1fff) + return -EINVAL; + + var->transp.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + var->red.msb_right = 0; + var->red.offset = 0; + var->red.length = var->bits_per_pixel; + var->green = var->red; + var->blue = var->red; + var->grayscale = var->bits_per_pixel > 1; + + return 0; +} + +static int clps711x_fb_set_par(struct fb_info *info) +{ + struct clps711x_fb_info *cfb = info->par; + resource_size_t size; + u32 lcdcon, pps; + + size = (info->var.xres * info->var.yres * info->var.bits_per_pixel) / 8; + if (size > cfb->buffsize) + return -EINVAL; + + switch (info->var.bits_per_pixel) { + case 1: + info->fix.visual = FB_VISUAL_MONO01; + break; + case 2: + case 4: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + default: + return -EINVAL; + } + + info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8; + info->fix.smem_len = size; + + lcdcon = (info->var.xres * info->var.yres * + info->var.bits_per_pixel) / 128 - 1; + lcdcon |= ((info->var.xres / 16) - 1) << 13; + lcdcon |= (cfb->ac_prescale & 0x1f) << 25; + + pps = clk_get_rate(cfb->clk) / (PICOS2KHZ(info->var.pixclock) * 1000); + if (pps) + pps--; + lcdcon |= (pps & 0x3f) << 19; + + if (info->var.bits_per_pixel == 4) + lcdcon |= LCDCON_GSMD; + if (info->var.bits_per_pixel >= 2) + lcdcon |= LCDCON_GSEN; + + /* LCDCON must only be changed while the LCD is disabled */ + regmap_update_bits(cfb->syscon, SYSCON_OFFSET, SYSCON1_LCDEN, 0); + writel(lcdcon, cfb->base + CLPS711X_LCDCON); + regmap_update_bits(cfb->syscon, SYSCON_OFFSET, + SYSCON1_LCDEN, SYSCON1_LCDEN); + + return 0; +} + +static int clps711x_fb_blank(int blank, struct fb_info *info) +{ + /* Return happy */ + return 0; +} + +static struct fb_ops clps711x_fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = clps711x_fb_setcolreg, + .fb_check_var = clps711x_fb_check_var, + .fb_set_par = clps711x_fb_set_par, + .fb_blank = clps711x_fb_blank, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, +}; + +static int clps711x_lcd_check_fb(struct lcd_device *lcddev, struct fb_info *fi) +{ + struct clps711x_fb_info *cfb = dev_get_drvdata(&lcddev->dev); + + return (!fi || fi->par == cfb) ? 1 : 0; +} + +static int clps711x_lcd_get_power(struct lcd_device *lcddev) +{ + struct clps711x_fb_info *cfb = dev_get_drvdata(&lcddev->dev); + + if (!IS_ERR_OR_NULL(cfb->lcd_pwr)) + if (!regulator_is_enabled(cfb->lcd_pwr)) + return FB_BLANK_NORMAL; + + return FB_BLANK_UNBLANK; +} + +static int clps711x_lcd_set_power(struct lcd_device *lcddev, int blank) +{ + struct clps711x_fb_info *cfb = dev_get_drvdata(&lcddev->dev); + + if (!IS_ERR_OR_NULL(cfb->lcd_pwr)) { + if (blank == FB_BLANK_UNBLANK) { + if (!regulator_is_enabled(cfb->lcd_pwr)) + return regulator_enable(cfb->lcd_pwr); + } else { + if (regulator_is_enabled(cfb->lcd_pwr)) + return regulator_disable(cfb->lcd_pwr); + } + } + + return 0; +} + +static struct lcd_ops clps711x_lcd_ops = { + .check_fb = clps711x_lcd_check_fb, + .get_power = clps711x_lcd_get_power, + .set_power = clps711x_lcd_set_power, +}; + +static int clps711x_fb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *disp, *np = dev->of_node; + struct clps711x_fb_info *cfb; + struct lcd_device *lcd; + struct fb_info *info; + struct resource *res; + int ret = -ENOENT; + u32 val; + + if (fb_get_options(CLPS711X_FB_NAME, NULL)) + return -ENODEV; + + info = framebuffer_alloc(sizeof(*cfb), dev); + if (!info) + return -ENOMEM; + + cfb = info->par; + platform_set_drvdata(pdev, info); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + goto out_fb_release; + cfb->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!cfb->base) { + ret = -ENOMEM; + goto out_fb_release; + } + + info->fix.mmio_start = res->start; + info->fix.mmio_len = resource_size(res); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + info->screen_base = devm_ioremap_resource(dev, res); + if (IS_ERR(info->screen_base)) { + ret = PTR_ERR(info->screen_base); + goto out_fb_release; + } + + /* Physical address should be aligned to 256 MiB */ + if (res->start & 0x0fffffff) { + ret = -EINVAL; + goto out_fb_release; + } + + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_fb_release; + } + + cfb->buffsize = resource_size(res); + info->fix.smem_start = res->start; + info->apertures->ranges[0].base = info->fix.smem_start; + info->apertures->ranges[0].size = cfb->buffsize; + + cfb->clk = devm_clk_get(dev, NULL); + if (IS_ERR(cfb->clk)) { + ret = PTR_ERR(cfb->clk); + goto out_fb_release; + } + + cfb->syscon = + syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1"); + if (IS_ERR(cfb->syscon)) { + ret = PTR_ERR(cfb->syscon); + goto out_fb_release; + } + + disp = of_parse_phandle(np, "display", 0); + if (!disp) { + dev_err(&pdev->dev, "No display defined\n"); + ret = -ENODATA; + goto out_fb_release; + } + + ret = of_get_fb_videomode(disp, &cfb->mode, OF_USE_NATIVE_MODE); + if (ret) + goto out_fb_release; + + of_property_read_u32(disp, "ac-prescale", &cfb->ac_prescale); + cfb->cmap_invert = of_property_read_bool(disp, "cmap-invert"); + + ret = of_property_read_u32(disp, "bits-per-pixel", + &info->var.bits_per_pixel); + if (ret) + goto out_fb_release; + + /* Force disable LCD on any mismatch */ + if (info->fix.smem_start != (readb(cfb->base + CLPS711X_FBADDR) << 28)) + regmap_update_bits(cfb->syscon, SYSCON_OFFSET, + SYSCON1_LCDEN, 0); + + ret = regmap_read(cfb->syscon, SYSCON_OFFSET, &val); + if (ret) + goto out_fb_release; + + if (!(val & SYSCON1_LCDEN)) { + /* Setup start FB address */ + writeb(info->fix.smem_start >> 28, cfb->base + CLPS711X_FBADDR); + /* Clean FB memory */ + memset_io(info->screen_base, 0, cfb->buffsize); + } + + cfb->lcd_pwr = devm_regulator_get(dev, "lcd"); + if (PTR_ERR(cfb->lcd_pwr) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_fb_release; + } + + info->fbops = &clps711x_fb_ops; + info->flags = FBINFO_DEFAULT; + info->var.activate = FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.vmode = FB_VMODE_NONINTERLACED; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.accel = FB_ACCEL_NONE; + strlcpy(info->fix.id, CLPS711X_FB_NAME, sizeof(info->fix.id)); + fb_videomode_to_var(&info->var, &cfb->mode); + + ret = fb_alloc_cmap(&info->cmap, BIT(CLPS711X_FB_BPP_MAX), 0); + if (ret) + goto out_fb_release; + + ret = fb_set_var(info, &info->var); + if (ret) + goto out_fb_dealloc_cmap; + + ret = register_framebuffer(info); + if (ret) + goto out_fb_dealloc_cmap; + + lcd = devm_lcd_device_register(dev, "clps711x-lcd", dev, cfb, + &clps711x_lcd_ops); + if (!IS_ERR(lcd)) + return 0; + + ret = PTR_ERR(lcd); + unregister_framebuffer(info); + +out_fb_dealloc_cmap: + regmap_update_bits(cfb->syscon, SYSCON_OFFSET, SYSCON1_LCDEN, 0); + fb_dealloc_cmap(&info->cmap); + +out_fb_release: + framebuffer_release(info); + + return ret; +} + +static int clps711x_fb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct clps711x_fb_info *cfb = info->par; + + regmap_update_bits(cfb->syscon, SYSCON_OFFSET, SYSCON1_LCDEN, 0); + + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + + return 0; +} + +static const struct of_device_id clps711x_fb_dt_ids[] = { + { .compatible = "cirrus,clps711x-fb", }, + { } +}; +MODULE_DEVICE_TABLE(of, clps711x_fb_dt_ids); + +static struct platform_driver clps711x_fb_driver = { + .driver = { + .name = CLPS711X_FB_NAME, + .owner = THIS_MODULE, + .of_match_table = clps711x_fb_dt_ids, + }, + .probe = clps711x_fb_probe, + .remove = clps711x_fb_remove, +}; +module_platform_driver(clps711x_fb_driver); + +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("Cirrus Logic CLPS711X FB driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index a8484f768d04..788f6b37fce7 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -1447,18 +1447,15 @@ static int fb_probe(struct platform_device *device) da8xx_fb_fix.line_length - 1; /* allocate palette buffer */ - par->v_palette_base = dma_alloc_coherent(NULL, - PALETTE_SIZE, - (resource_size_t *) - &par->p_palette_base, - GFP_KERNEL | GFP_DMA); + par->v_palette_base = dma_zalloc_coherent(NULL, PALETTE_SIZE, + (resource_size_t *)&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; } - memset(par->v_palette_base, 0, PALETTE_SIZE); par->irq = platform_get_irq(device, 0); if (par->irq < 0) { diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index e23392ec5af3..569e7562fa3d 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -224,6 +224,11 @@ struct hvfb_par { u32 pseudo_palette[16]; u8 init_buf[MAX_VMBUS_PKT_SIZE]; u8 recv_buf[MAX_VMBUS_PKT_SIZE]; + + /* If true, the VSC notifies the VSP on every framebuffer change */ + bool synchronous_fb; + + struct notifier_block hvfb_panic_nb; }; static uint screen_width = HVFB_WIDTH; @@ -532,6 +537,19 @@ static void hvfb_update_work(struct work_struct *w) schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY); } +static int hvfb_on_panic(struct notifier_block *nb, + unsigned long e, void *p) +{ + struct hvfb_par *par; + struct fb_info *info; + + par = container_of(nb, struct hvfb_par, hvfb_panic_nb); + par->synchronous_fb = true; + info = par->info; + synthvid_update(info); + + return NOTIFY_DONE; +} /* Framebuffer operation handlers */ @@ -582,14 +600,44 @@ static int hvfb_blank(int blank, struct fb_info *info) return 1; /* get fb_blank to set the colormap to all black */ } +static void hvfb_cfb_fillrect(struct fb_info *p, + const struct fb_fillrect *rect) +{ + struct hvfb_par *par = p->par; + + cfb_fillrect(p, rect); + if (par->synchronous_fb) + synthvid_update(p); +} + +static void hvfb_cfb_copyarea(struct fb_info *p, + const struct fb_copyarea *area) +{ + struct hvfb_par *par = p->par; + + cfb_copyarea(p, area); + if (par->synchronous_fb) + synthvid_update(p); +} + +static void hvfb_cfb_imageblit(struct fb_info *p, + const struct fb_image *image) +{ + struct hvfb_par *par = p->par; + + cfb_imageblit(p, image); + if (par->synchronous_fb) + synthvid_update(p); +} + static struct fb_ops hvfb_ops = { .owner = THIS_MODULE, .fb_check_var = hvfb_check_var, .fb_set_par = hvfb_set_par, .fb_setcolreg = hvfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = hvfb_cfb_fillrect, + .fb_copyarea = hvfb_cfb_copyarea, + .fb_imageblit = hvfb_cfb_imageblit, .fb_blank = hvfb_blank, }; @@ -801,6 +849,11 @@ static int hvfb_probe(struct hv_device *hdev, par->fb_ready = true; + par->synchronous_fb = false; + par->hvfb_panic_nb.notifier_call = hvfb_on_panic; + atomic_notifier_chain_register(&panic_notifier_list, + &par->hvfb_panic_nb); + return 0; error: @@ -820,6 +873,9 @@ static int hvfb_remove(struct hv_device *hdev) struct fb_info *info = hv_get_drvdata(hdev); struct hvfb_par *par = info->par; + atomic_notifier_chain_unregister(&panic_notifier_list, + &par->hvfb_panic_nb); + par->update = false; par->fb_ready = false; diff --git a/drivers/video/fbdev/mbx/mbxfb.c b/drivers/video/fbdev/mbx/mbxfb.c index 2bd52ed8832c..698df9543e30 100644 --- a/drivers/video/fbdev/mbx/mbxfb.c +++ b/drivers/video/fbdev/mbx/mbxfb.c @@ -628,14 +628,14 @@ static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, case MBXFB_IOCS_PLANEORDER: if (copy_from_user(&porder, (void __user*)arg, sizeof(struct mbxfb_planeorder))) - return -EFAULT; + return -EFAULT; return mbxfb_ioctl_planeorder(&porder); case MBXFB_IOCS_ALPHA: if (copy_from_user(&alpha, (void __user*)arg, sizeof(struct mbxfb_alphaCtl))) - return -EFAULT; + return -EFAULT; return mbxfb_ioctl_alphactl(&alpha); diff --git a/drivers/video/fbdev/msm/mddi_client_dummy.c b/drivers/video/fbdev/msm/mddi_client_dummy.c index f1b0dfcc9717..cdb8f69a5d88 100644 --- a/drivers/video/fbdev/msm/mddi_client_dummy.c +++ b/drivers/video/fbdev/msm/mddi_client_dummy.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include <linux/device.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/kernel.h> @@ -51,8 +52,7 @@ static int mddi_dummy_probe(struct platform_device *pdev) { struct msm_mddi_client_data *client_data = pdev->dev.platform_data; struct panel_info *panel = - kzalloc(sizeof(struct panel_info), GFP_KERNEL); - int ret; + devm_kzalloc(&pdev->dev, sizeof(struct panel_info), GFP_KERNEL); if (!panel) return -ENOMEM; platform_set_drvdata(pdev, panel); @@ -67,24 +67,11 @@ static int mddi_dummy_probe(struct platform_device *pdev) client_data->fb_resource, 1); panel->panel_data.fb_data = client_data->private_client_data; panel->pdev.dev.platform_data = &panel->panel_data; - ret = platform_device_register(&panel->pdev); - if (ret) { - kfree(panel); - return ret; - } - return 0; -} - -static int mddi_dummy_remove(struct platform_device *pdev) -{ - struct panel_info *panel = platform_get_drvdata(pdev); - kfree(panel); - return 0; + return platform_device_register(&panel->pdev); } static struct platform_driver mddi_client_dummy = { .probe = mddi_dummy_probe, - .remove = mddi_dummy_remove, .driver = { .name = "mddi_c_dummy" }, }; diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c index 4420ccb69aa9..131c6e260898 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c @@ -262,6 +262,23 @@ static int hdmic_audio_config(struct omap_dss_device *dssdev, return 0; } +static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + struct omap_dss_device *in = ddata->in; + + return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode); +} + +static int hdmic_set_infoframe(struct omap_dss_device *dssdev, + const struct hdmi_avi_infoframe *avi) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + struct omap_dss_device *in = ddata->in; + + return in->ops.hdmi->set_infoframe(in, avi); +} + static struct omap_dss_driver hdmic_driver = { .connect = hdmic_connect, .disconnect = hdmic_disconnect, @@ -277,6 +294,8 @@ static struct omap_dss_driver hdmic_driver = { .read_edid = hdmic_read_edid, .detect = hdmic_detect, + .set_hdmi_mode = hdmic_set_hdmi_mode, + .set_hdmi_infoframe = hdmic_set_infoframe, .audio_enable = hdmic_audio_enable, .audio_disable = hdmic_audio_disable, diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c index 7e33686171e3..c891d8f84cb2 100644 --- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c @@ -242,6 +242,24 @@ static int tpd_audio_config(struct omap_dss_device *dssdev, return in->ops.hdmi->audio_config(in, audio); } +static int tpd_set_infoframe(struct omap_dss_device *dssdev, + const struct hdmi_avi_infoframe *avi) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + struct omap_dss_device *in = ddata->in; + + return in->ops.hdmi->set_infoframe(in, avi); +} + +static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev, + bool hdmi_mode) +{ + struct panel_drv_data *ddata = to_panel_data(dssdev); + struct omap_dss_device *in = ddata->in; + + return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode); +} + static const struct omapdss_hdmi_ops tpd_hdmi_ops = { .connect = tpd_connect, .disconnect = tpd_disconnect, @@ -255,6 +273,8 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = { .read_edid = tpd_read_edid, .detect = tpd_detect, + .set_infoframe = tpd_set_infoframe, + .set_hdmi_mode = tpd_set_hdmi_mode, .audio_enable = tpd_audio_enable, .audio_disable = tpd_audio_disable, diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c index c7ba4d8b928a..617f8d2f5127 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c @@ -817,6 +817,10 @@ static int acx565akm_probe(struct spi_device *spi) bldev = backlight_device_register("acx565akm", &ddata->spi->dev, ddata, &acx565akm_bl_ops, &props); + if (IS_ERR(bldev)) { + r = PTR_ERR(bldev); + goto err_reg_bl; + } ddata->bl_dev = bldev; if (ddata->has_cabc) { r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group); @@ -862,6 +866,7 @@ err_reg: sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group); err_sysfs: backlight_device_unregister(bldev); +err_reg_bl: err_detect: err_gpio: omap_dss_put_device(ddata->in); diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig index 285bcd103dce..3d5eb6c36c22 100644 --- a/drivers/video/fbdev/omap2/dss/Kconfig +++ b/drivers/video/fbdev/omap2/dss/Kconfig @@ -5,6 +5,7 @@ menuconfig OMAP2_DSS tristate "OMAP2+ Display Subsystem support" select VIDEOMODE_HELPERS select OMAP2_DSS_INIT + select HDMI help OMAP2+ Display Subsystem support. diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index 7aa33b0f4a1f..be053aa80880 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c @@ -2879,19 +2879,24 @@ static bool _dispc_mgr_pclk_ok(enum omap_channel channel, bool dispc_mgr_timings_ok(enum omap_channel channel, const struct omap_video_timings *timings) { - bool timings_ok; - - timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); + if (!_dispc_mgr_size_ok(timings->x_res, timings->y_res)) + return false; - timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixelclock); + if (!_dispc_mgr_pclk_ok(channel, timings->pixelclock)) + return false; if (dss_mgr_is_lcd(channel)) { - timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp, + /* TODO: OMAP4+ supports interlace for LCD outputs */ + if (timings->interlace) + return false; + + if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp, timings->hbp, timings->vsw, timings->vfp, - timings->vbp); + timings->vbp)) + return false; } - return timings_ok; + return true; } static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, @@ -3257,13 +3262,10 @@ static void dispc_dump_regs(struct seq_file *s) if (i == OMAP_DSS_CHANNEL_DIGIT) continue; - DUMPREG(i, DISPC_DEFAULT_COLOR); - DUMPREG(i, DISPC_TRANS_COLOR); DUMPREG(i, DISPC_TIMING_H); DUMPREG(i, DISPC_TIMING_V); DUMPREG(i, DISPC_POL_FREQ); DUMPREG(i, DISPC_DIVISORo); - DUMPREG(i, DISPC_SIZE_MGR); DUMPREG(i, DISPC_DATA_CYCLE1); DUMPREG(i, DISPC_DATA_CYCLE2); diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 4755a34a5422..56b92444c54f 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c @@ -5658,18 +5658,11 @@ err_runtime_get: return r; } -static int dsi_unregister_child(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - platform_device_unregister(pdev); - return 0; -} - static int __exit omap_dsihw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child); + of_platform_depopulate(&dsidev->dev); WARN_ON(dsi->scp_clk_refcount > 0); diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index fbee07816337..262771b9b76b 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/hdmi.h> #include <video/omapdss.h> #include "dss.h" @@ -142,7 +143,7 @@ enum hdmi_audio_samples_perword { HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1 }; -enum hdmi_audio_sample_size { +enum hdmi_audio_sample_size_omap { HDMI_AUDIO_SAMPLE_16BITS = 0, HDMI_AUDIO_SAMPLE_24BITS = 1 }; @@ -178,59 +179,6 @@ enum hdmi_audio_mclk_mode { HDMI_AUDIO_MCLK_192FS = 7 }; -/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */ -enum hdmi_core_infoframe { - HDMI_INFOFRAME_AVI_DB1Y_RGB = 0, - HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1, - HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2, - HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0, - HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON = 1, - HDMI_INFOFRAME_AVI_DB1B_NO = 0, - HDMI_INFOFRAME_AVI_DB1B_VERT = 1, - HDMI_INFOFRAME_AVI_DB1B_HORI = 2, - HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3, - HDMI_INFOFRAME_AVI_DB1S_0 = 0, - HDMI_INFOFRAME_AVI_DB1S_1 = 1, - HDMI_INFOFRAME_AVI_DB1S_2 = 2, - HDMI_INFOFRAME_AVI_DB2C_NO = 0, - HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1, - HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2, - HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3, - HDMI_INFOFRAME_AVI_DB2M_NO = 0, - HDMI_INFOFRAME_AVI_DB2M_43 = 1, - HDMI_INFOFRAME_AVI_DB2M_169 = 2, - HDMI_INFOFRAME_AVI_DB2R_SAME = 8, - HDMI_INFOFRAME_AVI_DB2R_43 = 9, - HDMI_INFOFRAME_AVI_DB2R_169 = 10, - HDMI_INFOFRAME_AVI_DB2R_149 = 11, - HDMI_INFOFRAME_AVI_DB3ITC_NO = 0, - HDMI_INFOFRAME_AVI_DB3ITC_YES = 1, - HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0, - HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1, - HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0, - HDMI_INFOFRAME_AVI_DB3Q_LR = 1, - HDMI_INFOFRAME_AVI_DB3Q_FR = 2, - HDMI_INFOFRAME_AVI_DB3SC_NO = 0, - HDMI_INFOFRAME_AVI_DB3SC_HORI = 1, - HDMI_INFOFRAME_AVI_DB3SC_VERT = 2, - HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3, - HDMI_INFOFRAME_AVI_DB5PR_NO = 0, - HDMI_INFOFRAME_AVI_DB5PR_2 = 1, - HDMI_INFOFRAME_AVI_DB5PR_3 = 2, - HDMI_INFOFRAME_AVI_DB5PR_4 = 3, - HDMI_INFOFRAME_AVI_DB5PR_5 = 4, - HDMI_INFOFRAME_AVI_DB5PR_6 = 5, - HDMI_INFOFRAME_AVI_DB5PR_7 = 6, - HDMI_INFOFRAME_AVI_DB5PR_8 = 7, - HDMI_INFOFRAME_AVI_DB5PR_9 = 8, - HDMI_INFOFRAME_AVI_DB5PR_10 = 9, -}; - -struct hdmi_cm { - int code; - int mode; -}; - struct hdmi_video_format { enum hdmi_packing_mode packing_mode; u32 y_res; /* Line per panel */ @@ -239,7 +187,8 @@ struct hdmi_video_format { struct hdmi_config { struct omap_video_timings timings; - struct hdmi_cm cm; + struct hdmi_avi_infoframe infoframe; + enum hdmi_core_hdmi_dvi hdmi_dvi_mode; }; /* HDMI PLL structure */ @@ -260,7 +209,7 @@ struct hdmi_audio_format { enum hdmi_audio_justify justification; enum hdmi_audio_sample_order sample_order; enum hdmi_audio_samples_perword samples_per_word; - enum hdmi_audio_sample_size sample_size; + enum hdmi_audio_sample_size_omap sample_size; enum hdmi_audio_blk_strt_end_sig en_sig_blk_strt_end; }; @@ -298,47 +247,6 @@ struct hdmi_core_audio_config { bool en_spdif; }; -/* - * Refer to section 8.2 in HDMI 1.3 specification for - * details about infoframe databytes - */ -struct hdmi_core_infoframe_avi { - /* Y0, Y1 rgb,yCbCr */ - u8 db1_format; - /* A0 Active information Present */ - u8 db1_active_info; - /* B0, B1 Bar info data valid */ - u8 db1_bar_info_dv; - /* S0, S1 scan information */ - u8 db1_scan_info; - /* C0, C1 colorimetry */ - u8 db2_colorimetry; - /* M0, M1 Aspect ratio (4:3, 16:9) */ - u8 db2_aspect_ratio; - /* R0...R3 Active format aspect ratio */ - u8 db2_active_fmt_ar; - /* ITC IT content. */ - u8 db3_itc; - /* EC0, EC1, EC2 Extended colorimetry */ - u8 db3_ec; - /* Q1, Q0 Quantization range */ - u8 db3_q_range; - /* SC1, SC0 Non-uniform picture scaling */ - u8 db3_nup_scaling; - /* VIC0..6 Video format identification */ - u8 db4_videocode; - /* PR0..PR3 Pixel repetition factor */ - u8 db5_pixel_repeat; - /* Line number end of top bar */ - u16 db6_7_line_eoftop; - /* Line number start of bottom bar */ - u16 db8_9_line_sofbottom; - /* Pixel number end of left bar */ - u16 db10_11_pixel_eofleft; - /* Pixel number start of right bar */ - u16 db12_13_pixel_sofright; -}; - struct hdmi_wp_data { void __iomem *base; }; @@ -358,8 +266,6 @@ struct hdmi_phy_data { struct hdmi_core_data { void __iomem *base; - - struct hdmi_core_infoframe_avi avi_cfg; }; static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx, @@ -425,9 +331,6 @@ int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); /* HDMI common funcs */ -const struct hdmi_config *hdmi_default_timing(void); -const struct hdmi_config *hdmi_get_timings(int mode, int code); -struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing); int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, struct hdmi_phy_data *phy); diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 626aad2bef46..6a8550cf43e5 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -281,29 +281,11 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, static void hdmi_display_set_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - struct hdmi_cm cm; - const struct hdmi_config *t; - mutex_lock(&hdmi.lock); - cm = hdmi_get_code(timings); - hdmi.cfg.cm = cm; - - t = hdmi_get_timings(cm.mode, cm.code); - if (t != NULL) { - hdmi.cfg = *t; - - dispc_set_tv_pclk(t->timings.pixelclock); - } else { - hdmi.cfg.timings = *timings; - hdmi.cfg.cm.code = 0; - hdmi.cfg.cm.mode = HDMI_DVI; - - dispc_set_tv_pclk(timings->pixelclock); - } + hdmi.cfg.timings = *timings; - DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ? - "DVI" : "HDMI", hdmi.cfg.cm.code); + dispc_set_tv_pclk(timings->pixelclock); mutex_unlock(&hdmi.lock); } @@ -311,14 +293,7 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev, static void hdmi_display_get_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - const struct hdmi_config *cfg; - struct hdmi_cm cm = hdmi.cfg.cm; - - cfg = hdmi_get_timings(cm.mode, cm.code); - if (cfg == NULL) - cfg = hdmi_default_timing(); - - memcpy(timings, &cfg->timings, sizeof(cfg->timings)); + *timings = hdmi.cfg.timings; } static void hdmi_dump_regs(struct seq_file *s) @@ -516,7 +491,7 @@ static int hdmi_audio_enable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) { + if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { r = -EPERM; goto err; } @@ -554,7 +529,7 @@ static bool hdmi_audio_supported(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - r = hdmi_mode_has_audio(hdmi.cfg.cm.mode); + r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode); mutex_unlock(&hdmi.lock); return r; @@ -568,7 +543,7 @@ static int hdmi_audio_config(struct omap_dss_device *dssdev, mutex_lock(&hdmi.lock); - if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) { + if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { r = -EPERM; goto err; } @@ -615,6 +590,20 @@ static int hdmi_audio_config(struct omap_dss_device *dssdev, } #endif +static int hdmi_set_infoframe(struct omap_dss_device *dssdev, + const struct hdmi_avi_infoframe *avi) +{ + hdmi.cfg.infoframe = *avi; + return 0; +} + +static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, + bool hdmi_mode) +{ + hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; + return 0; +} + static const struct omapdss_hdmi_ops hdmi_ops = { .connect = hdmi_connect, .disconnect = hdmi_disconnect, @@ -627,6 +616,8 @@ static const struct omapdss_hdmi_ops hdmi_ops = { .get_timings = hdmi_display_get_timings, .read_edid = hdmi_read_edid, + .set_infoframe = hdmi_set_infoframe, + .set_hdmi_mode = hdmi_set_hdmi_mode, .audio_enable = hdmi_audio_enable, .audio_disable = hdmi_audio_disable, diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c index 8bde7b7e95ff..4ad39cfce254 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c @@ -197,9 +197,7 @@ int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len) return l; } -static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, - struct hdmi_core_infoframe_avi *avi_cfg, - struct hdmi_core_packet_enable_repeat *repeat_cfg) +static void hdmi_core_init(struct hdmi_core_video_config *video_cfg) { DSSDBG("Enter hdmi_core_init\n"); @@ -210,35 +208,6 @@ static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; video_cfg->hdmi_dvi = HDMI_DVI; video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; - - /* info frame */ - avi_cfg->db1_format = 0; - avi_cfg->db1_active_info = 0; - avi_cfg->db1_bar_info_dv = 0; - avi_cfg->db1_scan_info = 0; - avi_cfg->db2_colorimetry = 0; - avi_cfg->db2_aspect_ratio = 0; - avi_cfg->db2_active_fmt_ar = 0; - avi_cfg->db3_itc = 0; - avi_cfg->db3_ec = 0; - avi_cfg->db3_q_range = 0; - avi_cfg->db3_nup_scaling = 0; - avi_cfg->db4_videocode = 0; - avi_cfg->db5_pixel_repeat = 0; - avi_cfg->db6_7_line_eoftop = 0; - avi_cfg->db8_9_line_sofbottom = 0; - avi_cfg->db10_11_pixel_eofleft = 0; - avi_cfg->db12_13_pixel_sofright = 0; - - /* packet enable and repeat */ - repeat_cfg->audio_pkt = 0; - repeat_cfg->audio_pkt_repeat = 0; - repeat_cfg->avi_infoframe = 0; - repeat_cfg->avi_infoframe_repeat = 0; - repeat_cfg->gen_cntrl_pkt = 0; - repeat_cfg->gen_cntrl_pkt_repeat = 0; - repeat_cfg->generic_pkt = 0; - repeat_cfg->generic_pkt_repeat = 0; } static void hdmi_core_powerdown_disable(struct hdmi_core_data *core) @@ -303,80 +272,22 @@ static void hdmi_core_video_config(struct hdmi_core_data *core, HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5); } -static void hdmi_core_aux_infoframe_avi_config(struct hdmi_core_data *core) +static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core, + struct hdmi_avi_infoframe *frame) { - u32 val; - char sum = 0, checksum = 0; void __iomem *av_base = hdmi_av_base(core); - struct hdmi_core_infoframe_avi info_avi = core->avi_cfg; - - sum += 0x82 + 0x002 + 0x00D; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_VERS, 0x002); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_LEN, 0x00D); - - val = (info_avi.db1_format << 5) | - (info_avi.db1_active_info << 4) | - (info_avi.db1_bar_info_dv << 2) | - (info_avi.db1_scan_info); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(0), val); - sum += val; - - val = (info_avi.db2_colorimetry << 6) | - (info_avi.db2_aspect_ratio << 4) | - (info_avi.db2_active_fmt_ar); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(1), val); - sum += val; - - val = (info_avi.db3_itc << 7) | - (info_avi.db3_ec << 4) | - (info_avi.db3_q_range << 2) | - (info_avi.db3_nup_scaling); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(2), val); - sum += val; - - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(3), - info_avi.db4_videocode); - sum += info_avi.db4_videocode; - - val = info_avi.db5_pixel_repeat; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(4), val); - sum += val; - - val = info_avi.db6_7_line_eoftop & 0x00FF; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(5), val); - sum += val; - - val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(6), val); - sum += val; - - val = info_avi.db8_9_line_sofbottom & 0x00FF; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(7), val); - sum += val; - - val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(8), val); - sum += val; - - val = info_avi.db10_11_pixel_eofleft & 0x00FF; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(9), val); - sum += val; - - val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(10), val); - sum += val; - - val = info_avi.db12_13_pixel_sofright & 0x00FF; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(11), val); - sum += val; - - val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(12), val); - sum += val; + u8 data[HDMI_INFOFRAME_SIZE(AVI)]; + int i; - checksum = 0x100 - sum; - hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_CHSUM, checksum); + hdmi_avi_infoframe_pack(frame, data, sizeof(data)); + + print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data, + HDMI_INFOFRAME_SIZE(AVI), false); + + for (i = 0; i < sizeof(data); ++i) { + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_BASE + i * 4, + data[i]); + } } static void hdmi_core_av_packet_config(struct hdmi_core_data *core, @@ -404,11 +315,10 @@ void hdmi4_configure(struct hdmi_core_data *core, struct omap_video_timings video_timing; struct hdmi_video_format video_format; /* HDMI core */ - struct hdmi_core_infoframe_avi *avi_cfg = &core->avi_cfg; struct hdmi_core_video_config v_core_cfg; - struct hdmi_core_packet_enable_repeat repeat_cfg; + struct hdmi_core_packet_enable_repeat repeat_cfg = { 0 }; - hdmi_core_init(&v_core_cfg, avi_cfg, &repeat_cfg); + hdmi_core_init(&v_core_cfg); hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg); @@ -431,44 +341,24 @@ void hdmi4_configure(struct hdmi_core_data *core, hdmi_core_powerdown_disable(core); v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; - v_core_cfg.hdmi_dvi = cfg->cm.mode; + v_core_cfg.hdmi_dvi = cfg->hdmi_dvi_mode; hdmi_core_video_config(core, &v_core_cfg); /* release software reset in the core */ hdmi_core_swreset_release(core); - /* - * configure packet - * info frame video see doc CEA861-D page 65 - */ - avi_cfg->db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; - avi_cfg->db1_active_info = - HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; - avi_cfg->db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; - avi_cfg->db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; - avi_cfg->db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; - avi_cfg->db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; - avi_cfg->db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; - avi_cfg->db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; - avi_cfg->db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; - avi_cfg->db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; - avi_cfg->db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; - avi_cfg->db4_videocode = cfg->cm.code; - avi_cfg->db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; - avi_cfg->db6_7_line_eoftop = 0; - avi_cfg->db8_9_line_sofbottom = 0; - avi_cfg->db10_11_pixel_eofleft = 0; - avi_cfg->db12_13_pixel_sofright = 0; - - hdmi_core_aux_infoframe_avi_config(core); + if (cfg->hdmi_dvi_mode == HDMI_HDMI) { + hdmi_core_write_avi_infoframe(core, &cfg->infoframe); + + /* enable/repeat the infoframe */ + repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; + repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; + /* wakeup */ + repeat_cfg.audio_pkt = HDMI_PACKETENABLE; + repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; + } - /* enable/repeat the infoframe */ - repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; - repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; - /* wakeup */ - repeat_cfg.audio_pkt = HDMI_PACKETENABLE; - repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; hdmi_core_av_packet_config(core, repeat_cfg); } diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/dss/hdmi4_core.h index bb646896fa82..827909eb6c50 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.h +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.h @@ -145,6 +145,7 @@ #define HDMI_CORE_AV_DPD 0xF4 #define HDMI_CORE_AV_PB_CTRL1 0xF8 #define HDMI_CORE_AV_PB_CTRL2 0xFC +#define HDMI_CORE_AV_AVI_BASE 0x100 #define HDMI_CORE_AV_AVI_TYPE 0x100 #define HDMI_CORE_AV_AVI_VERS 0x104 #define HDMI_CORE_AV_AVI_LEN 0x108 diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c index c468b9e1f295..32d02ec34d23 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5.c @@ -299,29 +299,11 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, static void hdmi_display_set_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - struct hdmi_cm cm; - const struct hdmi_config *t; - mutex_lock(&hdmi.lock); - cm = hdmi_get_code(timings); - hdmi.cfg.cm = cm; - - t = hdmi_get_timings(cm.mode, cm.code); - if (t != NULL) { - hdmi.cfg = *t; - - dispc_set_tv_pclk(t->timings.pixelclock); - } else { - hdmi.cfg.timings = *timings; - hdmi.cfg.cm.code = 0; - hdmi.cfg.cm.mode = HDMI_DVI; - - dispc_set_tv_pclk(timings->pixelclock); - } + hdmi.cfg.timings = *timings; - DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ? - "DVI" : "HDMI", hdmi.cfg.cm.code); + dispc_set_tv_pclk(timings->pixelclock); mutex_unlock(&hdmi.lock); } @@ -329,14 +311,7 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev, static void hdmi_display_get_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - const struct hdmi_config *cfg; - struct hdmi_cm cm = hdmi.cfg.cm; - - cfg = hdmi_get_timings(cm.mode, cm.code); - if (cfg == NULL) - cfg = hdmi_default_timing(); - - memcpy(timings, &cfg->timings, sizeof(cfg->timings)); + *timings = hdmi.cfg.timings; } static void hdmi_dump_regs(struct seq_file *s) @@ -541,7 +516,7 @@ static int hdmi_audio_enable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) { + if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { r = -EPERM; goto err; } @@ -579,7 +554,7 @@ static bool hdmi_audio_supported(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - r = hdmi_mode_has_audio(hdmi.cfg.cm.mode); + r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode); mutex_unlock(&hdmi.lock); return r; @@ -593,7 +568,7 @@ static int hdmi_audio_config(struct omap_dss_device *dssdev, mutex_lock(&hdmi.lock); - if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) { + if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { r = -EPERM; goto err; } @@ -640,6 +615,20 @@ static int hdmi_audio_config(struct omap_dss_device *dssdev, } #endif +static int hdmi_set_infoframe(struct omap_dss_device *dssdev, + const struct hdmi_avi_infoframe *avi) +{ + hdmi.cfg.infoframe = *avi; + return 0; +} + +static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, + bool hdmi_mode) +{ + hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI; + return 0; +} + static const struct omapdss_hdmi_ops hdmi_ops = { .connect = hdmi_connect, .disconnect = hdmi_disconnect, @@ -652,6 +641,8 @@ static const struct omapdss_hdmi_ops hdmi_ops = { .get_timings = hdmi_display_get_timings, .read_edid = hdmi_read_edid, + .set_infoframe = hdmi_set_infoframe, + .set_hdmi_mode = hdmi_set_hdmi_mode, .audio_enable = hdmi_audio_enable, .audio_disable = hdmi_audio_disable, diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c index 7528c7a42aa5..83acbf7a8c89 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c @@ -290,7 +290,6 @@ void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s) } static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg, - struct hdmi_core_infoframe_avi *avi_cfg, struct hdmi_config *cfg) { DSSDBG("hdmi_core_init\n"); @@ -312,27 +311,8 @@ static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg, video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */ video_cfg->vblank = cfg->timings.vsw + cfg->timings.vfp + cfg->timings.vbp; - video_cfg->v_fc_config.cm.mode = cfg->cm.mode; + video_cfg->v_fc_config.hdmi_dvi_mode = cfg->hdmi_dvi_mode; video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace; - - /* info frame */ - avi_cfg->db1_format = 0; - avi_cfg->db1_active_info = 0; - avi_cfg->db1_bar_info_dv = 0; - avi_cfg->db1_scan_info = 0; - avi_cfg->db2_colorimetry = 0; - avi_cfg->db2_aspect_ratio = 0; - avi_cfg->db2_active_fmt_ar = 0; - avi_cfg->db3_itc = 0; - avi_cfg->db3_ec = 0; - avi_cfg->db3_q_range = 0; - avi_cfg->db3_nup_scaling = 0; - avi_cfg->db4_videocode = 0; - avi_cfg->db5_pixel_repeat = 0; - avi_cfg->db6_7_line_eoftop = 0; - avi_cfg->db8_9_line_sofbottom = 0; - avi_cfg->db10_11_pixel_eofleft = 0; - avi_cfg->db12_13_pixel_sofright = 0; } /* DSS_HDMI_CORE_VIDEO_CONFIG */ @@ -398,7 +378,7 @@ static void hdmi_core_video_config(struct hdmi_core_data *core, /* select DVI mode */ REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF, - cfg->v_fc_config.cm.mode, 3, 3); + cfg->v_fc_config.hdmi_dvi_mode, 3, 3); } static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core) @@ -438,24 +418,60 @@ static void hdmi_core_config_video_sampler(struct hdmi_core_data *core) REG_FLD_MOD(core->base, HDMI_CORE_TX_INVID0, video_mapping, 4, 0); } -static void hdmi_core_aux_infoframe_avi_config(struct hdmi_core_data *core) +static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core, + struct hdmi_avi_infoframe *frame) { void __iomem *base = core->base; - struct hdmi_core_infoframe_avi avi = core->avi_cfg; - - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_format, 1, 0); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_active_info, 6, 6); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_bar_info_dv, 3, 2); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_scan_info, 5, 4); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_colorimetry, 7, 6); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_aspect_ratio, 5, 4); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_active_fmt_ar, 3, 0); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_itc, 7, 7); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_ec, 6, 4); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_q_range, 3, 2); - REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_nup_scaling, 1, 0); - REG_FLD_MOD(base, HDMI_CORE_FC_AVIVID, avi.db4_videocode, 6, 0); - REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, avi.db5_pixel_repeat, 3, 0); + u8 data[HDMI_INFOFRAME_SIZE(AVI)]; + u8 *ptr; + unsigned y, a, b, s; + unsigned c, m, r; + unsigned itc, ec, q, sc; + unsigned vic; + unsigned yq, cn, pr; + + hdmi_avi_infoframe_pack(frame, data, sizeof(data)); + + print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data, + HDMI_INFOFRAME_SIZE(AVI), false); + + ptr = data + HDMI_INFOFRAME_HEADER_SIZE; + + y = (ptr[0] >> 5) & 0x3; + a = (ptr[0] >> 4) & 0x1; + b = (ptr[0] >> 2) & 0x3; + s = (ptr[0] >> 0) & 0x3; + + c = (ptr[1] >> 6) & 0x3; + m = (ptr[1] >> 4) & 0x3; + r = (ptr[1] >> 0) & 0x3; + + itc = (ptr[2] >> 7) & 0x1; + ec = (ptr[2] >> 4) & 0x7; + q = (ptr[2] >> 2) & 0x3; + sc = (ptr[2] >> 0) & 0x3; + + vic = ptr[3]; + + yq = (ptr[4] >> 6) & 0x3; + cn = (ptr[4] >> 4) & 0x3; + pr = (ptr[4] >> 0) & 0xf; + + hdmi_write_reg(base, HDMI_CORE_FC_AVICONF0, + (a << 6) | (s << 4) | (b << 2) | (y << 0)); + + hdmi_write_reg(base, HDMI_CORE_FC_AVICONF1, + (c << 6) | (m << 4) | (r << 0)); + + hdmi_write_reg(base, HDMI_CORE_FC_AVICONF2, + (itc << 7) | (ec << 4) | (q << 2) | (sc << 0)); + + hdmi_write_reg(base, HDMI_CORE_FC_AVIVID, vic); + + hdmi_write_reg(base, HDMI_CORE_FC_AVICONF3, + (yq << 2) | (cn << 0)); + + REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, pr, 3, 0); } static void hdmi_core_csc_config(struct hdmi_core_data *core, @@ -497,10 +513,8 @@ static void hdmi_core_configure_range(struct hdmi_core_data *core) /* support limited range with 24 bit color depth for now */ csc_coeff = csc_table_deepcolor[0]; - core->avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_LR; hdmi_core_csc_config(core, csc_coeff); - hdmi_core_aux_infoframe_avi_config(core); } static void hdmi_core_enable_video_path(struct hdmi_core_data *core) @@ -591,11 +605,10 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, struct omap_video_timings video_timing; struct hdmi_video_format video_format; struct hdmi_core_vid_config v_core_cfg; - struct hdmi_core_infoframe_avi *avi_cfg = &core->avi_cfg; hdmi_core_mask_interrupts(core); - hdmi_core_init(&v_core_cfg, avi_cfg, cfg); + hdmi_core_init(&v_core_cfg, cfg); hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg); @@ -608,7 +621,9 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, hdmi_wp_video_config_interface(wp, &video_timing); + /* support limited range with 24 bit color depth for now */ hdmi_core_configure_range(core); + cfg->infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; /* * configure core video part, set software reset in the core @@ -621,29 +636,8 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, hdmi_core_config_csc(core); hdmi_core_config_video_sampler(core); - /* - * configure packet info frame video see doc CEA861-D page 65 - */ - avi_cfg->db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; - avi_cfg->db1_active_info = - HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; - avi_cfg->db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; - avi_cfg->db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; - avi_cfg->db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; - avi_cfg->db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; - avi_cfg->db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; - avi_cfg->db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; - avi_cfg->db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; - avi_cfg->db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; - avi_cfg->db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; - avi_cfg->db4_videocode = cfg->cm.code; - avi_cfg->db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; - avi_cfg->db6_7_line_eoftop = 0; - avi_cfg->db8_9_line_sofbottom = 0; - avi_cfg->db10_11_pixel_eofleft = 0; - avi_cfg->db12_13_pixel_sofright = 0; - - hdmi_core_aux_infoframe_avi_config(core); + if (cfg->hdmi_dvi_mode == HDMI_HDMI) + hdmi_core_write_avi_infoframe(core, &cfg->infoframe); hdmi_core_enable_video_path(core); diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c index 9a2c39cf297f..7d5f1039de9f 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_common.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c @@ -1,18 +1,4 @@ -/* - * Logic for the below structure : - * user enters the CEA or VESA timings by specifying the HDMI/DVI code. - * There is a correspondence between CEA/VESA timing and code, please - * refer to section 6.3 in HDMI 1.3 specification for timing code. - * - * In the below structure, cea_vesa_timings corresponds to all OMAP4 - * supported CEA and VESA timing values.code_cea corresponds to the CEA - * code, It is used to get the timing from cea_vesa_timing array.Similarly - * with code_vesa. Code_index is used for back mapping, that is once EDID - * is read from the TV, EDID is parsed to find the timing values and then - * map it to corresponding CEA or VESA index. - */ - #define DSS_SUBSYS_NAME "HDMI" #include <linux/kernel.h> @@ -22,308 +8,6 @@ #include "hdmi.h" -static const struct hdmi_config cea_timings[] = { - { - { 640, 480, 25200000, 96, 16, 48, 2, 10, 33, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 1, HDMI_HDMI }, - }, - { - { 720, 480, 27027000, 62, 16, 60, 6, 9, 30, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 2, HDMI_HDMI }, - }, - { - { 1280, 720, 74250000, 40, 110, 220, 5, 5, 20, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 4, HDMI_HDMI }, - }, - { - { 1920, 540, 74250000, 44, 88, 148, 5, 2, 15, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - true, }, - { 5, HDMI_HDMI }, - }, - { - { 1440, 240, 27027000, 124, 38, 114, 3, 4, 15, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - true, }, - { 6, HDMI_HDMI }, - }, - { - { 1920, 1080, 148500000, 44, 88, 148, 5, 4, 36, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 16, HDMI_HDMI }, - }, - { - { 720, 576, 27000000, 64, 12, 68, 5, 5, 39, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 17, HDMI_HDMI }, - }, - { - { 1280, 720, 74250000, 40, 440, 220, 5, 5, 20, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 19, HDMI_HDMI }, - }, - { - { 1920, 540, 74250000, 44, 528, 148, 5, 2, 15, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - true, }, - { 20, HDMI_HDMI }, - }, - { - { 1440, 288, 27000000, 126, 24, 138, 3, 2, 19, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - true, }, - { 21, HDMI_HDMI }, - }, - { - { 1440, 576, 54000000, 128, 24, 136, 5, 5, 39, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 29, HDMI_HDMI }, - }, - { - { 1920, 1080, 148500000, 44, 528, 148, 5, 4, 36, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 31, HDMI_HDMI }, - }, - { - { 1920, 1080, 74250000, 44, 638, 148, 5, 4, 36, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 32, HDMI_HDMI }, - }, - { - { 2880, 480, 108108000, 248, 64, 240, 6, 9, 30, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 35, HDMI_HDMI }, - }, - { - { 2880, 576, 108000000, 256, 48, 272, 5, 5, 39, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 37, HDMI_HDMI }, - }, -}; - -static const struct hdmi_config vesa_timings[] = { -/* VESA From Here */ - { - { 640, 480, 25175000, 96, 16, 48, 2, 11, 31, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 4, HDMI_DVI }, - }, - { - { 800, 600, 40000000, 128, 40, 88, 4, 1, 23, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 9, HDMI_DVI }, - }, - { - { 848, 480, 33750000, 112, 16, 112, 8, 6, 23, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0xE, HDMI_DVI }, - }, - { - { 1280, 768, 79500000, 128, 64, 192, 7, 3, 20, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 0x17, HDMI_DVI }, - }, - { - { 1280, 800, 83500000, 128, 72, 200, 6, 3, 22, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 0x1C, HDMI_DVI }, - }, - { - { 1360, 768, 85500000, 112, 64, 256, 6, 3, 18, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x27, HDMI_DVI }, - }, - { - { 1280, 960, 108000000, 112, 96, 312, 3, 1, 36, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x20, HDMI_DVI }, - }, - { - { 1280, 1024, 108000000, 112, 48, 248, 3, 1, 38, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x23, HDMI_DVI }, - }, - { - { 1024, 768, 65000000, 136, 24, 160, 6, 3, 29, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 0x10, HDMI_DVI }, - }, - { - { 1400, 1050, 121750000, 144, 88, 232, 4, 3, 32, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 0x2A, HDMI_DVI }, - }, - { - { 1440, 900, 106500000, 152, 80, 232, 6, 3, 25, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 0x2F, HDMI_DVI }, - }, - { - { 1680, 1050, 146250000, 176 , 104, 280, 6, 3, 30, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, - false, }, - { 0x3A, HDMI_DVI }, - }, - { - { 1366, 768, 85500000, 143, 70, 213, 3, 3, 24, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x51, HDMI_DVI }, - }, - { - { 1920, 1080, 148500000, 44, 148, 80, 5, 4, 36, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x52, HDMI_DVI }, - }, - { - { 1280, 768, 68250000, 32, 48, 80, 7, 3, 12, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x16, HDMI_DVI }, - }, - { - { 1400, 1050, 101000000, 32, 48, 80, 4, 3, 23, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x29, HDMI_DVI }, - }, - { - { 1680, 1050, 119000000, 32, 48, 80, 6, 3, 21, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x39, HDMI_DVI }, - }, - { - { 1280, 800, 79500000, 32, 48, 80, 6, 3, 14, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x1B, HDMI_DVI }, - }, - { - { 1280, 720, 74250000, 40, 110, 220, 5, 5, 20, - OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x55, HDMI_DVI }, - }, - { - { 1920, 1200, 154000000, 32, 48, 80, 6, 3, 26, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, - false, }, - { 0x44, HDMI_DVI }, - }, -}; - -const struct hdmi_config *hdmi_default_timing(void) -{ - return &vesa_timings[0]; -} - -static const struct hdmi_config *hdmi_find_timing(int code, - const struct hdmi_config *timings_arr, int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (timings_arr[i].cm.code == code) - return &timings_arr[i]; - } - - return NULL; -} - -const struct hdmi_config *hdmi_get_timings(int mode, int code) -{ - const struct hdmi_config *arr; - int len; - - if (mode == HDMI_DVI) { - arr = vesa_timings; - len = ARRAY_SIZE(vesa_timings); - } else { - arr = cea_timings; - len = ARRAY_SIZE(cea_timings); - } - - return hdmi_find_timing(code, arr, len); -} - -static bool hdmi_timings_compare(struct omap_video_timings *timing1, - const struct omap_video_timings *timing2) -{ - int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; - - if ((DIV_ROUND_CLOSEST(timing2->pixelclock, 1000000) == - DIV_ROUND_CLOSEST(timing1->pixelclock, 1000000)) && - (timing2->x_res == timing1->x_res) && - (timing2->y_res == timing1->y_res)) { - - timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp; - timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp; - timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp; - timing1_vsync = timing1->vfp + timing1->vsw + timing1->vbp; - - DSSDBG("timing1_hsync = %d timing1_vsync = %d"\ - "timing2_hsync = %d timing2_vsync = %d\n", - timing1_hsync, timing1_vsync, - timing2_hsync, timing2_vsync); - - if ((timing1_hsync == timing2_hsync) && - (timing1_vsync == timing2_vsync)) { - return true; - } - } - return false; -} - -struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) -{ - int i; - struct hdmi_cm cm = {-1}; - DSSDBG("hdmi_get_code\n"); - - for (i = 0; i < ARRAY_SIZE(cea_timings); i++) { - if (hdmi_timings_compare(timing, &cea_timings[i].timings)) { - cm = cea_timings[i].cm; - goto end; - } - } - for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) { - if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) { - cm = vesa_timings[i].cm; - goto end; - } - } - -end: - return cm; -} - int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, struct hdmi_phy_data *phy) { diff --git a/drivers/video/fbdev/s3c2410fb.c b/drivers/video/fbdev/s3c2410fb.c index 81af5a63e9e1..d68595dcc5fd 100644 --- a/drivers/video/fbdev/s3c2410fb.c +++ b/drivers/video/fbdev/s3c2410fb.c @@ -932,7 +932,7 @@ static int s3c24xxfb_probe(struct platform_device *pdev, goto release_irq; } - clk_enable(info->clk); + clk_prepare_enable(info->clk); dprintk("got and enabled clock\n"); usleep_range(1000, 1100); @@ -996,7 +996,7 @@ static int s3c24xxfb_probe(struct platform_device *pdev, free_video_memory: s3c2410fb_unmap_video_memory(fbinfo); release_clock: - clk_disable(info->clk); + clk_disable_unprepare(info->clk); clk_put(info->clk); release_irq: free_irq(irq, info); @@ -1038,7 +1038,7 @@ static int s3c2410fb_remove(struct platform_device *pdev) s3c2410fb_unmap_video_memory(fbinfo); if (info->clk) { - clk_disable(info->clk); + clk_disable_unprepare(info->clk); clk_put(info->clk); info->clk = NULL; } @@ -1070,7 +1070,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) * before the clock goes off again (bjd) */ usleep_range(1000, 1100); - clk_disable(info->clk); + clk_disable_unprepare(info->clk); return 0; } @@ -1080,7 +1080,7 @@ static int s3c2410fb_resume(struct platform_device *dev) struct fb_info *fbinfo = platform_get_drvdata(dev); struct s3c2410fb_info *info = fbinfo->par; - clk_enable(info->clk); + clk_prepare_enable(info->clk); usleep_range(1000, 1100); s3c2410fb_init_registers(fbinfo); diff --git a/drivers/video/fbdev/sis/init.c b/drivers/video/fbdev/sis/init.c index bd40f5ecd901..dfe3eb769638 100644 --- a/drivers/video/fbdev/sis/init.c +++ b/drivers/video/fbdev/sis/init.c @@ -1511,7 +1511,7 @@ SiS_Get310DRAMType(struct SiS_Private *SiS_Pr) } else if(SiS_Pr->ChipType >= SIS_340) { /* TODO */ data = 0; - } if(SiS_Pr->ChipType >= SIS_661) { + } else if(SiS_Pr->ChipType >= SIS_661) { if(SiS_Pr->SiS_ROMNew) { data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6); } else { diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c index 22ad028bf123..3f12a2dd959a 100644 --- a/drivers/video/fbdev/sis/sis_main.c +++ b/drivers/video/fbdev/sis/sis_main.c @@ -1572,10 +1572,6 @@ sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) /* Adapt RGB settings */ sisfb_bpp_to_var(ivideo, var); - /* Sanity check for offsets */ - if(var->xoffset < 0) var->xoffset = 0; - if(var->yoffset < 0) var->yoffset = 0; - if(var->xres > var->xres_virtual) var->xres_virtual = var->xres; |