fbdev: sh_mobile_lcdc: Split LCDC start code from sh_mobile_lcdc_start
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Wed, 13 Jul 2011 10:13:47 +0000 (12:13 +0200)
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Fri, 19 Aug 2011 06:22:40 +0000 (08:22 +0200)
Splitting the LCDC start code from clock, MERAM and panel management
will make the code usable by runtime PM.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.h

index 2d935db..292cfc0 100644 (file)
@@ -435,48 +435,42 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
        lcdc_write_chan(ch, LDHAJR, tmp);
 }
 
-static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
+/*
+ * __sh_mobile_lcdc_start - Configure and tart the LCDC
+ * @priv: LCDC device
+ *
+ * Configure all enabled channels and start the LCDC device. All external
+ * devices (clocks, MERAM, panels, ...) are not touched by this function.
+ */
+static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 {
        struct sh_mobile_lcdc_chan *ch;
-       struct sh_mobile_lcdc_board_cfg *board_cfg;
        unsigned long tmp;
        int bpp = 0;
-       unsigned long ldddsr;
-       int k, m, ret;
+       int k, m;
 
-       /* enable clocks before accessing the hardware */
-       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) | LDCNT2R_BR);
-       lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
-
-       /* enable LCDC channels */
-       tmp = lcdc_read(priv, _LDCNT2R);
-       tmp |= priv->ch[0].enabled;
-       tmp |= priv->ch[1].enabled;
-       lcdc_write(priv, _LDCNT2R, tmp);
-
-       /* read data from external memory, avoid using the BEU for now */
-       lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~LDCNT2R_MD);
+       /* Enable LCDC channels. Read data from external memory, avoid using the
+        * BEU for now.
+        */
+       lcdc_write(priv, _LDCNT2R, priv->ch[0].enabled | priv->ch[1].enabled);
 
-       /* stop the lcdc first */
+       /* Stop the LCDC first and disable all interrupts. */
        sh_mobile_lcdc_start_stop(priv, 0);
+       lcdc_write(priv, _LDINTR, 0);
 
-       /* configure clocks */
+       /* Configure power supply, dot clocks and start them. */
        tmp = priv->lddckr;
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
-
-               if (!priv->ch[k].enabled)
+               if (!ch->enabled)
                        continue;
 
+               if (!bpp)
+                       bpp = ch->info->var.bits_per_pixel;
+
+               /* Power supply */
+               lcdc_write_chan(ch, LDPMR, 0);
+
                m = ch->cfg.clock_divider;
                if (!m)
                        continue;
@@ -493,188 +487,187 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        }
 
        lcdc_write(priv, _LDDCKR, tmp);
-
-       /* start dotclock again */
        lcdc_write(priv, _LDDCKSTPR, 0);
        lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
 
-       /* interrupts are disabled to begin with */
-       lcdc_write(priv, _LDINTR, 0);
-
+       /* Setup geometry, format, frame buffer memory and operation mode. */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
-
                if (!ch->enabled)
                        continue;
 
                sh_mobile_lcdc_geometry(ch);
 
-               /* power supply */
-               lcdc_write_chan(ch, LDPMR, 0);
-
-               board_cfg = &ch->cfg.board_cfg;
-               if (board_cfg->setup_sys) {
-                       ret = board_cfg->setup_sys(board_cfg->board_data,
-                                               ch, &sh_mobile_lcdc_sys_bus_ops);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       /* word and long word swap */
-       ldddsr = lcdc_read(priv, _LDDDSR);
-       if  (priv->ch[0].info->var.nonstd)
-               ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
-       else {
-               switch (bpp) {
-               case 16:
-                       ldddsr |= LDDDSR_LS | LDDDSR_WS;
-                       break;
-               case 24:
-                       ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
-                       break;
-               case 32:
-                       ldddsr |= LDDDSR_LS;
-                       break;
-               }
-       }
-       lcdc_write(priv, _LDDDSR, ldddsr);
-
-       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-               unsigned long base_addr_y;
-               unsigned long base_addr_c = 0;
-               int pitch;
-               ch = &priv->ch[k];
-
-               if (!priv->ch[k].enabled)
-                       continue;
-
-               /* set bpp format in PKF[4:0] */
-               tmp = lcdc_read_chan(ch, LDDFR);
-               tmp &= ~(LDDFR_CF0 | LDDFR_CC | LDDFR_YF_MASK | LDDFR_PKF_MASK);
                if (ch->info->var.nonstd) {
-                       tmp |= (ch->info->var.nonstd << 16);
+                       tmp = (ch->info->var.nonstd << 16);
                        switch (ch->info->var.bits_per_pixel) {
                        case 12:
+                               tmp |= LDDFR_YF_420;
                                break;
                        case 16:
                                tmp |= LDDFR_YF_422;
                                break;
                        case 24:
+                       default:
                                tmp |= LDDFR_YF_444;
                                break;
                        }
                } else {
                        switch (ch->info->var.bits_per_pixel) {
                        case 16:
-                               tmp |= LDDFR_PKF_RGB16;
+                               tmp = LDDFR_PKF_RGB16;
                                break;
                        case 24:
-                               tmp |= LDDFR_PKF_RGB24;
+                               tmp = LDDFR_PKF_RGB24;
                                break;
                        case 32:
-                               tmp |= LDDFR_PKF_ARGB32;
+                       default:
+                               tmp = LDDFR_PKF_ARGB32;
                                break;
                        }
                }
+
                lcdc_write_chan(ch, LDDFR, tmp);
+               lcdc_write_chan(ch, LDMLSR, ch->pitch);
+               lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
+               if (ch->info->var.nonstd)
+                       lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
 
-               base_addr_y = ch->info->fix.smem_start;
-               base_addr_c = base_addr_y +
-                               ch->info->var.xres *
-                               ch->info->var.yres_virtual;
-               pitch = ch->info->fix.line_length;
+               /* When using deferred I/O mode, configure the LCDC for one-shot
+                * operation and enable the frame end interrupt. Otherwise use
+                * continuous read mode.
+                */
+               if (ch->ldmt1r_value & LDMT1R_IFM &&
+                   ch->cfg.sys_bus_cfg.deferred_io_msec) {
+                       lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
+                       lcdc_write(priv, _LDINTR, LDINTR_FE);
+               } else {
+                       lcdc_write_chan(ch, LDSM1R, 0);
+               }
+       }
 
-               /* test if we can enable meram */
-               if (ch->cfg.meram_cfg && priv->meram_dev &&
-                               priv->meram_dev->ops) {
-                       struct sh_mobile_meram_cfg *cfg;
-                       struct sh_mobile_meram_info *mdev;
-                       unsigned long icb_addr_y, icb_addr_c;
-                       int icb_pitch;
-                       int pf;
+       /* Word and long word swap. */
+       if  (priv->ch[0].info->var.nonstd)
+               tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+       else {
+               switch (bpp) {
+               case 16:
+                       tmp = LDDDSR_LS | LDDDSR_WS;
+                       break;
+               case 24:
+                       tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
+                       break;
+               case 32:
+               default:
+                       tmp = LDDDSR_LS;
+                       break;
+               }
+       }
+       lcdc_write(priv, _LDDDSR, tmp);
 
-                       cfg = ch->cfg.meram_cfg;
-                       mdev = priv->meram_dev;
-                       /* we need to de-init configured ICBs before we
-                        * we can re-initialize them.
-                        */
-                       if (ch->meram_enabled)
-                               mdev->ops->meram_unregister(mdev, cfg);
+       /* Enable the display output. */
+       lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
+       sh_mobile_lcdc_start_stop(priv, 1);
+       priv->started = 1;
+}
 
-                       ch->meram_enabled = 0;
+static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
+{
+       struct sh_mobile_meram_info *mdev = priv->meram_dev;
+       struct sh_mobile_lcdc_board_cfg *board_cfg;
+       struct sh_mobile_lcdc_chan *ch;
+       unsigned long tmp;
+       int ret;
+       int k;
 
-                       if (ch->info->var.nonstd) {
-                               if (ch->info->var.bits_per_pixel == 24)
-                                       pf = SH_MOBILE_MERAM_PF_NV24;
-                               else
-                                       pf = SH_MOBILE_MERAM_PF_NV;
-                       } else {
-                               pf = SH_MOBILE_MERAM_PF_RGB;
-                       }
+       /* enable clocks before accessing the hardware */
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               if (priv->ch[k].enabled)
+                       sh_mobile_lcdc_clk_on(priv);
+       }
 
-                       ret = mdev->ops->meram_register(mdev, cfg, pitch,
-                                               ch->info->var.yres,
-                                               pf,
-                                               base_addr_y,
-                                               base_addr_c,
-                                               &icb_addr_y,
-                                               &icb_addr_c,
-                                               &icb_pitch);
-                       if (!ret)  {
-                               /* set LDSA1R value */
-                               base_addr_y = icb_addr_y;
-                               pitch = icb_pitch;
-
-                               /* set LDSA2R value if required */
-                               if (base_addr_c)
-                                       base_addr_c = icb_addr_c;
-
-                               ch->meram_enabled = 1;
-                       }
-               }
+       /* reset */
+       lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LDCNT2R_BR);
+       lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
 
-               /* point out our frame buffer */
-               lcdc_write_chan(ch, LDSA1R, base_addr_y);
-               if (ch->info->var.nonstd)
-                       lcdc_write_chan(ch, LDSA2R, base_addr_c);
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               ch = &priv->ch[k];
 
-               /* set line size */
-               lcdc_write_chan(ch, LDMLSR, pitch);
+               if (!ch->enabled)
+                       continue;
 
-               /* setup deferred io if SYS bus */
-               tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
-               if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
-                       ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
-                       ch->defio.delay = msecs_to_jiffies(tmp);
-                       ch->info->fbdefio = &ch->defio;
-                       fb_deferred_io_init(ch->info);
+               board_cfg = &ch->cfg.board_cfg;
+               if (board_cfg->setup_sys) {
+                       ret = board_cfg->setup_sys(board_cfg->board_data, ch,
+                                                  &sh_mobile_lcdc_sys_bus_ops);
+                       if (ret)
+                               return ret;
+               }
+       }
 
-                       /* one-shot mode */
-                       lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
+       /* Compute frame buffer base address and pitch for each channel. */
+       for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               struct sh_mobile_meram_cfg *cfg;
+               int pixelformat;
 
-                       /* enable "Frame End Interrupt Enable" bit */
-                       lcdc_write(priv, _LDINTR, LDINTR_FE);
+               ch = &priv->ch[k];
+               if (!ch->enabled)
+                       continue;
 
-               } else {
-                       /* continuous read mode */
-                       lcdc_write_chan(ch, LDSM1R, 0);
+               ch->base_addr_y = ch->info->fix.smem_start;
+               ch->base_addr_c = ch->base_addr_y
+                               + ch->info->var.xres
+                               * ch->info->var.yres_virtual;
+               ch->pitch = ch->info->fix.line_length;
+
+               /* Enable MERAM if possible. */
+               cfg = ch->cfg.meram_cfg;
+               if (mdev == NULL || mdev->ops == NULL || cfg == NULL)
+                       continue;
+
+               /* we need to de-init configured ICBs before we can
+                * re-initialize them.
+                */
+               if (ch->meram_enabled) {
+                       mdev->ops->meram_unregister(mdev, cfg);
+                       ch->meram_enabled = 0;
                }
-       }
 
-       /* display output */
-       lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
+               if (!ch->info->var.nonstd)
+                       pixelformat = SH_MOBILE_MERAM_PF_RGB;
+               else if (ch->info->var.bits_per_pixel == 24)
+                       pixelformat = SH_MOBILE_MERAM_PF_NV24;
+               else
+                       pixelformat = SH_MOBILE_MERAM_PF_NV;
+
+               ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
+                                       ch->info->var.yres, pixelformat,
+                                       ch->base_addr_y, ch->base_addr_c,
+                                       &ch->base_addr_y, &ch->base_addr_c,
+                                       &ch->pitch);
+               if (!ret)
+                       ch->meram_enabled = 1;
+       }
 
-       /* start the lcdc */
-       sh_mobile_lcdc_start_stop(priv, 1);
-       priv->started = 1;
+       /* Start the LCDC. */
+       __sh_mobile_lcdc_start(priv);
 
-       /* tell the board code to enable the panel */
+       /* Setup deferred I/O, tell the board code to enable the panels, and
+        * turn backlight on.
+        */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
                if (!ch->enabled)
                        continue;
 
+               tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+               if (ch->ldmt1r_value & LDMT1R_IFM && tmp) {
+                       ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
+                       ch->defio.delay = msecs_to_jiffies(tmp);
+                       ch->info->fbdefio = &ch->defio;
+                       fb_deferred_io_init(ch->info);
+               }
+
                board_cfg = &ch->cfg.board_cfg;
                if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
                        board_cfg->display_on(board_cfg->board_data, ch->info);
index aeed668..a06219b 100644 (file)
@@ -18,6 +18,13 @@ struct sh_mobile_lcdc_priv;
 struct fb_info;
 struct backlight_device;
 
+/*
+ * struct sh_mobile_lcdc_chan - LCDC display channel
+ *
+ * @base_addr_y: Frame buffer viewport base address (luma component)
+ * @base_addr_c: Frame buffer viewport base address (chroma component)
+ * @pitch: Frame buffer line pitch
+ */
 struct sh_mobile_lcdc_chan {
        struct sh_mobile_lcdc_priv *lcdc;
        unsigned long *reg_offs;
@@ -40,6 +47,10 @@ struct sh_mobile_lcdc_chan {
        int blank_status;
        struct mutex open_lock;         /* protects the use counter */
        int meram_enabled;
+
+       unsigned long base_addr_y;
+       unsigned long base_addr_c;
+       unsigned int pitch;
 };
 
 #endif