Merge branch 'sh-mobile-lcdc' of git://linuxtv.org/pinchartl/fbdev into fbdev-next
authorFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>
Tue, 30 Aug 2011 20:02:02 +0000 (20:02 +0000)
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>
Tue, 30 Aug 2011 20:02:02 +0000 (20:02 +0000)
arch/arm/mach-shmobile/board-mackerel.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.h
drivers/video/sh_mobile_meram.c
drivers/video/sh_mobile_meram.h [deleted file]
include/video/sh_mobile_lcdc.h

index d41c01f83f152f75589cc228a186a6f98da59a5e..6e3c2dfdcb81766d514577001ad51c267d62d1db 100644 (file)
@@ -1583,6 +1583,7 @@ static void __init mackerel_init(void)
 
        sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
        sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);
+       sh7372_add_device_to_domain(&sh7372_a4lc, &meram_device);
        sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
 
        hdmi_init_pm_clock();
index b048417247e8f1e54268871932d68e23cdb3a9dd..088cb17857e31bb5378c3ed19504dc8ca14eba76 100644 (file)
 #include <linux/backlight.h>
 #include <linux/gpio.h>
 #include <video/sh_mobile_lcdc.h>
+#include <video/sh_mobile_meram.h>
 #include <linux/atomic.h>
 
 #include "sh_mobile_lcdcfb.h"
-#include "sh_mobile_meram.h"
 
 #define SIDE_B_OFFSET 0x1000
 #define MIRROR_OFFSET 0x2000
 
-/* shared registers */
-#define _LDDCKR 0x410
-#define _LDDCKSTPR 0x414
-#define _LDINTR 0x468
-#define _LDSR 0x46c
-#define _LDCNT1R 0x470
-#define _LDCNT2R 0x474
-#define _LDRCNTR 0x478
-#define _LDDDSR 0x47c
-#define _LDDWD0R 0x800
-#define _LDDRDR 0x840
-#define _LDDWAR 0x900
-#define _LDDRAR 0x904
-
-/* shared registers and their order for context save/restore */
-static int lcdc_shared_regs[] = {
-       _LDDCKR,
-       _LDDCKSTPR,
-       _LDINTR,
-       _LDDDSR,
-       _LDCNT1R,
-       _LDCNT2R,
-};
-#define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs)
-
 #define MAX_XRES 1920
 #define MAX_YRES 1080
 
@@ -98,22 +73,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
        [LDPMR] = 0x63c,
 };
 
-#define START_LCDC     0x00000001
-#define LCDC_RESET     0x00000100
-#define DISPLAY_BEU    0x00000008
-#define LCDC_ENABLE    0x00000001
-#define LDINTR_FE      0x00000400
-#define LDINTR_VSE     0x00000200
-#define LDINTR_VEE     0x00000100
-#define LDINTR_FS      0x00000004
-#define LDINTR_VSS     0x00000002
-#define LDINTR_VES     0x00000001
-#define LDRCNTR_SRS    0x00020000
-#define LDRCNTR_SRC    0x00010000
-#define LDRCNTR_MRS    0x00000002
-#define LDRCNTR_MRC    0x00000001
-#define LDSR_MRS       0x00000100
-
 static const struct fb_videomode default_720p = {
        .name = "HDMI 720p",
        .xres = 1280,
@@ -141,7 +100,6 @@ struct sh_mobile_lcdc_priv {
        unsigned long lddckr;
        struct sh_mobile_lcdc_chan ch[2];
        struct notifier_block notifier;
-       unsigned long saved_shared_regs[NR_SHARED_REGS];
        int started;
        int forced_bpp; /* 2 channel LCDC must share bpp setting */
        struct sh_mobile_meram_info *meram_dev;
@@ -218,33 +176,36 @@ static void lcdc_sys_write_index(void *handle, unsigned long data)
 {
        struct sh_mobile_lcdc_chan *ch = handle;
 
-       lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
-       lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+       lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+       lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
+                  (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
 }
 
 static void lcdc_sys_write_data(void *handle, unsigned long data)
 {
        struct sh_mobile_lcdc_chan *ch = handle;
 
-       lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
-       lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+       lcdc_write(ch->lcdc, _LDDWD0R, data | LDDWDxR_WDACT | LDDWDxR_RSW);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+       lcdc_write(ch->lcdc, _LDDWAR, LDDWAR_WA |
+                  (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
 }
 
 static unsigned long lcdc_sys_read_data(void *handle)
 {
        struct sh_mobile_lcdc_chan *ch = handle;
 
-       lcdc_write(ch->lcdc, _LDDRDR, 0x01000000);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
-       lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0));
+       lcdc_write(ch->lcdc, _LDDRDR, LDDRDR_RSR);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
+       lcdc_write(ch->lcdc, _LDDRAR, LDDRAR_RA |
+                  (lcdc_chan_is_sublcd(ch) ? 2 : 0));
        udelay(1);
-       lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0);
+       lcdc_wait_bit(ch->lcdc, _LDSR, LDSR_AS, 0);
 
-       return lcdc_read(ch->lcdc, _LDDRDR) & 0x3ffff;
+       return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK;
 }
 
 struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
@@ -256,18 +217,22 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_inc_and_test(&priv->hw_usecnt)) {
-               pm_runtime_get_sync(priv->dev);
                if (priv->dot_clk)
                        clk_enable(priv->dot_clk);
+               pm_runtime_get_sync(priv->dev);
+               if (priv->meram_dev && priv->meram_dev->pdev)
+                       pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
        }
 }
 
 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
+               if (priv->meram_dev && priv->meram_dev->pdev)
+                       pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
+               pm_runtime_put(priv->dev);
                if (priv->dot_clk)
                        clk_disable(priv->dot_clk);
-               pm_runtime_put(priv->dev);
        }
 }
 
@@ -319,13 +284,13 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
                if (bcfg->start_transfer)
                        bcfg->start_transfer(bcfg->board_data, ch,
                                             &sh_mobile_lcdc_sys_bus_ops);
-               lcdc_write_chan(ch, LDSM2R, 1);
+               lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
                dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
        } else {
                if (bcfg->start_transfer)
                        bcfg->start_transfer(bcfg->board_data, ch,
                                             &sh_mobile_lcdc_sys_bus_ops);
-               lcdc_write_chan(ch, LDSM2R, 1);
+               lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
        }
 }
 
@@ -341,22 +306,16 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 {
        struct sh_mobile_lcdc_priv *priv = data;
        struct sh_mobile_lcdc_chan *ch;
-       unsigned long tmp;
        unsigned long ldintr;
        int is_sub;
        int k;
 
-       /* acknowledge interrupt */
-       ldintr = tmp = lcdc_read(priv, _LDINTR);
-       /*
-        * disable further VSYNC End IRQs, preserve all other enabled IRQs,
-        * write 0 to bits 0-6 to ack all triggered IRQs.
-        */
-       tmp &= 0xffffff00 & ~LDINTR_VEE;
-       lcdc_write(priv, _LDINTR, tmp);
+       /* Acknowledge interrupts and disable further VSYNC End IRQs. */
+       ldintr = lcdc_read(priv, _LDINTR);
+       lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
 
        /* figure out if this interrupt is for main or sub lcd */
-       is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
+       is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
 
        /* wake up channel and disable clocks */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -365,7 +324,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
                if (!ch->enabled)
                        continue;
 
-               /* Frame Start */
+               /* Frame End */
                if (ldintr & LDINTR_FS) {
                        if (is_sub == lcdc_chan_is_sublcd(ch)) {
                                ch->frame_end = 1;
@@ -391,16 +350,17 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
 
        /* start or stop the lcdc */
        if (start)
-               lcdc_write(priv, _LDCNT2R, tmp | START_LCDC);
+               lcdc_write(priv, _LDCNT2R, tmp | LDCNT2R_DO);
        else
-               lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC);
+               lcdc_write(priv, _LDCNT2R, tmp & ~LDCNT2R_DO);
 
        /* wait until power is applied/stopped on all channels */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
                if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled)
                        while (1) {
-                               tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3;
-                               if (start && tmp == 3)
+                               tmp = lcdc_read_chan(&priv->ch[k], LDPMR)
+                                   & LDPMR_LPS;
+                               if (start && tmp == LDPMR_LPS)
                                        break;
                                if (!start && tmp == 0)
                                        break;
@@ -418,13 +378,13 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
        u32 tmp;
 
        tmp = ch->ldmt1r_value;
-       tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
-       tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
-       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
+       tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL;
+       tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0;
+       tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0;
        lcdc_write_chan(ch, LDMT1R, tmp);
 
        /* setup SYS bus */
@@ -463,242 +423,239 @@ 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;
-
-       /* 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) | LCDC_RESET);
-       lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
-
-       /* enable LCDC channels */
-       tmp = lcdc_read(priv, _LDCNT2R);
-       tmp |= priv->ch[0].enabled;
-       tmp |= priv->ch[1].enabled;
-       lcdc_write(priv, _LDCNT2R, tmp);
+       int k, m;
 
-       /* read data from external memory, avoid using the BEU for now */
-       lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
+       /* 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;
 
-               if (m == 1)
-                       m = 1 << 6;
-               tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
-
-               /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */
+               /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
+                * denominator.
+                */
                lcdc_write_chan(ch, LDDCKPAT1R, 0);
                lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1);
+
+               if (m == 1)
+                       m = LDDCKR_MOSEL;
+               tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
        }
 
        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)
-               lcdc_write(priv, _LDDDSR, ldddsr | 7);
-       else {
-               switch (bpp) {
-               case 16:
-                       lcdc_write(priv, _LDDDSR, ldddsr | 6);
-                       break;
-               case 24:
-                       lcdc_write(priv, _LDDDSR, ldddsr | 7);
-                       break;
-               case 32:
-                       lcdc_write(priv, _LDDDSR, ldddsr | 4);
-                       break;
-               }
-       }
-
-       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 &= ~0x0003031f;
                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 |= (0x1 << 8);
+                               tmp |= LDDFR_YF_422;
                                break;
                        case 24:
-                               tmp |= (0x2 << 8);
+                       default:
+                               tmp |= LDDFR_YF_444;
                                break;
                        }
                } else {
                        switch (ch->info->var.bits_per_pixel) {
                        case 16:
-                               tmp |= 0x03;
+                               tmp = LDDFR_PKF_RGB16;
                                break;
                        case 24:
-                               tmp |= 0x0b;
+                               tmp = LDDFR_PKF_RGB24;
                                break;
                        case 32:
+                       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 & (1 << 12) && 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, 1);
+       /* 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, LCDC_ENABLE);
+               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);
@@ -776,42 +733,42 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
 
 static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
 {
-       int ifm, miftyp;
-
-       switch (ch->cfg.interface_type) {
-       case RGB8: ifm = 0; miftyp = 0; break;
-       case RGB9: ifm = 0; miftyp = 4; break;
-       case RGB12A: ifm = 0; miftyp = 5; break;
-       case RGB12B: ifm = 0; miftyp = 6; break;
-       case RGB16: ifm = 0; miftyp = 7; break;
-       case RGB18: ifm = 0; miftyp = 10; break;
-       case RGB24: ifm = 0; miftyp = 11; break;
-       case SYS8A: ifm = 1; miftyp = 0; break;
-       case SYS8B: ifm = 1; miftyp = 1; break;
-       case SYS8C: ifm = 1; miftyp = 2; break;
-       case SYS8D: ifm = 1; miftyp = 3; break;
-       case SYS9: ifm = 1; miftyp = 4; break;
-       case SYS12: ifm = 1; miftyp = 5; break;
-       case SYS16A: ifm = 1; miftyp = 7; break;
-       case SYS16B: ifm = 1; miftyp = 8; break;
-       case SYS16C: ifm = 1; miftyp = 9; break;
-       case SYS18: ifm = 1; miftyp = 10; break;
-       case SYS24: ifm = 1; miftyp = 11; break;
-       default: goto bad;
+       int interface_type = ch->cfg.interface_type;
+
+       switch (interface_type) {
+       case RGB8:
+       case RGB9:
+       case RGB12A:
+       case RGB12B:
+       case RGB16:
+       case RGB18:
+       case RGB24:
+       case SYS8A:
+       case SYS8B:
+       case SYS8C:
+       case SYS8D:
+       case SYS9:
+       case SYS12:
+       case SYS16A:
+       case SYS16B:
+       case SYS16C:
+       case SYS18:
+       case SYS24:
+               break;
+       default:
+               return -EINVAL;
        }
 
        /* SUBLCD only supports SYS interface */
        if (lcdc_chan_is_sublcd(ch)) {
-               if (ifm == 0)
-                       goto bad;
-               else
-                       ifm = 0;
+               if (!(interface_type & LDMT1R_IFM))
+                       return -EINVAL;
+
+               interface_type &= ~LDMT1R_IFM;
        }
 
-       ch->ldmt1r_value = (ifm << 12) | miftyp;
+       ch->ldmt1r_value = interface_type;
        return 0;
- bad:
-       return -EINVAL;
 }
 
 static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
@@ -819,18 +776,24 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
                                       struct sh_mobile_lcdc_priv *priv)
 {
        char *str;
-       int icksel;
 
        switch (clock_source) {
-       case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break;
-       case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break;
-       case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break;
+       case LCDC_CLK_BUS:
+               str = "bus_clk";
+               priv->lddckr = LDDCKR_ICKSEL_BUS;
+               break;
+       case LCDC_CLK_PERIPHERAL:
+               str = "peripheral_clk";
+               priv->lddckr = LDDCKR_ICKSEL_MIPI;
+               break;
+       case LCDC_CLK_EXTERNAL:
+               str = NULL;
+               priv->lddckr = LDDCKR_ICKSEL_HDMI;
+               break;
        default:
                return -EINVAL;
        }
 
-       priv->lddckr = icksel << 16;
-
        if (str) {
                priv->dot_clk = clk_get(&pdev->dev, str);
                if (IS_ERR(priv->dot_clk)) {
@@ -940,32 +903,28 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
                        base_addr_c += 2 * var->xoffset;
                else
                        base_addr_c += var->xoffset;
-       } else
-               base_addr_c = 0;
+       }
 
-       if (!ch->meram_enabled) {
-               lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-               if (base_addr_c)
-                       lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
-       } else {
+       if (ch->meram_enabled) {
                struct sh_mobile_meram_cfg *cfg;
                struct sh_mobile_meram_info *mdev;
-               unsigned long icb_addr_y, icb_addr_c;
                int ret;
 
                cfg = ch->cfg.meram_cfg;
                mdev = priv->meram_dev;
                ret = mdev->ops->meram_update(mdev, cfg,
                                        base_addr_y, base_addr_c,
-                                       &icb_addr_y, &icb_addr_c);
+                                       &base_addr_y, &base_addr_c);
                if (ret)
                        return ret;
+       }
 
-               lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y);
-               if (icb_addr_c)
-                       lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c);
+       ch->base_addr_y = base_addr_y;
+       ch->base_addr_c = base_addr_c;
 
-       }
+       lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
+       if (var->nonstd)
+               lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
 
        if (lcdc_chan_is_sublcd(ch))
                lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
@@ -985,9 +944,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info)
        unsigned long ldintr;
        int ret;
 
-       /* Enable VSync End interrupt */
+       /* Enable VSync End interrupt and be careful not to acknowledge any
+        * pending interrupt.
+        */
        ldintr = lcdc_read(ch->lcdc, _LDINTR);
-       ldintr |= LDINTR_VEE;
+       ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
        lcdc_write(ch->lcdc, _LDINTR, ldintr);
 
        ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
@@ -1316,47 +1277,20 @@ static int sh_mobile_lcdc_resume(struct device *dev)
 static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev);
-       struct sh_mobile_lcdc_chan *ch;
-       int k, n;
-
-       /* save per-channel registers */
-       for (k = 0; k < ARRAY_SIZE(p->ch); k++) {
-               ch = &p->ch[k];
-               if (!ch->enabled)
-                       continue;
-               for (n = 0; n < NR_CH_REGS; n++)
-                       ch->saved_ch_regs[n] = lcdc_read_chan(ch, n);
-       }
-
-       /* save shared registers */
-       for (n = 0; n < NR_SHARED_REGS; n++)
-               p->saved_shared_regs[n] = lcdc_read(p, lcdc_shared_regs[n]);
+       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
 
        /* turn off LCDC hardware */
-       lcdc_write(p, _LDCNT1R, 0);
+       lcdc_write(priv, _LDCNT1R, 0);
+
        return 0;
 }
 
 static int sh_mobile_lcdc_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_lcdc_priv *p = platform_get_drvdata(pdev);
-       struct sh_mobile_lcdc_chan *ch;
-       int k, n;
-
-       /* restore per-channel registers */
-       for (k = 0; k < ARRAY_SIZE(p->ch); k++) {
-               ch = &p->ch[k];
-               if (!ch->enabled)
-                       continue;
-               for (n = 0; n < NR_CH_REGS; n++)
-                       lcdc_write_chan(ch, n, ch->saved_ch_regs[n]);
-       }
+       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
 
-       /* restore shared registers */
-       for (n = 0; n < NR_SHARED_REGS; n++)
-               lcdc_write(p, lcdc_shared_regs[n], p->saved_shared_regs[n]);
+       __sh_mobile_lcdc_start(priv);
 
        return 0;
 }
@@ -1472,12 +1406,12 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 
                switch (pdata->ch[i].chan) {
                case LCDC_CHAN_MAINLCD:
-                       ch->enabled = 1 << 1;
+                       ch->enabled = LDCNT2R_ME;
                        ch->reg_offs = lcdc_offs_mainlcd;
                        j++;
                        break;
                case LCDC_CHAN_SUBLCD:
-                       ch->enabled = 1 << 2;
+                       ch->enabled = LDCNT2R_SE;
                        ch->reg_offs = lcdc_offs_sublcd;
                        j++;
                        break;
index aeed6687e6a737b9d51852380c48bea7e5ab0e6d..a58a0f38848b03679a649af291f3457683781121 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;
@@ -25,7 +32,6 @@ struct sh_mobile_lcdc_chan {
        unsigned long enabled; /* ME and SE in LDCNT2R */
        struct sh_mobile_lcdc_chan_cfg cfg;
        u32 pseudo_palette[PALETTE_NR];
-       unsigned long saved_ch_regs[NR_CH_REGS];
        struct fb_info *info;
        struct backlight_device *bl;
        dma_addr_t dma_handle;
@@ -40,6 +46,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
index cc7d7329dc151af821153feb999998e42460267e..f632970991939900636fc44b94734a18a80072e4 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
-
-#include "sh_mobile_meram.h"
+#include <video/sh_mobile_meram.h>
 
 /* meram registers */
-#define MExxCTL 0x0
-#define MExxBSIZE 0x4
-#define MExxMNCF 0x8
-#define MExxSARA 0x10
-#define MExxSARB 0x14
-#define MExxSBSIZE 0x18
-
-#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
-       ((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
-#define        MERAM_MExxBSIZE_VAL(a, b, c) \
-       (((a) << 28) | ((b) << 16) | (c))
-
-#define MEVCR1 0x4
-#define MEACTS 0x10
-#define MEQSEL1 0x40
-#define MEQSEL2 0x44
+#define MEVCR1                 0x4
+#define MEVCR1_RST             (1 << 31)
+#define MEVCR1_WD              (1 << 30)
+#define MEVCR1_AMD1            (1 << 29)
+#define MEVCR1_AMD0            (1 << 28)
+#define MEQSEL1                        0x40
+#define MEQSEL2                        0x44
+
+#define MExxCTL                        0x400
+#define MExxCTL_BV             (1 << 31)
+#define MExxCTL_BSZ_SHIFT      28
+#define MExxCTL_MSAR_MASK      (0x7ff << MExxCTL_MSAR_SHIFT)
+#define MExxCTL_MSAR_SHIFT     16
+#define MExxCTL_NXT_MASK       (0x1f << MExxCTL_NXT_SHIFT)
+#define MExxCTL_NXT_SHIFT      11
+#define MExxCTL_WD1            (1 << 10)
+#define MExxCTL_WD0            (1 << 9)
+#define MExxCTL_WS             (1 << 8)
+#define MExxCTL_CB             (1 << 7)
+#define MExxCTL_WBF            (1 << 6)
+#define MExxCTL_WF             (1 << 5)
+#define MExxCTL_RF             (1 << 4)
+#define MExxCTL_CM             (1 << 3)
+#define MExxCTL_MD_READ                (1 << 0)
+#define MExxCTL_MD_WRITE       (2 << 0)
+#define MExxCTL_MD_ICB_WB      (3 << 0)
+#define MExxCTL_MD_ICB         (4 << 0)
+#define MExxCTL_MD_FB          (7 << 0)
+#define MExxCTL_MD_MASK                (7 << 0)
+#define MExxBSIZE              0x404
+#define MExxBSIZE_RCNT_SHIFT   28
+#define MExxBSIZE_YSZM1_SHIFT  16
+#define MExxBSIZE_XSZM1_SHIFT  0
+#define MExxMNCF               0x408
+#define MExxMNCF_KWBNM_SHIFT   28
+#define MExxMNCF_KRBNM_SHIFT   24
+#define MExxMNCF_BNM_SHIFT     16
+#define MExxMNCF_XBV           (1 << 15)
+#define MExxMNCF_CPL_YCBCR444  (1 << 12)
+#define MExxMNCF_CPL_YCBCR420  (2 << 12)
+#define MExxMNCF_CPL_YCBCR422  (3 << 12)
+#define MExxMNCF_CPL_MSK       (3 << 12)
+#define MExxMNCF_BL            (1 << 2)
+#define MExxMNCF_LNM_SHIFT     0
+#define MExxSARA               0x410
+#define MExxSARB               0x414
+#define MExxSBSIZE             0x418
+#define MExxSBSIZE_HDV         (1 << 31)
+#define MExxSBSIZE_HSZ16       (0 << 28)
+#define MExxSBSIZE_HSZ32       (1 << 28)
+#define MExxSBSIZE_HSZ64       (2 << 28)
+#define MExxSBSIZE_HSZ128      (3 << 28)
+#define MExxSBSIZE_SBSIZZ_SHIFT        0
+
+#define MERAM_MExxCTL_VAL(next, addr)  \
+       ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
+        (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
+#define        MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
+       (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
+        ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
+        ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
+
+#define SH_MOBILE_MERAM_ICB_NUM                32
+
+static unsigned long common_regs[] = {
+       MEVCR1,
+       MEQSEL1,
+       MEQSEL2,
+};
+#define CMN_REGS_SIZE ARRAY_SIZE(common_regs)
+
+static unsigned long icb_regs[] = {
+       MExxCTL,
+       MExxBSIZE,
+       MExxMNCF,
+       MExxSARA,
+       MExxSARB,
+       MExxSBSIZE,
+};
+#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
+
+struct sh_mobile_meram_priv {
+       void __iomem    *base;
+       struct mutex    lock;
+       unsigned long   used_icb;
+       int             used_meram_cache_regions;
+       unsigned long   used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
+       unsigned long   cmn_saved_regs[CMN_REGS_SIZE];
+       unsigned long   icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM];
+};
 
 /* settings */
 #define MERAM_SEC_LINE 15
  * MERAM/ICB access functions
  */
 
-#define MERAM_ICB_OFFSET(base, idx, off)       \
-       ((base) + (0x400 + ((idx) * 0x20) + (off)))
+#define MERAM_ICB_OFFSET(base, idx, off)       ((base) + (off) + (idx) * 0x20)
 
 static inline void meram_write_icb(void __iomem *base, int idx, int off,
        unsigned long val)
@@ -280,17 +353,18 @@ static int meram_init(struct sh_mobile_meram_priv *priv,
        /*
         * Set MERAM for framebuffer
         *
-        * 0x70f:  WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
         * we also chain the cache_icb and the marker_icb.
         * we also split the allocated MERAM buffer between two ICBs.
         */
        meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
-                       MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
-                                         icb->meram_offset));
+                       MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) |
+                       MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+                       MExxCTL_MD_FB);
        meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
-                       MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
-                                         icb->meram_offset +
-                                         icb->meram_size / 2));
+                       MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset +
+                                         icb->meram_size / 2) |
+                       MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
+                       MExxCTL_MD_FB);
 
        return 0;
 }
@@ -337,24 +411,22 @@ static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
                xres, yres, (!pixelformat) ? "yuv" : "rgb",
                base_addr_y, base_addr_c);
 
-       mutex_lock(&priv->lock);
-
        /* we can't handle wider than 8192px */
        if (xres > 8192) {
                dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
-               error = -EINVAL;
-               goto err;
-       }
-
-       if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
-               dev_err(&pdev->dev, "no more ICB available.");
-               error = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        /* do we have at least one ICB config? */
        if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
                dev_err(&pdev->dev, "at least one ICB is required.");
+               return -EINVAL;
+       }
+
+       mutex_lock(&priv->lock);
+
+       if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
+               dev_err(&pdev->dev, "no more ICB available.");
                error = -EINVAL;
                goto err;
        }
@@ -460,6 +532,57 @@ static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
        return 0;
 }
 
+static int sh_mobile_meram_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+       int k, j;
+
+       for (k = 0; k < CMN_REGS_SIZE; k++)
+               priv->cmn_saved_regs[k] = meram_read_reg(priv->base,
+                       common_regs[k]);
+
+       for (j = 0; j < 32; j++) {
+               if (!test_bit(j, &priv->used_icb))
+                       continue;
+               for (k = 0; k < ICB_REGS_SIZE; k++) {
+                       priv->icb_saved_regs[j * ICB_REGS_SIZE + k] =
+                               meram_read_icb(priv->base, j, icb_regs[k]);
+                       /* Reset ICB on resume */
+                       if (icb_regs[k] == MExxCTL)
+                               priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |=
+                                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
+               }
+       }
+       return 0;
+}
+
+static int sh_mobile_meram_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+       int k, j;
+
+       for (j = 0; j < 32; j++) {
+               if (!test_bit(j, &priv->used_icb))
+                       continue;
+               for (k = 0; k < ICB_REGS_SIZE; k++) {
+                       meram_write_icb(priv->base, j, icb_regs[k],
+                       priv->icb_saved_regs[j * ICB_REGS_SIZE + k]);
+               }
+       }
+
+       for (k = 0; k < CMN_REGS_SIZE; k++)
+               meram_write_reg(priv->base, common_regs[k],
+                       priv->cmn_saved_regs[k]);
+       return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = {
+       .runtime_suspend = sh_mobile_meram_runtime_suspend,
+       .runtime_resume = sh_mobile_meram_runtime_resume,
+};
+
 static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
        .module                 = THIS_MODULE,
        .meram_register         = sh_mobile_meram_register,
@@ -513,7 +636,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
 
        /* initialize ICB addressing mode */
        if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
-               meram_write_reg(priv->base, MEVCR1, 1 << 29);
+               meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
+
+       pm_runtime_enable(&pdev->dev);
 
        dev_info(&pdev->dev, "sh_mobile_meram initialized.");
 
@@ -530,6 +655,8 @@ static int sh_mobile_meram_remove(struct platform_device *pdev)
 {
        struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
 
+       pm_runtime_disable(&pdev->dev);
+
        if (priv->base)
                iounmap(priv->base);
 
@@ -544,6 +671,7 @@ static struct platform_driver sh_mobile_meram_driver = {
        .driver = {
                .name           = "sh_mobile_meram",
                .owner          = THIS_MODULE,
+               .pm             = &sh_mobile_meram_dev_pm_ops,
        },
        .probe          = sh_mobile_meram_probe,
        .remove         = sh_mobile_meram_remove,
diff --git a/drivers/video/sh_mobile_meram.h b/drivers/video/sh_mobile_meram.h
deleted file mode 100644 (file)
index 82c54fb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __sh_mobile_meram_h__
-#define __sh_mobile_meram_h__
-
-#include <linux/mutex.h>
-#include <video/sh_mobile_meram.h>
-
-/*
- * MERAM private
- */
-
-#define MERAM_ICB_Y 0x1
-#define MERAM_ICB_C 0x2
-
-/* MERAM cache size */
-#define SH_MOBILE_MERAM_ICB_NUM                32
-
-#define SH_MOBILE_MERAM_CACHE_OFFSET(p)        ((p) >> 16)
-#define SH_MOBILE_MERAM_CACHE_SIZE(p)  ((p) & 0xffff)
-
-struct sh_mobile_meram_priv {
-       void __iomem    *base;
-       struct mutex    lock;
-       unsigned long   used_icb;
-       int             used_meram_cache_regions;
-       unsigned long   used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
-};
-
-int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
-                  int xres,
-                  int yres,
-                  unsigned int base_addr,
-                  int yuv_mode,
-                  int *marker_icb,
-                  int *out_pitch);
-
-void sh_mobile_meram_free_icb(int marker_icb);
-
-#define SH_MOBILE_MERAM_START(ind, ab) \
-       (0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
-
-#endif /* !__sh_mobile_meram_h__ */
index d964e68fc61dab119e504f3f8feb1a5d0a44d36d..8101b726b48a273240558cb57a8b7b348b222f24 100644 (file)
 #include <linux/fb.h>
 #include <video/sh_mobile_meram.h>
 
+/* Register definitions */
+#define _LDDCKR                        0x410
+#define LDDCKR_ICKSEL_BUS      (0 << 16)
+#define LDDCKR_ICKSEL_MIPI     (1 << 16)
+#define LDDCKR_ICKSEL_HDMI     (2 << 16)
+#define LDDCKR_ICKSEL_EXT      (3 << 16)
+#define LDDCKR_ICKSEL_MASK     (7 << 16)
+#define LDDCKR_MOSEL           (1 << 6)
+#define _LDDCKSTPR             0x414
+#define _LDINTR                        0x468
+#define LDINTR_FE              (1 << 10)
+#define LDINTR_VSE             (1 << 9)
+#define LDINTR_VEE             (1 << 8)
+#define LDINTR_FS              (1 << 2)
+#define LDINTR_VSS             (1 << 1)
+#define LDINTR_VES             (1 << 0)
+#define LDINTR_STATUS_MASK     (0xff << 0)
+#define _LDSR                  0x46c
+#define LDSR_MSS               (1 << 10)
+#define LDSR_MRS               (1 << 8)
+#define LDSR_AS                        (1 << 1)
+#define _LDCNT1R               0x470
+#define LDCNT1R_DE             (1 << 0)
+#define _LDCNT2R               0x474
+#define LDCNT2R_BR             (1 << 8)
+#define LDCNT2R_MD             (1 << 3)
+#define LDCNT2R_SE             (1 << 2)
+#define LDCNT2R_ME             (1 << 1)
+#define LDCNT2R_DO             (1 << 0)
+#define _LDRCNTR               0x478
+#define LDRCNTR_SRS            (1 << 17)
+#define LDRCNTR_SRC            (1 << 16)
+#define LDRCNTR_MRS            (1 << 1)
+#define LDRCNTR_MRC            (1 << 0)
+#define _LDDDSR                        0x47c
+#define LDDDSR_LS              (1 << 2)
+#define LDDDSR_WS              (1 << 1)
+#define LDDDSR_BS              (1 << 0)
+
+#define LDMT1R_VPOL            (1 << 28)
+#define LDMT1R_HPOL            (1 << 27)
+#define LDMT1R_DWPOL           (1 << 26)
+#define LDMT1R_DIPOL           (1 << 25)
+#define LDMT1R_DAPOL           (1 << 24)
+#define LDMT1R_HSCNT           (1 << 17)
+#define LDMT1R_DWCNT           (1 << 16)
+#define LDMT1R_IFM             (1 << 12)
+#define LDMT1R_MIFTYP_RGB8     (0x0 << 0)
+#define LDMT1R_MIFTYP_RGB9     (0x4 << 0)
+#define LDMT1R_MIFTYP_RGB12A   (0x5 << 0)
+#define LDMT1R_MIFTYP_RGB12B   (0x6 << 0)
+#define LDMT1R_MIFTYP_RGB16    (0x7 << 0)
+#define LDMT1R_MIFTYP_RGB18    (0xa << 0)
+#define LDMT1R_MIFTYP_RGB24    (0xb << 0)
+#define LDMT1R_MIFTYP_YCBCR    (0xf << 0)
+#define LDMT1R_MIFTYP_SYS8A    (0x0 << 0)
+#define LDMT1R_MIFTYP_SYS8B    (0x1 << 0)
+#define LDMT1R_MIFTYP_SYS8C    (0x2 << 0)
+#define LDMT1R_MIFTYP_SYS8D    (0x3 << 0)
+#define LDMT1R_MIFTYP_SYS9     (0x4 << 0)
+#define LDMT1R_MIFTYP_SYS12    (0x5 << 0)
+#define LDMT1R_MIFTYP_SYS16A   (0x7 << 0)
+#define LDMT1R_MIFTYP_SYS16B   (0x8 << 0)
+#define LDMT1R_MIFTYP_SYS16C   (0x9 << 0)
+#define LDMT1R_MIFTYP_SYS18    (0xa << 0)
+#define LDMT1R_MIFTYP_SYS24    (0xb << 0)
+#define LDMT1R_MIFTYP_MASK     (0xf << 0)
+
+#define LDDFR_CF1              (1 << 18)
+#define LDDFR_CF0              (1 << 17)
+#define LDDFR_CC               (1 << 16)
+#define LDDFR_YF_420           (0 << 8)
+#define LDDFR_YF_422           (1 << 8)
+#define LDDFR_YF_444           (2 << 8)
+#define LDDFR_YF_MASK          (3 << 8)
+#define LDDFR_PKF_ARGB32       (0x00 << 0)
+#define LDDFR_PKF_RGB16                (0x03 << 0)
+#define LDDFR_PKF_RGB24                (0x0b << 0)
+#define LDDFR_PKF_MASK         (0x1f << 0)
+
+#define LDSM1R_OS              (1 << 0)
+
+#define LDSM2R_OSTRG           (1 << 0)
+
+#define LDPMR_LPS              (3 << 0)
+
+#define _LDDWD0R               0x800
+#define LDDWDxR_WDACT          (1 << 28)
+#define LDDWDxR_RSW            (1 << 24)
+#define _LDDRDR                        0x840
+#define LDDRDR_RSR             (1 << 24)
+#define LDDRDR_DRD_MASK                (0x3ffff << 0)
+#define _LDDWAR                        0x900
+#define LDDWAR_WA              (1 << 0)
+#define _LDDRAR                        0x904
+#define LDDRAR_RA              (1 << 0)
+
 enum {
-       RGB8,   /* 24bpp, 8:8:8 */
-       RGB9,   /* 18bpp, 9:9 */
-       RGB12A, /* 24bpp, 12:12 */
-       RGB12B, /* 12bpp */
-       RGB16,  /* 16bpp */
-       RGB18,  /* 18bpp */
-       RGB24,  /* 24bpp */
-       YUV422, /* 16bpp */
-       SYS8A,  /* 24bpp, 8:8:8 */
-       SYS8B,  /* 18bpp, 8:8:2 */
-       SYS8C,  /* 18bpp, 2:8:8 */
-       SYS8D,  /* 16bpp, 8:8 */
-       SYS9,   /* 18bpp, 9:9 */
-       SYS12,  /* 24bpp, 12:12 */
-       SYS16A, /* 16bpp */
-       SYS16B, /* 18bpp, 16:2 */
-       SYS16C, /* 18bpp, 2:16 */
-       SYS18,  /* 18bpp */
-       SYS24,  /* 24bpp */
+       RGB8    = LDMT1R_MIFTYP_RGB8,   /* 24bpp, 8:8:8 */
+       RGB9    = LDMT1R_MIFTYP_RGB9,   /* 18bpp, 9:9 */
+       RGB12A  = LDMT1R_MIFTYP_RGB12A, /* 24bpp, 12:12 */
+       RGB12B  = LDMT1R_MIFTYP_RGB12B, /* 12bpp */
+       RGB16   = LDMT1R_MIFTYP_RGB16,  /* 16bpp */
+       RGB18   = LDMT1R_MIFTYP_RGB18,  /* 18bpp */
+       RGB24   = LDMT1R_MIFTYP_RGB24,  /* 24bpp */
+       YUV422  = LDMT1R_MIFTYP_YCBCR,  /* 16bpp */
+       SYS8A   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A,     /* 24bpp, 8:8:8 */
+       SYS8B   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B,     /* 18bpp, 8:8:2 */
+       SYS8C   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C,     /* 18bpp, 2:8:8 */
+       SYS8D   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D,     /* 16bpp, 8:8 */
+       SYS9    = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9,      /* 18bpp, 9:9 */
+       SYS12   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12,     /* 24bpp, 12:12 */
+       SYS16A  = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A,    /* 16bpp */
+       SYS16B  = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B,    /* 18bpp, 16:2 */
+       SYS16C  = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C,    /* 18bpp, 2:16 */
+       SYS18   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18,     /* 18bpp */
+       SYS24   = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24,     /* 24bpp */
 };
 
 enum { LCDC_CHAN_DISABLED = 0,
This page took 0.047251 seconds and 5 git commands to generate.