* [PATCH 0/3] sh_mobile_lcdc cleanup and fixes
From: Laurent Pinchart @ 2011-07-15 21:52 UTC (permalink / raw)
To: linux-fbdev
Hi everybody,
When trying to understand the sh_mobile_lcdc driver, I found it hard to read
statements that include hardcoded register values. I thus wrote a patch that
replace them with macros, making the code more readable.
While doing so, I found two potential issues in the driver. See patches 2 and
3 for detailed explanations and fixes.
Laurent Pinchart (3):
fbdev: sh_mobile_lcdc: Replace hardcoded register values with macros
fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
fbdev: sh_mobile_lcdc: Compute clock pattern using divider
denominator
drivers/video/sh_mobile_lcdcfb.c | 232 +++++++++++++++++---------------------
include/video/sh_mobile_lcdc.h | 135 +++++++++++++++++++---
2 files changed, 222 insertions(+), 145 deletions(-)
--
Best regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH 1/3] fbdev: sh_mobile_lcdc: Replace hardcoded register values with macros
From: Laurent Pinchart @ 2011-07-15 21:52 UTC (permalink / raw)
To: linux-fbdev
Instead of hardcoding register values through the driver, define macros
for individual register bits using the register name and the bit name,
and use the macros.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 204 +++++++++++++++++---------------------
include/video/sh_mobile_lcdc.h | 135 +++++++++++++++++++++----
2 files changed, 209 insertions(+), 130 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e9b80bc..7d77651 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -32,20 +32,6 @@
#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,
@@ -98,22 +84,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,
@@ -218,33 +188,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 = {
@@ -323,13 +296,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);
}
}
@@ -356,11 +329,11 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
* 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;
+ tmp &= ~LDINTR_STATUS_MASK & ~LDINTR_VEE;
lcdc_write(priv, _LDINTR, tmp);
/* 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++) {
@@ -395,16 +368,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;
@@ -422,13 +396,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 */
@@ -486,8 +460,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
/* reset */
- lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
- lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
+ 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);
@@ -496,7 +470,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
lcdc_write(priv, _LDCNT2R, tmp);
/* read data from external memory, avoid using the BEU for now */
- lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
+ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~LDCNT2R_MD);
/* stop the lcdc first */
sh_mobile_lcdc_start_stop(priv, 0);
@@ -514,7 +488,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
continue;
if (m = 1)
- m = 1 << 6;
+ m = LDDCKR_MOSEL;
tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */
@@ -554,20 +528,21 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* word and long word swap */
ldddsr = lcdc_read(priv, _LDDDSR);
if (priv->ch[0].info->var.nonstd)
- lcdc_write(priv, _LDDDSR, ldddsr | 7);
+ ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
else {
switch (bpp) {
case 16:
- lcdc_write(priv, _LDDDSR, ldddsr | 6);
+ ldddsr |= LDDDSR_LS | LDDDSR_WS;
break;
case 24:
- lcdc_write(priv, _LDDDSR, ldddsr | 7);
+ ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
break;
case 32:
- lcdc_write(priv, _LDDDSR, ldddsr | 4);
+ ldddsr |= LDDDSR_LS;
break;
}
}
+ lcdc_write(priv, _LDDDSR, ldddsr);
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
unsigned long base_addr_y;
@@ -580,28 +555,29 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* set bpp format in PKF[4:0] */
tmp = lcdc_read_chan(ch, LDDFR);
- tmp &= ~0x0003031f;
+ tmp &= ~(LDDFR_CF0 | LDDFR_CC | LDDFR_YF_MASK | LDDFR_PKF_MASK);
if (ch->info->var.nonstd) {
tmp |= (ch->info->var.nonstd << 16);
switch (ch->info->var.bits_per_pixel) {
case 12:
break;
case 16:
- tmp |= (0x1 << 8);
+ tmp |= LDDFR_YF_422;
break;
case 24:
- tmp |= (0x2 << 8);
+ 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:
+ tmp |= LDDFR_PKF_ARGB32;
break;
}
}
@@ -672,14 +648,14 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* setup deferred io if SYS bus */
tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
- if (ch->ldmt1r_value & (1 << 12) && tmp) {
+ 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);
/* one-shot mode */
- lcdc_write_chan(ch, LDSM1R, 1);
+ lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
/* enable "Frame End Interrupt Enable" bit */
lcdc_write(priv, _LDINTR, LDINTR_FE);
@@ -691,7 +667,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
/* display output */
- lcdc_write(priv, _LDCNT1R, LCDC_ENABLE);
+ lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
/* start the lcdc */
sh_mobile_lcdc_start_stop(priv, 1);
@@ -780,42 +756,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,
@@ -823,18 +799,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)) {
@@ -1476,12 +1458,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/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index d964e68..8101b72 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -4,26 +4,123 @@
#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,
--
1.7.3.4
^ permalink raw reply related
* [PATCH 2/3] fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
From: Laurent Pinchart @ 2011-07-15 21:52 UTC (permalink / raw)
To: linux-fbdev
The LDINTR register caries both interrupt enable and interrupt status
bits. When setting or clearing interrupt enable bits, write all status
bits to 1 to avoid acknowledging interrupts by mistake.
When acknowledging interrupts, write 1 to all non-triggered interrupt
bits to avoid losing interrupts.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 20 ++++++++------------
1 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 7d77651..32f884e 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -318,19 +318,13 @@ 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 &= ~LDINTR_STATUS_MASK & ~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) & LDSR_MSS) ? 1 : 0;
@@ -342,7 +336,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;
@@ -971,9 +965,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,
--
1.7.3.4
^ permalink raw reply related
* [PATCH 3/3] fbdev: sh_mobile_lcdc: Compute clock pattern using divider denominator
From: Laurent Pinchart @ 2011-07-15 21:52 UTC (permalink / raw)
To: linux-fbdev
The clock divider pattern is computed based on the dot clock register
value which stores the divider denumerator. However, when using a 1:1
divider ratio, the register is programmed with a value that must not be
interpreted as a denominator. This results in a shift left operation
with a value of 32, which produces undefined behaviour.
Compute the clock pattern using the divider denominator, not the dot
clock register value.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 32f884e..856f6a9 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -481,13 +481,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
if (!m)
continue;
+ /* 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);
-
- /* 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);
}
lcdc_write(priv, _LDDCKR, tmp);
--
1.7.3.4
^ permalink raw reply related
* [PATCH 2/2] viafb: improve pitch handling
From: Florian Tobias Schandinat @ 2011-07-17 0:34 UTC (permalink / raw)
To: linux-fbdev; +Cc: linux-kernel, Florian Tobias Schandinat, stable
This patch adds checks for minimum and maximum pitch size to prevent
invalid settings which could otherwise crash the machine. Also the
alignment is done in a slightly more readable way.
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: stable@kernel.org
---
drivers/video/via/via_modesetting.h | 5 +++++
drivers/video/via/viafbdev.c | 11 ++++++++---
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h
index ae35cfd..0138845 100644
--- a/drivers/video/via/via_modesetting.h
+++ b/drivers/video/via/via_modesetting.h
@@ -28,6 +28,11 @@
#include <linux/types.h>
+
+#define VIA_PITCH_SIZE (1<<3)
+#define VIA_PITCH_MAX 0x3FF8
+
+
void via_set_primary_address(u32 addr);
void via_set_secondary_address(u32 addr);
void via_set_primary_pitch(u32 pitch);
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index aa87529..bddae58 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_info *info)
info->fix.visual bpp = 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
+ info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
+ VIA_PITCH_SIZE);
}
static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
depth = 24;
viafb_fill_var_color_info(var, depth);
- line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
- if (line * var->yres_virtual > ppar->memsize)
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+
+ line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
+ VIA_PITCH_SIZE);
+ if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
return -EINVAL;
/* Based on var passed in to calculate the refresh,
--
1.6.3.2
^ permalink raw reply related
* RE: [PATCH V7 1/5] ARM: EXYNOS4: Change clock name for FIMD
From: Kukjin Kim @ 2011-07-18 1:22 UTC (permalink / raw)
To: 'Jingoo Han', 'Paul Mundt', linux-samsung-soc,
linux-fbdev, 'Jonghun Han'
Cc: 'Thomas Abraham'
In-Reply-To: <1309171740-27146-1-git-send-email-jg1.han@samsung.com>
Jingoo Han wrote:
>
> This patch changes clock name for FIMD from "fimd" to "lcd".
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
> ---
> arch/arm/mach-exynos4/clock.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
> index 871f9d5..12e6853 100644
> --- a/arch/arm/mach-exynos4/clock.c
> +++ b/arch/arm/mach-exynos4/clock.c
> @@ -433,12 +433,12 @@ static struct clk init_clocks_off[] = {
> .enable = exynos4_clk_ip_cam_ctrl,
> .ctrlbit = (1 << 3),
> }, {
> - .name = "fimd",
> + .name = "lcd",
> .id = 0,
> .enable = exynos4_clk_ip_lcd0_ctrl,
> .ctrlbit = (1 << 0),
> }, {
> - .name = "fimd",
> + .name = "lcd",
> .id = 1,
> .enable = exynos4_clk_ip_lcd1_ctrl,
> .ctrlbit = (1 << 0),
> --
> 1.7.1
This should be re-worked based on latest my for-next which includes clkdev.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply
* RE: [PATCH V7 2/5] ARM: EXYNOS4: Add FIMD resource definition
From: Kukjin Kim @ 2011-07-18 1:25 UTC (permalink / raw)
To: 'Jingoo Han', 'Paul Mundt', linux-samsung-soc,
linux-fbdev, 'Jonghun Han'
Cc: 'Thomas Abraham'
In-Reply-To: <1309171837-30299-1-git-send-email-jg1.han@samsung.com>
Jingoo Han wrote:
>
> From: Jonghun Han <jonghun.han@samsung.com>
>
> This patch adds resource definitions for EXYNOS4 FIMD.
> IRQ and SFR definitions are added.
>
> Signed-off-by: Jonghun Han <jonghun.han@samsung.com>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
> ---
> arch/arm/mach-exynos4/include/mach/irqs.h | 8 ++++++++
> arch/arm/mach-exynos4/include/mach/map.h | 5 +++++
> 2 files changed, 13 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-
> exynos4/include/mach/irqs.h
> index 5d03730..2cd2090 100644
> --- a/arch/arm/mach-exynos4/include/mach/irqs.h
> +++ b/arch/arm/mach-exynos4/include/mach/irqs.h
> @@ -73,6 +73,14 @@
> #define IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6)
> #define IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7)
>
> +#define IRQ_FIMD0_FIFO COMBINER_IRQ(11, 0)
> +#define IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1)
> +#define IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2)
> +
> +#define IRQ_FIMD1_FIFO COMBINER_IRQ(12, 0)
> +#define IRQ_FIMD1_VSYNC COMBINER_IRQ(12, 1)
> +#define IRQ_FIMD1_SYSTEM COMBINER_IRQ(12, 2)
> +
> #define IRQ_PDMA0 COMBINER_IRQ(21, 0)
> #define IRQ_PDMA1 COMBINER_IRQ(21, 1)
>
> diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-
> exynos4/include/mach/map.h
> index 0009e77..94006f7 100644
> --- a/arch/arm/mach-exynos4/include/mach/map.h
> +++ b/arch/arm/mach-exynos4/include/mach/map.h
> @@ -93,6 +93,9 @@
> #define EXYNOS4_PA_MIPI_CSIS0 0x11880000
> #define EXYNOS4_PA_MIPI_CSIS1 0x11890000
>
> +#define EXYNOS4_PA_FIMD0 0x11C00000
> +#define EXYNOS4_PA_FIMD1 0x12000000
> +
> #define EXYNOS4_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
>
> #define EXYNOS4_PA_SATA 0x12560000
> @@ -140,6 +143,8 @@
> #define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3
> #define S5P_PA_MIPI_CSIS0 EXYNOS4_PA_MIPI_CSIS0
> #define S5P_PA_MIPI_CSIS1 EXYNOS4_PA_MIPI_CSIS1
> +#define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0
> +#define S5P_PA_FIMD1 EXYNOS4_PA_FIMD1
> #define S5P_PA_ONENAND EXYNOS4_PA_ONENAND
> #define S5P_PA_ONENAND_DMA
> EXYNOS4_PA_ONENAND_DMA
> #define S5P_PA_SDRAM EXYNOS4_PA_SDRAM
> --
> 1.7.1
Firstly, needs to update based on latest my for-next.
Secondly, do you think we really need to define regarding FIMD1 even though
I couldn't find it in your patch?
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply
* RE: [PATCH V7 3/5] ARM: EXYNOS4: Add platform device and helper
From: Kukjin Kim @ 2011-07-18 1:59 UTC (permalink / raw)
To: 'Jingoo Han', 'Paul Mundt', linux-samsung-soc,
linux-fbdev, 'Jonghun Han'
In-Reply-To: <1309171845-30331-1-git-send-email-jg1.han@samsung.com>
Jingoo Han wrote:
>
> From: Jonghun Han <jonghun.han@samsung.com>
>
> This patch adds platform device s5p_device_fimd0 for EXYNOS4 FIMD0.
> EXYNOS4 has two FIMDs(FIMD0, FIMD1). FIMD1 will be added later.
> Some definitions used to enable EXYNOS4 FIMD0 are added.
>
> Signed-off-by: Jonghun Han <jonghun.han@samsung.com>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
> ---
> arch/arm/mach-exynos4/Kconfig | 9 ++++
> arch/arm/mach-exynos4/Makefile | 1 +
> arch/arm/mach-exynos4/cpu.c | 4 +-
> arch/arm/mach-exynos4/include/mach/regs-fb.h | 21 ++++++++
> arch/arm/mach-exynos4/setup-fimd0.c | 48 ++++++++++++++++++
> arch/arm/plat-s5p/Kconfig | 5 ++
> arch/arm/plat-s5p/Makefile | 1 +
> arch/arm/plat-s5p/dev-fimd0.c | 67
> ++++++++++++++++++++++++++
> arch/arm/plat-samsung/include/plat/devs.h | 1 +
> arch/arm/plat-samsung/include/plat/fb-core.h | 15 ++++++
> arch/arm/plat-samsung/include/plat/fb.h | 15 ++++++
> 11 files changed, 186 insertions(+), 1 deletions(-)
> create mode 100644 arch/arm/mach-exynos4/include/mach/regs-fb.h
> create mode 100644 arch/arm/mach-exynos4/setup-fimd0.c
> create mode 100644 arch/arm/plat-s5p/dev-fimd0.c
>
> diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
> index 1435fc3..2024f50 100644
> --- a/arch/arm/mach-exynos4/Kconfig
> +++ b/arch/arm/mach-exynos4/Kconfig
> @@ -25,6 +25,11 @@ config EXYNOS4_DEV_AHCI
> help
> Compile in platform device definitions for AHCI
>
> +config EXYNOS4_SETUP_FIMD0
> + bool
> + help
> + Common setup code for FIMD0.
> +
> config EXYNOS4_DEV_PD
> bool
> help
> @@ -103,6 +108,7 @@ menu "EXYNOS4 Machines"
> config MACH_SMDKC210
> bool "SMDKC210"
> select CPU_EXYNOS4210
> + select S5P_DEV_FIMD0
> select S3C_DEV_RTC
> select S3C_DEV_WDT
> select S3C_DEV_I2C1
> @@ -112,6 +118,7 @@ config MACH_SMDKC210
> select S3C_DEV_HSMMC3
> select EXYNOS4_DEV_PD
> select EXYNOS4_DEV_SYSMMU
> + select EXYNOS4_SETUP_FIMD0
> select EXYNOS4_SETUP_I2C1
> select EXYNOS4_SETUP_SDHCI
> help
> @@ -120,6 +127,7 @@ config MACH_SMDKC210
> config MACH_SMDKV310
> bool "SMDKV310"
> select CPU_EXYNOS4210
> + select S5P_DEV_FIMD0
> select S3C_DEV_RTC
> select S3C_DEV_WDT
> select S3C_DEV_I2C1
> @@ -130,6 +138,7 @@ config MACH_SMDKV310
> select SAMSUNG_DEV_KEYPAD
> select EXYNOS4_DEV_PD
> select EXYNOS4_DEV_SYSMMU
> + select EXYNOS4_SETUP_FIMD0
> select EXYNOS4_SETUP_I2C1
> select EXYNOS4_SETUP_KEYPAD
> select EXYNOS4_SETUP_SDHCI
> diff --git a/arch/arm/mach-exynos4/Makefile
b/arch/arm/mach-exynos4/Makefile
> index 60fe5ec..96472f1 100644
> --- a/arch/arm/mach-exynos4/Makefile
> +++ b/arch/arm/mach-exynos4/Makefile
> @@ -45,6 +45,7 @@ obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-
> pd.o
> obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
>
> obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
> +obj-$(CONFIG_EXYNOS4_SETUP_FIMD0) += setup-fimd0.o
> obj-$(CONFIG_EXYNOS4_SETUP_I2C1) += setup-i2c1.o
> obj-$(CONFIG_EXYNOS4_SETUP_I2C2) += setup-i2c2.o
> obj-$(CONFIG_EXYNOS4_SETUP_I2C3) += setup-i2c3.o
> diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
> index 9babe44..778a5b0 100644
> --- a/arch/arm/mach-exynos4/cpu.c
> +++ b/arch/arm/mach-exynos4/cpu.c
> @@ -19,9 +19,10 @@
>
> #include <plat/cpu.h>
> #include <plat/clock.h>
> +#include <plat/devs.h>
Is there any reason moving <plat/devs.h> from below?
> +#include <plat/fb-core.h>
> #include <plat/exynos4.h>
> #include <plat/sdhci.h>
> -#include <plat/devs.h>
> #include <plat/fimc-core.h>
>
> #include <mach/regs-irq.h>
> @@ -132,6 +133,7 @@ void __init exynos4_map_io(void)
> s3c_fimc_setname(1, "exynos4-fimc");
> s3c_fimc_setname(2, "exynos4-fimc");
> s3c_fimc_setname(3, "exynos4-fimc");
> + s5p_fb_setname(0, "exynos4-fb"); /* FIMD0 */
FB or FIMD?
sometimes used fb, sometimes fimd...
> }
>
> void __init exynos4_init_clocks(int xtal)
> diff --git a/arch/arm/mach-exynos4/include/mach/regs-fb.h b/arch/arm/mach-
> exynos4/include/mach/regs-fb.h
> new file mode 100644
> index 0000000..f320105
> --- /dev/null
> +++ b/arch/arm/mach-exynos4/include/mach/regs-fb.h
> @@ -0,0 +1,21 @@
> +/*
> + * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
> + *
> + * Dummy framebuffer to allow build for the moment.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#ifndef __ASM_ARCH_MACH_REGS_FB_H
> +#define __ASM_ARCH_MACH_REGS_FB_H __FILE__
> +
> +#include <plat/regs-fb-v4.h>
> +
> +static inline unsigned int s3c_fb_pal_reg(unsigned int window, int reg)
> +{
> + return 0x2400 + (window * 256 * 4) + reg;
> +}
> +
> +#endif /* __ASM_ARCH_MACH_REGS_FB_H */
> diff --git a/arch/arm/mach-exynos4/setup-fimd0.c
b/arch/arm/mach-exynos4/setup-
> fimd0.c
> new file mode 100644
> index 0000000..be58294
> --- /dev/null
> +++ b/arch/arm/mach-exynos4/setup-fimd0.c
> @@ -0,0 +1,48 @@
> +/* linux/arch/arm/mach-exynos4/setup-fimd0.c
> + *
> + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
> + * http://www.samsung.com
> + *
> + * Base Exynos4 FIMD 0 configuration
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/fb.h>
> +#include <linux/gpio.h>
> +#include <linux/clk.h>
> +
> +#include <plat/fb.h>
> +#include <plat/gpio-cfg.h>
> +
> +#include <mach/regs-clock.h>
> +#include <mach/regs-fb.h>
> +#include <mach/map.h>
> +
> +void exynos4_fimd0_gpio_setup_24bpp(void)
> +{
> + unsigned int reg = 0;
+ unsigned int reg;
> +
> + s3c_gpio_cfgrange_nopull(EXYNOS4_GPF0(0), 8, S3C_GPIO_SFN(2));
> + s3c_gpio_cfgrange_nopull(EXYNOS4_GPF1(0), 8, S3C_GPIO_SFN(2));
> + s3c_gpio_cfgrange_nopull(EXYNOS4_GPF2(0), 8, S3C_GPIO_SFN(2));
> + s3c_gpio_cfgrange_nopull(EXYNOS4_GPF3(0), 4, S3C_GPIO_SFN(2));
> +
> + /*
> + * Set DISPLAY_CONTROL register for Display path selection.
> + *
> + * DISPLAY_CONTROL[1:0]
> + * ---------------------
> + * 00 | MIE
> + * 01 | MDINE
> + * 10 | FIMD : selected
> + * 11 | FIMD
> + */
> + reg = __raw_readl(S3C_VA_SYS + 0x0210);
> + reg |= (1 << 1);
> + __raw_writel(reg, S3C_VA_SYS + 0x0210);
> +}
> diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
> index e98f5c5..46de16e 100644
> --- a/arch/arm/plat-s5p/Kconfig
> +++ b/arch/arm/plat-s5p/Kconfig
> @@ -70,6 +70,11 @@ config S5P_DEV_FIMC3
> help
> Compile in platform device definitions for FIMC controller 3
>
> +config S5P_DEV_FIMD0
> + bool
> + help
> + Compile in platform device definitions for FIMD controller 0
> +
> config S5P_DEV_ONENAND
> bool
> help
> diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
> index e234cc4..eec7e24 100644
> --- a/arch/arm/plat-s5p/Makefile
> +++ b/arch/arm/plat-s5p/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o
> obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o
> obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o
> obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
> +obj-$(CONFIG_S5P_DEV_FIMD0) += dev-fimd0.o
> obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
> obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
> obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
> diff --git a/arch/arm/plat-s5p/dev-fimd0.c b/arch/arm/plat-s5p/dev-fimd0.c
> new file mode 100644
> index 0000000..9e7176c
> --- /dev/null
> +++ b/arch/arm/plat-s5p/dev-fimd0.c
> @@ -0,0 +1,67 @@
> +/* linux/arch/arm/plat-s5p/dev-fimd0.c
> + *
> + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
> + * http://www.samsung.com
> + *
> + * Core file for Samsung Display Controller (FIMD) driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <linux/platform_device.h>
> +#include <linux/fb.h>
> +#include <linux/gfp.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <mach/irqs.h>
> +#include <mach/map.h>
> +
> +#include <plat/fb.h>
> +#include <plat/devs.h>
> +#include <plat/cpu.h>
> +
> +static struct resource s5p_fimd0_resource[] = {
> + [0] = {
> + .start = S5P_PA_FIMD0,
^^
> + .end = S5P_PA_FIMD0 + SZ_32K - 1,
^^^^
> + .flags = IORESOURCE_MEM,
^^
> + },
> + [1] = {
> + .start = IRQ_FIMD0_VSYNC,
^^
> + .end = IRQ_FIMD0_VSYNC,
^^^^
> + .flags = IORESOURCE_IRQ,
^^
> + },
> + [2] = {
> + .start = IRQ_FIMD0_FIFO,
^^
> + .end = IRQ_FIMD0_FIFO,
^^^^
> + .flags = IORESOURCE_IRQ,
^^
> + },
> + [3] = {
> + .start = IRQ_FIMD0_SYSTEM,
^^
> + .end = IRQ_FIMD0_SYSTEM,
^^^^
> + .flags = IORESOURCE_IRQ,
^^
> + },
> +};
> +
> +static u64 fimd0_dmamask = DMA_BIT_MASK(32);
> +
> +struct platform_device s5p_device_fimd0 = {
> + .name = "s5p-fb",
^^^^^^^^^^^
> + .id = 0,
^^^^^^^^^^^^^
> + .num_resources = ARRAY_SIZE(s5p_fimd0_resource),
^^
> + .resource = s5p_fimd0_resource,
^^^^^^^
> + .dev = {
^^^^^^^^^^^^
> + .dma_mask = &fimd0_dmamask,
^^^^^^^^^^^^^^^
> + .coherent_dma_mask = DMA_BIT_MASK(32),
^^^^^^
I think, tab in above '^' mark?
> + },
> +};
> +
> +void __init s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd)
> +{
> + s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
> + &s5p_device_fimd0);
> +}
> diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-
> samsung/include/plat/devs.h
> index 4af108f..370bd2b 100644
> --- a/arch/arm/plat-samsung/include/plat/devs.h
> +++ b/arch/arm/plat-samsung/include/plat/devs.h
> @@ -45,6 +45,7 @@ extern struct platform_device s3c64xx_device_ac97;
> extern struct platform_device s3c_device_ts;
>
> extern struct platform_device s3c_device_fb;
> +extern struct platform_device s5p_device_fimd0;
> extern struct platform_device s3c_device_ohci;
> extern struct platform_device s3c_device_lcd;
> extern struct platform_device s3c_device_wdt;
> diff --git a/arch/arm/plat-samsung/include/plat/fb-core.h b/arch/arm/plat-
> samsung/include/plat/fb-core.h
> index bca383e..6abcbf1 100644
> --- a/arch/arm/plat-samsung/include/plat/fb-core.h
> +++ b/arch/arm/plat-samsung/include/plat/fb-core.h
> @@ -26,4 +26,19 @@ static inline void s3c_fb_setname(char *name)
> #endif
> }
>
> +/* Re-define device name depending on support. */
> +static inline void s5p_fb_setname(int id, char *name)
> +{
> + switch (id) {
> +#ifdef CONFIG_S5P_DEV_FIMD0
> + case 0:
> + s5p_device_fimd0.name = name;
> + break;
> +#endif
> + default:
> + printk(KERN_ERR "%s: invalid device id(%d)\n", __func__,
id);
> + break;
> + }
> +}
> +
> #endif /* __ASM_PLAT_FB_CORE_H */
> diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-
> samsung/include/plat/fb.h
> index cb3ca3a..01f10e4 100644
> --- a/arch/arm/plat-samsung/include/plat/fb.h
> +++ b/arch/arm/plat-samsung/include/plat/fb.h
> @@ -74,6 +74,14 @@ struct s3c_fb_platdata {
> extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd);
>
> /**
> + * s5p_fimd0_set_platdata() - Setup the FB device with platform data.
> + * @pd: The platform data to set. The data is copied from the passed
structure
> + * so the machine data can mark the data __initdata so that any
unused
> + * machines will end up dumping their data at runtime.
> + */
> +extern void s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd);
> +
> +/**
> * s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD
> *
> * Initialise the GPIO for an 24bpp LCD display on the RGB interface.
> @@ -94,4 +102,11 @@ extern void s5pc100_fb_gpio_setup_24bpp(void);
> */
> extern void s5pv210_fb_gpio_setup_24bpp(void);
>
> +/**
> + * exynos4_fimd0_gpio_setup_24bpp() - Exynos4 setup function for 24bpp
LCD0
> + *
> + * Initialise the GPIO for an 24bpp LCD display on the RGB interface 0.
> + */
> +extern void exynos4_fimd0_gpio_setup_24bpp(void);
> +
> #endif /* __PLAT_S3C_FB_H */
> --
> 1.7.1
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply
* [PATCH v3] video: da8xx-fb: Increased resolution configuration of revised LCDC IP
From: Manjunathappa, Prakash @ 2011-07-18 4:40 UTC (permalink / raw)
To: linux-fbdev
Revised LCD controller in upcoming TI SoC which is an updated version of
LCDC IP that was found on TI's DA850 SoC supports 2048*2048 resolution.
Below are the encoding details:
Width:
Pixels Per Line = {pplmsb, ppllsb, 4'b1111} + 1
Where pplmsb:1bit=>Raster Timing0[3], ppllsb:6bits=>Raster Timing0[9:4].
And encoded value can range from 16 to 2048 in multiples of 16.
Height:
Lines Per Panel = {lpp_b10, lpp}
Where lpp:10bits=>Raster Timing1[9:0], lpp_b10:1bit=>Raster Timing2[26].
And encoded value can range from 1 to 2048, programmable range is 0 to
2047.
Patch is verified on emulation platform of upcoming SoC for updated
feature and on DA850 platform to make sure nothing existing breaks.
Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
---
Since v2:
Corrected comment describing horizontal resolution bits and removed unnecessary
outer parenthesis.
Since v1:
1)Fixed the bug in configuration of lpp_b10 in Raster Timing2[26] register.
2)Reframed commit message.
drivers/video/da8xx-fb.c | 31 ++++++++++++++++++++++++++++---
1 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 620f1c3..94b611a 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -460,18 +460,43 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
/* Set the Panel Width */
/* Pixels per line = (PPL + 1)*16 */
- /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
- width &= 0x3f0;
+ if (lcd_revision = LCD_VERSION_1) {
+ /*
+ * 0x3F in bits 4..9 gives max horizontal resolution = 1024
+ * pixels.
+ */
+ width &= 0x3f0;
+ } else {
+ /*
+ * 0x7F in bits 4..10 gives max horizontal resolution = 2048
+ * pixels.
+ */
+ width &= 0x7f0;
+ }
+
reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
reg &= 0xfffffc00;
- reg |= ((width >> 4) - 1) << 4;
+ if (lcd_revision = LCD_VERSION_1) {
+ reg |= ((width >> 4) - 1) << 4;
+ } else {
+ width = (width >> 4) - 1;
+ reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
+ }
lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
/* Set the Panel Height */
+ /* Set bits 9:0 of Lines Per Pixel */
reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
+ /* Set bit 10 of Lines Per Pixel */
+ if (lcd_revision = LCD_VERSION_2) {
+ reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
+ reg |= ((height - 1) & 0x400) << 16;
+ lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
+ }
+
/* Set the Raster Order of the Frame Buffer */
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
if (raster_order)
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] video: backlight: fix const array syntax
From: Greg Dietsche @ 2011-07-20 2:09 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1309560431-17389-1-git-send-email-Gregory.Dietsche@cuw.edu>
On 07/01/2011 05:47 PM, Greg Dietsche wrote:
> Correct the syntax so that both array and pointer are const.
>
> Signed-off-by: Greg Dietsche<Gregory.Dietsche@cuw.edu>
> ---
> drivers/video/backlight/backlight.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
> index 80d292f..4bda2e7 100644
> --- a/drivers/video/backlight/backlight.c
> +++ b/drivers/video/backlight/backlight.c
> @@ -19,7 +19,7 @@
> #include<asm/backlight.h>
> #endif
>
> -static const char const *backlight_types[] = {
> +static const char * const backlight_types[] = {
> [BACKLIGHT_RAW] = "raw",
> [BACKLIGHT_PLATFORM] = "platform",
> [BACKLIGHT_FIRMWARE] = "firmware",
>
adding trivial@kernel.org to the cc list since this is trivial and no
one has picked up this patch to date.
Greg
^ permalink raw reply
* [PATCH] atmel_lcdfb: Fix compilation
From: Laurent Pinchart @ 2011-07-20 10:25 UTC (permalink / raw)
To: linux-fbdev
A typo in the "atmel_lcdfb: use display information in info not in var
for panning" patch broke compilation. Fix it.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/atmel_lcdfb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
Paul,
This patch applies on top of the fbdev/panning-fixes branch in
git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-3.x.git
You can apply it, squash it with patch "atmel_lcdfb: use display information
in info not in var for panning" in that branch, or replace the whole branch
with my "[PATCH v3 00/29] Use display information in info not in var for
panning" patch series posted to the linux-fbdev list.
Do you plan to push the result for v3.1 ?
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 8b5d755..5f1de1f 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -59,7 +59,7 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
- dma2dcfg = (info-var.xres_virtual - info->var.xres)
+ dma2dcfg = (info->var.xres_virtual - info->var.xres)
* info->var.bits_per_pixel / 8;
dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
--
Regards,
Laurent Pinchart
^ permalink raw reply related
* My associate has helped me to send your first payment
From: WESTERN UNION OFFICE @ 2011-07-20 10:30 UTC (permalink / raw)
To: linux-fbdev
My associate has helped me to send your first payment
of $7,500 USD to you as instructed by the Malaysian
Government and Mr. David Cameron the United Kingdom
prime minister after the last G20 meeting that was
held in Malaysia, making you one of the beneficiaries.
Here is the information below.
MTCN Numbers: 6096147516
Sender Name Is = Patrick Lee Chun
I told him to keep sending you $7,500 USD twice a week
until the FULL payment of ($820000.00 United State Dollars)
is completed.
A certificate will be made to change the Receivers Name
to your name as stated by the Malaysian Government, send
your Full Names and address via Email to: Mr Garry Moore
to proceed.
Note:
You cannot pickup the money until the certificate is
obtained by you.
Regards
Mr. Garry Moore.
Tel: +(60) 136910048.
^ permalink raw reply
* [PATCH v2 0/6] sh_mobile_lcdc cleanup and fixes
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
Hi everybody,
Here's a second version of my sh_mobile_lcdc cleanup and fixes patch set.
Compared to v1, it adds three new patches that clean the driver's runtime PM
resume handling, and fix a panning issue on resume.
The first three patches have not been modified.
Laurent Pinchart (6):
fbdev: sh_mobile_lcdc: Replace hardcoded register values with macros
fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
fbdev: sh_mobile_lcdc: Compute clock pattern using divider
denominator
fbdev: sh_mobile_lcdc: Split LCDC start code from
sh_mobile_lcdc_start
fbdev: sh_mobile_lcdc: Store the frame buffer base address when
panning
fbdev: sh_mobile_lcdc: Restart LCDC in runtime PM resume handler
drivers/video/sh_mobile_lcdcfb.c | 582 +++++++++++++++++---------------------
drivers/video/sh_mobile_lcdcfb.h | 12 +-
include/video/sh_mobile_lcdc.h | 135 ++++++++--
3 files changed, 383 insertions(+), 346 deletions(-)
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH v2 1/6] fbdev: sh_mobile_lcdc: Replace hardcoded register values with macros
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
Instead of hardcoding register values through the driver, define macros
for individual register bits using the register name and the bit name,
and use the macros.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 204 +++++++++++++++++---------------------
include/video/sh_mobile_lcdc.h | 135 +++++++++++++++++++++----
2 files changed, 209 insertions(+), 130 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e9b80bc..abc2a91 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -32,20 +32,6 @@
#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,
@@ -98,22 +84,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,
@@ -218,33 +188,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 = {
@@ -323,13 +296,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);
}
}
@@ -356,11 +329,11 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
* 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;
+ tmp &= ~LDINTR_STATUS_MASK & ~LDINTR_VEE;
lcdc_write(priv, _LDINTR, tmp);
/* 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++) {
@@ -395,16 +368,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;
@@ -422,13 +396,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 */
@@ -486,8 +460,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
/* reset */
- lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
- lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
+ 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);
@@ -496,7 +470,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
lcdc_write(priv, _LDCNT2R, tmp);
/* read data from external memory, avoid using the BEU for now */
- lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU);
+ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~LDCNT2R_MD);
/* stop the lcdc first */
sh_mobile_lcdc_start_stop(priv, 0);
@@ -514,7 +488,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
continue;
if (m = 1)
- m = 1 << 6;
+ m = LDDCKR_MOSEL;
tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0);
/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */
@@ -554,20 +528,21 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* word and long word swap */
ldddsr = lcdc_read(priv, _LDDDSR);
if (priv->ch[0].info->var.nonstd)
- lcdc_write(priv, _LDDDSR, ldddsr | 7);
+ ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
else {
switch (bpp) {
case 16:
- lcdc_write(priv, _LDDDSR, ldddsr | 6);
+ ldddsr |= LDDDSR_LS | LDDDSR_WS;
break;
case 24:
- lcdc_write(priv, _LDDDSR, ldddsr | 7);
+ ldddsr |= LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
break;
case 32:
- lcdc_write(priv, _LDDDSR, ldddsr | 4);
+ ldddsr |= LDDDSR_LS;
break;
}
}
+ lcdc_write(priv, _LDDDSR, ldddsr);
for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
unsigned long base_addr_y;
@@ -580,28 +555,29 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* set bpp format in PKF[4:0] */
tmp = lcdc_read_chan(ch, LDDFR);
- tmp &= ~0x0003031f;
+ tmp &= ~(LDDFR_CF0 | LDDFR_CC | LDDFR_YF_MASK | LDDFR_PKF_MASK);
if (ch->info->var.nonstd) {
tmp |= (ch->info->var.nonstd << 16);
switch (ch->info->var.bits_per_pixel) {
case 12:
break;
case 16:
- tmp |= (0x1 << 8);
+ tmp |= LDDFR_YF_422;
break;
case 24:
- tmp |= (0x2 << 8);
+ 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:
+ tmp |= LDDFR_PKF_ARGB32;
break;
}
}
@@ -672,14 +648,14 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
/* setup deferred io if SYS bus */
tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
- if (ch->ldmt1r_value & (1 << 12) && tmp) {
+ 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);
/* one-shot mode */
- lcdc_write_chan(ch, LDSM1R, 1);
+ lcdc_write_chan(ch, LDSM1R, LDSM1R_OS);
/* enable "Frame End Interrupt Enable" bit */
lcdc_write(priv, _LDINTR, LDINTR_FE);
@@ -691,7 +667,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
/* display output */
- lcdc_write(priv, _LDCNT1R, LCDC_ENABLE);
+ lcdc_write(priv, _LDCNT1R, LDCNT1R_DE);
/* start the lcdc */
sh_mobile_lcdc_start_stop(priv, 1);
@@ -780,42 +756,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,
@@ -823,18 +799,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)) {
@@ -1476,12 +1458,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/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index d964e68..8101b72 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -4,26 +4,123 @@
#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,
--
1.7.3.4
^ permalink raw reply related
* [PATCH v2 2/6] fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
The LDINTR register caries both interrupt enable and interrupt status
bits. When setting or clearing interrupt enable bits, write all status
bits to 1 to avoid acknowledging interrupts by mistake.
When acknowledging interrupts, write 1 to all non-triggered interrupt
bits to avoid losing interrupts.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 20 ++++++++------------
1 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index abc2a91..ba946f4 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -318,19 +318,13 @@ 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 &= ~LDINTR_STATUS_MASK & ~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) & LDSR_MSS) ? 1 : 0;
@@ -342,7 +336,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;
@@ -971,9 +965,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,
--
1.7.3.4
^ permalink raw reply related
* [PATCH v2 3/6] fbdev: sh_mobile_lcdc: Compute clock pattern using divider denominator
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
The clock divider pattern is computed based on the dot clock register
value which stores the divider denumerator. However, when using a 1:1
divider ratio, the register is programmed with a value that must not be
interpreted as a denominator. This results in a shift left operation
with a value of 32, which produces undefined behaviour.
Compute the clock pattern using the divider denominator, not the dot
clock register value.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index ba946f4..31aef60 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -481,13 +481,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
if (!m)
continue;
+ /* 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);
-
- /* 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);
}
lcdc_write(priv, _LDDCKR, tmp);
--
1.7.3.4
^ permalink raw reply related
* [PATCH v2 4/6] fbdev: sh_mobile_lcdc: Split LCDC start code from sh_mobile_lcdc_start
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
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 | 313 +++++++++++++++++++-------------------
drivers/video/sh_mobile_lcdcfb.h | 11 ++
2 files changed, 164 insertions(+), 160 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 31aef60..785521e 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -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);
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index aeed668..a06219b 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;
@@ -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
--
1.7.3.4
^ permalink raw reply related
* [PATCH v2 5/6] fbdev: sh_mobile_lcdc: Store the frame buffer base address when panning
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
When the frame buffer base address is changed by a panning operation,
store it in the channel structure. It will be reused when runtime PM
code will use __sh_mobile_lcdc_start().
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 22 +++++++++-------------
1 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 785521e..f0a3d54 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -915,32 +915,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);
--
1.7.3.4
^ permalink raw reply related
* [PATCH v2 6/6] fbdev: sh_mobile_lcdc: Restart LCDC in runtime PM resume handler
From: Laurent Pinchart @ 2011-07-20 11:24 UTC (permalink / raw)
To: linux-fbdev
Instead of restoring registers blindly, restart the LCDC by going
through the startup sequence when resuming from runtime PM suspend. All
registers are now correctly initialized in the right order.
As a side effect, this also gets rid fo a possible panning restore issue
caused by always saving the frame buffer base address registers from set
A instead of the currently active set.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 49 ++++----------------------------------
drivers/video/sh_mobile_lcdcfb.h | 1 -
2 files changed, 5 insertions(+), 45 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index f0a3d54..d0f768e 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -32,17 +32,6 @@
#define SIDE_B_OFFSET 0x1000
#define MIRROR_OFFSET 0x2000
-/* 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
@@ -111,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;
@@ -1289,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;
}
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index a06219b..a58a0f3 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -32,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;
--
1.7.3.4
^ permalink raw reply related
* [GIT PULL] viafb updates for 3.1
From: Florian Tobias Schandinat @ 2011-07-20 15:22 UTC (permalink / raw)
To: linux-fbdev
Hi Paul,
please pull the viafb updates below. It contains only 2 fixes.
Thanks,
Florian Tobias Schandinat
The following changes since commit 8aa4d96fe3e4cda9a6469b22b3f017ed30996b10:
Daniel Drake (1):
viafb: Automatic OLPC XO-1.5 configuration
are available in the git repository at:
git://github.com/schandinat/linux-2.6.git viafb-next
Florian Tobias Schandinat (2):
viafb: use display information in info not in var for panning
viafb: improve pitch handling
drivers/video/via/via_modesetting.h | 5 +++++
drivers/video/via/viafbdev.c | 16 +++++++++++-----
2 files changed, 16 insertions(+), 5 deletions(-)
^ permalink raw reply
* Re: [PATCH] fb: avoid possible deadlock caused by fb_set_suspend
From: Florian Tobias Schandinat @ 2011-07-20 18:16 UTC (permalink / raw)
To: lethal
Cc: linux-fbdev, francis.moro, torvalds, bonbons, linux-kernel,
Herton Ronaldo Krzesinski, stable
In-Reply-To: <1308337359-3480-1-git-send-email-FlorianSchandinat@gmx.de>
Hi Paul,
what are your plans for the patch below? Do you queue it for 3.1?
The only feedback so far was that one driver (sh_mobile_hdmi) would require more
work with a patch for that proposed. Without any objections to the patch I think
we should take it as fixing the subsystem is more important than causing
potential issues with a single driver.
Thanks,
Florian Tobias Schandinat
On 06/17/2011 07:02 PM, Florian Tobias Schandinat wrote:
> From: Herton Ronaldo Krzesinski<herton@mandriva.com.br>
>
> A lock ordering issue can cause deadlocks: in framebuffer/console code,
> all needed struct fb_info locks are taken before acquire_console_sem(),
> in places which need to take console semaphore.
>
> But fb_set_suspend is always called with console semaphore held, and
> inside it we call lock_fb_info which gets the fb_info lock, inverse
> locking order of what the rest of the code does. This causes a real
> deadlock issue, when we write to state fb sysfs attribute (which calls
> fb_set_suspend) while a framebuffer is being unregistered by
> remove_conflicting_framebuffers, as can be shown by following show
> blocked state trace on a test program which loads i915 and runs another
> forked processes writing to state attribute:
>
> Test process with semaphore held and trying to get fb_info lock:
> ..
> fb-test2 D 0000000000000000 0 237 228 0x00000000
> ffff8800774f3d68 0000000000000082 00000000000135c0 00000000000135c0
> ffff880000000000 ffff8800774f3fd8 ffff8800774f3fd8 ffff880076ee4530
> 00000000000135c0 ffff8800774f3fd8 ffff8800774f2000 00000000000135c0
> Call Trace:
> [<ffffffff8141287a>] __mutex_lock_slowpath+0x11a/0x1e0
> [<ffffffff814142f2>] ? _raw_spin_lock_irq+0x22/0x40
> [<ffffffff814123d3>] mutex_lock+0x23/0x50
> [<ffffffff8125dfc5>] lock_fb_info+0x25/0x60
> [<ffffffff8125e3f0>] fb_set_suspend+0x20/0x80
> [<ffffffff81263e2f>] store_fbstate+0x4f/0x70
> [<ffffffff812e7f70>] dev_attr_store+0x20/0x30
> [<ffffffff811c46b4>] sysfs_write_file+0xd4/0x160
> [<ffffffff81155a26>] vfs_write+0xc6/0x190
> [<ffffffff81155d51>] sys_write+0x51/0x90
> [<ffffffff8100c012>] system_call_fastpath+0x16/0x1b
> ..
> modprobe process stalled because has the fb_info lock (got inside
> unregister_framebuffer) but waiting for the semaphore held by the
> test process which is waiting to get the fb_info lock:
> ..
> modprobe D 0000000000000000 0 230 218 0x00000000
> ffff880077a4d618 0000000000000082 0000000000000001 0000000000000001
> ffff880000000000 ffff880077a4dfd8 ffff880077a4dfd8 ffff8800775a2e20
> 00000000000135c0 ffff880077a4dfd8 ffff880077a4c000 00000000000135c0
> Call Trace:
> [<ffffffff81411fe5>] schedule_timeout+0x215/0x310
> [<ffffffff81058051>] ? get_parent_ip+0x11/0x50
> [<ffffffff814130dd>] __down+0x6d/0xb0
> [<ffffffff81089f71>] down+0x41/0x50
> [<ffffffff810629ac>] acquire_console_sem+0x2c/0x50
> [<ffffffff812ca53d>] unbind_con_driver+0xad/0x2d0
> [<ffffffff8126f5f7>] fbcon_event_notify+0x457/0x890
> [<ffffffff814144ff>] ? _raw_spin_unlock_irqrestore+0x1f/0x50
> [<ffffffff81058051>] ? get_parent_ip+0x11/0x50
> [<ffffffff8141836d>] notifier_call_chain+0x4d/0x70
> [<ffffffff8108a3b8>] __blocking_notifier_call_chain+0x58/0x80
> [<ffffffff8108a3f6>] blocking_notifier_call_chain+0x16/0x20
> [<ffffffff8125dabb>] fb_notifier_call_chain+0x1b/0x20
> [<ffffffff8125e6ac>] unregister_framebuffer+0x7c/0x130
> [<ffffffff8125e8b3>] remove_conflicting_framebuffers+0x153/0x180
> [<ffffffff8125eef3>] register_framebuffer+0x93/0x2c0
> [<ffffffffa0331112>] drm_fb_helper_single_fb_probe+0x252/0x2f0 [drm_kms_helper]
> [<ffffffffa03314a3>] drm_fb_helper_initial_config+0x2f3/0x6d0 [drm_kms_helper]
> [<ffffffffa03318dd>] ? drm_fb_helper_single_add_all_connectors+0x5d/0x1c0 [drm_kms_helper]
> [<ffffffffa037b588>] intel_fbdev_init+0xa8/0x160 [i915]
> [<ffffffffa0343d74>] i915_driver_load+0x854/0x12b0 [i915]
> [<ffffffffa02f0e7e>] drm_get_pci_dev+0x19e/0x360 [drm]
> [<ffffffff8141821d>] ? sub_preempt_count+0x9d/0xd0
> [<ffffffffa0386f91>] i915_pci_probe+0x15/0x17 [i915]
> [<ffffffff8124481f>] local_pci_probe+0x5f/0xd0
> [<ffffffff81244f89>] pci_device_probe+0x119/0x120
> [<ffffffff812eccaa>] ? driver_sysfs_add+0x7a/0xb0
> [<ffffffff812ed003>] driver_probe_device+0xa3/0x290
> [<ffffffff812ed1f0>] ? __driver_attach+0x0/0xb0
> [<ffffffff812ed29b>] __driver_attach+0xab/0xb0
> [<ffffffff812ed1f0>] ? __driver_attach+0x0/0xb0
> [<ffffffff812ebd3e>] bus_for_each_dev+0x5e/0x90
> [<ffffffff812ecc2e>] driver_attach+0x1e/0x20
> [<ffffffff812ec6f2>] bus_add_driver+0xe2/0x320
> [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
> [<ffffffff812ed536>] driver_register+0x76/0x140
> [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
> [<ffffffff81245216>] __pci_register_driver+0x56/0xd0
> [<ffffffffa02f1264>] drm_pci_init+0xe4/0xf0 [drm]
> [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
> [<ffffffffa02e84a8>] drm_init+0x58/0x70 [drm]
> [<ffffffffa03aa094>] i915_init+0x94/0x96 [i915]
> [<ffffffff81002194>] do_one_initcall+0x44/0x190
> [<ffffffff810a066b>] sys_init_module+0xcb/0x210
> [<ffffffff8100c012>] system_call_fastpath+0x16/0x1b
> ..
>
> fb-test2 which reproduces above is available on kernel.org bug #26232.
> To solve this issue, avoid calling lock_fb_info inside fb_set_suspend,
> and move it out to where needed (callers of fb_set_suspend must call
> lock_fb_info before if needed). So far, the only place which needs to
> call lock_fb_info is store_fbstate, all other places which calls
> fb_set_suspend are suspend/resume hooks that should not need the lock as
> they should be run only when processes are already frozen in
> suspend/resume.
>
> References: https://bugzilla.kernel.org/show_bug.cgi?id&232
> Signed-off-by: Herton Ronaldo Krzesinski<herton@mandriva.com.br>
> Signed-off-by: Florian Tobias Schandinat<FlorianSchandinat@gmx.de>
> Cc: stable@kernel.org
> ---
> drivers/video/fbmem.c | 3 ---
> drivers/video/fbsysfs.c | 3 +++
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
> index 5aac00e..ad93629 100644
> --- a/drivers/video/fbmem.c
> +++ b/drivers/video/fbmem.c
> @@ -1738,8 +1738,6 @@ void fb_set_suspend(struct fb_info *info, int state)
> {
> struct fb_event event;
>
> - if (!lock_fb_info(info))
> - return;
> event.info = info;
> if (state) {
> fb_notifier_call_chain(FB_EVENT_SUSPEND,&event);
> @@ -1748,7 +1746,6 @@ void fb_set_suspend(struct fb_info *info, int state)
> info->state = FBINFO_STATE_RUNNING;
> fb_notifier_call_chain(FB_EVENT_RESUME,&event);
> }
> - unlock_fb_info(info);
> }
>
> /**
> diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
> index 04251ce..67afa9c 100644
> --- a/drivers/video/fbsysfs.c
> +++ b/drivers/video/fbsysfs.c
> @@ -399,9 +399,12 @@ static ssize_t store_fbstate(struct device *device,
>
> state = simple_strtoul(buf,&last, 0);
>
> + if (!lock_fb_info(fb_info))
> + return -ENODEV;
> console_lock();
> fb_set_suspend(fb_info, (int)state);
> console_unlock();
> + unlock_fb_info(fb_info);
>
> return count;
> }
^ permalink raw reply
* [PATCH V8 0/5] ARM: EXYNOS4: Add support EXYNOS4 FIMD
From: Jingoo Han @ 2011-07-20 22:53 UTC (permalink / raw)
To: Kukjin Kim, Paul Mundt, linux-samsung-soc, linux-fbdev
Cc: Jonghun Han, Ben Dooks, Jingoo Han
The patches are created against "for-next" branch of Kukjin Kim's tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git
This was originally submitted by Jonghun Han <jonghun.han@samsung.com>
http://www.spinics.net/lists/arm-kernel/msg101781.html
This patch adds support FIMD(Fully Interactive Mobile Display) on Exynos4.
The 4th patch is update for s3c-fb and others are for platform data
NOTE: The common part for SMDKV310 will be updated later.
v2: change clock name of exynos4 FIMD: "fimd" -> "lcd"
use 'has_clksel' variable in order to distinguish FIMD version
add 'lcd_clk' that can be used for only lcd pixel clock
add callback 'enable_clk()' to enable parent clock 'sclk_fimd'.
v3: remove the callback from the platform data structure
v4: move clk_enable(sfb->lcd_clk) under the if statement
v5: add clk_enable/disable(sfb->lcd_clk) to s3c_fb_runtime_suspend/resume().
v6: rename dev-fimd-24bpp.c to dev-fimd0.c
add 'exynos4_fimd0_setup_clock()' to dev-fimd0.c to setup parent clock.
v7: remove parent clock setting from machine directory
use ¡®gpio_request_one()¡¯ to simply the gpio setting step
v8: updated minor fixes
o To Kukjin Kim
[PATCH V8 1/5] ARM: EXYNOS4: Change clock name for FIMD
[PATCH V8 2/5] ARM: EXYNOS4: Add resource definition for FIMD
[PATCH V8 3/5] ARM: EXYNOS4: Add platform device and helper functions for FIMD
[PATCH V8 5/5] ARM: EXYNOS4: Add platform data for EXYNOS4 FIMD and LTE480WV platform-lcd on SMDKC210
o To Paul Mundt
[PATCH V8 4/5] video: s3c-fb: Add support EXYNOS4
^ permalink raw reply
* [PATCH V8 1/5] ARM: EXYNOS4: Change clock name for FIMD
From: Jingoo Han @ 2011-07-20 22:54 UTC (permalink / raw)
To: Kukjin Kim, Paul Mundt, linux-samsung-soc, linux-fbdev
Cc: Jonghun Han, Ben Dooks, Jingoo Han
This patch changes clock for FIMD from 'fimd' to 'lcd'.
Also, devname for FIMD is changed from 's5pv310-fb' to 'exynos4-fb'.
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
arch/arm/mach-exynos4/clock.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index 98b5cc4..778a202 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -405,13 +405,13 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 3),
}, {
- .name = "fimd",
- .devname = "s5pv310-fb.0",
+ .name = "lcd",
+ .devname = "exynos4-fb.0",
.enable = exynos4_clk_ip_lcd0_ctrl,
.ctrlbit = (1 << 0),
}, {
- .name = "fimd",
- .devname = "s5pv310-fb.1",
+ .name = "lcd",
+ .devname = "exynos4-fb.1",
.enable = exynos4_clk_ip_lcd1_ctrl,
.ctrlbit = (1 << 0),
}, {
@@ -909,7 +909,7 @@ static struct clksrc_clk clksrcs[] = {
}, {
.clk = {
.name = "sclk_fimd",
- .devname = "s5pv310-fb.0",
+ .devname = "exynos4-fb.0",
.enable = exynos4_clksrc_mask_lcd0_ctrl,
.ctrlbit = (1 << 0),
},
@@ -919,7 +919,7 @@ static struct clksrc_clk clksrcs[] = {
}, {
.clk = {
.name = "sclk_fimd",
- .devname = "s5pv310-fb.1",
+ .devname = "exynos4-fb.1",
.enable = exynos4_clksrc_mask_lcd1_ctrl,
.ctrlbit = (1 << 0),
},
--
1.7.1
^ permalink raw reply related
* [PATCH V8 2/5] ARM: EXYNOS4: Add resource definition for FIMD
From: Jingoo Han @ 2011-07-20 22:54 UTC (permalink / raw)
To: Kukjin Kim, Paul Mundt, linux-samsung-soc, linux-fbdev
Cc: Jonghun Han, Ben Dooks, Jingoo Han
From: Jonghun Han <jonghun.han@samsung.com>
This patch adds resource definitions for EXYNOS4 FIMD.
IRQ and SFR definitions are added.
Signed-off-by: Jonghun Han <jonghun.han@samsung.com>
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
arch/arm/mach-exynos4/include/mach/irqs.h | 4 ++++
arch/arm/mach-exynos4/include/mach/map.h | 3 +++
2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
index 250427f..0d315a9 100644
--- a/arch/arm/mach-exynos4/include/mach/irqs.h
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -137,6 +137,10 @@
#define IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6)
#define IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7)
+#define IRQ_FIMD0_FIFO COMBINER_IRQ(11, 0)
+#define IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1)
+#define IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2)
+
#define MAX_COMBINER_NR 16
#define S5P_IRQ_EINT_BASE COMBINER_IRQ(MAX_COMBINER_NR, 0)
diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos4/include/mach/map.h
index 3677356..2a5a6f6 100644
--- a/arch/arm/mach-exynos4/include/mach/map.h
+++ b/arch/arm/mach-exynos4/include/mach/map.h
@@ -95,6 +95,8 @@
#define EXYNOS4_PA_MIPI_CSIS0 0x11880000
#define EXYNOS4_PA_MIPI_CSIS1 0x11890000
+#define EXYNOS4_PA_FIMD0 0x11C00000
+
#define EXYNOS4_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
#define EXYNOS4_PA_SATA 0x12560000
@@ -142,6 +144,7 @@
#define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3
#define S5P_PA_MIPI_CSIS0 EXYNOS4_PA_MIPI_CSIS0
#define S5P_PA_MIPI_CSIS1 EXYNOS4_PA_MIPI_CSIS1
+#define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0
#define S5P_PA_ONENAND EXYNOS4_PA_ONENAND
#define S5P_PA_ONENAND_DMA EXYNOS4_PA_ONENAND_DMA
#define S5P_PA_SDRAM EXYNOS4_PA_SDRAM
--
1.7.1
^ permalink raw reply related
* [PATCH V8 3/5] ARM: EXYNOS4: Add platform device and helper functions for FIMD
From: Jingoo Han @ 2011-07-20 22:54 UTC (permalink / raw)
To: Kukjin Kim, Paul Mundt, linux-samsung-soc, linux-fbdev
Cc: Jonghun Han, Ben Dooks, Jingoo Han
From: Jonghun Han <jonghun.han@samsung.com>
This patch adds platform device s5p_device_fimd0 for EXYNOS4 FIMD0.
EXYNOS4 has two FIMDs(FIMD0, FIMD1). FIMD1 will be added later.
Some definitions used to enable EXYNOS4 FIMD0 are added.
Signed-off-by: Jonghun Han <jonghun.han@samsung.com>
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
arch/arm/mach-exynos4/Kconfig | 9 ++++
arch/arm/mach-exynos4/Makefile | 1 +
arch/arm/mach-exynos4/cpu.c | 3 +
arch/arm/mach-exynos4/setup-fimd0.c | 43 ++++++++++++++++
arch/arm/plat-s5p/Kconfig | 5 ++
arch/arm/plat-s5p/Makefile | 1 +
arch/arm/plat-s5p/dev-fimd0.c | 67 ++++++++++++++++++++++++++
arch/arm/plat-samsung/include/plat/devs.h | 1 +
arch/arm/plat-samsung/include/plat/fb-core.h | 15 ++++++
arch/arm/plat-samsung/include/plat/fb.h | 15 ++++++
10 files changed, 160 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-exynos4/setup-fimd0.c
create mode 100644 arch/arm/plat-s5p/dev-fimd0.c
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index a4fb109..83518b5 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -26,6 +26,11 @@ config EXYNOS4_DEV_AHCI
help
Compile in platform device definitions for AHCI
+config EXYNOS4_SETUP_FIMD0
+ bool
+ help
+ Common setup code for FIMD0.
+
config EXYNOS4_DEV_PD
bool
help
@@ -104,6 +109,7 @@ menu "EXYNOS4 Machines"
config MACH_SMDKC210
bool "SMDKC210"
select CPU_EXYNOS4210
+ select S5P_DEV_FIMD0
select S3C_DEV_RTC
select S3C_DEV_WDT
select S3C_DEV_I2C1
@@ -113,6 +119,7 @@ config MACH_SMDKC210
select S3C_DEV_HSMMC3
select EXYNOS4_DEV_PD
select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_SDHCI
help
@@ -121,6 +128,7 @@ config MACH_SMDKC210
config MACH_SMDKV310
bool "SMDKV310"
select CPU_EXYNOS4210
+ select S5P_DEV_FIMD0
select S3C_DEV_RTC
select S3C_DEV_WDT
select S3C_DEV_I2C1
@@ -132,6 +140,7 @@ config MACH_SMDKV310
select SAMSUNG_DEV_KEYPAD
select EXYNOS4_DEV_PD
select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
select EXYNOS4_SETUP_SDHCI
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
index c3c70ab..b1077f4 100644
--- a/arch/arm/mach-exynos4/Makefile
+++ b/arch/arm/mach-exynos4/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o
obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
+obj-$(CONFIG_EXYNOS4_SETUP_FIMD0) += setup-fimd0.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C2) += setup-i2c2.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C3) += setup-i2c3.o
diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
index 910ade6..85a0b96 100644
--- a/arch/arm/mach-exynos4/cpu.c
+++ b/arch/arm/mach-exynos4/cpu.c
@@ -23,6 +23,7 @@
#include <plat/exynos4.h>
#include <plat/sdhci.h>
#include <plat/devs.h>
+#include <plat/fb-core.h>
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
@@ -149,6 +150,8 @@ void __init exynos4_map_io(void)
s3c_i2c0_setname("s3c2440-i2c");
s3c_i2c1_setname("s3c2440-i2c");
s3c_i2c2_setname("s3c2440-i2c");
+
+ s5p_fb_setname(0, "exynos4-fb");
}
void __init exynos4_init_clocks(int xtal)
diff --git a/arch/arm/mach-exynos4/setup-fimd0.c b/arch/arm/mach-exynos4/setup-fimd0.c
new file mode 100644
index 0000000..ca7ae71
--- /dev/null
+++ b/arch/arm/mach-exynos4/setup-fimd0.c
@@ -0,0 +1,43 @@
+/* linux/arch/arm/mach-exynos4/setup-fimd0.c
+ *
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base Exynos4 FIMD 0 configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/fb.h>
+#include <linux/gpio.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-fb-v4.h>
+
+#include <mach/map.h>
+
+void exynos4_fimd0_gpio_setup_24bpp(void)
+{
+ unsigned int reg;
+
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPF0(0), 8, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPF1(0), 8, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPF2(0), 8, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPF3(0), 4, S3C_GPIO_SFN(2));
+
+ /*
+ * Set DISPLAY_CONTROL register for Display path selection.
+ *
+ * DISPLAY_CONTROL[1:0]
+ * ---------------------
+ * 00 | MIE
+ * 01 | MDINE
+ * 10 | FIMD : selected
+ * 11 | FIMD
+ */
+ reg = __raw_readl(S3C_VA_SYS + 0x0210);
+ reg |= (1 << 1);
+ __raw_writel(reg, S3C_VA_SYS + 0x0210);
+}
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 7f9ff2a..7537ad5 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -71,6 +71,11 @@ config S5P_DEV_FIMC3
help
Compile in platform device definitions for FIMC controller 3
+config S5P_DEV_FIMD0
+ bool
+ help
+ Compile in platform device definitions for FIMD controller 0
+
config S5P_DEV_ONENAND
bool
help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index e234cc4..eec7e24 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o
obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o
obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o
obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
+obj-$(CONFIG_S5P_DEV_FIMD0) += dev-fimd0.o
obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
diff --git a/arch/arm/plat-s5p/dev-fimd0.c b/arch/arm/plat-s5p/dev-fimd0.c
new file mode 100644
index 0000000..f728bb5
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-fimd0.c
@@ -0,0 +1,67 @@
+/* linux/arch/arm/plat-s5p/dev-fimd0.c
+ *
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Core file for Samsung Display Controller (FIMD) driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/fb.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s5p_fimd0_resource[] = {
+ [0] = {
+ .start = S5P_PA_FIMD0,
+ .end = S5P_PA_FIMD0 + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_FIMD0_VSYNC,
+ .end = IRQ_FIMD0_VSYNC,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_FIMD0_FIFO,
+ .end = IRQ_FIMD0_FIFO,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = IRQ_FIMD0_SYSTEM,
+ .end = IRQ_FIMD0_SYSTEM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 fimd0_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5p_device_fimd0 = {
+ .name = "s5p-fb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5p_fimd0_resource),
+ .resource = s5p_fimd0_resource,
+ .dev = {
+ .dma_mask = &fimd0_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd)
+{
+ s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
+ &s5p_device_fimd0);
+}
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index e3b31c2..81143b7 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -49,6 +49,7 @@ extern struct platform_device s3c64xx_device_ac97;
extern struct platform_device s3c_device_ts;
extern struct platform_device s3c_device_fb;
+extern struct platform_device s5p_device_fimd0;
extern struct platform_device s3c_device_ohci;
extern struct platform_device s3c_device_lcd;
extern struct platform_device s3c_device_wdt;
diff --git a/arch/arm/plat-samsung/include/plat/fb-core.h b/arch/arm/plat-samsung/include/plat/fb-core.h
index bca383e..6abcbf1 100644
--- a/arch/arm/plat-samsung/include/plat/fb-core.h
+++ b/arch/arm/plat-samsung/include/plat/fb-core.h
@@ -26,4 +26,19 @@ static inline void s3c_fb_setname(char *name)
#endif
}
+/* Re-define device name depending on support. */
+static inline void s5p_fb_setname(int id, char *name)
+{
+ switch (id) {
+#ifdef CONFIG_S5P_DEV_FIMD0
+ case 0:
+ s5p_device_fimd0.name = name;
+ break;
+#endif
+ default:
+ printk(KERN_ERR "%s: invalid device id(%d)\n", __func__, id);
+ break;
+ }
+}
+
#endif /* __ASM_PLAT_FB_CORE_H */
diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h
index cb3ca3a..01f10e4 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -74,6 +74,14 @@ struct s3c_fb_platdata {
extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd);
/**
+ * s5p_fimd0_set_platdata() - Setup the FB device with platform data.
+ * @pd: The platform data to set. The data is copied from the passed structure
+ * so the machine data can mark the data __initdata so that any unused
+ * machines will end up dumping their data at runtime.
+ */
+extern void s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd);
+
+/**
* s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD
*
* Initialise the GPIO for an 24bpp LCD display on the RGB interface.
@@ -94,4 +102,11 @@ extern void s5pc100_fb_gpio_setup_24bpp(void);
*/
extern void s5pv210_fb_gpio_setup_24bpp(void);
+/**
+ * exynos4_fimd0_gpio_setup_24bpp() - Exynos4 setup function for 24bpp LCD0
+ *
+ * Initialise the GPIO for an 24bpp LCD display on the RGB interface 0.
+ */
+extern void exynos4_fimd0_gpio_setup_24bpp(void);
+
#endif /* __PLAT_S3C_FB_H */
--
1.7.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox