diff options
author | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-08-30 22:02:02 +0200 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-08-30 22:02:02 +0200 |
commit | 8edbeb6eea647c26da482bd268ff67da209cba81 (patch) | |
tree | 251e607854abb6f8e7d82838ff3d7fd36586cc27 /drivers/video | |
parent | Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal... (diff) | |
parent | fbdev: sh_mobile_meram: Remove unneeded sh_mobile_meram.h (diff) | |
download | linux-8edbeb6eea647c26da482bd268ff67da209cba81.tar.xz linux-8edbeb6eea647c26da482bd268ff67da209cba81.zip |
Merge branch 'sh-mobile-lcdc' of git://linuxtv.org/pinchartl/fbdev into fbdev-next
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 592 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 12 | ||||
-rw-r--r-- | drivers/video/sh_mobile_meram.c | 202 | ||||
-rw-r--r-- | drivers/video/sh_mobile_meram.h | 41 |
4 files changed, 439 insertions, 408 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index b048417247e8..088cb17857e3 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -24,39 +24,14 @@ #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; diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index aeed6687e6a7..a58a0f38848b 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -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 diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index cc7d7329dc15..f63297099193 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -12,29 +12,103 @@ #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 @@ -44,8 +118,7 @@ * 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 index 82c54fbce8bd..000000000000 --- a/drivers/video/sh_mobile_meram.h +++ /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__ */ |