Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
authorPaul Mundt <lethal@linux-sh.org>
Thu, 6 Jan 2011 09:27:34 +0000 (18:27 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Thu, 6 Jan 2011 09:27:34 +0000 (18:27 +0900)
Conflicts:
drivers/video/sh_mobile_lcdcfb.c

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
1  2 
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c

@@@ -209,11 -209,7 +209,11 @@@ enum hotplug_state 
  struct sh_hdmi {
        void __iomem *base;
        enum hotplug_state hp_state;    /* hot-plug status */
 -      bool preprogrammed_mode;        /* use a pre-programmed VIC or the external mode */
 +      u8 preprogrammed_vic;           /* use a pre-programmed VIC or
 +                                         the external mode */
 +      u8 edid_block_addr;
 +      u8 edid_segment_nr;
 +      u8 edid_blocks;
        struct clk *hdmi_clk;
        struct device *dev;
        struct fb_info *info;
@@@ -346,7 -342,7 +346,7 @@@ static void sh_hdmi_external_video_para
        hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION);
  
        /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */
 -      if (!hdmi->preprogrammed_mode)
 +      if (!hdmi->preprogrammed_vic)
                hdmi_write(hdmi, sync | 1 | (voffset << 4),
                           HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS);
  }
@@@ -470,18 -466,7 +470,18 @@@ static void sh_hdmi_audio_config(struc
   */
  static void sh_hdmi_phy_config(struct sh_hdmi *hdmi)
  {
 -      if (hdmi->var.yres > 480) {
 +      if (hdmi->var.pixclock < 10000) {
 +              /* for 1080p8bit 148MHz */
 +              hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1);
 +              hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2);
 +              hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3);
 +              hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5);
 +              hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6);
 +              hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7);
 +              hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8);
 +              hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9);
 +              hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10);
 +      } else if (hdmi->var.pixclock < 30000) {
                /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */
                /*
                 * [1:0]        Speed_A
@@@ -580,11 -565,13 +580,11 @@@ static void sh_hdmi_avi_infoframe_setup
        hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3);
  
        /*
 -       * VIC = 1280 x 720p: ignored if external config is used
 -       * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode
 +       * VIC should be ignored if external config is used, so, we could just use 0,
 +       * but play safe and use a valid value in any case just in case
         */
 -      if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920)
 -              vic = 16;
 -      else if (hdmi->var.yres == 480 && hdmi->var.xres == 720)
 -              vic = 2;
 +      if (hdmi->preprogrammed_vic)
 +              vic = hdmi->preprogrammed_vic;
        else
                vic = 4;
        hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4);
@@@ -698,21 -685,11 +698,21 @@@ static void sh_hdmi_configure(struct sh
  }
  
  static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
 -                                      const struct fb_videomode *mode)
 +              const struct fb_videomode *mode,
 +              unsigned long *hdmi_rate, unsigned long *parent_rate)
  {
 -      long target = PICOS2KHZ(mode->pixclock) * 1000,
 -              rate = clk_round_rate(hdmi->hdmi_clk, target);
 -      unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX;
 +      unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error;
 +      struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
 +
 +      *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target);
 +      if ((long)*hdmi_rate < 0)
 +              *hdmi_rate = clk_get_rate(hdmi->hdmi_clk);
 +
 +      rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX;
 +      if (rate_error && pdata->clk_optimize_parent)
 +              rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate);
 +      else if (clk_get_parent(hdmi->hdmi_clk))
 +              *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
  
        dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n",
                mode->left_margin, mode->xres,
                mode->upper_margin, mode->yres,
                mode->lower_margin, mode->vsync_len);
  
 -      dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target,
 -               rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0,
 -               mode->refresh);
 +      dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target,
 +              rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0,
 +              mode->refresh, *parent_rate);
  
        return rate_error;
  }
  
 -static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
 +static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 +                           unsigned long *parent_rate)
  {
        struct fb_var_screeninfo tmpvar;
        struct fb_var_screeninfo *var = &tmpvar;
        printk(KERN_CONT "\n");
  #endif
  
 -      fb_edid_to_monspecs(edid, &hdmi->monspec);
 +      if (!hdmi->edid_blocks) {
 +              fb_edid_to_monspecs(edid, &hdmi->monspec);
 +              hdmi->edid_blocks = edid[126] + 1;
 +
 +              dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n",
 +                      hdmi->monspec.modedb_len, hdmi->edid_blocks - 1);
 +      } else {
 +              dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n",
 +                      edid[0], edid[2]);
 +              fb_edid_add_monspecs(edid, &hdmi->monspec);
 +      }
 +
 +      if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 +
 +          (hdmi->edid_block_addr >> 7) + 1) {
 +              /* More blocks to read */
 +              if (hdmi->edid_block_addr) {
 +                      hdmi->edid_block_addr = 0;
 +                      hdmi->edid_segment_nr++;
 +              } else {
 +                      hdmi->edid_block_addr = 0x80;
 +              }
 +              /* Set EDID word address  */
 +              hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
 +              /* Enable EDID interrupt */
 +              hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
 +              /* Set EDID segment pointer - starts reading EDID */
 +              hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
 +              return -EAGAIN;
 +      }
 +
 +      /* All E-EDID blocks ready */
 +      dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len);
  
        fb_get_options("sh_mobile_lcdc", &forced);
        if (forced && *forced) {
        for (i = 0, mode = hdmi->monspec.modedb;
             f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match;
             i++, mode++) {
 -              unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode);
 +              unsigned long rate_error;
  
                /* No interest in unmatching modes */
                if (f_width != mode->xres || f_height != mode->yres)
                        continue;
 +
 +              rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate);
 +
                if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
                        /*
                         * Exact match if either the refresh rate matches or it
                found_rate_error = rate_error;
        }
  
+       hdmi->var.width = hdmi->monspec.max_x * 10;
+       hdmi->var.height = hdmi->monspec.max_y * 10;
        /*
         * TODO 1: if no ->info is present, postpone running the config until
         * after ->info first gets registered.
  
                if (modelist) {
                        found = &modelist->mode;
 -                      found_rate_error = sh_hdmi_rate_error(hdmi, found);
 +                      found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate);
                }
        }
  
        if (!found)
                return -ENXIO;
  
 -      dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n",
 -               modelist ? "default" : "EDID", found->xres, found->yres,
 -               found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error);
 -
 -      if ((found->xres == 720 && found->yres == 480) ||
 -          (found->xres == 1280 && found->yres == 720) ||
 -          (found->xres == 1920 && found->yres == 1080))
 -              hdmi->preprogrammed_mode = true;
 +      if (found->xres == 640 && found->yres == 480 && found->refresh == 60)
 +              hdmi->preprogrammed_vic = 1;
 +      else if (found->xres == 720 && found->yres == 480 && found->refresh == 60)
 +              hdmi->preprogrammed_vic = 2;
 +      else if (found->xres == 720 && found->yres == 576 && found->refresh == 50)
 +              hdmi->preprogrammed_vic = 17;
 +      else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60)
 +              hdmi->preprogrammed_vic = 4;
 +      else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24)
 +              hdmi->preprogrammed_vic = 32;
 +      else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50)
 +              hdmi->preprogrammed_vic = 31;
 +      else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60)
 +              hdmi->preprogrammed_vic = 16;
        else
 -              hdmi->preprogrammed_mode = false;
 +              hdmi->preprogrammed_vic = 0;
 +
 +      dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n",
 +              modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external",
 +              found->xres, found->yres, found->refresh,
 +              PICOS2KHZ(found->pixclock) * 1000, found_rate_error);
  
        fb_videomode_to_var(&hdmi->var, found);
        sh_hdmi_external_video_param(hdmi);
@@@ -937,34 -871,32 +940,34 @@@ static irqreturn_t sh_hdmi_hotplug(int 
                /* Check, if hot plug & MSENS pin status are both high */
                if ((msens & 0xC0) == 0xC0) {
                        /* Display plug in */
 +                      hdmi->edid_segment_nr = 0;
 +                      hdmi->edid_block_addr = 0;
 +                      hdmi->edid_blocks = 0;
                        hdmi->hp_state = HDMI_HOTPLUG_CONNECTED;
  
                        /* Set EDID word address  */
                        hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS);
 -                      /* Set EDID segment pointer */
 -                      hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
                        /* Enable EDID interrupt */
                        hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1);
 +                      /* Set EDID segment pointer - starts reading EDID */
 +                      hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
                } else if (!(status1 & 0x80)) {
                        /* Display unplug, beware multiple interrupts */
 -                      if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED)
 +                      if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) {
 +                              hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
                                schedule_delayed_work(&hdmi->edid_work, 0);
 -
 -                      hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
 +                      }
                        /* display_off will switch back to mode_a */
                }
        } else if (status1 & 2) {
                /* EDID error interrupt: retry */
                /* Set EDID word address  */
 -              hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS);
 +              hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS);
                /* Set EDID segment pointer */
 -              hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER);
 +              hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER);
        } else if (status1 & 4) {
                /* Disable EDID interrupt */
                hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1);
 -              hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
                schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10));
        }
  
@@@ -1031,8 -963,12 +1034,12 @@@ static bool sh_hdmi_must_reconfigure(st
        dev_dbg(info->dev, "Old %ux%u, new %ux%u\n",
                mode1.xres, mode1.yres, mode2.xres, mode2.yres);
  
-       if (fb_mode_is_equal(&mode1, &mode2))
+       if (fb_mode_is_equal(&mode1, &mode2)) {
+               /* It can be a different monitor with an equal video-mode */
+               old_var->width = new_var->width;
+               old_var->height = new_var->height;
                return false;
+       }
  
        dev_dbg(info->dev, "Switching %u -> %u lines\n",
                mode1.yres, mode2.yres);
  
  /**
   * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
 - * @hdmi:     driver context
 - * @pixclock: pixel clock period in picoseconds
 - * return:    configured positive rate if successful
 - *            0 if couldn't set the rate, but managed to enable the clock
 - *            negative error, if couldn't enable the clock
 + * @hdmi:             driver context
 + * @hdmi_rate:                HDMI clock frequency in Hz
 + * @parent_rate:      if != 0 - set parent clock rate for optimal precision
 + * return:            configured positive rate if successful
 + *                    0 if couldn't set the rate, but managed to enable the
 + *                    clock, negative error, if couldn't enable the clock
   */
 -static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock)
 +static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
 +                                unsigned long parent_rate)
  {
 -      long rate;
        int ret;
  
 -      rate = PICOS2KHZ(pixclock) * 1000;
 -      rate = clk_round_rate(hdmi->hdmi_clk, rate);
 -      if (rate > 0) {
 -              ret = clk_set_rate(hdmi->hdmi_clk, rate);
 +      if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
 +              ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
                if (ret < 0) {
 -                      dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret);
 -                      rate = 0;
 +                      dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret);
 +                      hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate);
                } else {
 -                      dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate);
 +                      dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate);
                }
 -      } else {
 -              rate = 0;
 -              dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate);
        }
  
 -      ret = clk_enable(hdmi->hdmi_clk);
 +      ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate);
        if (ret < 0) {
 -              dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret);
 -              return ret;
 +              dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret);
 +              hdmi_rate = 0;
 +      } else {
 +              dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate);
        }
  
 -      return rate;
 +      return hdmi_rate;
  }
  
  /* Hotplug interrupt occurred, read EDID */
@@@ -1092,20 -1030,17 +1099,20 @@@ static void sh_hdmi_edid_work_fn(struc
  
        mutex_lock(&hdmi->mutex);
  
 -      if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) {
 +      if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
 +              unsigned long parent_rate = 0, hdmi_rate;
 +
                /* A device has been plugged in */
                pm_runtime_get_sync(hdmi->dev);
  
 -              ret = sh_hdmi_read_edid(hdmi);
 +              ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
                if (ret < 0)
                        goto out;
  
 +              hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
 +
                /* Reconfigure the clock */
 -              clk_disable(hdmi->hdmi_clk);
 -              ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock);
 +              ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
                if (ret < 0)
                        goto out;
  
                         * on, if we run a resume here, the logo disappears
                         */
                        if (lock_fb_info(hdmi->info)) {
-                               sh_hdmi_display_on(hdmi, hdmi->info);
-                               unlock_fb_info(hdmi->info);
+                               struct fb_info *info = hdmi->info;
+                               info->var.width = hdmi->var.width;
+                               info->var.height = hdmi->var.height;
+                               sh_hdmi_display_on(hdmi, info);
+                               unlock_fb_info(info);
                        }
                } else {
                        /* New monitor or have to wake up */
        }
  
  out:
 -      if (ret < 0)
 +      if (ret < 0 && ret != -EAGAIN)
                hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
        mutex_unlock(&hdmi->mutex);
  
@@@ -1238,22 -1176,13 +1248,22 @@@ static int __init sh_hdmi_probe(struct 
                goto egetclk;
        }
  
 -      /* Some arbitrary relaxed pixclock just to get things started */
 -      rate = sh_hdmi_clk_configure(hdmi, 37037);
 +      /* An arbitrary relaxed pixclock just to get things started: from standard 480p */
 +      rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037));
 +      if (rate > 0)
 +              rate = sh_hdmi_clk_configure(hdmi, rate, 0);
 +
        if (rate < 0) {
                ret = rate;
                goto erate;
        }
  
 +      ret = clk_enable(hdmi->hdmi_clk);
 +      if (ret < 0) {
 +              dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret);
 +              goto erate;
 +      }
 +
        dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate);
  
        if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) {
  
        platform_set_drvdata(pdev, hdmi);
  
 -      /* Product and revision IDs are 0 in sh-mobile version */
 -      dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
 -               hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID));
 -
        /* Set up LCDC callbacks */
        board_cfg = &pdata->lcd_chan->board_cfg;
        board_cfg->owner = THIS_MODULE;
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
  
 +      /* Product and revision IDs are 0 in sh-mobile version */
 +      dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
 +               hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID));
 +
        ret = request_irq(irq, sh_hdmi_hotplug, 0,
                          dev_name(&pdev->dev), hdmi);
        if (ret < 0) {
@@@ -139,7 -139,6 +139,7 @@@ struct sh_mobile_lcdc_priv 
        struct notifier_block notifier;
        unsigned long saved_shared_regs[NR_SHARED_REGS];
        int started;
 +      int forced_bpp; /* 2 channel LCDC must share bpp setting */
  };
  
  static bool banked(int reg_nr)
@@@ -462,18 -461,13 +462,18 @@@ static int sh_mobile_lcdc_start(struct 
        struct sh_mobile_lcdc_chan *ch;
        struct sh_mobile_lcdc_board_cfg *board_cfg;
        unsigned long tmp;
 +      int bpp = 0;
        int k, m;
        int ret = 0;
  
        /* enable clocks before accessing the hardware */
 -      for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
 -              if (priv->ch[k].enabled)
 +      for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
 +              if (priv->ch[k].enabled) {
                        sh_mobile_lcdc_clk_on(priv);
 +                      if (!bpp)
 +                              bpp = priv->ch[k].info->var.bits_per_pixel;
 +              }
 +      }
  
        /* reset */
        lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
        }
  
        /* word and long word swap */
 -      lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
 +      switch (bpp) {
 +      case 16:
 +              lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
 +              break;
 +      case 24:
 +              lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7);
 +              break;
 +      case 32:
 +              lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4);
 +              break;
 +      }
  
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
                /* set bpp format in PKF[4:0] */
                tmp = lcdc_read_chan(ch, LDDFR);
                tmp &= ~0x0001001f;
 -              tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0;
 +              switch (ch->info->var.bits_per_pixel) {
 +              case 16:
 +                      tmp |= 0x03;
 +                      break;
 +              case 24:
 +                      tmp |= 0x0b;
 +                      break;
 +              case 32:
 +                      break;
 +              }
                lcdc_write_chan(ch, LDDFR, tmp);
  
                /* point out our frame buffer */
@@@ -938,30 -913,15 +938,30 @@@ static int sh_mobile_open(struct fb_inf
  static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  {
        struct sh_mobile_lcdc_chan *ch = info->par;
 +      struct sh_mobile_lcdc_priv *p = ch->lcdc;
  
        if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
            var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
 -              dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %ukHz!\n",
 +              dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n",
                         var->left_margin, var->xres, var->right_margin, var->hsync_len,
                         var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
                         PICOS2KHZ(var->pixclock));
                return -EINVAL;
        }
 +
 +      /* only accept the forced_bpp for dual channel configurations */
 +      if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
 +              return -EINVAL;
 +
 +      switch (var->bits_per_pixel) {
 +      case 16: /* PKF[4:0] = 00011 - RGB 565 */
 +      case 24: /* PKF[4:0] = 01011 - RGB 888 */
 +      case 32: /* PKF[4:0] = 00000 - RGBA 888 */
 +              break;
 +      default:
 +              return -EINVAL;
 +      }
 +
        return 0;
  }
  
@@@ -994,27 -954,19 +994,27 @@@ static int sh_mobile_lcdc_set_bpp(struc
                var->transp.length = 0;
                break;
  
 -      case 32: /* PKF[4:0] = 00000 - RGB 888
 -                * sh7722 pdf says 00RRGGBB but reality is GGBB00RR
 -                * this may be because LDDDSR has word swap enabled..
 -                */
 -              var->red.offset = 0;
 +      case 24: /* PKF[4:0] = 01011 - RGB 888 */
 +              var->red.offset = 16;
                var->red.length = 8;
 -              var->green.offset = 24;
 +              var->green.offset = 8;
                var->green.length = 8;
 -              var->blue.offset = 16;
 +              var->blue.offset = 0;
                var->blue.length = 8;
                var->transp.offset = 0;
                var->transp.length = 0;
                break;
 +
 +      case 32: /* PKF[4:0] = 00000 - RGBA 888 */
 +              var->red.offset = 16;
 +              var->red.length = 8;
 +              var->green.offset = 8;
 +              var->green.length = 8;
 +              var->blue.offset = 0;
 +              var->blue.length = 8;
 +              var->transp.offset = 24;
 +              var->transp.length = 8;
 +              break;
        default:
                return -EINVAL;
        }
@@@ -1218,10 -1170,6 +1218,10 @@@ static int __devinit sh_mobile_lcdc_pro
                goto err1;
        }
  
 +      /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
 +      if (j == 2)
 +              priv->forced_bpp = pdata->ch[0].bpp;
 +
        priv->base = ioremap_nocache(res->start, resource_size(res));
        if (!priv->base)
                goto err1;
                        mode = &default_720p;
                        num_cfg = 1;
                } else {
-                       num_cfg = ch->cfg.num_cfg;
+                       num_cfg = cfg->num_cfg;
                }
  
                fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
  
                fb_videomode_to_var(var, mode);
+               var->width = cfg->lcd_size_cfg.width;
+               var->height = cfg->lcd_size_cfg.height;
                /* Default Y virtual resolution is 2x panel size */
                var->yres_virtual = var->yres * 2;
                var->activate = FB_ACTIVATE_NOW;