Merge remote-tracking branch 'omap_dss2/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 01:28:21 +0000 (11:28 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 01:28:21 +0000 (11:28 +1000)
22 files changed:
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/amba-clcd-nomadik.c [new file with mode: 0644]
drivers/video/fbdev/amba-clcd-nomadik.h [new file with mode: 0644]
drivers/video/fbdev/amba-clcd-versatile.c
drivers/video/fbdev/amba-clcd-versatile.h [new file with mode: 0644]
drivers/video/fbdev/amba-clcd.c
drivers/video/fbdev/bfin_adv7393fb.c
drivers/video/fbdev/efifb.c
drivers/video/fbdev/mb862xx/mb862xx-i2c.c
drivers/video/fbdev/mx3fb.c
drivers/video/fbdev/mxsfb.c
drivers/video/fbdev/omap/lcd_mipid.c
drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
drivers/video/fbdev/omap2/omapfb/dss/dsi.c
drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/s3c2410fb.c
drivers/video/fbdev/s3c2410fb.h
include/linux/amba/clcd.h

index 88b008fb8a4ec9f4f4458b8b65a5e7d4ccef57e5..6c28ecc3958cee1e3ae651efa3991e3bc1479d45 100644 (file)
@@ -284,12 +284,14 @@ config FB_PM2_FIFO_DISCONNECT
 config FB_ARMCLCD
        tristate "ARM PrimeCell PL110 support"
        depends on ARM || ARM64 || COMPILE_TEST
-       depends on FB && ARM_AMBA
+       depends on FB && ARM_AMBA && HAS_IOMEM
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select FB_MODE_HELPERS if OF
        select VIDEOMODE_HELPERS if OF
+       select BACKLIGHT_LCD_SUPPORT if OF
+       select BACKLIGHT_CLASS_DEVICE if OF
        help
          This framebuffer device driver is for the ARM PrimeCell PL110
          Colour LCD controller.  ARM PrimeCells provide the building
@@ -305,6 +307,8 @@ config PLAT_VERSATILE_CLCD
        def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR
        depends on ARM
        depends on FB_ARMCLCD && FB=y
+       select REGMAP
+       select MFD_SYSCON
 
 config FB_ACORN
        bool "Acorn VIDC support"
index f6731867dd26dfc4318799e5204cd583a5d27670..5550944f0ad776d9da7174d3aac537e04c86e599 100644 (file)
@@ -79,6 +79,7 @@ obj-$(CONFIG_FB_ATMEL)                  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)         += amba-clcd.o
+obj-$(CONFIG_ARCH_NOMADIK)       += amba-clcd-nomadik.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += amba-clcd-versatile.o
 obj-$(CONFIG_FB_GOLDFISH)         += goldfishfb.o
 obj-$(CONFIG_FB_68328)            += 68328fb.o
diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c
new file mode 100644 (file)
index 0000000..0c06fca
--- /dev/null
@@ -0,0 +1,259 @@
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "amba-clcd-nomadik.h"
+
+static struct gpio_desc *grestb;
+static struct gpio_desc *scen;
+static struct gpio_desc *scl;
+static struct gpio_desc *sda;
+
+static u8 tpg110_readwrite_reg(bool write, u8 address, u8 outval)
+{
+       int i;
+       u8 inval = 0;
+
+       /* Assert SCEN */
+       gpiod_set_value_cansleep(scen, 1);
+       ndelay(150);
+       /* Hammer out the address */
+       for (i = 5; i >= 0; i--) {
+               if (address & BIT(i))
+                       gpiod_set_value_cansleep(sda, 1);
+               else
+                       gpiod_set_value_cansleep(sda, 0);
+               ndelay(150);
+               /* Send an SCL pulse */
+               gpiod_set_value_cansleep(scl, 1);
+               ndelay(160);
+               gpiod_set_value_cansleep(scl, 0);
+               ndelay(160);
+       }
+
+       if (write) {
+               /* WRITE */
+               gpiod_set_value_cansleep(sda, 0);
+       } else {
+               /* READ */
+               gpiod_set_value_cansleep(sda, 1);
+       }
+       ndelay(150);
+       /* Send an SCL pulse */
+       gpiod_set_value_cansleep(scl, 1);
+       ndelay(160);
+       gpiod_set_value_cansleep(scl, 0);
+       ndelay(160);
+
+       if (!write)
+               /* HiZ turn-around cycle */
+               gpiod_direction_input(sda);
+       ndelay(150);
+       /* Send an SCL pulse */
+       gpiod_set_value_cansleep(scl, 1);
+       ndelay(160);
+       gpiod_set_value_cansleep(scl, 0);
+       ndelay(160);
+
+       /* Hammer in/out the data */
+       for (i = 7; i >= 0; i--) {
+               int value;
+
+               if (write) {
+                       value = !!(outval & BIT(i));
+                       gpiod_set_value_cansleep(sda, value);
+               } else {
+                       value = gpiod_get_value(sda);
+                       if (value)
+                               inval |= BIT(i);
+               }
+               ndelay(150);
+               /* Send an SCL pulse */
+               gpiod_set_value_cansleep(scl, 1);
+               ndelay(160);
+               gpiod_set_value_cansleep(scl, 0);
+               ndelay(160);
+       }
+
+       gpiod_direction_output(sda, 0);
+       /* Deassert SCEN */
+       gpiod_set_value_cansleep(scen, 0);
+       /* Satisfies SCEN pulse width */
+       udelay(1);
+
+       return inval;
+}
+
+static u8 tpg110_read_reg(u8 address)
+{
+       return tpg110_readwrite_reg(false, address, 0);
+}
+
+static void tpg110_write_reg(u8 address, u8 outval)
+{
+       tpg110_readwrite_reg(true, address, outval);
+}
+
+static void tpg110_startup(struct device *dev)
+{
+       u8 val;
+
+       dev_info(dev, "TPG110 display enable\n");
+       /* De-assert the reset signal */
+       gpiod_set_value_cansleep(grestb, 0);
+       mdelay(1);
+       dev_info(dev, "de-asserted GRESTB\n");
+
+       /* Test display communication */
+       tpg110_write_reg(0x00, 0x55);
+       val = tpg110_read_reg(0x00);
+       if (val == 0x55)
+               dev_info(dev, "passed communication test\n");
+       val = tpg110_read_reg(0x01);
+       dev_info(dev, "TPG110 chip ID: %d version: %d\n",
+               val>>4, val&0x0f);
+
+       /* Show display resolution */
+       val = tpg110_read_reg(0x02);
+       val &= 7;
+       switch (val) {
+       case 0x0:
+               dev_info(dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)");
+               break;
+       case 0x1:
+               dev_info(dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)");
+               break;
+       case 0x4:
+               dev_info(dev, "480x640 RGB");
+               break;
+       case 0x5:
+               dev_info(dev, "480x272 RGB");
+               break;
+       case 0x6:
+               dev_info(dev, "640x480 RGB");
+               break;
+       case 0x7:
+               dev_info(dev, "800x480 RGB");
+               break;
+       default:
+               dev_info(dev, "ILLEGAL RESOLUTION");
+               break;
+       }
+
+       val = tpg110_read_reg(0x03);
+       dev_info(dev, "resolution is controlled by %s\n",
+               (val & BIT(7)) ? "software" : "hardware");
+}
+
+static void tpg110_enable(struct clcd_fb *fb)
+{
+       struct device *dev = &fb->dev->dev;
+       static bool startup;
+       u8 val;
+
+       if (!startup) {
+               tpg110_startup(dev);
+               startup = true;
+       }
+
+       /* Take chip out of standby */
+       val = tpg110_read_reg(0x03);
+       val |= BIT(0);
+       tpg110_write_reg(0x03, val);
+}
+
+static void tpg110_disable(struct clcd_fb *fb)
+{
+       u8 val;
+
+       dev_info(&fb->dev->dev, "TPG110 display disable\n");
+       val = tpg110_read_reg(0x03);
+       /* Put into standby */
+       val &= ~BIT(0);
+       tpg110_write_reg(0x03, val);
+}
+
+static void tpg110_init(struct device *dev, struct device_node *np,
+                       struct clcd_board *board)
+{
+       dev_info(dev, "TPG110 display init\n");
+
+       grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode);
+       if (IS_ERR(grestb)) {
+               dev_err(dev, "no GRESTB GPIO\n");
+               return;
+       }
+       /* This asserts the GRESTB signal, putting the display into reset */
+       gpiod_direction_output(grestb, 1);
+
+       scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode);
+       if (IS_ERR(scen)) {
+               dev_err(dev, "no SCEN GPIO\n");
+               return;
+       }
+       gpiod_direction_output(scen, 0);
+       scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode);
+       if (IS_ERR(scl)) {
+               dev_err(dev, "no SCL GPIO\n");
+               return;
+       }
+       gpiod_direction_output(scl, 0);
+       sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode);
+       if (IS_ERR(sda)) {
+               dev_err(dev, "no SDA GPIO\n");
+               return;
+       }
+       gpiod_direction_output(sda, 0);
+       board->enable = tpg110_enable;
+       board->disable = tpg110_disable;
+}
+
+int nomadik_clcd_init_panel(struct clcd_fb *fb,
+                           struct device_node *endpoint)
+{
+       struct device_node *panel;
+
+       panel = of_graph_get_remote_port_parent(endpoint);
+       if (!panel)
+               return -ENODEV;
+
+       if (of_device_is_compatible(panel, "tpo,tpg110"))
+               tpg110_init(&fb->dev->dev, panel, fb->board);
+       else
+               dev_info(&fb->dev->dev, "unknown panel\n");
+
+       /* Unknown panel, fall through */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nomadik_clcd_init_panel);
+
+#define PMU_CTRL_OFFSET 0x0000
+#define PMU_CTRL_LCDNDIF BIT(26)
+
+int nomadik_clcd_init_board(struct amba_device *adev,
+                           struct clcd_board *board)
+{
+       struct regmap *pmu_regmap;
+
+       dev_info(&adev->dev, "Nomadik CLCD board init\n");
+       pmu_regmap =
+               syscon_regmap_lookup_by_compatible("stericsson,nomadik-pmu");
+       if (IS_ERR(pmu_regmap)) {
+               dev_err(&adev->dev, "could not find PMU syscon regmap\n");
+               return PTR_ERR(pmu_regmap);
+       }
+       regmap_update_bits(pmu_regmap,
+                          PMU_CTRL_OFFSET,
+                          PMU_CTRL_LCDNDIF,
+                          0);
+       dev_info(&adev->dev, "set PMU mux to CLCD mode\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nomadik_clcd_init_board);
diff --git a/drivers/video/fbdev/amba-clcd-nomadik.h b/drivers/video/fbdev/amba-clcd-nomadik.h
new file mode 100644 (file)
index 0000000..50aa9bd
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _AMBA_CLCD_NOMADIK_H
+#define _AMBA_CLCD_NOMADIK_H
+
+#include <linux/amba/bus.h>
+
+#ifdef CONFIG_ARCH_NOMADIK
+int nomadik_clcd_init_board(struct amba_device *adev,
+                            struct clcd_board *board);
+int nomadik_clcd_init_panel(struct clcd_fb *fb,
+                           struct device_node *endpoint);
+#else
+static inline int nomadik_clcd_init_board(struct amba_device *adev,
+                                         struct clcd_board *board)
+{
+       return 0;
+}
+static inline int nomadik_clcd_init_panel(struct clcd_fb *fb,
+                                         struct device_node *endpoint)
+{
+       return 0;
+}
+#endif
+
+#endif /* inclusion guard */
index a8a22daa3f9d2a70a6fa1ca5f4e0f526e7380375..19ad8645d93cd25a9f41375bcb30a1677ae721b7 100644 (file)
@@ -3,6 +3,12 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
 #include <linux/platform_data/video-clcd-versatile.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/bitops.h>
+#include "amba-clcd-versatile.h"
 
 static struct clcd_panel vga = {
        .mode           = {
@@ -178,3 +184,392 @@ void versatile_clcd_remove_dma(struct clcd_fb *fb)
        dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base,
                    fb->fb.fix.smem_start);
 }
+
+#ifdef CONFIG_OF
+
+static struct regmap *versatile_syscon_map;
+static struct regmap *versatile_ib2_map;
+
+/*
+ * We detect the different syscon types from the compatible strings.
+ */
+enum versatile_clcd {
+       INTEGRATOR_CLCD_CM,
+       VERSATILE_CLCD,
+       REALVIEW_CLCD_EB,
+       REALVIEW_CLCD_PB1176,
+       REALVIEW_CLCD_PB11MP,
+       REALVIEW_CLCD_PBA8,
+       REALVIEW_CLCD_PBX,
+};
+
+static const struct of_device_id versatile_clcd_of_match[] = {
+       {
+               .compatible = "arm,core-module-integrator",
+               .data = (void *)INTEGRATOR_CLCD_CM,
+       },
+       {
+               .compatible = "arm,versatile-sysreg",
+               .data = (void *)VERSATILE_CLCD,
+       },
+       {
+               .compatible = "arm,realview-eb-syscon",
+               .data = (void *)REALVIEW_CLCD_EB,
+       },
+       {
+               .compatible = "arm,realview-pb1176-syscon",
+               .data = (void *)REALVIEW_CLCD_PB1176,
+       },
+       {
+               .compatible = "arm,realview-pb11mp-syscon",
+               .data = (void *)REALVIEW_CLCD_PB11MP,
+       },
+       {
+               .compatible = "arm,realview-pba8-syscon",
+               .data = (void *)REALVIEW_CLCD_PBA8,
+       },
+       {
+               .compatible = "arm,realview-pbx-syscon",
+               .data = (void *)REALVIEW_CLCD_PBX,
+       },
+       {},
+};
+
+/*
+ * Core module CLCD control on the Integrator/CP, bits
+ * 8 thru 19 of the CM_CONTROL register controls a bunch
+ * of CLCD settings.
+ */
+#define INTEGRATOR_HDR_CTRL_OFFSET     0x0C
+#define INTEGRATOR_CLCD_LCDBIASEN      BIT(8)
+#define INTEGRATOR_CLCD_LCDBIASUP      BIT(9)
+#define INTEGRATOR_CLCD_LCDBIASDN      BIT(10)
+/* Bits 11,12,13 controls the LCD type */
+#define INTEGRATOR_CLCD_LCDMUX_MASK    (BIT(11)|BIT(12)|BIT(13))
+#define INTEGRATOR_CLCD_LCDMUX_LCD24   BIT(11)
+#define INTEGRATOR_CLCD_LCDMUX_VGA565  BIT(12)
+#define INTEGRATOR_CLCD_LCDMUX_SHARP   (BIT(11)|BIT(12))
+#define INTEGRATOR_CLCD_LCDMUX_VGA555  BIT(13)
+#define INTEGRATOR_CLCD_LCDMUX_VGA24   (BIT(11)|BIT(12)|BIT(13))
+#define INTEGRATOR_CLCD_LCD0_EN                BIT(14)
+#define INTEGRATOR_CLCD_LCD1_EN                BIT(15)
+/* R/L flip on Sharp */
+#define INTEGRATOR_CLCD_LCD_STATIC1    BIT(16)
+/* U/D flip on Sharp */
+#define INTEGRATOR_CLCD_LCD_STATIC2    BIT(17)
+/* No connection on Sharp */
+#define INTEGRATOR_CLCD_LCD_STATIC     BIT(18)
+/* 0 = 24bit VGA, 1 = 18bit VGA */
+#define INTEGRATOR_CLCD_LCD_N24BITEN   BIT(19)
+
+#define INTEGRATOR_CLCD_MASK           (INTEGRATOR_CLCD_LCDBIASEN | \
+                                        INTEGRATOR_CLCD_LCDBIASUP | \
+                                        INTEGRATOR_CLCD_LCDBIASDN | \
+                                        INTEGRATOR_CLCD_LCDMUX_MASK | \
+                                        INTEGRATOR_CLCD_LCD0_EN | \
+                                        INTEGRATOR_CLCD_LCD1_EN | \
+                                        INTEGRATOR_CLCD_LCD_STATIC1 | \
+                                        INTEGRATOR_CLCD_LCD_STATIC2 | \
+                                        INTEGRATOR_CLCD_LCD_STATIC | \
+                                        INTEGRATOR_CLCD_LCD_N24BITEN)
+
+static void integrator_clcd_enable(struct clcd_fb *fb)
+{
+       struct fb_var_screeninfo *var = &fb->fb.var;
+       u32 val;
+
+       dev_info(&fb->dev->dev, "enable Integrator CLCD connectors\n");
+
+       /* FIXME: really needed? */
+       val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
+               INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
+       if (var->bits_per_pixel <= 8 ||
+           (var->bits_per_pixel == 16 && var->green.length == 5))
+               /* Pseudocolor, RGB555, BGR555 */
+               val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
+       else if (fb->fb.var.bits_per_pixel <= 16)
+               /* truecolor RGB565 */
+               val |= INTEGRATOR_CLCD_LCDMUX_VGA565;
+       else
+               val = 0; /* no idea for this, don't trust the docs */
+
+       regmap_update_bits(versatile_syscon_map,
+                          INTEGRATOR_HDR_CTRL_OFFSET,
+                          INTEGRATOR_CLCD_MASK,
+                          val);
+}
+
+/*
+ * This configuration register in the Versatile and RealView
+ * family is uniformly present but appears more and more
+ * unutilized starting with the RealView series.
+ */
+#define SYS_CLCD                       0x50
+#define SYS_CLCD_MODE_MASK             (BIT(0)|BIT(1))
+#define SYS_CLCD_MODE_888              0
+#define SYS_CLCD_MODE_5551             BIT(0)
+#define SYS_CLCD_MODE_565_R_LSB                BIT(1)
+#define SYS_CLCD_MODE_565_B_LSB                (BIT(0)|BIT(1))
+#define SYS_CLCD_CONNECTOR_MASK                (BIT(2)|BIT(3)|BIT(4)|BIT(5))
+#define SYS_CLCD_NLCDIOON              BIT(2)
+#define SYS_CLCD_VDDPOSSWITCH          BIT(3)
+#define SYS_CLCD_PWR3V5SWITCH          BIT(4)
+#define SYS_CLCD_VDDNEGSWITCH          BIT(5)
+#define SYS_CLCD_TSNSS                 BIT(6) /* touchscreen enable */
+#define SYS_CLCD_SSPEXP                        BIT(7) /* SSP expansion enable */
+
+/* The Versatile can detect the connected panel type */
+#define SYS_CLCD_CLCDID_MASK           (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12))
+#define SYS_CLCD_ID_SANYO_3_8          (0x00 << 8)
+#define SYS_CLCD_ID_SHARP_8_4          (0x01 << 8)
+#define SYS_CLCD_ID_EPSON_2_2          (0x02 << 8)
+#define SYS_CLCD_ID_SANYO_2_5          (0x07 << 8)
+#define SYS_CLCD_ID_VGA                        (0x1f << 8)
+
+#define SYS_CLCD_TSNDAV                        BIT(13) /* data ready from TS */
+
+/* IB2 control register for the Versatile daughterboard */
+#define IB2_CTRL                       0x00
+#define IB2_CTRL_LCD_SD                        BIT(1) /* 1 = shut down LCD */
+#define IB2_CTRL_LCD_BL_ON             BIT(0)
+#define IB2_CTRL_LCD_MASK              (BIT(0)|BIT(1))
+
+static void versatile_clcd_disable(struct clcd_fb *fb)
+{
+       dev_info(&fb->dev->dev, "disable Versatile CLCD connectors\n");
+       regmap_update_bits(versatile_syscon_map,
+                          SYS_CLCD,
+                          SYS_CLCD_CONNECTOR_MASK,
+                          0);
+
+       /* If we're on an IB2 daughterboard, turn off display */
+       if (versatile_ib2_map) {
+               dev_info(&fb->dev->dev, "disable IB2 display\n");
+               regmap_update_bits(versatile_ib2_map,
+                                  IB2_CTRL,
+                                  IB2_CTRL_LCD_MASK,
+                                  IB2_CTRL_LCD_SD);
+       }
+}
+
+static void versatile_clcd_enable(struct clcd_fb *fb)
+{
+       struct fb_var_screeninfo *var = &fb->fb.var;
+       u32 val = 0;
+
+       dev_info(&fb->dev->dev, "enable Versatile CLCD connectors\n");
+       switch (var->green.length) {
+       case 5:
+               val |= SYS_CLCD_MODE_5551;
+               break;
+       case 6:
+               if (var->red.offset == 0)
+                       val |= SYS_CLCD_MODE_565_R_LSB;
+               else
+                       val |= SYS_CLCD_MODE_565_B_LSB;
+               break;
+       case 8:
+               val |= SYS_CLCD_MODE_888;
+               break;
+       }
+
+       /* Set up the MUX */
+       regmap_update_bits(versatile_syscon_map,
+                          SYS_CLCD,
+                          SYS_CLCD_MODE_MASK,
+                          val);
+
+       /* Then enable the display */
+       regmap_update_bits(versatile_syscon_map,
+                          SYS_CLCD,
+                          SYS_CLCD_CONNECTOR_MASK,
+                          SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
+
+       /* If we're on an IB2 daughterboard, turn on display */
+       if (versatile_ib2_map) {
+               dev_info(&fb->dev->dev, "enable IB2 display\n");
+               regmap_update_bits(versatile_ib2_map,
+                                  IB2_CTRL,
+                                  IB2_CTRL_LCD_MASK,
+                                  IB2_CTRL_LCD_BL_ON);
+       }
+}
+
+static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
+{
+       clcdfb_decode(fb, regs);
+
+       /* Always clear BGR for RGB565: we do the routing externally */
+       if (fb->fb.var.green.length == 6)
+               regs->cntl &= ~CNTL_BGR;
+}
+
+static void realview_clcd_disable(struct clcd_fb *fb)
+{
+       dev_info(&fb->dev->dev, "disable RealView CLCD connectors\n");
+       regmap_update_bits(versatile_syscon_map,
+                          SYS_CLCD,
+                          SYS_CLCD_CONNECTOR_MASK,
+                          0);
+}
+
+static void realview_clcd_enable(struct clcd_fb *fb)
+{
+       dev_info(&fb->dev->dev, "enable RealView CLCD connectors\n");
+       regmap_update_bits(versatile_syscon_map,
+                          SYS_CLCD,
+                          SYS_CLCD_CONNECTOR_MASK,
+                          SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
+}
+
+struct versatile_panel {
+       u32 id;
+       char *compatible;
+       bool ib2;
+};
+
+static const struct versatile_panel versatile_panels[] = {
+       {
+               .id = SYS_CLCD_ID_VGA,
+               .compatible = "VGA",
+       },
+       {
+               .id = SYS_CLCD_ID_SANYO_3_8,
+               .compatible = "sanyo,tm38qv67a02a",
+       },
+       {
+               .id = SYS_CLCD_ID_SHARP_8_4,
+               .compatible = "sharp,lq084v1dg21",
+       },
+       {
+               .id = SYS_CLCD_ID_EPSON_2_2,
+               .compatible = "epson,l2f50113t00",
+       },
+       {
+               .id = SYS_CLCD_ID_SANYO_2_5,
+               .compatible = "sanyo,alr252rgt",
+               .ib2 = true,
+       },
+};
+
+static void versatile_panel_probe(struct device *dev,
+                                 struct device_node *endpoint)
+{
+       struct versatile_panel const *vpanel = NULL;
+       struct device_node *panel = NULL;
+       u32 val;
+       int ret;
+       int i;
+
+       /*
+        * The Versatile CLCD has a panel auto-detection mechanism.
+        * We use this and look for the compatible panel in the
+        * device tree.
+        */
+       ret = regmap_read(versatile_syscon_map, SYS_CLCD, &val);
+       if (ret) {
+               dev_err(dev, "cannot read CLCD syscon register\n");
+               return;
+       }
+       val &= SYS_CLCD_CLCDID_MASK;
+
+       /* First find corresponding panel information */
+       for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) {
+               vpanel = &versatile_panels[i];
+
+               if (val == vpanel->id) {
+                       dev_err(dev, "autodetected panel \"%s\"\n",
+                               vpanel->compatible);
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(versatile_panels)) {
+               dev_err(dev, "could not auto-detect panel\n");
+               return;
+       }
+
+       panel = of_graph_get_remote_port_parent(endpoint);
+       if (!panel) {
+               dev_err(dev, "could not locate panel in DT\n");
+               return;
+       }
+       if (!of_device_is_compatible(panel, vpanel->compatible))
+               dev_err(dev, "panel in DT is not compatible with the "
+                       "auto-detected panel, continuing anyway\n");
+
+       /*
+        * If we have a Sanyo 2.5" port
+        * that we're running on an IB2 and proceed to look for the
+        * IB2 syscon regmap.
+        */
+       if (!vpanel->ib2)
+               return;
+
+       versatile_ib2_map = syscon_regmap_lookup_by_compatible(
+               "arm,versatile-ib2-syscon");
+       if (IS_ERR(versatile_ib2_map)) {
+               dev_err(dev, "could not locate IB2 control register\n");
+               versatile_ib2_map = NULL;
+               return;
+       }
+}
+
+int versatile_clcd_init_panel(struct clcd_fb *fb,
+                             struct device_node *endpoint)
+{
+       const struct of_device_id *clcd_id;
+       enum versatile_clcd versatile_clcd_type;
+       struct device_node *np;
+       struct regmap *map;
+       struct device *dev = &fb->dev->dev;
+
+       np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
+                                            &clcd_id);
+       if (!np) {
+               dev_err(dev, "no Versatile syscon node\n");
+               return -ENODEV;
+       }
+       versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
+
+       map = syscon_node_to_regmap(np);
+       if (IS_ERR(map)) {
+               dev_err(dev, "no Versatile syscon regmap\n");
+               return PTR_ERR(map);
+       }
+
+       switch (versatile_clcd_type) {
+       case INTEGRATOR_CLCD_CM:
+               versatile_syscon_map = map;
+               fb->board->enable = integrator_clcd_enable;
+               /* Override the caps, we have only these */
+               fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 |
+                       CLCD_CAP_888;
+               dev_info(dev, "set up callbacks for Integrator PL110\n");
+               break;
+       case VERSATILE_CLCD:
+               versatile_syscon_map = map;
+               fb->board->enable = versatile_clcd_enable;
+               fb->board->disable = versatile_clcd_disable;
+               fb->board->decode = versatile_clcd_decode;
+               versatile_panel_probe(dev, endpoint);
+               dev_info(dev, "set up callbacks for Versatile\n");
+               break;
+       case REALVIEW_CLCD_EB:
+       case REALVIEW_CLCD_PB1176:
+       case REALVIEW_CLCD_PB11MP:
+       case REALVIEW_CLCD_PBA8:
+       case REALVIEW_CLCD_PBX:
+               versatile_syscon_map = map;
+               fb->board->enable = realview_clcd_enable;
+               fb->board->disable = realview_clcd_disable;
+               dev_info(dev, "set up callbacks for RealView PL111\n");
+               break;
+       default:
+               dev_info(dev, "unknown Versatile system controller\n");
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(versatile_clcd_init_panel);
+#endif
diff --git a/drivers/video/fbdev/amba-clcd-versatile.h b/drivers/video/fbdev/amba-clcd-versatile.h
new file mode 100644 (file)
index 0000000..1b14359
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Special local versatile callbacks
+ */
+#include <linux/of.h>
+#include <linux/amba/bus.h>
+#include <linux/platform_data/video-clcd-versatile.h>
+
+#if defined(CONFIG_PLAT_VERSATILE_CLCD) && defined(CONFIG_OF)
+int versatile_clcd_init_panel(struct clcd_fb *fb,
+                             struct device_node *endpoint);
+#else
+static inline int versatile_clcd_init_panel(struct clcd_fb *fb,
+                               struct device_node *endpoint)
+{
+       return 0;
+}
+#endif
index 9b158869cb89158acc0178f034708a276f2f839c..ec2671d98abcccb5f3afa6bfd68158a14557ce6e 100644 (file)
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_graph.h>
+#include <linux/backlight.h>
 #include <video/display_timing.h>
 #include <video/of_display_timing.h>
 #include <video/videomode.h>
 
+#include "amba-clcd-nomadik.h"
+#include "amba-clcd-versatile.h"
+
 #define to_clcd(info)  container_of(info, struct clcd_fb, fb)
 
 /* This is limited to 16 characters when displayed by X startup */
@@ -71,6 +75,11 @@ static void clcdfb_disable(struct clcd_fb *fb)
        if (fb->board->disable)
                fb->board->disable(fb);
 
+       if (fb->panel->backlight) {
+               fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
+               backlight_update_status(fb->panel->backlight);
+       }
+
        val = readl(fb->regs + fb->off_cntl);
        if (val & CNTL_LCDPWR) {
                val &= ~CNTL_LCDPWR;
@@ -116,6 +125,14 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
        cntl |= CNTL_LCDPWR;
        writel(cntl, fb->regs + fb->off_cntl);
 
+       /*
+        * Turn on backlight
+        */
+       if (fb->panel->backlight) {
+               fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
+               backlight_update_status(fb->panel->backlight);
+       }
+
        /*
         * finally, enable the interface.
         */
@@ -211,6 +228,15 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
                        var->blue.length = 4;
                }
                break;
+       case 24:
+               if (fb->vendor->packed_24_bit_pixels) {
+                       var->red.length = 8;
+                       var->green.length = 8;
+                       var->blue.length = 8;
+               } else {
+                       ret = -EINVAL;
+               }
+               break;
        case 32:
                /* If we can't do 888, reject */
                caps &= CLCD_CAP_888;
@@ -297,6 +323,12 @@ static int clcdfb_set_par(struct fb_info *info)
 
        clcdfb_disable(fb);
 
+       /* Some variants must be clocked here */
+       if (fb->vendor->clock_timregs && !fb->clk_enabled) {
+               fb->clk_enabled = true;
+               clk_enable(fb->clk);
+       }
+
        writel(regs.tim0, fb->regs + CLCD_TIM0);
        writel(regs.tim1, fb->regs + CLCD_TIM1);
        writel(regs.tim2, fb->regs + CLCD_TIM2);
@@ -551,7 +583,7 @@ static int clcdfb_register(struct clcd_fb *fb)
 
 #ifdef CONFIG_OF
 static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
-               struct fb_videomode *mode)
+               struct clcd_panel *clcd_panel)
 {
        int err;
        struct display_timing timing;
@@ -563,10 +595,31 @@ static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
 
        videomode_from_timing(&timing, &video);
 
-       err = fb_videomode_from_videomode(&video, mode);
+       err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
        if (err)
                return err;
 
+       /* Set up some inversion flags */
+       if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+               clcd_panel->tim2 |= TIM2_IPC;
+       else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
+               /*
+                * To preserve backwards compatibility, the IPC (inverted
+                * pixel clock) flag needs to be set on any display that
+                * doesn't explicitly specify that the pixel clock is
+                * active on the negative or positive edge.
+                */
+               clcd_panel->tim2 |= TIM2_IPC;
+
+       if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
+               clcd_panel->tim2 |= TIM2_IHS;
+
+       if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
+               clcd_panel->tim2 |= TIM2_IVS;
+
+       if (timing.flags & DISPLAY_FLAGS_DE_LOW)
+               clcd_panel->tim2 |= TIM2_IOE;
+
        return 0;
 }
 
@@ -576,11 +629,34 @@ static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
                        mode->refresh);
 }
 
+static int clcdfb_of_get_backlight(struct device_node *endpoint,
+                                  struct clcd_panel *clcd_panel)
+{
+       struct device_node *panel;
+       struct device_node *backlight;
+
+       panel = of_graph_get_remote_port_parent(endpoint);
+       if (!panel)
+               return -ENODEV;
+
+       /* Look up the optional backlight phandle */
+       backlight = of_parse_phandle(panel, "backlight", 0);
+       if (backlight) {
+               clcd_panel->backlight = of_find_backlight_by_node(backlight);
+               of_node_put(backlight);
+
+               if (!clcd_panel->backlight)
+                       return -EPROBE_DEFER;
+       }
+       return 0;
+}
+
 static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint,
-               struct fb_videomode *mode)
+               struct clcd_panel *clcd_panel)
 {
        int err;
        struct device_node *panel;
+       struct fb_videomode *mode;
        char *name;
        int len;
 
@@ -590,11 +666,12 @@ static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint,
 
        /* 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);
+               err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
        else
                err = -ENOENT;
        if (err)
                return err;
+       mode = &clcd_panel->mode;
 
        len = clcdfb_snprintf_mode(NULL, 0, mode);
        name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
@@ -616,6 +693,7 @@ static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
        } panels[] = {
                { 0x110, 1,  7, 13, CLCD_CAP_5551 },
                { 0x110, 0,  8, 16, CLCD_CAP_888 },
+               { 0x110, 16, 8, 0,  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 |
@@ -625,8 +703,8 @@ static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
        };
        int i;
 
-       /* Bypass pixel clock divider, data output on the falling edge */
-       fb->panel->tim2 = TIM2_BCD | TIM2_IPC;
+       /* Bypass pixel clock divider */
+       fb->panel->tim2 |= TIM2_BCD;
 
        /* TFT display, vert. comp. interrupt at the start of the back porch */
        fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
@@ -643,6 +721,49 @@ static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
                        fb->panel->caps = panels[i].caps;
        }
 
+       /*
+        * If we actually physically connected the R lines to B and
+        * vice versa
+        */
+       if (r0 != 0 && b0 == 0)
+               fb->panel->bgr_connection = true;
+
+       if (fb->panel->caps && fb->vendor->st_bitmux_control) {
+               /*
+                * Set up the special bits for the Nomadik control register
+                * (other platforms tend to do this through an external
+                * register).
+                */
+
+               /* Offset of the highest used color */
+               int maxoff = max3(r0, g0, b0);
+               /* Most significant bit out, highest used bit */
+               int msb = 0;
+
+               if (fb->panel->caps & CLCD_CAP_888) {
+                       msb = maxoff + 8 - 1;
+               } else if (fb->panel->caps & CLCD_CAP_565) {
+                       msb = maxoff + 5 - 1;
+                       fb->panel->cntl |= CNTL_ST_1XBPP_565;
+               } else if (fb->panel->caps & CLCD_CAP_5551) {
+                       msb = maxoff + 5 - 1;
+                       fb->panel->cntl |= CNTL_ST_1XBPP_5551;
+               } else if (fb->panel->caps & CLCD_CAP_444) {
+                       msb = maxoff + 4 - 1;
+                       fb->panel->cntl |= CNTL_ST_1XBPP_444;
+               }
+
+               /* Send out as many bits as we need */
+               if (msb > 17)
+                       fb->panel->cntl |= CNTL_ST_CDWID_24;
+               else if (msb > 15)
+                       fb->panel->cntl |= CNTL_ST_CDWID_18;
+               else if (msb > 11)
+                       fb->panel->cntl |= CNTL_ST_CDWID_16;
+               else
+                       fb->panel->cntl |= CNTL_ST_CDWID_12;
+       }
+
        return fb->panel->caps ? 0 : -EINVAL;
 }
 
@@ -658,11 +779,24 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
        if (!fb->panel)
                return -ENOMEM;
 
+       /*
+        * Fetch the panel endpoint.
+        */
        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 (fb->vendor->init_panel) {
+               err = fb->vendor->init_panel(fb, endpoint);
+               if (err)
+                       return err;
+       }
+
+       err = clcdfb_of_get_backlight(endpoint, fb->panel);
+       if (err)
+               return err;
+
+       err = clcdfb_of_get_mode(&fb->dev->dev, endpoint, fb->panel);
        if (err)
                return err;
 
@@ -693,11 +827,11 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
 
        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]);
+                       tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0)
+               return -ENOENT;
 
-       return -ENOENT;
+       return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
+                                       tft_r0b0g0[1],  tft_r0b0g0[2]);
 }
 
 static int clcdfb_of_vram_setup(struct clcd_fb *fb)
@@ -818,6 +952,7 @@ static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
        struct clcd_board *board = dev_get_platdata(&dev->dev);
+       struct clcd_vendor_data *vendor = id->data;
        struct clcd_fb *fb;
        int ret;
 
@@ -827,6 +962,12 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
        if (!board)
                return -EINVAL;
 
+       if (vendor->init_board) {
+               ret = vendor->init_board(dev, board);
+               if (ret)
+                       return ret;
+       }
+
        ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
        if (ret)
                goto out;
@@ -845,17 +986,18 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
        }
 
        fb->dev = dev;
+       fb->vendor = vendor;
        fb->board = board;
 
-       dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n",
-               amba_part(dev), amba_rev(dev),
+       dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
+               amba_part(dev), amba_manf(dev), amba_rev(dev),
                (unsigned long long)dev->res.start);
 
        ret = fb->board->setup(fb);
        if (ret)
                goto free_fb;
 
-       ret = clcdfb_register(fb); 
+       ret = clcdfb_register(fb);
        if (ret == 0) {
                amba_set_drvdata(dev, fb);
                goto out;
@@ -891,10 +1033,30 @@ static int clcdfb_remove(struct amba_device *dev)
        return 0;
 }
 
+static struct clcd_vendor_data vendor_arm = {
+       /* Sets up the versatile board displays */
+       .init_panel = versatile_clcd_init_panel,
+};
+
+static struct clcd_vendor_data vendor_nomadik = {
+       .clock_timregs = true,
+       .packed_24_bit_pixels = true,
+       .st_bitmux_control = true,
+       .init_board = nomadik_clcd_init_board,
+       .init_panel = nomadik_clcd_init_panel,
+};
+
 static struct amba_id clcdfb_id_table[] = {
        {
                .id     = 0x00041110,
                .mask   = 0x000ffffe,
+               .data   = &vendor_arm,
+       },
+       /* ST Electronics Nomadik variant */
+       {
+               .id     = 0x00180110,
+               .mask   = 0x00fffffe,
+               .data   = &vendor_nomadik,
        },
        { 0, 0 },
 };
index e2d7d039ce3b23e8f8fec2fbe863a1c8e04ca46f..542ffaddc6ab43fd75a1a38cdd8350e7d6692a07 100644 (file)
@@ -375,7 +375,6 @@ static int bfin_adv7393_fb_probe(struct i2c_client *client,
 {
        int ret = 0;
        struct proc_dir_entry *entry;
-       int num_modes = ARRAY_SIZE(known_modes);
 
        struct adv7393fb_device *fbdev = NULL;
 
@@ -384,7 +383,7 @@ static int bfin_adv7393_fb_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       if (mode > num_modes) {
+       if (mode >= ARRAY_SIZE(known_modes)) {
                dev_err(&client->dev, "mode %d: not supported", mode);
                return -EFAULT;
        }
@@ -797,7 +796,7 @@ static struct i2c_driver bfin_adv7393_fb_driver = {
 
 static int __init bfin_adv7393_fb_driver_init(void)
 {
-#if  defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+#if IS_ENABLED(CONFIG_I2C_BLACKFIN_TWI)
        request_module("i2c-bfin-twi");
 #else
        request_module("i2c-gpio");
index 924bad45c17642c778932a9a00b4bb8f19d4f268..37a37c4d04cbeb7211c5a02cef724cf47b16de5f 100644 (file)
@@ -50,9 +50,9 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
                return 1;
 
        if (regno < 16) {
-               red   >>= 8;
-               green >>= 8;
-               blue  >>= 8;
+               red   >>= 16 - info->var.red.length;
+               green >>= 16 - info->var.green.length;
+               blue  >>= 16 - info->var.blue.length;
                ((u32 *)(info->pseudo_palette))[regno] =
                        (red   << info->var.red.offset)   |
                        (green << info->var.green.offset) |
index c87e17afb3e2c9c74d9131c578235672d325f3d8..ba96c44f27612973b8f0bcea357d4b4e2ca0d200 100644 (file)
@@ -157,17 +157,10 @@ static struct i2c_adapter mb862xx_i2c_adapter = {
 
 int mb862xx_i2c_init(struct mb862xxfb_par *par)
 {
-       int ret;
-
        mb862xx_i2c_adapter.algo_data = par;
        par->adap = &mb862xx_i2c_adapter;
 
-       ret = i2c_add_adapter(par->adap);
-       if (ret < 0) {
-               dev_err(par->dev, "failed to add %s\n",
-                       mb862xx_i2c_adapter.name);
-       }
-       return ret;
+       return i2c_add_adapter(par->adap);
 }
 
 void mb862xx_i2c_exit(struct mb862xxfb_par *par)
index f91b1db262b04a2b131911009e3c69914b254013..8778e01cebac642fe4a03a7d292c967d9e3eb13a 100644 (file)
@@ -845,7 +845,7 @@ static int __set_par(struct fb_info *fbi, bool lock)
                if (fbi->var.sync & FB_SYNC_SHARP_MODE)
                        mode = IPU_PANEL_SHARP_TFT;
 
-               dev_dbg(fbi->device, "pixclock = %ul Hz\n",
+               dev_dbg(fbi->device, "pixclock = %u Hz\n",
                        (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
 
                if (sdc_init_panel(mx3fb, mode,
index 4e6608ceac09c20f8d85d844386d22c1207e8230..7846f0e8bbbb55f9ad691b733b6d2333452a672e 100644 (file)
@@ -800,6 +800,7 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host,
                        struct fb_videomode *vmode)
 {
        int ret;
+       struct device *dev = &host->pdev->dev;
        struct fb_info *fb_info = &host->fb_info;
        struct fb_var_screeninfo *var = &fb_info->var;
        dma_addr_t fb_phys;
@@ -825,12 +826,10 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host,
 
        /* Memory allocation for framebuffer */
        fb_size = SZ_2M;
-       fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
+       fb_virt = dma_alloc_wc(dev, PAGE_ALIGN(fb_size), &fb_phys, GFP_KERNEL);
        if (!fb_virt)
                return -ENOMEM;
 
-       fb_phys = virt_to_phys(fb_virt);
-
        fb_info->fix.smem_start = fb_phys;
        fb_info->screen_base = fb_virt;
        fb_info->screen_size = fb_info->fix.smem_len = fb_size;
@@ -843,9 +842,11 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host,
 
 static void mxsfb_free_videomem(struct mxsfb_info *host)
 {
+       struct device *dev = &host->pdev->dev;
        struct fb_info *fb_info = &host->fb_info;
 
-       free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len);
+       dma_free_wc(dev, fb_info->screen_size, fb_info->screen_base,
+                   fb_info->fix.smem_start);
 }
 
 static const struct platform_device_id mxsfb_devtype[] = {
index 0e4cee9a8d796b70ae5eefb585cff35bba292a01..c81f150589e1f8a2c4a9c342d305ef2684f121cb 100644 (file)
@@ -60,7 +60,6 @@ struct mipid_device {
        struct mutex            mutex;
        struct lcd_panel        panel;
 
-       struct workqueue_struct *esd_wq;
        struct delayed_work     esd_work;
        void                    (*esd_check)(struct mipid_device *m);
 };
@@ -390,7 +389,7 @@ static void ls041y3_esd_check(struct mipid_device *md)
 static void mipid_esd_start_check(struct mipid_device *md)
 {
        if (md->esd_check != NULL)
-               queue_delayed_work(md->esd_wq, &md->esd_work,
+               schedule_delayed_work(&md->esd_work,
                                   MIPID_ESD_CHECK_PERIOD);
 }
 
@@ -476,11 +475,6 @@ static int mipid_init(struct lcd_panel *panel,
        struct mipid_device *md = to_mipid_device(panel);
 
        md->fbdev = fbdev;
-       md->esd_wq = create_singlethread_workqueue("mipid_esd");
-       if (md->esd_wq == NULL) {
-               dev_err(&md->spi->dev, "can't create ESD workqueue\n");
-               return -ENOMEM;
-       }
        INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work);
        mutex_init(&md->mutex);
 
@@ -500,7 +494,6 @@ static void mipid_cleanup(struct lcd_panel *panel)
 
        if (md->enabled)
                mipid_esd_stop_check(md);
-       destroy_workqueue(md->esd_wq);
 }
 
 static struct lcd_panel mipid_panel = {
index b58012b82b6fe93fb81b2429fb2d060c43c9bf9e..8b810696a42b6c421db61cadec9774d590959f48 100644 (file)
@@ -75,8 +75,6 @@ struct panel_drv_data {
 
        bool intro_printed;
 
-       struct workqueue_struct *workqueue;
-
        bool ulps_enabled;
        unsigned ulps_timeout;
        struct delayed_work ulps_work;
@@ -232,7 +230,7 @@ static int dsicm_set_update_window(struct panel_drv_data *ddata,
 static void dsicm_queue_ulps_work(struct panel_drv_data *ddata)
 {
        if (ddata->ulps_timeout > 0)
-               queue_delayed_work(ddata->workqueue, &ddata->ulps_work,
+               schedule_delayed_work(&ddata->ulps_work,
                                msecs_to_jiffies(ddata->ulps_timeout));
 }
 
@@ -1244,11 +1242,6 @@ static int dsicm_probe(struct platform_device *pdev)
                dev_dbg(dev, "Using GPIO TE\n");
        }
 
-       ddata->workqueue = create_singlethread_workqueue("dsicm_wq");
-       if (ddata->workqueue == NULL) {
-               dev_err(dev, "can't create workqueue\n");
-               return -ENOMEM;
-       }
        INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);
 
        dsicm_hw_reset(ddata);
@@ -1262,7 +1255,7 @@ static int dsicm_probe(struct platform_device *pdev)
                                dev, ddata, &dsicm_bl_ops, &props);
                if (IS_ERR(bldev)) {
                        r = PTR_ERR(bldev);
-                       goto err_bl;
+                       goto err_reg;
                }
 
                ddata->bldev = bldev;
@@ -1285,8 +1278,6 @@ static int dsicm_probe(struct platform_device *pdev)
 err_sysfs_create:
        if (bldev != NULL)
                backlight_device_unregister(bldev);
-err_bl:
-       destroy_workqueue(ddata->workqueue);
 err_reg:
        return r;
 }
@@ -1316,7 +1307,6 @@ static int __exit dsicm_remove(struct platform_device *pdev)
        omap_dss_put_device(ddata->in);
 
        dsicm_cancel_ulps_work(ddata);
-       destroy_workqueue(ddata->workqueue);
 
        /* reset, to be sure that the panel is in a valid state */
        dsicm_hw_reset(ddata);
index 3691bde4ce0a01a0d7ae76aaec3e3779db4d54c7..a864608c5df1242a1a84cdca86b34c9cbce2034f 100644 (file)
@@ -644,6 +644,7 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
 {
 
        int r;
+       long time_left;
        DECLARE_COMPLETION_ONSTACK(completion);
 
        r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
@@ -652,15 +653,15 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
        if (r)
                return r;
 
-       timeout = wait_for_completion_interruptible_timeout(&completion,
+       time_left = wait_for_completion_interruptible_timeout(&completion,
                        timeout);
 
        omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
 
-       if (timeout == 0)
+       if (time_left == 0)
                return -ETIMEDOUT;
 
-       if (timeout == -ERESTARTSYS)
+       if (time_left == -ERESTARTSYS)
                return -ERESTARTSYS;
 
        return 0;
index 9e4800a4e3d11cff2ec29f78a260d4777c19784e..b72e57e13ae30375a3948d5d0e3846427cebd4bf 100644 (file)
@@ -1167,7 +1167,6 @@ static int dsi_regulator_init(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct regulator *vdds_dsi;
-       int r;
 
        if (dsi->vdds_dsi_reg != NULL)
                return 0;
@@ -1180,13 +1179,6 @@ static int dsi_regulator_init(struct platform_device *dsidev)
                return PTR_ERR(vdds_dsi);
        }
 
-       r = regulator_set_voltage(vdds_dsi, 1800000, 1800000);
-       if (r) {
-               devm_regulator_put(vdds_dsi);
-               DSSERR("can't set the DSI regulator voltage\n");
-               return r;
-       }
-
        dsi->vdds_dsi_reg = vdds_dsi;
 
        return 0;
index 926a6f20dbb233ea541dc2dbbd1e90c0484e3a1a..156a254705ea5e090bbd1e3c1915adb96264e238 100644 (file)
@@ -100,7 +100,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
 
 static int hdmi_init_regulator(void)
 {
-       int r;
        struct regulator *reg;
 
        if (hdmi.vdda_reg != NULL)
@@ -114,13 +113,6 @@ static int hdmi_init_regulator(void)
                return PTR_ERR(reg);
        }
 
-       r = regulator_set_voltage(reg, 1800000, 1800000);
-       if (r) {
-               devm_regulator_put(reg);
-               DSSWARN("can't set the regulator voltage\n");
-               return r;
-       }
-
        hdmi.vdda_reg = reg;
 
        return 0;
index 0ee829a165c3a974f6fb6560543303a97cd761da..4da36bcab97798c370971731c0541772b357378c 100644 (file)
@@ -119,7 +119,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
 
 static int hdmi_init_regulator(void)
 {
-       int r;
        struct regulator *reg;
 
        if (hdmi.vdda_reg != NULL)
@@ -131,13 +130,6 @@ static int hdmi_init_regulator(void)
                return PTR_ERR(reg);
        }
 
-       r = regulator_set_voltage(reg, 1800000, 1800000);
-       if (r) {
-               devm_regulator_put(reg);
-               DSSWARN("can't set the regulator voltage\n");
-               return r;
-       }
-
        hdmi.vdda_reg = reg;
 
        return 0;
index 2c0487f4f805cf7d4c9153d4c966f7cc67c45c81..ef73f14d7ba00d4b185739d65006cb50ebea7580 100644 (file)
@@ -2125,7 +2125,7 @@ static int of_get_pxafb_display(struct device *dev, struct device_node *disp,
 
        timings = of_get_display_timings(disp);
        if (!timings)
-               goto out;
+               return -EINVAL;
 
        ret = -ENOMEM;
        info->modes = kmalloc_array(timings->num_timings,
@@ -2186,6 +2186,7 @@ static int of_get_pxafb_mode_info(struct device *dev,
        ret = of_property_read_u32(np, "bus-width", &bus_width);
        if (ret) {
                dev_err(dev, "no bus-width specified: %d\n", ret);
+               of_node_put(np);
                return ret;
        }
 
index 0dd86be36afbb5bdff4d268ae58c17337a98c6b9..a67e4567e65619632fc8479b8feb9133bf801239 100644 (file)
@@ -767,7 +767,7 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
 
 static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
                                        unsigned long val, void *data)
index 47a17bd2301169d9368d041b83d2b2b9d80835bf..cdd11e2f885910def4f7d8537dbf4943aedaa568 100644 (file)
@@ -32,7 +32,7 @@ struct s3c2410fb_info {
        unsigned long           clk_rate;
        unsigned int            palette_ready;
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
        struct notifier_block   freq_transition;
 #endif
 
index e82e3ee2c54abf368f3e3d5cd30908156c863479..1035879b322cb750aeac5de0a0c38542350514f5 100644 (file)
 #define CNTL_LDMAFIFOTIME      (1 << 15)
 #define CNTL_WATERMARK         (1 << 16)
 
+/* ST Microelectronics variant bits */
+#define CNTL_ST_1XBPP_444      0x0
+#define CNTL_ST_1XBPP_5551     (1 << 17)
+#define CNTL_ST_1XBPP_565      (1 << 18)
+#define CNTL_ST_CDWID_12       0x0
+#define CNTL_ST_CDWID_16       (1 << 19)
+#define CNTL_ST_CDWID_18       (1 << 20)
+#define CNTL_ST_CDWID_24       ((1 << 19)|(1 << 20))
+#define CNTL_ST_CEAEN          (1 << 21)
+#define CNTL_ST_LCDBPP24_PACKED        (6 << 1)
+
 enum {
        /* individual formats */
        CLCD_CAP_RGB444         = (1 << 0),
@@ -93,6 +104,8 @@ enum {
        CLCD_CAP_ALL            = CLCD_CAP_BGR | CLCD_CAP_RGB,
 };
 
+struct backlight_device;
+
 struct clcd_panel {
        struct fb_videomode     mode;
        signed short            width;  /* width in mm */
@@ -105,6 +118,13 @@ struct clcd_panel {
                                fixedtimings:1,
                                grayscale:1;
        unsigned int            connector;
+       struct backlight_device *backlight;
+       /*
+        * If the B/R lines are switched between the CLCD
+        * and the panel we need to know this and not try to
+        * compensate with the BGR bit in the control register.
+        */
+       bool                    bgr_connection;
 };
 
 struct clcd_regs {
@@ -170,11 +190,38 @@ struct clcd_board {
 struct amba_device;
 struct clk;
 
+/**
+ * struct clcd_vendor_data - holds hardware (IP-block) vendor-specific
+ * variant information
+ *
+ * @clock_timregs: the CLCD needs to be clocked when accessing the
+ * timer registers, or the hardware will hang.
+ * @packed_24_bit_pixels: this variant supports 24bit packed pixel data,
+ * so that RGB accesses 3 bytes at a time, not just on even 32bit
+ * boundaries, packing the pixel data in memory. ST Microelectronics
+ * have this.
+ * @st_bitmux_control: ST Microelectronics have implemented output
+ * bit line multiplexing into the CLCD control register. This indicates
+ * that we need to use this.
+ * @init_board: custom board init function for this variant
+ * @init_panel: custom panel init function for this variant
+ */
+struct clcd_vendor_data {
+       bool    clock_timregs;
+       bool    packed_24_bit_pixels;
+       bool    st_bitmux_control;
+       int     (*init_board)(struct amba_device *adev,
+                             struct clcd_board *board);
+       int     (*init_panel)(struct clcd_fb *fb,
+                             struct device_node *panel);
+};
+
 /* this data structure describes each frame buffer device we find */
 struct clcd_fb {
        struct fb_info          fb;
        struct amba_device      *dev;
        struct clk              *clk;
+       struct clcd_vendor_data *vendor;
        struct clcd_panel       *panel;
        struct clcd_board       *board;
        void                    *board_data;
@@ -231,16 +278,22 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
        if (var->grayscale)
                val |= CNTL_LCDBW;
 
-       if (fb->panel->caps && fb->board->caps &&
-           var->bits_per_pixel >= 16) {
+       if (fb->panel->caps && fb->board->caps && var->bits_per_pixel >= 16) {
                /*
                 * if board and panel supply capabilities, we can support
-                * changing BGR/RGB depending on supplied parameters
+                * changing BGR/RGB depending on supplied parameters. Here
+                * we switch to what the framebuffer is providing if need
+                * be, so if the framebuffer is BGR but the display connection
+                * is RGB (first case) we switch it around. Vice versa mutatis
+                * mutandis if the framebuffer is RGB but the display connection
+                * is BGR, we flip it around.
                 */
                if (var->red.offset == 0)
                        val &= ~CNTL_BGR;
                else
                        val |= CNTL_BGR;
+               if (fb->panel->bgr_connection)
+                       val ^= CNTL_BGR;
        }
 
        switch (var->bits_per_pixel) {
@@ -270,6 +323,10 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
                else
                        val |= CNTL_LCDBPP16_444;
                break;
+       case 24:
+               /* Modified variant supporting 24 bit packed pixels */
+               val |= CNTL_ST_LCDBPP24_PACKED;
+               break;
        case 32:
                val |= CNTL_LCDBPP24;
                break;
This page took 0.052322 seconds and 5 git commands to generate.