* [PATCHv2 0/4] LS1021A: Add dcfb framebuffer driver support.
From: Xiubo Li @ 2014-12-03 9:15 UTC (permalink / raw)
To: linux-arm-kernel
Framebuffer driver for the Freescale SoC Display Controller.
Change in V2:
- Use the native-mode timing as default.
- Add to_fsl_private().
Xiubo Li (4):
video: fsl-dcfb: Add dcfb framebuffer driver for LS1021A platform
video: fsl-dcfb: Add devicetree binding support
ARM: ls1021a: dtsi: Add dt node support for dcfb.
ARM: ls1021a: dts: Add and enable dt node for dcfb.
.../devicetree/bindings/video/fsl,dcfb.txt | 52 ++
arch/arm/boot/dts/ls1021a-twr.dts | 26 +
arch/arm/boot/dts/ls1021a.dtsi | 10 +
drivers/video/fbdev/Kconfig | 19 +
drivers/video/fbdev/Makefile | 1 +
drivers/video/fbdev/fsl-dcfb.c | 814 +++++++++++++++++++++
6 files changed, 922 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/fsl,dcfb.txt
create mode 100644 drivers/video/fbdev/fsl-dcfb.c
--
2.1.0.27.g96db324
^ permalink raw reply
* [PATCHv2 1/4] video: fsl-dcfb: Add dcfb framebuffer driver for LS1021A platform
From: Xiubo Li @ 2014-12-03 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417598162-40433-1-git-send-email-Li.Xiubo@freescale.com>
The Display Controller module is a system master that fetches graphics
stored in internal/external memory and displays them on a TFT LCD panel.
A wide range of panel sizes is supported and the timing of the interface
signals is configurable.
The dcfb has these features:
o Full RGB888 output to TFT LCD panel.
o Optional output to system memory dependent on implementation.
o Supports Programmable panel size upto a maximum of 2032x2047. The actual
resolution supported depends upon the pixel clock and bus bandwidth
available.
o Gamma correction with 8-bit resolution on each color component.
o Dedicated memory blocks to store a cursor and Color Look Up Tables(CLUTs).
o Temporal Dithering.
Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com>
---
drivers/video/fbdev/Kconfig | 19 +
drivers/video/fbdev/Makefile | 1 +
drivers/video/fbdev/fsl-dcfb.c | 814 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 834 insertions(+)
create mode 100644 drivers/video/fbdev/fsl-dcfb.c
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 4916c97..460fe39 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1948,6 +1948,25 @@ config FB_MBX_DEBUG
If unsure, say N.
+config FB_FSL_DCFB
+ tristate "Freescale Display Control Framebuffer Support"
+ depends on FB
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
+ select REGMAP_MMIO
+ ---help---
+ Framebuffer driver for the Freescale SoC Display Control.
+
+ This driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want).
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/kbuild/modules.txt>.
+
+ If unsure, say N.
+
config FB_FSL_DIU
tristate "Freescale DIU framebuffer support"
depends on FB && FSL_SOC
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 1979aff..9015138 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
+obj-$(CONFIG_FB_FSL_DCFB) += fsl-dcfb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
diff --git a/drivers/video/fbdev/fsl-dcfb.c b/drivers/video/fbdev/fsl-dcfb.c
new file mode 100644
index 0000000..c3843bf
--- /dev/null
+++ b/drivers/video/fbdev/fsl-dcfb.c
@@ -0,0 +1,814 @@
+/*
+ * Copyright 2012-2014 Freescale Semiconductor, Inc.
+ *
+ * Freescale Dispaly Controller Framebuffer Driver
+ *
+ * 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/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+#define FSL_SCFG_CTRL 0x28
+#define FSL_SCFG_PIXEL_EN BIT(31)
+
+#define FSL_DCFB_MODE 0x10
+#define FSL_DCFB_BGND 0x14
+#define FSL_DCFB_FIX_SIZE 0x18
+#define FSL_DCFB_HSYN 0x1c
+#define FSL_DCFB_VSYN 0x20
+#define FSL_DCFB_SP 0x24
+#define FSL_DCFB_TS 0x28
+#define FSL_DCFB_DIV_RATIO 0x54
+#define FSL_DCFB_UPDATE 0xcc
+#define FSL_DCFB_VAR_SIZE 0x200
+#define FSL_DCFB_POS 0x204
+#define FSL_DCFB_BASE 0x208
+#define FSL_DCFB_CTRL 0x20c
+#define FSL_DCFB_CKMAX 0x210
+#define FSL_DCFB_CKMIN 0x214
+#define FSL_DCFB_FCOLOR 0x21c
+#define FSL_DCFB_BCOLOR 0x220
+#define FSL_DCFB_SKIP 0x224
+#define FSL_DCFB_MAX 0x300
+
+#define FSL_DCFB_HSYN_BP(x) ((x) << 22)
+#define FSL_DCFB_HSYN_PW(x) ((x) << 11)
+#define FSL_DCFB_HSYN_FP(x) (x)
+#define FSL_DCFB_VSYN_BP(x) ((x) << 22)
+#define FSL_DCFB_VSYN_PW(x) ((x) << 11)
+#define FSL_DCFB_VSYN_FP(x) (x)
+
+#define FSL_DCFB_SP_VS BIT(1)
+#define FSL_DCFB_SP_HS BIT(0)
+
+#define FSL_DCFB_TS_LBV(x) ((x) << 16)
+#define FSL_DCFB_TS_OBH(x) ((x) << 8)
+#define FSL_DCFB_TS_OBL(x) (x)
+
+#define FSL_DCFB_UPDATE_MODE BIT(31)
+#define FSL_DCFB_UPDATE_READREG BIT(30)
+
+#define FSL_DCFB_VAR_SIZE_H(x) ((x) << 16)
+#define FSL_DCFB_VAR_SIZE_W(x) (x)
+
+#define FSL_DCFB_POSY(x) ((x) << 16)
+#define FSL_DCFB_POSX(x) (x)
+
+#define FSL_DCFB_CTRL_EN BIT(31)
+#define FSL_DCFB_CTRL_TILE_EN BIT(30)
+#define FSL_DCFB_CTRL_DATA_SEL_CLUT BIT(29)
+#define FSL_DCFB_CTRL_SAFETY_EN BIT(28)
+#define FSL_DCFB_CTRL_TRANS(x) ((x) << 20)
+#define FSL_DCFB_CTRL_BPP(x) ((x) << 16)
+#define FSL_DCFB_CTRL_RLE_EN BIT(15)
+#define FSL_DCFB_CTRL_LUOFFS(x) ((x) << 4)
+#define FSL_DCFB_CTRL_BB_ON BIT(2)
+
+#define FSL_DCFB_CKMAX_R(x) ((x) << 16)
+#define FSL_DCFB_CKMAX_G(x) ((x) << 8)
+#define FSL_DCFB_CKMAX_B(x) (x)
+
+#define FSL_DCFB_CKMIN_R(x) ((x) << 16)
+#define FSL_DCFB_CKMIN_G(x) ((x) << 8)
+#define FSL_DCFB_CKMIN_B(x) (x)
+
+#define FSL_DCFB_TILE_SIZE_W(x) ((x) << 16)
+#define FSL_DCFB_TILE_SIZE_H(x) (x)
+
+#define FSL_DCFB_FCOLOR_OFF(x) (x)
+#define FSL_DCFB_BCOLOR_OFF(x) (x)
+
+#define FSL_DCFB_MODE_BITER(x) ((x) << 20)
+#define FSL_DCFB_MODE_RASTER_EN BIT(14)
+#define FSL_DCFB_MODE_MODE(x) (x)
+#define FSL_DCFB_MODE_MODE_MASK 0x03
+
+#define FSL_DCFB_BGND_R(x) ((x) << 16)
+#define FSL_DCFB_BGND_G(x) ((x) << 8)
+#define FSL_DCFB_BGND_B(x) (x)
+
+#define FSL_DCFB_FIX_SIZE_Y(x) ((x) << 16)
+#define FSL_DCFB_FIX_SIZE_X(x) (x)
+
+enum fsl_dcfb_fmt {
+ FSL_DCFB_RGB565 = 4,
+ FSL_DCFB_RGB888,
+ FSL_DCFB_ARGB8888,
+};
+
+enum fsl_dcfb_mode {
+ FSL_DCFB_MOD_OFF = 0,
+ FSL_DCFB_MOD_NORMAL,
+ FSL_DCFB_MOD_TEST,
+ FSL_DCFB_MOD_COLORBAR,
+};
+
+struct fsl_dcfb_fb_private {
+ struct fb_info *fsl_dcfb_info;
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *clk;
+};
+
+struct fsl_dcfb_fb_info {
+ unsigned long pseudo_palette[16];
+ unsigned int count;
+ struct fsl_dcfb_fb_private *parent;
+};
+
+static inline struct fsl_dcfb_fb_private *to_fsl_private(struct fb_info *info)
+{
+ struct fsl_dcfb_fb_info *fsl_info = info->par;
+
+ return (struct fsl_dcfb_fb_private *)fsl_info->parent;
+}
+
+static int fsl_dcfb_get_bpp(unsigned int bits_per_pixel)
+{
+ int bpp;
+
+ switch (bits_per_pixel) {
+ case 16:
+ bpp = FSL_DCFB_RGB565;
+ break;
+ case 24:
+ bpp = FSL_DCFB_RGB888;
+ break;
+ case 32:
+ bpp = FSL_DCFB_ARGB8888;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return bpp;
+}
+
+static int fsl_dcfb_set_panel(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+ int bpp;
+
+ regmap_write(dcfb->regmap, FSL_DCFB_VAR_SIZE,
+ FSL_DCFB_VAR_SIZE_H(var->yres) |
+ FSL_DCFB_VAR_SIZE_W(var->xres));
+ regmap_write(dcfb->regmap, FSL_DCFB_POS,
+ FSL_DCFB_POSY(0) | FSL_DCFB_POSX(0));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_BASE, info->fix.smem_start);
+
+ bpp = fsl_dcfb_get_bpp(var->bits_per_pixel);
+ if (bpp < 0) {
+ dev_err(dcfb->dev, "unsupported color depth: %u\n",
+ var->bits_per_pixel);
+ return bpp;
+ }
+
+ regmap_write(dcfb->regmap, FSL_DCFB_CTRL, FSL_DCFB_CTRL_EN |
+ FSL_DCFB_CTRL_TRANS(0xFF) | FSL_DCFB_CTRL_BPP(bpp));
+ regmap_write(dcfb->regmap, FSL_DCFB_CKMAX, FSL_DCFB_CKMAX_R(0xFF) |
+ FSL_DCFB_CKMAX_G(0xFF) | FSL_DCFB_CKMAX_B(0xFF));
+ regmap_write(dcfb->regmap, FSL_DCFB_CKMIN, FSL_DCFB_CKMIN_R(0) |
+ FSL_DCFB_CKMIN_G(0) | FSL_DCFB_CKMIN_B(0));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_FCOLOR, FSL_DCFB_FCOLOR_OFF(0));
+ regmap_write(dcfb->regmap, FSL_DCFB_BCOLOR, FSL_DCFB_BCOLOR_OFF(0));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_UPDATE, FSL_DCFB_UPDATE_READREG);
+
+ return 0;
+}
+
+static int fsl_dcfb_reset_panel(struct fsl_dcfb_fb_private *dcfb)
+{
+ regmap_write(dcfb->regmap, FSL_DCFB_VAR_SIZE, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_POS, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_BASE, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_CTRL, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_CKMAX, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_CKMIN, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_FCOLOR, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_BCOLOR, 0x0);
+ regmap_write(dcfb->regmap, FSL_DCFB_SKIP, 0x0);
+
+ regmap_write(dcfb->regmap, FSL_DCFB_UPDATE, FSL_DCFB_UPDATE_READREG);
+
+ return 0;
+}
+
+static void fsl_dcfb_modeset(struct fsl_dcfb_fb_private *dcfb,
+ enum fsl_dcfb_mode mode)
+{
+ regmap_update_bits(dcfb->regmap, FSL_DCFB_MODE,
+ FSL_DCFB_MODE_MODE_MASK,
+ FSL_DCFB_MODE_MODE(mode));
+}
+
+static int fsl_dcfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->xoffset + info->var.xres > info->var.xres_virtual)
+ var->xoffset = info->var.xres_virtual - info->var.xres;
+
+ if (var->yoffset + info->var.yres > info->var.yres_virtual)
+ var->yoffset = info->var.yres_virtual - info->var.yres;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+ break;
+ default:
+ dev_err(dcfb->dev, "unsupported color depth: %u\n",
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fsl_dcfb_alloc_mem(struct fb_info *info)
+{
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+ u32 smem_len = info->fix.line_length * info->var.yres_virtual;
+
+ info->fix.smem_len = smem_len;
+
+ info->screen_base = dma_alloc_writecombine(info->device,
+ info->fix.smem_len, (dma_addr_t *)&info->fix.smem_start,
+ GFP_KERNEL);
+ if (!info->screen_base) {
+ dev_err(dcfb->dev, "unable to allocate fb memory\n");
+ return -ENOMEM;
+ }
+
+ memset(info->screen_base, 0, info->fix.smem_len);
+
+ return 0;
+}
+
+static void fsl_dcfb_free_mem(struct fb_info *info)
+{
+ if (!info->screen_base)
+ return;
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
+
+ info->screen_base = NULL;
+ info->fix.smem_start = 0;
+ info->fix.smem_len = 0;
+}
+
+static int fsl_dcfb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+ unsigned int div, len;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = fix->ypanstep = 1;
+
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ len = info->var.yres_virtual * info->fix.line_length;
+ if (len != info->fix.smem_len) {
+ if (info->fix.smem_start)
+ fsl_dcfb_free_mem(info);
+
+ if (fsl_dcfb_alloc_mem(info)) {
+ dev_err(dcfb->dev, "unable to allocate FB memory\n");
+ return -ENOMEM;
+ }
+ }
+
+ div = KHZ2PICOS(clk_get_rate(dcfb->clk) / 1000);
+ regmap_write(dcfb->regmap, FSL_DCFB_DIV_RATIO,
+ info->var.pixclock / div);
+
+ regmap_write(dcfb->regmap, FSL_DCFB_FIX_SIZE,
+ FSL_DCFB_FIX_SIZE_Y(var->yres) |
+ FSL_DCFB_FIX_SIZE_X(var->xres / 16));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_HSYN,
+ FSL_DCFB_HSYN_BP(var->left_margin) |
+ FSL_DCFB_HSYN_PW(var->hsync_len) |
+ FSL_DCFB_HSYN_FP(var->right_margin));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_VSYN,
+ FSL_DCFB_VSYN_BP(var->upper_margin) |
+ FSL_DCFB_VSYN_PW(var->vsync_len) |
+ FSL_DCFB_VSYN_FP(var->lower_margin));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_SP,
+ FSL_DCFB_SP_VS | FSL_DCFB_SP_HS);
+
+ regmap_write(dcfb->regmap, FSL_DCFB_BGND, FSL_DCFB_BGND_R(0) |
+ FSL_DCFB_BGND_G(0) | FSL_DCFB_BGND_B(0));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_MODE,
+ FSL_DCFB_MODE_BITER(1) | FSL_DCFB_MODE_RASTER_EN);
+
+ regmap_write(dcfb->regmap, FSL_DCFB_TS, FSL_DCFB_TS_LBV(0x03) |
+ FSL_DCFB_TS_OBH(0x78) | FSL_DCFB_TS_OBL(0x0A));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_UPDATE, FSL_DCFB_UPDATE_READREG);
+
+ fsl_dcfb_modeset(dcfb, FSL_DCFB_MOD_NORMAL);
+ fsl_dcfb_set_panel(info);
+
+ return 0;
+}
+
+#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
+static int fsl_dcfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+ u32 value;
+
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+
+ value = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ pal[regno] = value;
+ ret = 0;
+ }
+ break;
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+#undef CNVT_TOHW
+
+static int fsl_dcfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+ unsigned long addr;
+ int offset;
+
+ if ((info->var.xoffset = var->xoffset) &&
+ (info->var.yoffset = var->yoffset))
+ return 0;
+
+ if ((var->xoffset + info->var.xres) > info->var.xres_virtual
+ || (var->yoffset + info->var.yres) > info->var.yres_virtual)
+ return -EINVAL;
+
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+ offset = (info->var.yoffset * info->var.xres_virtual);
+ offset += info->var.xoffset;
+ addr = info->fix.smem_start +
+ (offset * (info->var.bits_per_pixel >> 3));
+
+ regmap_write(dcfb->regmap, FSL_DCFB_BASE, addr);
+ regmap_write(dcfb->regmap, FSL_DCFB_UPDATE, FSL_DCFB_UPDATE_READREG);
+
+ return 0;
+}
+
+static int fsl_dcfb_blank(int blank_mode, struct fb_info *info)
+{
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+
+ switch (blank_mode) {
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ fsl_dcfb_reset_panel(dcfb);
+ break;
+ case FB_BLANK_POWERDOWN:
+ fsl_dcfb_modeset(dcfb, FSL_DCFB_MOD_OFF);
+ break;
+ case FB_BLANK_UNBLANK:
+ fsl_dcfb_set_panel(info);
+ break;
+ }
+
+ return 0;
+}
+
+static int fsl_dcfb_open(struct fb_info *info, int user)
+{
+ struct fsl_dcfb_fb_info *fsl_info = info->par;
+ int ret = 0;
+
+ fsl_info->count++;
+ if (fsl_info->count = 1) {
+ fsl_dcfb_check_var(&info->var, info);
+ ret = fsl_dcfb_set_par(info);
+ if (ret < 0)
+ fsl_info->count--;
+ }
+
+ return ret;
+}
+
+static int fsl_dcfb_release(struct fb_info *info, int user)
+{
+ struct fsl_dcfb_fb_info *fsl_info = info->par;
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+ int ret = 0;
+
+ fsl_info->count--;
+ if (fsl_info->count = 0)
+ ret = fsl_dcfb_reset_panel(dcfb);
+
+ return ret;
+}
+
+static struct fb_ops fsl_dcfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = fsl_dcfb_check_var,
+ .fb_set_par = fsl_dcfb_set_par,
+ .fb_setcolreg = fsl_dcfb_setcolreg,
+ .fb_blank = fsl_dcfb_blank,
+ .fb_pan_display = fsl_dcfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_open = fsl_dcfb_open,
+ .fb_release = fsl_dcfb_release,
+};
+
+static int fsl_dcfb_init_fbinfo(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct fsl_dcfb_fb_private *dcfb = to_fsl_private(info);
+ struct device_node *np = dcfb->dev->of_node;
+ struct device_node *dnp, *tnp;
+ struct display_timings *timings;
+ struct fb_videomode fb_vm;
+ int i, ret;
+
+ INIT_LIST_HEAD(&info->modelist);
+
+ dnp = of_parse_phandle(np, "display", 0);
+ if (!dnp) {
+ dev_err(dcfb->dev, "failed to find \"display\" phandle.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(dnp, "bits-per-pixel",
+ &var->bits_per_pixel);
+ if (ret < 0) {
+ dev_err(dcfb->dev, "failed to get \"bits-per-pixel\" property.\n");
+ goto put_dnp;
+ }
+
+ timings = of_get_display_timings(dnp);
+ if (!timings) {
+ dev_err(dcfb->dev, "failed to get display timings\n");
+ return -ENODEV;
+ goto put_dnp;
+ }
+
+ tnp = of_find_node_by_name(dnp, "display-timings");
+ if (!tnp) {
+ dev_err(dcfb->dev, "failed to find \"display-timings\" node\n");
+ return -ENODEV;
+ goto put_dnp;
+ }
+
+ for (i = 0; i < of_get_child_count(tnp); i++) {
+ struct videomode vm;
+
+ ret = videomode_from_timings(timings, &vm, i);
+ if (ret < 0)
+ goto put_tnp;
+
+ ret = fb_videomode_from_videomode(&vm, &fb_vm);
+ if (ret < 0)
+ goto put_tnp;
+
+ fb_add_videomode(&fb_vm, &info->modelist);
+ }
+
+ ret = of_get_fb_videomode(dnp, &fb_vm, OF_USE_NATIVE_MODE);
+ if (ret)
+ goto put_dnp;
+
+ fb_videomode_to_var(&info->var, &fb_vm);
+ ret = fsl_dcfb_check_var(&info->var, info);
+
+put_tnp:
+ of_node_put(tnp);
+put_dnp:
+ of_node_put(dnp);
+
+ return ret;
+}
+
+static const struct regmap_config fsl_scfg_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = FSL_SCFG_CTRL,
+};
+
+static int scfg_config(struct fsl_dcfb_fb_private *dcfb, struct device_node *np)
+{
+ struct device_node *snp;
+ struct platform_device *pdev;
+ struct resource *res;
+ void __iomem *base;
+ struct regmap *regmap;
+ int ret = 0;
+
+ snp = of_parse_phandle(np, "scfg-controller", 0);
+ if (!snp)
+ return -ENODEV;
+
+ pdev = of_find_device_by_node(snp);
+ if (!pdev) {
+ ret = -ENODEV;
+ goto put_snp;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto put_snp;
+ }
+
+ base = ioremap(res->start, SZ_4K);
+ if (IS_ERR(base)) {
+ dev_err(&pdev->dev, "could not ioremap scfg resource\n");
+ ret = PTR_ERR(base);
+ goto put_snp;
+ }
+
+ regmap = regmap_init_mmio(&pdev->dev, base,
+ &fsl_scfg_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ ret = PTR_ERR(regmap);
+ goto ioremap;
+ }
+
+ regmap_write(regmap, FSL_SCFG_CTRL, FSL_SCFG_PIXEL_EN);
+
+ regmap_exit(regmap);
+ioremap:
+ iounmap(base);
+put_snp:
+ of_node_put(snp);
+
+ return ret;
+}
+
+static int fsl_dcfb_dev_init(struct device_node *np,
+ struct fsl_dcfb_fb_private *dcfb)
+{
+ int ret;
+
+ ret = scfg_config(dcfb, np);
+ if (ret) {
+ dev_err(dcfb->dev, "could not config scfg\n");
+ return -EINVAL;
+ }
+
+ return fsl_dcfb_reset_panel(dcfb);
+}
+
+static const struct regmap_config fsl_dcfb_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = FSL_DCFB_MAX,
+};
+
+static int fsl_dcfb_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_dcfb_fb_private *dcfb;
+ struct fsl_dcfb_fb_info *fsl_info;
+ struct fb_info *info;
+ struct resource *res;
+ void __iomem *base;
+ int ret = 0;
+
+ dcfb = devm_kzalloc(&pdev->dev,
+ sizeof(struct fsl_dcfb_fb_private), GFP_KERNEL);
+ if (!dcfb)
+ return -ENOMEM;
+
+ dcfb->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "could not get memory IO resource\n");
+ return -ENODEV;
+ }
+
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
+ dev_err(&pdev->dev, "could not ioremap resource\n");
+ return PTR_ERR(base);
+ }
+
+ dcfb->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+ NULL, base, &fsl_dcfb_regmap_config);
+ if (IS_ERR(dcfb->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(dcfb->regmap);
+ }
+
+ dcfb->clk = devm_clk_get(&pdev->dev, "dcfb");
+ if (IS_ERR(dcfb->clk)) {
+ ret = PTR_ERR(dcfb->clk);
+ dev_err(&pdev->dev, "could not get clock\n");
+ return -EINVAL;
+ }
+ clk_prepare_enable(dcfb->clk);
+
+ fsl_dcfb_dev_init(np, dcfb);
+
+ dcfb->fsl_dcfb_info + framebuffer_alloc(sizeof(struct fsl_dcfb_fb_info), &pdev->dev);
+ if (!dcfb->fsl_dcfb_info) {
+ ret = -ENOMEM;
+ goto err_clk;
+ }
+
+ dcfb->fsl_dcfb_info->fix.smem_start = 0;
+
+ fsl_info = dcfb->fsl_dcfb_info->par;
+ fsl_info->count = 0,
+ fsl_info->parent = dcfb;
+
+ info = dcfb->fsl_dcfb_info;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->fbops = &fsl_dcfb_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->pseudo_palette = &fsl_info->pseudo_palette;
+
+ ret = fb_alloc_cmap(&info->cmap, 16, 0);
+ if (ret) {
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ ret = fsl_dcfb_init_fbinfo(info);
+ if (ret)
+ goto err_cmap;
+
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(dcfb->dev, "failed to register framebuffer device\n");
+ goto err_cmap;
+ }
+
+ dev_set_drvdata(&pdev->dev, dcfb);
+
+ goto out;
+
+err_cmap:
+ fb_dealloc_cmap(&info->cmap);
+err_mem:
+ framebuffer_release(dcfb->fsl_dcfb_info);
+err_clk:
+ clk_disable_unprepare(dcfb->clk);
+out:
+ return ret;
+}
+
+static int fsl_dcfb_remove(struct platform_device *pdev)
+{
+ struct fsl_dcfb_fb_private *dcfb = dev_get_drvdata(&pdev->dev);
+ struct fb_info *info = dcfb->fsl_dcfb_info;
+
+ fsl_dcfb_modeset(dcfb, FSL_DCFB_MOD_OFF);
+ fsl_dcfb_free_mem(info);
+
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(dcfb->fsl_dcfb_info);
+ clk_disable_unprepare(dcfb->clk);
+
+ return 0;
+}
+
+static struct of_device_id fsl_dcfb_dt_ids[] = {
+ { .compatible = "fsl,ls1021a-dcfb", },
+ {}
+};
+
+static struct platform_driver fsl_dcfb_driver = {
+ .driver = {
+ .name = "fsl-dcfb",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_dcfb_dt_ids,
+ },
+ .probe = fsl_dcfb_probe,
+ .remove = fsl_dcfb_remove,
+};
+
+module_platform_driver(fsl_dcfb_driver);
+
+MODULE_DESCRIPTION("Freescale Simple Display Controller FB Driver");
+MODULE_ALIAS("platform:fsl-dcfb");
+MODULE_LICENSE("GPL v2");
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCHv2 2/4] video: fsl-dcfb: Add devicetree binding support
From: Xiubo Li @ 2014-12-03 9:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417598162-40433-1-git-send-email-Li.Xiubo@freescale.com>
Add devicetree binding support for fsl-dcfb framebuffer driver. It
uses the generic display bindings and helper functions.
Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com>
---
.../devicetree/bindings/video/fsl,dcfb.txt | 52 ++++++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/fsl,dcfb.txt
diff --git a/Documentation/devicetree/bindings/video/fsl,dcfb.txt b/Documentation/devicetree/bindings/video/fsl,dcfb.txt
new file mode 100644
index 0000000..2f3d02b
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/fsl,dcfb.txt
@@ -0,0 +1,52 @@
+* Freescale Simple Display Controller FB Driver
+
+== For dcfb node =+Required properties:
+- compatible: Should be one of "fsl,ls1021a-dcfb".
+- reg: Address and length of the register set for dcfb.
+- clocks: From common clock binding: handle to dcfb clock.
+- clock-names: From common clock binding: Shall be "dcfb".
+- display: The phandle to display node.
+
+Optional properties:
+- scfg-controller: The phandle of scfg node.
+
+== For display sub-node =+Required properties:
+- bits-per-pixel: <16> for RGB565,
+ <24> for RGB888,
+ <32> for RGB8888.
+
+Required timing node for dispplay sub-node:
+- display-timings: Refer to binding doc display-timing.txt for details.
+
+Examples:
+dcfb: dcfb@2ce0000 {
+ compatible = "fsl,ls1021a-dcfb";
+ reg = <0x0 0x2ce0000 0x0 0x10000>;
+ clocks = <&platform_clk 0>;
+ clock-names = "dcfb";
+ scfg-controller = <&scfg>;
+ display = <&display>;
+
+ display: display@0 {
+ bits-per-pixel = <24>;
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: nl4827hc19 {
+ clock-frequency = <10870000>;
+ hactive = <480>;
+ vactive = <272>;
+ hback-porch = <2>;
+ hfront-porch = <2>;
+ vback-porch = <1>;
+ vfront-porch = <1>;
+ hsync-len = <41>;
+ vsync-len = <2>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ };
+ };
+ };
+};
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCHv2 3/4] ARM: ls1021a: dtsi: Add dt node support for dcfb.
From: Xiubo Li @ 2014-12-03 9:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417598162-40433-1-git-send-email-Li.Xiubo@freescale.com>
On LS1021A SoC, the dcfb device is in BE mode.
Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com>
---
arch/arm/boot/dts/ls1021a.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index c70bb27..740a04e 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -383,6 +383,16 @@
<&platform_clk 1>;
};
+ dcfb: dcfb@2ce0000 {
+ compatible = "fsl,ls1021a-dcfb";
+ reg = <0x0 0x2ce0000 0x0 0x10000>;
+ clocks = <&platform_clk 0>;
+ clock-names = "dcfb";
+ scfg-controller = <&scfg>;
+ big-endian;
+ status = "disabled";
+ };
+
mdio0: mdio@2d24000 {
compatible = "gianfar";
device_type = "mdio";
--
2.1.0.27.g96db324
^ permalink raw reply related
* [PATCHv2 4/4] ARM: ls1021a: dts: Add and enable dt node for dcfb.
From: Xiubo Li @ 2014-12-03 9:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417598162-40433-1-git-send-email-Li.Xiubo@freescale.com>
On LS1021A TWR board, the TFT LCD panel is WQVGA "480x272", and
the bpp is 24.
Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com>
---
arch/arm/boot/dts/ls1021a-twr.dts | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts
index a2c591e..3602286 100644
--- a/arch/arm/boot/dts/ls1021a-twr.dts
+++ b/arch/arm/boot/dts/ls1021a-twr.dts
@@ -58,6 +58,32 @@
};
};
+&dcfb {
+ display = <&display>;
+ status = "okay";
+
+ display: display@0 {
+ bits-per-pixel = <24>;
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: nl4827hc19 {
+ clock-frequency = <10870000>;
+ hactive = <480>;
+ vactive = <272>;
+ hback-porch = <2>;
+ hfront-porch = <2>;
+ vback-porch = <2>;
+ vfront-porch = <2>;
+ hsync-len = <41>;
+ vsync-len = <4>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ };
+ };
+ };
+};
+
&dspi1 {
bus-num = <0>;
status = "okay";
--
2.1.0.27.g96db324
^ permalink raw reply related
* Re: [PATCHv2 0/4] LS1021A: Add dcfb framebuffer driver support.
From: Arnd Bergmann @ 2014-12-03 9:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417598162-40433-1-git-send-email-Li.Xiubo@freescale.com>
On Wednesday 03 December 2014 17:15:58 Xiubo Li wrote:
> Framebuffer driver for the Freescale SoC Display Controller.
>
>
> Change in V2:
> - Use the native-mode timing as default.
> - Add to_fsl_private().
<standard reply>
We try to not have any new framebuffer drivers. Please consider making
this a DRM/KMS driver instead.
</standard reply>
Arnd
^ permalink raw reply
* Re: [PATCH v10 2/6] backlight: Add support Skyworks SKY81452 backlight driver
From: Oliver Neukum @ 2014-12-03 10:02 UTC (permalink / raw)
To: gyungoh
Cc: sameo, lee.jones, grant.likely, robh+dt, jg1.han, cooloney,
pawel.moll, mark.rutland, ijc+devicetree, galak, trivial, akpm,
jic23, thomas.petazzoni, ktsai, hs, stwiss.opensource,
matti.vaittinen, broonie, jason, heiko, shawn.guo,
florian.vaussard, andrew, antonynpavlov, hytszk, plagnioj,
tomi.valkeinen, jack.yoo, linux-fbdev, linux-kernel, devicetree
In-Reply-To: <1417590332-4912-3-git-send-email-jack.yoo@skyworksinc.com>
On Wed, 2014-12-03 at 16:05 +0900, gyungoh@gmail.com wrote:
> +static ssize_t sky81452_bl_store_enable(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t
> count)
> +{
> + struct regmap *regmap = bl_get_data(to_backlight_device(dev));
> + unsigned long value;
> + int ret;
> +
> + ret = kstrtoul(buf, 16, &value);
> + if (IS_ERR_VALUE(ret))
> + return ret;
> +
> + ret = regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN,
> + value << CTZ(SKY81452_EN));
No range checking for value?
> + if (IS_ERR_VALUE(ret))
> + return ret;
> +
> + return count;
> +}
Regards
Oliver
--
Oliver Neukum <oneukum@suse.de>
^ permalink raw reply
* Re: [PATCH v2 1/2] backlight/lp855x: Refactor dt parsing code
From: Lee Jones @ 2014-12-03 10:15 UTC (permalink / raw)
To: Sean Paul
Cc: milo.kim-l0cyMroinI0, cooloney-Re5JQEeQqe8AvxtiuMwx3w,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, jg1.han-Sze3O3UU22JBDgjK7y7TUQ,
Stéphane Marchesin
In-Reply-To: <1417570752-23633-1-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
On Tue, 02 Dec 2014, Sean Paul wrote:
> This patch refactors the dt parsing code to avoid setting platform_data,
> instead just setting lp->pdata directly. This facilitates easier
> probe deferral since the current scheme would require us to clear out
> dev->platform_data before deferring.
>
> Cc: Stéphane Marchesin <marcheu@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
> drivers/video/backlight/lp855x_bl.c | 37 ++++++++++++++++++-------------------
> 1 file changed, 18 insertions(+), 19 deletions(-)
Applied with Acks, thanks.
> diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
> index 25fb8e3..257b3ba 100644
> --- a/drivers/video/backlight/lp855x_bl.c
> +++ b/drivers/video/backlight/lp855x_bl.c
> @@ -341,8 +341,10 @@ static const struct attribute_group lp855x_attr_group = {
> };
>
> #ifdef CONFIG_OF
> -static int lp855x_parse_dt(struct device *dev, struct device_node *node)
> +static int lp855x_parse_dt(struct lp855x *lp)
> {
> + struct device *dev = lp->dev;
> + struct device_node *node = dev->of_node;
> struct lp855x_platform_data *pdata;
> int rom_length;
>
> @@ -381,12 +383,12 @@ static int lp855x_parse_dt(struct device *dev, struct device_node *node)
> pdata->rom_data = &rom[0];
> }
>
> - dev->platform_data = pdata;
> + lp->pdata = pdata;
>
> return 0;
> }
> #else
> -static int lp855x_parse_dt(struct device *dev, struct device_node *node)
> +static int lp855x_parse_dt(struct lp855x *lp)
> {
> return -EINVAL;
> }
> @@ -395,18 +397,8 @@ static int lp855x_parse_dt(struct device *dev, struct device_node *node)
> static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> {
> struct lp855x *lp;
> - struct lp855x_platform_data *pdata = dev_get_platdata(&cl->dev);
> - struct device_node *node = cl->dev.of_node;
> int ret;
>
> - if (!pdata) {
> - ret = lp855x_parse_dt(&cl->dev, node);
> - if (ret < 0)
> - return ret;
> -
> - pdata = dev_get_platdata(&cl->dev);
> - }
> -
> if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
> return -EIO;
>
> @@ -414,16 +406,23 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> if (!lp)
> return -ENOMEM;
>
> - if (pdata->period_ns > 0)
> - lp->mode = PWM_BASED;
> - else
> - lp->mode = REGISTER_BASED;
> -
> lp->client = cl;
> lp->dev = &cl->dev;
> - lp->pdata = pdata;
> lp->chipname = id->name;
> lp->chip_id = id->driver_data;
> + lp->pdata = dev_get_platdata(&cl->dev);
> +
> + if (!lp->pdata) {
> + ret = lp855x_parse_dt(lp);
> + if (ret < 0)
> + return ret;
> + }
> +
> + if (lp->pdata->period_ns > 0)
> + lp->mode = PWM_BASED;
> + else
> + lp->mode = REGISTER_BASED;
> +
> i2c_set_clientdata(cl, lp);
>
> ret = lp855x_configure(lp);
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH v2 2/2] backlight/lp855x: Add supply regulator to lp855x
From: Lee Jones @ 2014-12-03 10:15 UTC (permalink / raw)
To: Sean Paul
Cc: milo.kim-l0cyMroinI0, cooloney-Re5JQEeQqe8AvxtiuMwx3w,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, jg1.han-Sze3O3UU22JBDgjK7y7TUQ,
Stéphane Marchesin, Aaron Durbin
In-Reply-To: <1417570752-23633-2-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
On Tue, 02 Dec 2014, Sean Paul wrote:
> This patch adds a supply regulator to the lp855x platform data to facilitate
> powering on/off the 3V rail attached to the controller.
>
> Cc: Stéphane Marchesin <marcheu@chromium.org>
> Cc: Aaron Durbin <adurbin@chromium.org>
> Acked-by: Milo Kim <milo.kim@ti.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>
> Changes in v2:
> - Add NULL check in lp855x_remove
>
>
> .../devicetree/bindings/video/backlight/lp855x.txt | 2 ++
> drivers/video/backlight/lp855x_bl.c | 18 ++++++++++++++++++
> include/linux/platform_data/lp855x.h | 2 ++
> 3 files changed, 22 insertions(+)
Applied with Acks, thanks.
> diff --git a/Documentation/devicetree/bindings/video/backlight/lp855x.txt b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
> index 96e83a5..0a3ecbc 100644
> --- a/Documentation/devicetree/bindings/video/backlight/lp855x.txt
> +++ b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
> @@ -12,6 +12,7 @@ Optional properties:
> - pwm-period: PWM period value. Set only PWM input mode used (u32)
> - rom-addr: Register address of ROM area to be updated (u8)
> - rom-val: Register value to be updated (u8)
> + - power-supply: Regulator which controls the 3V rail
>
> Example:
>
> @@ -56,6 +57,7 @@ Example:
> backlight@2c {
> compatible = "ti,lp8557";
> reg = <0x2c>;
> + power-supply = <&backlight_vdd>;
>
> dev-ctrl = /bits/ 8 <0x41>;
> init-brt = /bits/ 8 <0x0a>;
> diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
> index 257b3ba..a26d3bb 100644
> --- a/drivers/video/backlight/lp855x_bl.c
> +++ b/drivers/video/backlight/lp855x_bl.c
> @@ -17,6 +17,7 @@
> #include <linux/of.h>
> #include <linux/platform_data/lp855x.h>
> #include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>
>
> /* LP8550/1/2/3/6 Registers */
> #define LP855X_BRIGHTNESS_CTRL 0x00
> @@ -383,6 +384,13 @@ static int lp855x_parse_dt(struct lp855x *lp)
> pdata->rom_data = &rom[0];
> }
>
> + pdata->supply = devm_regulator_get(dev, "power");
> + if (IS_ERR(pdata->supply)) {
> + if (PTR_ERR(pdata->supply) = -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> + pdata->supply = NULL;
> + }
> +
> lp->pdata = pdata;
>
> return 0;
> @@ -423,6 +431,14 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> else
> lp->mode = REGISTER_BASED;
>
> + if (lp->pdata->supply) {
> + ret = regulator_enable(lp->pdata->supply);
> + if (ret < 0) {
> + dev_err(&cl->dev, "failed to enable supply: %d\n", ret);
> + return ret;
> + }
> + }
> +
> i2c_set_clientdata(cl, lp);
>
> ret = lp855x_configure(lp);
> @@ -454,6 +470,8 @@ static int lp855x_remove(struct i2c_client *cl)
>
> lp->bl->props.brightness = 0;
> backlight_update_status(lp->bl);
> + if (lp->pdata->supply)
> + regulator_disable(lp->pdata->supply);
> sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
>
> return 0;
> diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h
> index 1b2ba24..9c7fd1e 100644
> --- a/include/linux/platform_data/lp855x.h
> +++ b/include/linux/platform_data/lp855x.h
> @@ -136,6 +136,7 @@ struct lp855x_rom_data {
> Only valid when mode is PWM_BASED.
> * @size_program : total size of lp855x_rom_data
> * @rom_data : list of new eeprom/eprom registers
> + * @supply : regulator that supplies 3V input
> */
> struct lp855x_platform_data {
> const char *name;
> @@ -144,6 +145,7 @@ struct lp855x_platform_data {
> unsigned int period_ns;
> int size_program;
> struct lp855x_rom_data *rom_data;
> + struct regulator *supply;
> };
>
> #endif
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH 1/3] video: fbdev: vt8623fb: suppress build warning
From: Tomi Valkeinen @ 2014-12-03 11:49 UTC (permalink / raw)
To: Lad, Prabhakar, Jean-Christophe Plagniol-Villard
Cc: linux-fbdev, linux-kernel
In-Reply-To: <1417039645-5313-1-git-send-email-prabhakar.csengg@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1190 bytes --]
On 27/11/14 00:07, Lad, Prabhakar wrote:
> this patch fixes following build warning:
> drivers/video/fbdev/vt8623fb.c: In function ‘vt8623_pci_probe’:
> drivers/video/fbdev/vt8623fb.c:734:23: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> par->state.vgabase = (void __iomem *) vga_res.start;
> ^
> Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
> ---
> drivers/video/fbdev/vt8623fb.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
> index 5c7cbc6..ea7f056 100644
> --- a/drivers/video/fbdev/vt8623fb.c
> +++ b/drivers/video/fbdev/vt8623fb.c
> @@ -731,7 +731,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
>
> pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
>
> - par->state.vgabase = (void __iomem *) vga_res.start;
> + par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
This does look quite ugly... Where does the warning come from in the
first place. Isn't vga_res.start (resource_size_t) the size of a pointer?
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH] Converting int usage to bool
From: Tomi Valkeinen @ 2014-12-03 11:53 UTC (permalink / raw)
To: Quentin Lambert, Thomas Winischhofer
Cc: Jean-Christophe Plagniol-Villard, linux-fbdev, linux-kernel
In-Reply-To: <20141127104133.GA5051@wrath>
[-- Attachment #1: Type: text/plain, Size: 859 bytes --]
On 27/11/14 12:41, Quentin Lambert wrote:
> The following semantic patch was used to find
> functions and variables declared as int but
> used as boolean. The patch resulted in a
> significant number of false positive that I
> have ignored.
>
> I am not hyper confident about the modification
> I made to the functions. Some of them seem to
> have quite significant side effects, which is not
> necesserarily intended from a boolean function.
> In particular both *_rwtest functions write data.
> Moreover sisfb_find_host_bridge name may suggest
> more than a boolean return.
I don't think I'm going to apply based on the above. I do like bools
where a boolean value is used, but changing it like this to a single
fbdev driver.. Well, I don't really see much benefit in this patch, and
there's a possibility for regressions.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH v3 1/3] video: omapdss: Add opa362 driver
From: Tomi Valkeinen @ 2014-12-03 12:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417352867-7436-2-git-send-email-marek@goldelico.com>
[-- Attachment #1: Type: text/plain, Size: 1516 bytes --]
Hi,
On 30/11/14 15:07, Marek Belisko wrote:
> +#include <video/omap-panel-data.h>
This should not be needed, as the driver is DT only.
> +static int opa362_probe(struct platform_device *pdev)
> +{
> + struct device_node *node = pdev->dev.of_node;
> + struct panel_drv_data *ddata;
> + struct omap_dss_device *dssdev, *in;
> + struct gpio_desc *gpio;
> + int r;
> +
> + dev_dbg(&pdev->dev, "probe\n");
> +
> + if (node == NULL) {
> + dev_err(&pdev->dev, "Unable to find device tree\n");
> + return -EINVAL;
> + }
> +
> + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
> + if (!ddata)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, ddata);
> +
> + gpio = devm_gpiod_get(&pdev->dev, "enable");
> + if (IS_ERR(gpio)) {
> + if (PTR_ERR(gpio) != -ENOENT)
> + return PTR_ERR(gpio);
> + } else {
> + gpiod_direction_output(gpio, 0);
> + }
> +
> + ddata->enable_gpio = gpio;
The 'gpio' may be non-null here, if PTR_ERR(gpio) == -ENOENT. You should
set 'gpio' to NULL in the IS_ERR(gpio) path, as you later check the gpio
for NULL.
> +static struct platform_driver opa362_driver = {
> + .probe = opa362_probe,
> + .remove = __exit_p(opa362_remove),
> + .driver = {
> + .name = "amplifier-opa362",
> + .owner = THIS_MODULE,
> + .of_match_table = opa362_of_match,
> + },
Here you should add:
.suppress_bind_attrs = true,
so that the device/driver cannot be unbound via sysfs, as that's not
supported at the moment.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH v3 2/3] Documentation: DT: Add documentation for ti,opa362 bindings
From: Tomi Valkeinen @ 2014-12-03 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417352867-7436-3-git-send-email-marek@goldelico.com>
[-- Attachment #1: Type: text/plain, Size: 815 bytes --]
On 30/11/14 15:07, Marek Belisko wrote:
> Signed-off-by: Marek Belisko <marek@goldelico.com>
> ---
> .../devicetree/bindings/video/ti,opa362.txt | 38 ++++++++++++++++++++++
> 1 file changed, 38 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/video/ti,opa362.txt
>
> diff --git a/Documentation/devicetree/bindings/video/ti,opa362.txt b/Documentation/devicetree/bindings/video/ti,opa362.txt
> new file mode 100644
> index 0000000..4747ef9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/ti,opa362.txt
> @@ -0,0 +1,38 @@
> +OPA362 analog video amplifier
> +
> +Required properties:
> +- compatible: "ti,opa362"
> +- gpio: enable/disable output gpio
Either this or the example is wrong. If I'm not mistaken 'gpios' is the
correct form.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH] video: fbmon: Check Standard Timing against DMT and maxclk
From: Tomi Valkeinen @ 2014-12-03 12:57 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1416626512-12919-1-git-send-email-davidu@nvidia.com>
[-- Attachment #1: Type: text/plain, Size: 545 bytes --]
On 03/12/14 03:16, David Ung wrote:
> Ping?
Sorry I haven't been able to check this yet. I had a brief glance, and I
wonder if the patch should be split. You add modes to vesa_modes, I
presume those modes are valid even without any DMT or maxclk changes?
Also the maxclk check sounds like an independent change.
In any case, I think it's too late to include this into the next merge
window, as it's possible that this patch could break many fbdev drivers
and I'd rather have this patch sit on linux-next for a while.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH v2 2/2] backlight/lp855x: Add supply regulator to lp855x
From: Arnd Bergmann @ 2014-12-03 14:11 UTC (permalink / raw)
To: Sean Paul
Cc: milo.kim-l0cyMroinI0, cooloney-Re5JQEeQqe8AvxtiuMwx3w,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, jg1.han-Sze3O3UU22JBDgjK7y7TUQ,
lee.jones-QSEj5FYQhm4dnm+yROfE0A, Stéphane Marchesin,
Aaron Durbin
In-Reply-To: <1417570752-23633-2-git-send-email-seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
On Tuesday 02 December 2014 17:39:12 Sean Paul wrote:
>
> .../devicetree/bindings/video/backlight/lp855x.txt | 2 ++
> drivers/video/backlight/lp855x_bl.c | 18 ++++++++++++++++++
> include/linux/platform_data/lp855x.h | 2 ++
> 3 files changed, 22 insertions(+)
While your two patches are both correct (and applied already), I took
a look at the platform_data header and noticed that all users of this
file have been converted to DT a while ago, so it would be nice to clean
it up by integrating the linux/platform_data/lp855x.h header file into the
drivers/video/backlight/lp855x_bl.c itself.
You can then merge struct lp855x_platform_data into lp855x to avoid the
extra dynamic allocation and remove all the 'pdata' references in the
driver.
Arnd
^ permalink raw reply
* Re: [PATCH v2 2/2] backlight/lp855x: Add supply regulator to lp855x
From: Sean Paul @ 2014-12-03 17:28 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Sean Paul, Kim, Milo, Bryan Wu, linux-fbdev,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Jingoo Han,
Lee Jones, Stéphane Marchesin, Aaron Durbin
In-Reply-To: <5204192.bzM5jPIgHv@wuerfel>
On Wed, Dec 3, 2014 at 6:11 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 02 December 2014 17:39:12 Sean Paul wrote:
>>
>> .../devicetree/bindings/video/backlight/lp855x.txt | 2 ++
>> drivers/video/backlight/lp855x_bl.c | 18 ++++++++++++++++++
>> include/linux/platform_data/lp855x.h | 2 ++
>> 3 files changed, 22 insertions(+)
>
> While your two patches are both correct (and applied already), I took
> a look at the platform_data header and noticed that all users of this
> file have been converted to DT a while ago, so it would be nice to clean
> it up by integrating the linux/platform_data/lp855x.h header file into the
> drivers/video/backlight/lp855x_bl.c itself.
>
> You can then merge struct lp855x_platform_data into lp855x to avoid the
> extra dynamic allocation and remove all the 'pdata' references in the
> driver.
>
Hi Arnd,
Thanks for the suggestion. Indeed, that will be much cleaner, I'll
send a follow-up patch.
Sean
> Arnd
^ permalink raw reply
* Re: [PATCH 1/3] video: fbdev: vt8623fb: suppress build warning
From: Prabhakar Lad @ 2014-12-03 18:29 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: Jean-Christophe Plagniol-Villard, LFBDEV, LKML
In-Reply-To: <547EF8CC.9030502@ti.com>
On Wed, Dec 3, 2014 at 11:49 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> On 27/11/14 00:07, Lad, Prabhakar wrote:
>> this patch fixes following build warning:
>> drivers/video/fbdev/vt8623fb.c: In function ‘vt8623_pci_probe’:
>> drivers/video/fbdev/vt8623fb.c:734:23: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
>> par->state.vgabase = (void __iomem *) vga_res.start;
>> ^
>> Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
>> ---
>> drivers/video/fbdev/vt8623fb.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
>> index 5c7cbc6..ea7f056 100644
>> --- a/drivers/video/fbdev/vt8623fb.c
>> +++ b/drivers/video/fbdev/vt8623fb.c
>> @@ -731,7 +731,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
>>
>> pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
>>
>> - par->state.vgabase = (void __iomem *) vga_res.start;
>> + par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
>
> This does look quite ugly... Where does the warning come from in the
> first place. Isn't vga_res.start (resource_size_t) the size of a pointer?
>
Yes looks ugly, I am not sure what you meant from 'where does this warning
come from' its in the commit message.
Thanks,
--Prabhakar Lad
^ permalink raw reply
* RE: [PATCH] video: fbmon: Check Standard Timing against DMT and maxclk
From: David Ung @ 2014-12-03 20:51 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1416626512-12919-1-git-send-email-davidu@nvidia.com>
>
> Sorry I haven't been able to check this yet. I had a brief glance, and I wonder
> if the patch should be split. You add modes to vesa_modes, I presume those
> modes are valid even without any DMT or maxclk changes?
>
> Also the maxclk check sounds like an independent change.
>
I'll split the patch up and resubmit.
David
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information. Any unauthorized review, use, disclosure or distribution
is prohibited. If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
^ permalink raw reply
* [PATCH v4 0/3] omapdss: Add video output support for gta04
From: Marek Belisko @ 2014-12-03 21:33 UTC (permalink / raw)
To: linux-arm-kernel
changes from v3:
- use GPL v2 instead GPL
- fix wrong gpios property name in doc and DT
- set gpio to NULL if invalid
- drop unnecessary header
changes from v2:
- rename amplifier-opa362.c to encoder-opa362
- drop inversion handlign from driver
- add ti,invert-polarity to venc node
I also drop devconf1 handling patches because discussion how to
properly implement is not yet finished and this part is independent
from video driver.
changes from v1:
- fix opa362 compilation error
- fix opa362 DT documentation
- move devconf1 definition to omap3.dtsi
Marek Belisko (3):
video: omapdss: Add opa362 driver
Documentation: DT: Add documentation for ti,opa362 bindings
arm: dts: omap3-gta04: Add handling for tv output
.../devicetree/bindings/video/ti,opa362.txt | 38 +++
arch/arm/boot/dts/omap3-gta04.dtsi | 49 ++++
drivers/video/fbdev/omap2/displays-new/Kconfig | 6 +
drivers/video/fbdev/omap2/displays-new/Makefile | 1 +
.../fbdev/omap2/displays-new/encoder-opa362.c | 285 +++++++++++++++++++++
5 files changed, 379 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/ti,opa362.txt
create mode 100644 drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
--
1.9.1
^ permalink raw reply
* [PATCH v4 1/3] video: omapdss: Add opa362 driver
From: Marek Belisko @ 2014-12-03 21:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417642402-20538-1-git-send-email-marek@goldelico.com>
opa362 is amplifier for video and can be connected to the tvout pads
of the OMAP3. It has one gpio control for enable/disable of the output
(high impedance).
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
Signed-off-by: Marek Belisko <marek@goldelico.com>
---
drivers/video/fbdev/omap2/displays-new/Kconfig | 6 +
drivers/video/fbdev/omap2/displays-new/Makefile | 1 +
.../fbdev/omap2/displays-new/encoder-opa362.c | 285 +++++++++++++++++++++
3 files changed, 292 insertions(+)
create mode 100644 drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
diff --git a/drivers/video/fbdev/omap2/displays-new/Kconfig b/drivers/video/fbdev/omap2/displays-new/Kconfig
index e6cfc38..5747101 100644
--- a/drivers/video/fbdev/omap2/displays-new/Kconfig
+++ b/drivers/video/fbdev/omap2/displays-new/Kconfig
@@ -1,6 +1,12 @@
menu "OMAP Display Device Drivers (new device model)"
depends on OMAP2_DSS
+config DISPLAY_ENCODER_OPA362
+ tristate "OPA362 external analog amplifier"
+ help
+ Driver for OPA362 external analog TV amplifier controlled
+ through a GPIO.
+
config DISPLAY_ENCODER_TFP410
tristate "TFP410 DPI to DVI Encoder"
help
diff --git a/drivers/video/fbdev/omap2/displays-new/Makefile b/drivers/video/fbdev/omap2/displays-new/Makefile
index 0323a8a..9aa176b 100644
--- a/drivers/video/fbdev/omap2/displays-new/Makefile
+++ b/drivers/video/fbdev/omap2/displays-new/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
new file mode 100644
index 0000000..84a6b33
--- /dev/null
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
@@ -0,0 +1,285 @@
+/*
+ * OPA362 analog video amplifier with output/power control
+ *
+ * Copyright (C) 2014 Golden Delicious Computers
+ * Author: H. Nikolaus Schaller <hns@goldelico.com>
+ *
+ * based on encoder-tfp410
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct gpio_desc *enable_gpio;
+
+ struct omap_video_timings timings;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int opa362_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(dssdev->dev, "connect\n");
+
+ if (omapdss_device_is_connected(dssdev))
+ return -EBUSY;
+
+ r = in->ops.atv->connect(in, dssdev);
+ if (r)
+ return r;
+
+ dst->src = dssdev;
+ dssdev->dst = dst;
+
+ return 0;
+}
+
+static void opa362_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "disconnect\n");
+
+ WARN_ON(!omapdss_device_is_connected(dssdev));
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ WARN_ON(dst != dssdev->dst);
+ if (dst != dssdev->dst)
+ return;
+
+ dst->src = NULL;
+ dssdev->dst = NULL;
+
+ in->ops.atv->disconnect(in, &ddata->dssdev);
+}
+
+static int opa362_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(dssdev->dev, "enable\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.atv->set_timings(in, &ddata->timings);
+
+ r = in->ops.atv->enable(in);
+ if (r)
+ return r;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void opa362_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "disable\n");
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
+
+ in->ops.atv->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void opa362_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "set_timings\n");
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.atv->set_timings(in, timings);
+}
+
+static void opa362_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ dev_dbg(dssdev->dev, "get_timings\n");
+
+ *timings = ddata->timings;
+}
+
+static int opa362_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "check_timings\n");
+
+ return in->ops.atv->check_timings(in, timings);
+}
+
+static void opa362_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ /* we can only drive a COMPOSITE output */
+ WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
+
+}
+
+static const struct omapdss_atv_ops opa362_atv_ops = {
+ .connect = opa362_connect,
+ .disconnect = opa362_disconnect,
+
+ .enable = opa362_enable,
+ .disable = opa362_disable,
+
+ .check_timings = opa362_check_timings,
+ .set_timings = opa362_set_timings,
+ .get_timings = opa362_get_timings,
+
+ .set_type = opa362_set_type,
+};
+
+static int opa362_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev, *in;
+ struct gpio_desc *gpio;
+ int r;
+
+ dev_dbg(&pdev->dev, "probe\n");
+
+ if (node = NULL) {
+ dev_err(&pdev->dev, "Unable to find device tree\n");
+ return -EINVAL;
+ }
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ gpio = devm_gpiod_get(&pdev->dev, "enable");
+ if (IS_ERR(gpio)) {
+ if (PTR_ERR(gpio) != -ENOENT)
+ return PTR_ERR(gpio);
+
+ gpio = NULL;
+ } else {
+ gpiod_direction_output(gpio, 0);
+ }
+
+ ddata->enable_gpio = gpio;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->ops.atv = &opa362_atv_ops;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->owner = THIS_MODULE;
+
+ r = omapdss_register_output(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register output\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit opa362_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_output(&ddata->dssdev);
+
+ WARN_ON(omapdss_device_is_enabled(dssdev));
+ if (omapdss_device_is_enabled(dssdev))
+ opa362_disable(dssdev);
+
+ WARN_ON(omapdss_device_is_connected(dssdev));
+ if (omapdss_device_is_connected(dssdev))
+ opa362_disconnect(dssdev, dssdev->dst);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id opa362_of_match[] = {
+ { .compatible = "omapdss,ti,opa362", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, opa362_of_match);
+
+static struct platform_driver opa362_driver = {
+ .probe = opa362_probe,
+ .remove = __exit_p(opa362_remove),
+ .driver = {
+ .name = "amplifier-opa362",
+ .owner = THIS_MODULE,
+ .of_match_table = opa362_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(opa362_driver);
+
+MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
+MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v4 2/3] Documentation: DT: Add documentation for ti,opa362 bindings
From: Marek Belisko @ 2014-12-03 21:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417642402-20538-1-git-send-email-marek@goldelico.com>
Signed-off-by: Marek Belisko <marek@goldelico.com>
---
.../devicetree/bindings/video/ti,opa362.txt | 38 ++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/ti,opa362.txt
diff --git a/Documentation/devicetree/bindings/video/ti,opa362.txt b/Documentation/devicetree/bindings/video/ti,opa362.txt
new file mode 100644
index 0000000..f96083c
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/ti,opa362.txt
@@ -0,0 +1,38 @@
+OPA362 analog video amplifier
+
+Required properties:
+- compatible: "ti,opa362"
+- enable-gpios: enable/disable output gpio
+
+Required node:
+- Video port 0 for opa362 input
+- Video port 1 for opa362 output
+
+Example:
+
+tv_amp: opa362 {
+ compatible = "ti,opa362";
+ enable-gpios = <&gpio1 23 0>; /* GPIO to enable video out amplifier */
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ opa_in: endpoint@0 {
+ remote-endpoint = <&venc_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ opa_out: endpoint@0 {
+ remote-endpoint = <&tv_connector_in>;
+ };
+ };
+ };
+};
+
+
+
--
1.9.1
^ permalink raw reply related
* [PATCH v4 3/3] arm: dts: omap3-gta04: Add handling for tv output
From: Marek Belisko @ 2014-12-03 21:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1417642402-20538-1-git-send-email-marek@goldelico.com>
Add handling for gta04 tv out chain:
venc -> opa362 -> svideo
Use invert-polarity in venc node because opa362
is doing polarity inversion also.
Signed-off-by: Marek Belisko <marek@goldelico.com>
---
arch/arm/boot/dts/omap3-gta04.dtsi | 49 ++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index fd34f91..a6e995b 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -83,6 +83,41 @@
compatible = "usb-nop-xceiv";
reset-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
};
+
+ tv0: connector@1 {
+ compatible = "svideo-connector";
+ label = "tv";
+
+ port {
+ tv_connector_in: endpoint {
+ remote-endpoint = <&opa_out>;
+ };
+ };
+ };
+
+ tv_amp: opa362 {
+ compatible = "ti,opa362";
+ enable-gpios = <&gpio1 23 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ opa_in: endpoint@0 {
+ remote-endpoint = <&venc_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ opa_out: endpoint@0 {
+ remote-endpoint = <&tv_connector_in>;
+ };
+ };
+ };
+ };
};
&omap3_pmx_core {
@@ -396,6 +431,20 @@
};
};
+&venc {
+ status = "okay";
+
+ vdda-supply = <&vdac>;
+
+ port {
+ venc_out: endpoint {
+ remote-endpoint = <&opa_in>;
+ ti,channels = <2>;
+ ti,invert-polarity;
+ };
+ };
+};
+
&gpmc {
ranges = <0 0 0x30000000 0x04>; /* CS0: NAND */
--
1.9.1
^ permalink raw reply related
* [PATCH 1/3] video: fbdev: Add additional vesa modes
From: David Ung @ 2014-12-03 21:49 UTC (permalink / raw)
To: linux-fbdev
Add high resolution modes to vesa_modes struct.
Signed-off-by: David Ung <davidu@nvidia.com>
---
drivers/video/fbdev/core/modedb.c | 27 +++++++++++++++++++++++++++
include/linux/fb.h | 2 +-
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
index 388f797..0b57c1df 100644
--- a/drivers/video/fbdev/core/modedb.c
+++ b/drivers/video/fbdev/core/modedb.c
@@ -468,6 +468,33 @@ const struct fb_videomode vesa_modes[] = {
/* 33 1920x1440-75 VESA */
{ NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 34 1920x1200-60 RB VESA */
+ { NULL, 60, 1920, 1200, 6493, 80, 48, 26, 3, 32, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 35 1920x1200-60 VESA */
+ { NULL, 60, 1920, 1200, 5174, 336, 136, 36, 3, 200, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 36 1920x1200-75 VESA */
+ { NULL, 75, 1920, 1200, 4077, 344, 136, 46, 3, 208, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 37 1920x1200-85 VESA */
+ { NULL, 85, 1920, 1200, 3555, 352, 144, 53, 3, 208, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 38 2560x1600-60 RB VESA */
+ { NULL, 60, 2560, 1600, 3724, 80, 48, 37, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 39 2560x1600-60 VESA */
+ { NULL, 60, 2560, 1600, 2869, 472, 192, 49, 3, 280, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 40 2560x1600-75 VESA */
+ { NULL, 75, 2560, 1600, 2256, 488, 208, 63, 3, 280, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 41 2560x1600-85 VESA */
+ { NULL, 85, 2560, 1600, 1979, 488, 208, 73, 3, 280, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 42 2560x1600-120 RB VESA */
+ { NULL, 120, 2560, 1600, 1809, 80, 48, 85, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
EXPORT_SYMBOL(vesa_modes);
#endif /* CONFIG_FB_MODE_HELPERS */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 09bb7a1..882dbd1 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -726,7 +726,7 @@ extern int fb_videomode_from_videomode(const struct videomode *vm,
struct fb_videomode *fbmode);
/* drivers/video/modedb.c */
-#define VESA_MODEDB_SIZE 34
+#define VESA_MODEDB_SIZE 43
extern void fb_var_to_videomode(struct fb_videomode *mode,
const struct fb_var_screeninfo *var);
extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
--
1.8.1.5
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information. Any unauthorized review, use, disclosure or distribution
is prohibited. If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
^ permalink raw reply related
* [PATCH 2/3] video: fbdev: Check Standard Timing against DMT
From: David Ung @ 2014-12-03 21:49 UTC (permalink / raw)
To: linux-fbdev
Add the VESA Display Monitor Timing (DMT) table.
During parsing of Standard Timings, it compare the 2 byte STD code
with DMT to see what the VESA mode should be. If there is no entry
in the vesa_modes table or no match found, it fallsback to the
GTF timings.
Signed-off-by: David Ung <davidu@nvidia.com>
---
drivers/video/fbdev/core/fbmon.c | 20 ++++++----
drivers/video/fbdev/core/modedb.c | 84 +++++++++++++++++++++++++++++++++++++++
include/linux/fb.h | 10 +++++
3 files changed, 107 insertions(+), 7 deletions(-)
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 5b0e313..aa1110a 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -526,16 +526,22 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
refresh = (block[1] & 0x3f) + 60;
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
- for (i = 0; i < VESA_MODEDB_SIZE; i++) {
- if (vesa_modes[i].xres = xres &&
- vesa_modes[i].yres = yres &&
- vesa_modes[i].refresh = refresh) {
- *mode = vesa_modes[i];
+ for (i = 0; i < DMT_SIZE; i++) {
+ u32 std_2byte_code = block[0] << 8 | block[1];
+
+ if (std_2byte_code = dmt_modes[i].std_2byte_code) {
+ if (!dmt_modes[i].mode)
+ break;
+ *mode = *dmt_modes[i].mode;
mode->flag |= FB_MODE_IS_STANDARD;
- return 1;
+ DPRINTK(" DMT id=%d\n", dmt_modes[i].dmt_id);
+ break;
}
}
- calc_mode_timings(xres, yres, refresh, mode);
+
+ if (i = DMT_SIZE || !dmt_modes[i].mode)
+ calc_mode_timings(xres, yres, refresh, mode);
+
return 1;
}
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
index 0b57c1df..858a97e 100644
--- a/drivers/video/fbdev/core/modedb.c
+++ b/drivers/video/fbdev/core/modedb.c
@@ -497,6 +497,90 @@ const struct fb_videomode vesa_modes[] = {
FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
EXPORT_SYMBOL(vesa_modes);
+
+const struct dmt_videomode dmt_modes[DMT_SIZE] = {
+ { 0x01, 0x0000, 0x000000, &vesa_modes[0] },
+ { 0x02, 0x3119, 0x000000, &vesa_modes[1] },
+ { 0x03, 0x0000, 0x000000, &vesa_modes[2] },
+ { 0x04, 0x3140, 0x000000, &vesa_modes[3] },
+ { 0x05, 0x314c, 0x000000, &vesa_modes[4] },
+ { 0x06, 0x314f, 0x000000, &vesa_modes[5] },
+ { 0x07, 0x3159, 0x000000, &vesa_modes[6] },
+ { 0x08, 0x0000, 0x000000, &vesa_modes[7] },
+ { 0x09, 0x4540, 0x000000, &vesa_modes[8] },
+ { 0x0a, 0x454c, 0x000000, &vesa_modes[9] },
+ { 0x0b, 0x454f, 0x000000, &vesa_modes[10] },
+ { 0x0c, 0x4559, 0x000000, &vesa_modes[11] },
+ { 0x0d, 0x0000, 0x000000, 0 },
+ { 0x0e, 0x0000, 0x000000, 0 },
+ { 0x0f, 0x0000, 0x000000, &vesa_modes[12] },
+ { 0x10, 0x6140, 0x000000, &vesa_modes[13] },
+ { 0x11, 0x614a, 0x000000, &vesa_modes[14] },
+ { 0x12, 0x614f, 0x000000, &vesa_modes[15] },
+ { 0x13, 0x6159, 0x000000, &vesa_modes[16] },
+ { 0x14, 0x0000, 0x000000, 0 },
+ { 0x15, 0x714f, 0x000000, &vesa_modes[17] },
+ { 0x16, 0x0000, 0x7f1c21, 0 },
+ { 0x17, 0x0000, 0x7f1c28, 0 },
+ { 0x18, 0x0000, 0x7f1c44, 0 },
+ { 0x19, 0x0000, 0x7f1c62, 0 },
+ { 0x1a, 0x0000, 0x000000, 0 },
+ { 0x1b, 0x0000, 0x8f1821, 0 },
+ { 0x1c, 0x8100, 0x8f1828, 0 },
+ { 0x1d, 0x810f, 0x8f1844, 0 },
+ { 0x1e, 0x8119, 0x8f1862, 0 },
+ { 0x1f, 0x0000, 0x000000, 0 },
+ { 0x20, 0x8140, 0x000000, &vesa_modes[18] },
+ { 0x21, 0x8159, 0x000000, &vesa_modes[19] },
+ { 0x22, 0x0000, 0x000000, 0 },
+ { 0x23, 0x8180, 0x000000, &vesa_modes[20] },
+ { 0x24, 0x818f, 0x000000, &vesa_modes[21] },
+ { 0x25, 0x8199, 0x000000, &vesa_modes[22] },
+ { 0x26, 0x0000, 0x000000, 0 },
+ { 0x27, 0x0000, 0x000000, 0 },
+ { 0x28, 0x0000, 0x000000, 0 },
+ { 0x29, 0x0000, 0x0c2021, 0 },
+ { 0x2a, 0x9040, 0x0c2028, 0 },
+ { 0x2b, 0x904f, 0x0c2044, 0 },
+ { 0x2c, 0x9059, 0x0c2062, 0 },
+ { 0x2d, 0x0000, 0x000000, 0 },
+ { 0x2e, 0x9500, 0xc11821, 0 },
+ { 0x2f, 0x9500, 0xc11828, 0 },
+ { 0x30, 0x950f, 0xc11844, 0 },
+ { 0x31, 0x9519, 0xc11868, 0 },
+ { 0x32, 0x0000, 0x000000, 0 },
+ { 0x33, 0xa940, 0x000000, &vesa_modes[23] },
+ { 0x34, 0xa945, 0x000000, &vesa_modes[24] },
+ { 0x35, 0xa94a, 0x000000, &vesa_modes[25] },
+ { 0x36, 0xa94f, 0x000000, &vesa_modes[26] },
+ { 0x37, 0xa959, 0x000000, &vesa_modes[27] },
+ { 0x38, 0x0000, 0x000000, 0 },
+ { 0x39, 0x0000, 0x0c2821, 0 },
+ { 0x3a, 0xb300, 0x0c2828, 0 },
+ { 0x3b, 0xb30f, 0x0c2844, 0 },
+ { 0x3c, 0xb319, 0x0c2868, 0 },
+ { 0x3d, 0x0000, 0x000000, 0 },
+ { 0x3e, 0xc140, 0x000000, &vesa_modes[28] },
+ { 0x3f, 0xc14f, 0x000000, &vesa_modes[29] },
+ { 0x40, 0x0000, 0x000000, 0 },
+ { 0x41, 0xc940, 0x000000, &vesa_modes[30] },
+ { 0x42, 0xc94f, 0x000000, &vesa_modes[31] },
+ { 0x43, 0x0000, 0x000000, 0 },
+ { 0x44, 0x0000, 0x572821, &vesa_modes[34] },
+ { 0x45, 0xd100, 0x572828, &vesa_modes[35] },
+ { 0x46, 0xd10f, 0x572844, &vesa_modes[36] },
+ { 0x47, 0xd119, 0x572862, &vesa_modes[37] },
+ { 0x48, 0x0000, 0x000000, 0 },
+ { 0x49, 0xd140, 0x000000, &vesa_modes[32] },
+ { 0x4a, 0xd14f, 0x000000, &vesa_modes[33] },
+ { 0x4b, 0x0000, 0x000000, 0 },
+ { 0x4c, 0x0000, 0x1f3821, &vesa_modes[38] },
+ { 0x4d, 0x0000, 0x1f3828, &vesa_modes[39] },
+ { 0x4e, 0x0000, 0x1f3844, &vesa_modes[40] },
+ { 0x4f, 0x0000, 0x1f3862, &vesa_modes[41] },
+ { 0x50, 0x0000, 0x000000, &vesa_modes[42] },
+};
+EXPORT_SYMBOL(dmt_modes);
#endif /* CONFIG_FB_MODE_HELPERS */
/**
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 882dbd1..043f328 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -727,6 +727,8 @@ extern int fb_videomode_from_videomode(const struct videomode *vm,
/* drivers/video/modedb.c */
#define VESA_MODEDB_SIZE 43
+#define DMT_SIZE 0x50
+
extern void fb_var_to_videomode(struct fb_videomode *mode,
const struct fb_var_screeninfo *var);
extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
@@ -777,9 +779,17 @@ struct fb_videomode {
u32 flag;
};
+struct dmt_videomode {
+ u32 dmt_id;
+ u32 std_2byte_code;
+ u32 cvt_3byte_code;
+ const struct fb_videomode *mode;
+};
+
extern const char *fb_mode_option;
extern const struct fb_videomode vesa_modes[];
extern const struct fb_videomode cea_modes[64];
+extern const struct dmt_videomode dmt_modes[];
struct fb_modelist {
struct list_head list;
--
1.8.1.5
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information. Any unauthorized review, use, disclosure or distribution
is prohibited. If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
^ permalink raw reply related
* [PATCH 3/3] video: fbdev: Validate mode timing against monspec
From: David Ung @ 2014-12-03 21:49 UTC (permalink / raw)
To: linux-fbdev
fbmon may generate mode timings that are out of spec of the monitor.
eg DELL U2410 has a max clock 170mhz but advertises a resolutions of
1920x1200@60 in its Standard Timings, fbmon creates a mode using the
GTF timing calculation which gave it a 193mhz clock.
This patch checks to see if the mode can be supported by the monitor
by comparing against monspecs.dclkmax.
Signed-off-by: David Ung <davidu@nvidia.com>
---
drivers/video/fbdev/core/fbmon.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index aa1110a..cc3ea6c8 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -496,7 +496,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
}
static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
- int ver, int rev)
+ int ver, int rev, struct fb_monspecs *specs)
{
int xres, yres = 0, refresh, ratio, i;
@@ -542,16 +542,23 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
if (i = DMT_SIZE || !dmt_modes[i].mode)
calc_mode_timings(xres, yres, refresh, mode);
+ /* Check the mode we got is within valid spec of the monitor */
+ if (specs && specs->dclkmax
+ && PICOS2KHZ(mode->pixclock) * 1000 > specs->dclkmax) {
+ DPRINTK(" mode exceed max DCLK\n");
+ return 0;
+ }
+
return 1;
}
-static int get_dst_timing(unsigned char *block,
- struct fb_videomode *mode, int ver, int rev)
+static int get_dst_timing(unsigned char *block, struct fb_videomode *mode,
+ int ver, int rev, struct fb_monspecs *specs)
{
int j, num = 0;
for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
- num += get_std_timing(block, &mode[num], ver, rev);
+ num += get_std_timing(block, &mode[num], ver, rev, specs);
return num;
}
@@ -607,7 +614,8 @@ static void get_detailed_timing(unsigned char *block,
* This function builds a mode database using the contents of the EDID
* data
*/
-static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
+static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
+ struct fb_monspecs *specs)
{
struct fb_videomode *mode, *m;
unsigned char *block;
@@ -649,12 +657,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
DPRINTK(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
- num += get_std_timing(block, &mode[num], ver, rev);
+ num += get_std_timing(block, &mode[num], ver, rev, specs);
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
if (block[0] = 0x00 && block[1] = 0x00 && block[3] = 0xfa)
- num += get_dst_timing(block + 5, &mode[num], ver, rev);
+ num += get_dst_timing(block + 5, &mode[num],
+ ver, rev, specs);
}
/* Yikes, EDID data is totally useless */
@@ -713,7 +722,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
int num_modes, hz, hscan, pixclock;
int vtotal, htotal;
- modes = fb_create_modedb(edid, &num_modes);
+ modes = fb_create_modedb(edid, &num_modes, specs);
if (!modes) {
DPRINTK("None Available\n");
return 1;
@@ -970,7 +979,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
DPRINTK(" Display Characteristics:\n");
get_monspecs(edid, specs);
- specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
+ specs->modedb = fb_create_modedb(edid, &specs->modedb_len, specs);
/*
* Workaround for buggy EDIDs that sets that the first
--
1.8.1.5
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information. Any unauthorized review, use, disclosure or distribution
is prohibited. If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox