* [PATCH 54/57] fbdev: sh_mobile_meram: Remove unneeded sanity checks
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
To: linux-fbdev
The meram_register(), meram_unregister() and meram_update() operations
check that the pointers they get from the caller are not NULL. Those
checks can be remove, as the caller already ensures that the pointers
are valid.
The platform sanity checks can also be removed, as the operations can't
be accessed without valid platform data anyway.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 5 +----
drivers/video/sh_mobile_meram.c | 32 ++++++--------------------------
include/video/sh_mobile_meram.h | 15 +++++++--------
3 files changed, 14 insertions(+), 38 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e10a78a..edd195a 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1070,14 +1070,11 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
if (ch->meram) {
struct sh_mobile_meram_info *mdev;
- int ret;
mdev = priv->meram_dev;
- ret = mdev->ops->meram_update(mdev, ch->meram,
+ mdev->ops->meram_update(mdev, ch->meram,
base_addr_y, base_addr_c,
&base_addr_y, &base_addr_c);
- if (ret)
- return ret;
}
ch->base_addr_y = base_addr_y;
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
index aad8b0b..f0ae342 100644
--- a/drivers/video/sh_mobile_meram.c
+++ b/drivers/video/sh_mobile_meram.c
@@ -450,21 +450,15 @@ static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
unsigned int *pitch)
{
struct sh_mobile_meram_fb_cache *cache;
- struct sh_mobile_meram_priv *priv;
- struct platform_device *pdev;
+ struct sh_mobile_meram_priv *priv = pdata->priv;
+ struct platform_device *pdev = pdata->pdev;
unsigned int out_pitch;
- if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
- return ERR_PTR(-EINVAL);
-
if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
pixelformat != SH_MOBILE_MERAM_PF_RGB)
return ERR_PTR(-EINVAL);
- priv = pdata->priv;
- pdev = pdata->pdev;
-
dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres,
!pixelformat ? "yuv" : "rgb");
@@ -499,16 +493,11 @@ err:
return cache;
}
-static int
+static void
sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data)
{
struct sh_mobile_meram_fb_cache *cache = data;
- struct sh_mobile_meram_priv *priv;
-
- if (!pdata || !pdata->priv || !data)
- return -EINVAL;
-
- priv = pdata->priv;
+ struct sh_mobile_meram_priv *priv = pdata->priv;
mutex_lock(&priv->lock);
@@ -520,22 +509,15 @@ sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data)
meram_free(priv, cache);
mutex_unlock(&priv->lock);
-
- return 0;
}
-static int
+static void
sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,
unsigned long base_addr_y, unsigned long base_addr_c,
unsigned long *icb_addr_y, unsigned long *icb_addr_c)
{
struct sh_mobile_meram_fb_cache *cache = data;
- struct sh_mobile_meram_priv *priv;
-
- if (!pdata || !pdata->priv || !data)
- return -EINVAL;
-
- priv = pdata->priv;
+ struct sh_mobile_meram_priv *priv = pdata->priv;
mutex_lock(&priv->lock);
@@ -543,8 +525,6 @@ sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,
meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
mutex_unlock(&priv->lock);
-
- return 0;
}
static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
index 51c98ca..089e6d3 100644
--- a/include/video/sh_mobile_meram.h
+++ b/include/video/sh_mobile_meram.h
@@ -44,16 +44,15 @@ struct sh_mobile_meram_ops {
unsigned int *pitch);
/* unregister usage of meram */
- int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
- void *data);
+ void (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
+ void *data);
/* update meram settings */
- int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
- void *data,
- unsigned long base_addr_y,
- unsigned long base_addr_c,
- unsigned long *icb_addr_y,
- unsigned long *icb_addr_c);
+ void (*meram_update)(struct sh_mobile_meram_info *meram_dev, void *data,
+ unsigned long base_addr_y,
+ unsigned long base_addr_c,
+ unsigned long *icb_addr_y,
+ unsigned long *icb_addr_c);
};
#endif /* __VIDEO_SH_MOBILE_MERAM_H__ */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 55/57] fbdev: sh_mobile_lcdc: Constify sh_mobile_lcdc_fix structure
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
To: linux-fbdev
The structure is only read, make it const.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index edd195a..357cdc1 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1000,7 +1000,7 @@ static int sh_mobile_lcdc_setcolreg(u_int regno,
return 0;
}
-static struct fb_fix_screeninfo sh_mobile_lcdc_fix = {
+static const struct fb_fix_screeninfo sh_mobile_lcdc_fix = {
.id = "SH Mobile LCDC",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
--
1.7.3.4
^ permalink raw reply related
* [PATCH 56/57] fbdev: sh_mobile_lcdc: Rename fb operation handlers with a common prefix
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
To: linux-fbdev
Make all fb operation handlers start with sh_mobile_lcdc_ in preparation
for the multi-plane support.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 42 +++++++++++++++++++------------------
1 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 357cdc1..4b4e81e 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -583,7 +583,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
+static int sh_mobile_lcdc_wait_for_vsync(struct sh_mobile_lcdc_chan *ch)
{
unsigned long ldintr;
int ret;
@@ -684,7 +684,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
}
/*
- * __sh_mobile_lcdc_start - Configure and tart the LCDC
+ * __sh_mobile_lcdc_start - Configure and start the LCDC
* @priv: LCDC device
*
* Configure all enabled channels and start the LCDC device. All external
@@ -1032,8 +1032,8 @@ static void sh_mobile_lcdc_imageblit(struct fb_info *info,
sh_mobile_lcdc_deferred_io_touch(info);
}
-static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
+static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
struct sh_mobile_lcdc_priv *priv = ch->lcdc;
@@ -1096,14 +1096,15 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
return 0;
}
-static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
+static int sh_mobile_lcdc_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
{
+ struct sh_mobile_lcdc_chan *ch = info->par;
int retval;
switch (cmd) {
case FBIO_WAITFORVSYNC:
- retval = sh_mobile_wait_for_vsync(info->par);
+ retval = sh_mobile_lcdc_wait_for_vsync(ch);
break;
default:
@@ -1154,7 +1155,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
* Locking: both .fb_release() and .fb_open() are called with info->lock held if
* user = 1, or with console sem held, if user = 0.
*/
-static int sh_mobile_release(struct fb_info *info, int user)
+static int sh_mobile_lcdc_release(struct fb_info *info, int user)
{
struct sh_mobile_lcdc_chan *ch = info->par;
@@ -1175,7 +1176,7 @@ static int sh_mobile_release(struct fb_info *info, int user)
return 0;
}
-static int sh_mobile_open(struct fb_info *info, int user)
+static int sh_mobile_lcdc_open(struct fb_info *info, int user)
{
struct sh_mobile_lcdc_chan *ch = info->par;
@@ -1188,7 +1189,8 @@ static int sh_mobile_open(struct fb_info *info, int user)
return 0;
}
-static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
struct sh_mobile_lcdc_priv *p = ch->lcdc;
@@ -1309,7 +1311,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
return 0;
}
-static int sh_mobile_set_par(struct fb_info *info)
+static int sh_mobile_lcdc_set_par(struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
int ret;
@@ -1379,8 +1381,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
* mode will reenable the clocks and update the screen in time,
* so it does not need this. */
if (!info->fbdefio) {
- sh_mobile_wait_for_vsync(ch);
- sh_mobile_wait_for_vsync(ch);
+ sh_mobile_lcdc_wait_for_vsync(ch);
+ sh_mobile_lcdc_wait_for_vsync(ch);
}
sh_mobile_lcdc_clk_off(p);
}
@@ -1398,12 +1400,12 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_copyarea = sh_mobile_lcdc_copyarea,
.fb_imageblit = sh_mobile_lcdc_imageblit,
.fb_blank = sh_mobile_lcdc_blank,
- .fb_pan_display = sh_mobile_fb_pan_display,
- .fb_ioctl = sh_mobile_ioctl,
- .fb_open = sh_mobile_open,
- .fb_release = sh_mobile_release,
- .fb_check_var = sh_mobile_check_var,
- .fb_set_par = sh_mobile_set_par,
+ .fb_pan_display = sh_mobile_lcdc_pan,
+ .fb_ioctl = sh_mobile_lcdc_ioctl,
+ .fb_open = sh_mobile_lcdc_open,
+ .fb_release = sh_mobile_lcdc_release,
+ .fb_check_var = sh_mobile_lcdc_check_var,
+ .fb_set_par = sh_mobile_lcdc_set_par,
};
static void
@@ -1533,7 +1535,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
else
var->grayscale = ch->format->fourcc;
- ret = sh_mobile_check_var(var, info);
+ ret = sh_mobile_lcdc_check_var(var, info);
if (ret)
return ret;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 57/57] fbdev: sh_mobile_lcdc: Implement overlays support
From: Laurent Pinchart @ 2011-12-13 14:02 UTC (permalink / raw)
To: linux-fbdev
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 955 +++++++++++++++++++++++++++++++++++---
include/video/sh_mobile_lcdc.h | 7 +
2 files changed, 890 insertions(+), 72 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 4b4e81e..2ca9662 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -12,6 +12,7 @@
#include <linux/backlight.h>
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/ctype.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/gpio.h>
@@ -32,12 +33,176 @@
#include "sh_mobile_lcdcfb.h"
+/* ----------------------------------------------------------------------------
+ * Overlay register definitions
+ */
+
+#define LDBCR 0xb00
+#define LDBCR_UPC(n) (1 << ((n) + 16))
+#define LDBCR_UPF(n) (1 << ((n) + 8))
+#define LDBCR_UPD(n) (1 << ((n) + 0))
+#define LDBnBSIFR(n) (0xb20 + (n) * 0x20 + 0x00)
+#define LDBBSIFR_EN (1 << 31)
+#define LDBBSIFR_VS (1 << 29)
+#define LDBBSIFR_BRSEL (1 << 28)
+#define LDBBSIFR_MX (1 << 27)
+#define LDBBSIFR_MY (1 << 26)
+#define LDBBSIFR_CV3 (3 << 24)
+#define LDBBSIFR_CV2 (2 << 24)
+#define LDBBSIFR_CV1 (1 << 24)
+#define LDBBSIFR_CV0 (0 << 24)
+#define LDBBSIFR_CV_MASK (3 << 24)
+#define LDBBSIFR_LAY_MASK (0xff << 16)
+#define LDBBSIFR_LAY_SHIFT 16
+#define LDBBSIFR_ROP3_MASK (0xff << 16)
+#define LDBBSIFR_ROP3_SHIFT 16
+#define LDBBSIFR_AL_PL8 (3 << 14)
+#define LDBBSIFR_AL_PL1 (2 << 14)
+#define LDBBSIFR_AL_PK (1 << 14)
+#define LDBBSIFR_AL_1 (0 << 14)
+#define LDBBSIFR_AL_MASK (3 << 14)
+#define LDBBSIFR_SWPL (1 << 10)
+#define LDBBSIFR_SWPW (1 << 9)
+#define LDBBSIFR_SWPB (1 << 8)
+#define LDBBSIFR_RY (1 << 7)
+#define LDBBSIFR_CHRR_420 (2 << 0)
+#define LDBBSIFR_CHRR_422 (1 << 0)
+#define LDBBSIFR_CHRR_444 (0 << 0)
+#define LDBBSIFR_RPKF_ARGB32 (0x00 << 0)
+#define LDBBSIFR_RPKF_RGB16 (0x03 << 0)
+#define LDBBSIFR_RPKF_RGB24 (0x0b << 0)
+#define LDBBSIFR_RPKF_MASK (0x1f << 0)
+#define LDBnBSSZR(n) (0xb20 + (n) * 0x20 + 0x04)
+#define LDBBSSZR_BVSS_MASK (0xfff << 16)
+#define LDBBSSZR_BVSS_SHIFT 16
+#define LDBBSSZR_BHSS_MASK (0xfff << 0)
+#define LDBBSSZR_BHSS_SHIFT 0
+#define LDBnBLOCR(n) (0xb20 + (n) * 0x20 + 0x08)
+#define LDBBLOCR_CVLC_MASK (0xfff << 16)
+#define LDBBLOCR_CVLC_SHIFT 16
+#define LDBBLOCR_CHLC_MASK (0xfff << 0)
+#define LDBBLOCR_CHLC_SHIFT 0
+#define LDBnBSMWR(n) (0xb20 + (n) * 0x20 + 0x0c)
+#define LDBBSMWR_BSMWA_MASK (0xffff << 16)
+#define LDBBSMWR_BSMWA_SHIFT 16
+#define LDBBSMWR_BSMW_MASK (0xffff << 0)
+#define LDBBSMWR_BSMW_SHIFT 0
+#define LDBnBSAYR(n) (0xb20 + (n) * 0x20 + 0x10)
+#define LDBBSAYR_FG1A_MASK (0xff << 24)
+#define LDBBSAYR_FG1A_SHIFT 24
+#define LDBBSAYR_FG1R_MASK (0xff << 16)
+#define LDBBSAYR_FG1R_SHIFT 16
+#define LDBBSAYR_FG1G_MASK (0xff << 8)
+#define LDBBSAYR_FG1G_SHIFT 8
+#define LDBBSAYR_FG1B_MASK (0xff << 0)
+#define LDBBSAYR_FG1B_SHIFT 0
+#define LDBnBSACR(n) (0xb20 + (n) * 0x20 + 0x14)
+#define LDBBSACR_FG2A_MASK (0xff << 24)
+#define LDBBSACR_FG2A_SHIFT 24
+#define LDBBSACR_FG2R_MASK (0xff << 16)
+#define LDBBSACR_FG2R_SHIFT 16
+#define LDBBSACR_FG2G_MASK (0xff << 8)
+#define LDBBSACR_FG2G_SHIFT 8
+#define LDBBSACR_FG2B_MASK (0xff << 0)
+#define LDBBSACR_FG2B_SHIFT 0
+#define LDBnBSAAR(n) (0xb20 + (n) * 0x20 + 0x18)
+#define LDBBSAAR_AP_MASK (0xff << 24)
+#define LDBBSAAR_AP_SHIFT 24
+#define LDBBSAAR_R_MASK (0xff << 16)
+#define LDBBSAAR_R_SHIFT 16
+#define LDBBSAAR_GY_MASK (0xff << 8)
+#define LDBBSAAR_GY_SHIFT 8
+#define LDBBSAAR_B_MASK (0xff << 0)
+#define LDBBSAAR_B_SHIFT 0
+#define LDBnBPPCR(n) (0xb20 + (n) * 0x20 + 0x1c)
+#define LDBBPPCR_AP_MASK (0xff << 24)
+#define LDBBPPCR_AP_SHIFT 24
+#define LDBBPPCR_R_MASK (0xff << 16)
+#define LDBBPPCR_R_SHIFT 16
+#define LDBBPPCR_GY_MASK (0xff << 8)
+#define LDBBPPCR_GY_SHIFT 8
+#define LDBBPPCR_B_MASK (0xff << 0)
+#define LDBBPPCR_B_SHIFT 0
+#define LDBnBBGCL(n) (0xb10 + (n) * 0x04)
+#define LDBBBGCL_BGA_MASK (0xff << 24)
+#define LDBBBGCL_BGA_SHIFT 24
+#define LDBBBGCL_BGR_MASK (0xff << 16)
+#define LDBBBGCL_BGR_SHIFT 16
+#define LDBBBGCL_BGG_MASK (0xff << 8)
+#define LDBBBGCL_BGG_SHIFT 8
+#define LDBBBGCL_BGB_MASK (0xff << 0)
+#define LDBBBGCL_BGB_SHIFT 0
+
#define SIDE_B_OFFSET 0x1000
#define MIRROR_OFFSET 0x2000
#define MAX_XRES 1920
#define MAX_YRES 1080
+enum sh_mobile_lcdc_overlay_mode {
+ LCDC_OVERLAY_BLEND,
+ LCDC_OVERLAY_ROP3,
+};
+
+/*
+ * struct sh_mobile_lcdc_overlay - LCDC display overlay
+ *
+ * @channel: LCDC channel this overlay belongs to
+ * @cfg: Overlay configuration
+ * @info: Frame buffer device
+ * @index: Overlay index (0-3)
+ * @base: Overlay registers base address
+ * @enabled: True if the overlay is enabled
+ * @mode: Overlay blending mode (alpha blend or ROP3)
+ * @alpha: Global alpha blending value (0-255, for alpha blending mode)
+ * @rop3: Raster operation (for ROP3 mode)
+ * @fb_mem: Frame buffer virtual memory address
+ * @fb_size: Frame buffer size in bytes
+ * @dma_handle: Frame buffer DMA address
+ * @base_addr_y: Overlay base address (RGB or luma component)
+ * @base_addr_c: Overlay base address (chroma component)
+ * @pan_offset: Current pan offset in bytes
+ * @format: Current pixelf format
+ * @xres: Horizontal visible resolution
+ * @xres_virtual: Horizontal total resolution
+ * @yres: Vertical visible resolution
+ * @yres_virtual: Vertical total resolution
+ * @pitch: Overlay line pitch
+ * @pos_x: Horizontal overlay position
+ * @pos_y: Vertical overlay position
+ */
+struct sh_mobile_lcdc_overlay {
+ struct sh_mobile_lcdc_chan *channel;
+
+ const struct sh_mobile_lcdc_overlay_cfg *cfg;
+ struct fb_info *info;
+
+ unsigned int index;
+ unsigned long base;
+
+ bool enabled;
+ enum sh_mobile_lcdc_overlay_mode mode;
+ unsigned int alpha;
+ unsigned int rop3;
+
+ void *fb_mem;
+ unsigned long fb_size;
+
+ dma_addr_t dma_handle;
+ unsigned long base_addr_y;
+ unsigned long base_addr_c;
+ unsigned long pan_offset;
+
+ const struct sh_mobile_lcdc_format_info *format;
+ unsigned int xres;
+ unsigned int xres_virtual;
+ unsigned int yres;
+ unsigned int yres_virtual;
+ unsigned int pitch;
+ int pos_x;
+ int pos_y;
+};
+
struct sh_mobile_lcdc_priv {
void __iomem *base;
int irq;
@@ -45,7 +210,10 @@ struct sh_mobile_lcdc_priv {
struct device *dev;
struct clk *dot_clk;
unsigned long lddckr;
+
struct sh_mobile_lcdc_chan ch[2];
+ struct sh_mobile_lcdc_overlay overlays[4];
+
struct notifier_block notifier;
int started;
int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
@@ -141,6 +309,13 @@ static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan,
return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]);
}
+static void lcdc_write_overlay(struct sh_mobile_lcdc_overlay *ovl,
+ int reg, unsigned long data)
+{
+ iowrite32(data, ovl->channel->lcdc->base + reg);
+ iowrite32(data, ovl->channel->lcdc->base + reg + SIDE_B_OFFSET);
+}
+
static void lcdc_write(struct sh_mobile_lcdc_priv *priv,
unsigned long reg_offs, unsigned long data)
{
@@ -683,6 +858,93 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
lcdc_write_chan(ch, LDHAJR, tmp);
}
+static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
+{
+ u32 format = 0;
+
+ if (!ovl->enabled) {
+ lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), 0);
+ return;
+ }
+
+ ovl->base_addr_y = ovl->dma_handle;
+ ovl->base_addr_c = ovl->base_addr_y + ovl->xres
+ * ovl->yres_virtual;
+
+ switch (ovl->mode) {
+ case LCDC_OVERLAY_BLEND:
+ format = LDBBSIFR_EN | (ovl->alpha << LDBBSIFR_LAY_SHIFT);
+ break;
+
+ case LCDC_OVERLAY_ROP3:
+ format = LDBBSIFR_EN | LDBBSIFR_BRSEL
+ | (ovl->rop3 << LDBBSIFR_ROP3_SHIFT);
+ break;
+ }
+
+ switch (ovl->format->fourcc) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV42:
+ format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV24:
+ format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ default:
+ format |= LDBBSIFR_SWPL;
+ break;
+ }
+
+ switch (ovl->format->fourcc) {
+ case V4L2_PIX_FMT_RGB565:
+ format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
+ break;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
+ break;
+ case V4L2_PIX_FMT_NV24:
+ case V4L2_PIX_FMT_NV42:
+ format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
+ break;
+ }
+
+ lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index));
+
+ lcdc_write_overlay(ovl, LDBnBSIFR(ovl->index), format);
+
+ lcdc_write_overlay(ovl, LDBnBSSZR(ovl->index),
+ (ovl->yres << LDBBSSZR_BVSS_SHIFT) |
+ (ovl->xres << LDBBSSZR_BHSS_SHIFT));
+ lcdc_write_overlay(ovl, LDBnBLOCR(ovl->index),
+ (ovl->pos_y << LDBBLOCR_CVLC_SHIFT) |
+ (ovl->pos_x << LDBBLOCR_CHLC_SHIFT));
+ lcdc_write_overlay(ovl, LDBnBSMWR(ovl->index),
+ ovl->pitch << LDBBSMWR_BSMW_SHIFT);
+
+ lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
+ lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
+
+ lcdc_write(ovl->channel->lcdc, LDBCR,
+ LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index));
+}
+
/*
* __sh_mobile_lcdc_start - Configure and start the LCDC
* @priv: LCDC device
@@ -889,6 +1151,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
}
}
+ for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
+ struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[k];
+ sh_mobile_lcdc_overlay_setup(ovl);
+ }
+
/* Start the LCDC. */
__sh_mobile_lcdc_start(priv);
@@ -972,8 +1239,539 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
sh_mobile_lcdc_clk_off(priv);
}
+static int __sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if (var->xres > MAX_XRES || var->yres > MAX_YRES)
+ return -EINVAL;
+
+ /* Make sure the virtual resolution is at least as big as the visible
+ * resolution.
+ */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (sh_mobile_format_is_fourcc(var)) {
+ const struct sh_mobile_lcdc_format_info *format;
+
+ format = sh_mobile_format_info(var->grayscale);
+ if (format = NULL)
+ return -EINVAL;
+ var->bits_per_pixel = format->bpp;
+
+ /* Default to RGB and JPEG color-spaces for RGB and YUV formats
+ * respectively.
+ */
+ if (!format->yuv)
+ var->colorspace = V4L2_COLORSPACE_SRGB;
+ else if (var->colorspace != V4L2_COLORSPACE_REC709)
+ var->colorspace = V4L2_COLORSPACE_JPEG;
+ } else {
+ if (var->bits_per_pixel <= 16) { /* RGB 565 */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ } else if (var->bits_per_pixel <= 24) { /* RGB 888 */
+ var->bits_per_pixel = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ } else
+ return -EINVAL;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+ }
+
+ /* Make sure we don't exceed our allocated memory. */
+ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+ info->fix.smem_len)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Frame buffer operations - Overlays
+ */
+
+static ssize_t
+overlay_alpha_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->alpha);
+}
+
+static ssize_t
+overlay_alpha_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+ unsigned int alpha;
+ char *endp;
+
+ alpha = simple_strtoul(buf, &endp, 10);
+ if (isspace(*endp))
+ endp++;
+
+ if (endp - buf != count)
+ return -EINVAL;
+
+ if (alpha > 255)
+ return -EINVAL;
+
+ if (ovl->alpha != alpha) {
+ ovl->alpha = alpha;
+
+ if (ovl->mode = LCDC_OVERLAY_BLEND && ovl->enabled)
+ sh_mobile_lcdc_overlay_setup(ovl);
+ }
+
+ return count;
+}
+
+static ssize_t
+overlay_enabled_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->enabled);
+}
+
+static ssize_t
+overlay_enabled_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+ bool enabled;
+ char *endp;
+
+ enabled = !!simple_strtoul(buf, &endp, 10);
+ if (isspace(*endp))
+ endp++;
+
+ if (endp - buf != count)
+ return -EINVAL;
+
+ if (ovl->enabled != enabled) {
+ ovl->enabled = enabled;
+ sh_mobile_lcdc_overlay_setup(ovl);
+ }
+
+ return count;
+}
+
+static ssize_t
+overlay_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->mode);
+}
+
+static ssize_t
+overlay_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+ unsigned int mode;
+ char *endp;
+
+ mode = simple_strtoul(buf, &endp, 10);
+ if (isspace(*endp))
+ endp++;
+
+ if (endp - buf != count)
+ return -EINVAL;
+
+ if (mode != LCDC_OVERLAY_BLEND && mode != LCDC_OVERLAY_ROP3)
+ return -EINVAL;
+
+ if (ovl->mode != mode) {
+ ovl->mode = mode;
+
+ if (ovl->enabled)
+ sh_mobile_lcdc_overlay_setup(ovl);
+ }
+
+ return count;
+}
+
+static ssize_t
+overlay_position_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ return scnprintf(buf, PAGE_SIZE, "%d,%d\n", ovl->pos_x, ovl->pos_y);
+}
+
+static ssize_t
+overlay_position_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+ char *endp;
+ int pos_x;
+ int pos_y;
+
+ pos_x = simple_strtol(buf, &endp, 10);
+ if (*endp != ',')
+ return -EINVAL;
+
+ pos_y = simple_strtol(endp + 1, &endp, 10);
+ if (isspace(*endp))
+ endp++;
+
+ if (endp - buf != count)
+ return -EINVAL;
+
+ if (ovl->pos_x != pos_x || ovl->pos_y != pos_y) {
+ ovl->pos_x = pos_x;
+ ovl->pos_y = pos_y;
+
+ if (ovl->enabled)
+ sh_mobile_lcdc_overlay_setup(ovl);
+ }
+
+ return count;
+}
+
+static ssize_t
+overlay_rop3_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", ovl->rop3);
+}
+
+static ssize_t
+overlay_rop3_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+ unsigned int rop3;
+ char *endp;
+
+ rop3 = !!simple_strtoul(buf, &endp, 10);
+ if (isspace(*endp))
+ endp++;
+
+ if (endp - buf != count)
+ return -EINVAL;
+
+ if (rop3 > 255)
+ return -EINVAL;
+
+ if (ovl->rop3 != rop3) {
+ ovl->rop3 = rop3;
+
+ if (ovl->mode = LCDC_OVERLAY_ROP3 && ovl->enabled)
+ sh_mobile_lcdc_overlay_setup(ovl);
+ }
+
+ return count;
+}
+
+static const struct device_attribute overlay_sysfs_attrs[] = {
+ __ATTR(ovl_alpha, S_IRUGO|S_IWUSR,
+ overlay_alpha_show, overlay_alpha_store),
+ __ATTR(ovl_enabled, S_IRUGO|S_IWUSR,
+ overlay_enabled_show, overlay_enabled_store),
+ __ATTR(ovl_mode, S_IRUGO|S_IWUSR,
+ overlay_mode_show, overlay_mode_store),
+ __ATTR(ovl_position, S_IRUGO|S_IWUSR,
+ overlay_position_show, overlay_position_store),
+ __ATTR(ovl_rop3, S_IRUGO|S_IWUSR,
+ overlay_rop3_show, overlay_rop3_store),
+};
+
+static const struct fb_fix_screeninfo sh_mobile_lcdc_overlay_fix = {
+ .id = "SH Mobile LCDC",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .accel = FB_ACCEL_NONE,
+ .xpanstep = 0,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .capabilities = FB_CAP_FOURCC,
+};
+
+static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+ unsigned long base_addr_y;
+ unsigned long base_addr_c;
+ unsigned long pan_offset;
+ unsigned long c_offset;
+
+ if (!ovl->format->yuv)
+ pan_offset = var->yoffset * ovl->pitch
+ + var->xoffset * (ovl->format->bpp / 8);
+ else
+ pan_offset = var->yoffset * ovl->pitch + var->xoffset;
+
+ if (pan_offset = ovl->pan_offset)
+ return 0; /* No change, do nothing */
+
+ /* Set the source address for the next refresh */
+ base_addr_y = ovl->dma_handle + pan_offset;
+
+ ovl->base_addr_y = base_addr_y;
+ ovl->base_addr_c = base_addr_y;
+
+ if (ovl->format->yuv) {
+ /* Set Y offset */
+ c_offset = var->yoffset * ovl->pitch
+ * (ovl->format->bpp - 8) / 8;
+ base_addr_c = ovl->dma_handle
+ + ovl->xres * ovl->yres_virtual
+ + c_offset;
+ /* Set X offset */
+ if (ovl->format->fourcc = V4L2_PIX_FMT_NV24)
+ base_addr_c += 2 * var->xoffset;
+ else
+ base_addr_c += var->xoffset;
+
+ ovl->base_addr_c = base_addr_c;
+ }
+
+ lcdc_write_overlay(ovl, LDBnBSAYR(ovl->index), ovl->base_addr_y);
+ lcdc_write_overlay(ovl, LDBnBSACR(ovl->index), ovl->base_addr_c);
+
+ ovl->pan_offset = pan_offset;
+
+ return 0;
+}
+
+static int sh_mobile_lcdc_overlay_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ return sh_mobile_lcdc_wait_for_vsync(ovl->channel);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int sh_mobile_lcdc_overlay_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return __sh_mobile_lcdc_check_var(var, info);
+}
+
+static int sh_mobile_lcdc_overlay_set_par(struct fb_info *info)
+{
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ ovl->format + sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
+
+ ovl->xres = info->var.xres;
+ ovl->xres_virtual = info->var.xres_virtual;
+ ovl->yres = info->var.yres;
+ ovl->yres_virtual = info->var.yres_virtual;
+
+ if (ovl->format->yuv)
+ ovl->pitch = info->var.xres;
+ else
+ ovl->pitch = info->var.xres * ovl->format->bpp / 8;
+
+ sh_mobile_lcdc_overlay_setup(ovl);
+
+ info->fix.line_length = ovl->pitch;
+
+ if (sh_mobile_format_is_fourcc(&info->var)) {
+ info->fix.type = FB_TYPE_FOURCC;
+ info->fix.visual = FB_VISUAL_FOURCC;
+ } else {
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ }
+
+ return 0;
+}
+
+/* Overlay blanking. Disable the overlay when blanked. */
+static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
+{
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ printk(KERN_INFO "%s(%u)\n", __func__, blank);
+ ovl->enabled = !blank;
+
+ return 0;
+}
+
+static struct fb_ops sh_mobile_lcdc_overlay_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = fb_sys_write,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_blank = sh_mobile_lcdc_overlay_blank,
+ .fb_pan_display = sh_mobile_lcdc_overlay_pan,
+ .fb_ioctl = sh_mobile_lcdc_overlay_ioctl,
+ .fb_check_var = sh_mobile_lcdc_overlay_check_var,
+ .fb_set_par = sh_mobile_lcdc_overlay_set_par,
+};
+
+static void
+sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
+{
+ struct fb_info *info = ovl->info;
+
+ if (info = NULL || info->dev = NULL)
+ return;
+
+ unregister_framebuffer(ovl->info);
+}
+
+static int __devinit
+sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
+{
+ struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
+ struct fb_info *info = ovl->info;
+ unsigned int i;
+ int ret;
+
+ if (info = NULL)
+ return 0;
+
+ ret = register_framebuffer(info);
+ if (ret < 0)
+ return ret;
+
+ dev_info(lcdc->dev, "registered %s/overlay %u as %dx%d %dbpp.\n",
+ dev_name(lcdc->dev), ovl->index, info->var.xres,
+ info->var.yres, info->var.bits_per_pixel);
+
+ for (i = 0; i < ARRAY_SIZE(overlay_sysfs_attrs); ++i) {
+ ret = device_create_file(info->dev, &overlay_sysfs_attrs[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
+{
+ struct fb_info *info = ovl->info;
+
+ if (info = NULL || info->device = NULL)
+ return;
+
+ framebuffer_release(info);
+}
+
+static int __devinit
+sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
+{
+ struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
+ struct fb_var_screeninfo *var;
+ struct fb_info *info;
+
+ /* Allocate and initialize the frame buffer device. */
+ info = framebuffer_alloc(0, priv->dev);
+ if (info = NULL) {
+ dev_err(priv->dev, "unable to allocate fb_info\n");
+ return -ENOMEM;
+ }
+
+ ovl->info = info;
+
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->fbops = &sh_mobile_lcdc_overlay_ops;
+ info->device = priv->dev;
+ info->screen_base = ovl->fb_mem;
+ info->par = ovl;
+
+ /* Initialize fixed screen information. Restrict pan to 2 lines steps
+ * for NV12 and NV21.
+ */
+ info->fix = sh_mobile_lcdc_overlay_fix;
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "SH Mobile LCDC Overlay %u", ovl->index);
+ info->fix.smem_start = ovl->dma_handle;
+ info->fix.smem_len = ovl->fb_size;
+ info->fix.line_length = ovl->pitch;
+
+ if (ovl->format->yuv)
+ info->fix.visual = FB_VISUAL_FOURCC;
+ else
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+ if (ovl->format->fourcc = V4L2_PIX_FMT_NV12 ||
+ ovl->format->fourcc = V4L2_PIX_FMT_NV21)
+ info->fix.ypanstep = 2;
+
+ /* Initialize variable screen information. */
+ var = &info->var;
+ memset(var, 0, sizeof(*var));
+ var->xres = ovl->xres;
+ var->yres = ovl->yres;
+ var->xres_virtual = ovl->xres_virtual;
+ var->yres_virtual = ovl->yres_virtual;
+ var->activate = FB_ACTIVATE_NOW;
+
+ /* Use the legacy API by default for RGB formats, and the FOURCC API
+ * for YUV formats.
+ */
+ if (!ovl->format->yuv)
+ var->bits_per_pixel = ovl->format->bpp;
+ else
+ var->grayscale = ovl->format->fourcc;
+
+ return sh_mobile_lcdc_overlay_check_var(var, info);
+}
+
/* -----------------------------------------------------------------------------
- * Frame buffer operations
+ * Frame buffer operations - main frame buffer
*/
static int sh_mobile_lcdc_setcolreg(u_int regno,
@@ -1198,9 +1996,7 @@ static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
unsigned int best_xres = 0;
unsigned int best_yres = 0;
unsigned int i;
-
- if (var->xres > MAX_XRES || var->yres > MAX_YRES)
- return -EINVAL;
+ int ret;
/* If board code provides us with a list of available modes, make sure
* we use one of them. Find the mode closest to the requested one. The
@@ -1235,73 +2031,9 @@ static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
var->yres = best_yres;
}
- /* Make sure the virtual resolution is at least as big as the visible
- * resolution.
- */
- if (var->xres_virtual < var->xres)
- var->xres_virtual = var->xres;
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
-
- if (sh_mobile_format_is_fourcc(var)) {
- const struct sh_mobile_lcdc_format_info *format;
-
- format = sh_mobile_format_info(var->grayscale);
- if (format = NULL)
- return -EINVAL;
- var->bits_per_pixel = format->bpp;
-
- /* Default to RGB and JPEG color-spaces for RGB and YUV formats
- * respectively.
- */
- if (!format->yuv)
- var->colorspace = V4L2_COLORSPACE_SRGB;
- else if (var->colorspace != V4L2_COLORSPACE_REC709)
- var->colorspace = V4L2_COLORSPACE_JPEG;
- } else {
- if (var->bits_per_pixel <= 16) { /* RGB 565 */
- var->bits_per_pixel = 16;
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- } else if (var->bits_per_pixel <= 24) { /* RGB 888 */
- var->bits_per_pixel = 24;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */
- var->bits_per_pixel = 32;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- } else
- return -EINVAL;
-
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
- }
-
- /* Make sure we don't exceed our allocated memory. */
- if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
- info->fix.smem_len)
- return -EINVAL;
+ ret = __sh_mobile_lcdc_check_var(var, info);
+ if (ret < 0)
+ return ret;
/* only accept the forced_fourcc for dual channel configurations */
if (p->forced_fourcc &&
@@ -1710,15 +2442,20 @@ static const struct fb_videomode default_720p __devinitconst = {
static int sh_mobile_lcdc_remove(struct platform_device *pdev)
{
struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
- int i;
+ unsigned int i;
fb_unregister_client(&priv->notifier);
+ for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
+ sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
sh_mobile_lcdc_stop(priv);
+ for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
+ sh_mobile_lcdc_overlay_fb_cleanup(&priv->overlays[i]);
+
for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
@@ -1795,6 +2532,61 @@ sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
}
static int __devinit
+sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv,
+ struct sh_mobile_lcdc_overlay *ovl)
+{
+ const struct sh_mobile_lcdc_format_info *format;
+ int ret;
+
+ if (ovl->cfg->fourcc = 0)
+ return 0;
+
+ /* Validate the format. */
+ format = sh_mobile_format_info(ovl->cfg->fourcc);
+ if (format = NULL) {
+ dev_err(priv->dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc);
+ return -EINVAL;
+ }
+
+ ovl->enabled = false;
+ ovl->mode = LCDC_OVERLAY_BLEND;
+ ovl->alpha = 255;
+ ovl->rop3 = 0;
+ ovl->pos_x = 0;
+ ovl->pos_y = 0;
+
+ /* The default Y virtual resolution is twice the panel size to allow for
+ * double-buffering.
+ */
+ ovl->format = format;
+ ovl->xres = ovl->cfg->max_xres;
+ ovl->xres_virtual = ovl->xres;
+ ovl->yres = ovl->cfg->max_yres;
+ ovl->yres_virtual = ovl->yres * 2;
+
+ if (!format->yuv)
+ ovl->pitch = ovl->xres * format->bpp / 8;
+ else
+ ovl->pitch = ovl->xres;
+
+ /* Allocate frame buffer memory. */
+ ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres
+ * format->bpp / 8 * 2;
+ ovl->fb_mem = dma_alloc_coherent(priv->dev, ovl->fb_size,
+ &ovl->dma_handle, GFP_KERNEL);
+ if (!ovl->fb_mem) {
+ dev_err(priv->dev, "unable to allocate buffer\n");
+ return -ENOMEM;
+ }
+
+ ret = sh_mobile_lcdc_overlay_fb_init(ovl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int __devinit
sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
struct sh_mobile_lcdc_chan *ch)
{
@@ -2002,6 +2794,17 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
+ for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
+ struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
+
+ ovl->cfg = &pdata->overlays[i];
+ ovl->channel = &priv->ch[0];
+
+ error = sh_mobile_lcdc_overlay_init(priv, ovl);
+ if (error)
+ goto err1;
+ }
+
error = sh_mobile_lcdc_start(priv);
if (error) {
dev_err(&pdev->dev, "unable to start hardware\n");
@@ -2016,6 +2819,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
+ for (i = 0; i < ARRAY_SIZE(pdata->overlays); i++) {
+ struct sh_mobile_lcdc_overlay *ovl = &priv->overlays[i];
+
+ error = sh_mobile_lcdc_overlay_fb_register(ovl);
+ if (error)
+ goto err1;
+ }
+
/* Failure ignored */
priv->notifier.notifier_call = sh_mobile_lcdc_notify;
fb_register_client(&priv->notifier);
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 53cbbd4..04b889b 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -166,6 +166,12 @@ struct sh_mobile_lcdc_bl_info {
int (*get_brightness)(void);
};
+struct sh_mobile_lcdc_overlay_cfg {
+ int fourcc;
+ unsigned int max_xres;
+ unsigned int max_yres;
+};
+
struct sh_mobile_lcdc_chan_cfg {
int chan;
int fourcc;
@@ -186,6 +192,7 @@ struct sh_mobile_lcdc_chan_cfg {
struct sh_mobile_lcdc_info {
int clock_source;
struct sh_mobile_lcdc_chan_cfg ch[2];
+ struct sh_mobile_lcdc_overlay_cfg overlays[4];
struct sh_mobile_meram_info *meram_dev;
};
--
1.7.3.4
^ permalink raw reply related
* RE: [PATCH] video:da8xx-fb: Add 24bpp LCD configuration support
From: Manjunathappa, Prakash @ 2011-12-13 14:45 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1321358479-20390-1-git-send-email-prakash.pm@ti.com>
Hi Florian Tobias Schandinat,
On Sat, Nov 26, 2011 at 02:58:51, Florian Tobias Schandinat wrote:
> On 11/25/2011 07:45 AM, Manjunathappa, Prakash wrote:
> > Hi Florian Tobias Schandinat
> >
> > On Sun, Nov 20, 2011 at 06:11:44, Florian Tobias Schandinat wrote:
> >> On 11/15/2011 12:01 PM, Manjunathappa, Prakash wrote:
> >>> LCD controller on am335x supports 24bpp raster configuration
> >>> in addition to ones on da850. LCDC also supports 24bpp in unpacked
> >>> format having ARGB:8888 32bpp format data in DDR, but it doesn't
> >>> interpret Alpha component of the data.
> >>>
> >>> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
> >>> ---
> >>> drivers/video/da8xx-fb.c | 57 +++++++++++++++++++++++++++++++++++++++++++++-
> >>> 1 files changed, 56 insertions(+), 1 deletions(-)
> >>>
> >>> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> >>> index 55f91d9..e111971 100644
> >>> --- a/drivers/video/da8xx-fb.c
> >>> +++ b/drivers/video/da8xx-fb.c
> >>> @@ -82,6 +82,8 @@
> >>> #define LCD_V2_LIDD_CLK_EN BIT(1)
> >>> #define LCD_V2_CORE_CLK_EN BIT(0)
> >>> #define LCD_V2_LPP_B10 26
> >>> +#define LCD_V2_TFT_24BPP_MODE BIT(25)
> >>> +#define LCD_V2_TFT_24BPP_UNPACK BIT(26)
> >>>
> >>> /* LCD Raster Timing 2 Register */
> >>> #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
> >>> @@ -151,7 +153,7 @@ struct da8xx_fb_par {
> >>> unsigned int dma_end;
> >>> struct clk *lcdc_clk;
> >>> int irq;
> >>> - unsigned short pseudo_palette[16];
> >>> + unsigned short pseudo_palette[32];
> >>
> >> This looks wrong, include/linux/fb.h says:
> >> "void *pseudo_palette; /* Fake palette of 16 colors */"
> >> This will probably also simplify the code below to write to the pseudo palette.
> >> But I think you have to increase the data type of the palette, maybe to u32?
> >>
> >>
> >
> > Yes, I accept that data type has to be changed to u32. But how does it simplify updating of pseudo palette.
>
> Your code is even buggier than I saw. Where did you get the information how to
> write fb_setcolreg?
> First, as I wrote in my last mail, the pseudo_palette has always exactly 16
> colors, regardless of the color depth.
> Second, the existing code is some sort of wrong to check for bpp the only thing
> that really matters is whether it is Truecolor or not, the code for handling the
> Truecolor case will very likely be always the same regardless of the bpp, just
> the values in {red,green,blue}{length,offset} differ.
> Third your patch is wrong in using 24 in things like
> red >>= (24 - info->var.red.length);
> skeletonfb.c: "The values supplied have a 16 bit magnitude which needs to be
> scaled in this function for the hardware."
> So it has to be 16, always.
>
> Just have a look at drivers/video/skeletonfb.c, it contains much useful information.
>
>
> Best regards,
>
> Florian Tobias Schandinat
>
Thanks for pointing out to skeletonfb.c. I will submit next version based on this.
Thanks,
Prakash
[...]
^ permalink raw reply
* Re: [PATCH 02/57] fbdev: sh_mobile_lcdc: Mark init-only symbols with
From: Guennadi Liakhovetski @ 2011-12-13 22:23 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-3-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Laurent
On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> default_720p and sh_mobile_lcdc_check_interface are used at device
> initialization time only. Mark them as __devinitconst and __devinit
> respectively.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> drivers/video/sh_mobile_lcdcfb.c | 5 +++--
> 1 files changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
> index 8b18360..a6bf4fb 100644
> --- a/drivers/video/sh_mobile_lcdcfb.c
> +++ b/drivers/video/sh_mobile_lcdcfb.c
> @@ -1459,7 +1459,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
> * Probe/remove and driver init/exit
> */
>
> -static const struct fb_videomode default_720p = {
> +static const struct fb_videomode default_720p __devinitconst = {
> .name = "HDMI 720p",
> .xres = 1280,
> .yres = 720,
> @@ -1528,7 +1528,8 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
> return 0;
> }
>
> -static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
> +static int __devinit
> +sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
Personally, I don't like this type of line splitting very much, I prefer
the grep output to show the function type and all attributes, but this,
certainly, would not be the reason to change this specific hunk:-) But
this might be: the whole file so far has all function definitions at least
up to and including the first parameter on one line, so, I find, this
change would introduce an inconsistency in the file style. The line would
__only__ be 83 characters long if you put it all on one line. I think, it
would look better then:-)
> {
> int interface_type = ch->cfg.interface_type;
>
> --
> 1.7.3.4
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 06/57] fbdev: sh_mobile_hdmi: Don't access LCDC channel
From: Guennadi Liakhovetski @ 2011-12-13 23:02 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-7-git-send-email-laurent.pinchart@ideasonboard.com>
On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> Instead of relying on info->par being a pointer to an LCDC channel, cast
> the notifier block pointer to an sh_hdmi pointer.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> drivers/video/sh_mobile_hdmi.c | 6 +++---
> 1 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
> index 647ba98..b1e90f5 100644
> --- a/drivers/video/sh_mobile_hdmi.c
> +++ b/drivers/video/sh_mobile_hdmi.c
> @@ -225,6 +225,8 @@ struct sh_hdmi {
> struct notifier_block notifier;
> };
>
> +#define notifier_to_hdmi(n) container_of(n, struct sh_hdmi, notifier)
> +
> static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
> {
> iowrite8(data, hdmi->base + reg);
> @@ -1204,9 +1206,7 @@ static int sh_hdmi_notify(struct notifier_block *nb,
> {
> struct fb_event *event = data;
> struct fb_info *info = event->info;
> - struct sh_mobile_lcdc_chan *ch = info->par;
> - struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
> - struct sh_hdmi *hdmi = board_cfg->board_data;
> + struct sh_hdmi *hdmi = notifier_to_hdmi(nb);
>
> if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
Then you also can drop the first two of the three checks above. If I'm not
mistaken, in a HDMI / LCD set up, if this notifier is called for the LCD
panel, hdmi will wtill point to the HDMI-related sh_hdmi object, whose
->info will then mismatch the info pointer, derived from the notifier
"data" pointer.
> return NOTIFY_DONE;
> --
> 1.7.3.4
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 11/57] fbdev: sh_mobile_lcdc: Handle HDMI/MIPI transmitter
From: Guennadi Liakhovetski @ 2011-12-14 0:03 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-12-git-send-email-laurent.pinchart@ideasonboard.com>
On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> Pass a pointer to the transmitter device through platform data, retrieve
> the corresponding sh_mobile_lcdc_entity structure in the probe method
> and call the transmitter display_on/off methods directly.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> drivers/video/sh_mobile_lcdcfb.c | 33 ++++++++++++++++++++++++++++-----
> drivers/video/sh_mobile_lcdcfb.h | 2 ++
> include/video/sh_mobile_lcdc.h | 2 ++
> 3 files changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
> index afa1fac..f1bbae6 100644
> --- a/drivers/video/sh_mobile_lcdcfb.c
> +++ b/drivers/video/sh_mobile_lcdcfb.c
> @@ -338,6 +338,13 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
> static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
> {
> struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
> + int ret;
> +
> + if (ch->tx_dev) {
> + ret = ch->tx_dev->ops->display_on(ch->tx_dev, ch->info);
->ops or ->display_o{n,ff}() cannot be NULL?
also
+ int ret = ch->tx_dev->ops->display_on(ch->tx_dev, ch->info);
would suffice;-)
> + if (ret < 0)
> + return;
> + }
>
> /* HDMI must be enabled before LCDC configuration */
> if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
> @@ -354,6 +361,9 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
> board_cfg->display_off(board_cfg->board_data);
> module_put(board_cfg->owner);
> }
> +
> + if (ch->tx_dev)
> + ch->tx_dev->ops->display_off(ch->tx_dev);
> }
>
> /* -----------------------------------------------------------------------------
> @@ -1490,18 +1500,21 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
> sh_mobile_lcdc_stop(priv);
>
> for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
> - info = priv->ch[i].info;
> + struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
>
> + info = ch->info;
> if (!info || !info->device)
> continue;
>
> - if (priv->ch[i].sglist)
> - vfree(priv->ch[i].sglist);
> + if (ch->tx_dev)
> + module_put(ch->cfg.tx_dev->dev.driver->owner);
This is now the same ->owner, as the one taken in your
sh_mobile_lcdc_display_o{n,ff}() functions? IIUC, you're now adding this
new ->owner field to later (17/57) remove the original one?
> +
> + if (ch->sglist)
> + vfree(ch->sglist);
>
> if (info->screen_base)
> dma_free_coherent(&pdev->dev, info->fix.smem_len,
> - info->screen_base,
> - priv->ch[i].dma_handle);
> + info->screen_base, ch->dma_handle);
> fb_dealloc_cmap(&info->cmap);
> framebuffer_release(info);
> }
> @@ -1596,6 +1609,16 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
> info->pseudo_palette = &ch->pseudo_palette;
> info->flags = FBINFO_FLAG_DEFAULT;
>
> + if (cfg->tx_dev) {
> + if (!cfg->tx_dev->dev.driver ||
> + !try_module_get(cfg->tx_dev->dev.driver->owner)) {
> + dev_warn(priv->dev, "unable to get transmitter "
> + "device\n");
Grrr... Pleeeease, don't split strings. If you really have to program on
vt220;-) at least do
+ dev_warn(priv->dev,
+ "unable to get transmitter device\n");
> + return -EINVAL;
> + }
> + ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
> + }
> +
> /* Iterate through the modes to validate them and find the highest
> * resolution.
> */
> diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
> index d79e5aa..9601b92 100644
> --- a/drivers/video/sh_mobile_lcdcfb.h
> +++ b/drivers/video/sh_mobile_lcdcfb.h
> @@ -41,6 +41,8 @@ struct sh_mobile_lcdc_entity {
> */
> struct sh_mobile_lcdc_chan {
> struct sh_mobile_lcdc_priv *lcdc;
> + struct sh_mobile_lcdc_entity *tx_dev;
> +
> unsigned long *reg_offs;
> unsigned long ldmt1r_value;
> unsigned long enabled; /* ME and SE in LDCNT2R */
> diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
> index fe30b75..0ec59e1 100644
> --- a/include/video/sh_mobile_lcdc.h
> +++ b/include/video/sh_mobile_lcdc.h
> @@ -186,6 +186,8 @@ struct sh_mobile_lcdc_chan_cfg {
> struct sh_mobile_lcdc_bl_info bl_info;
> struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
> struct sh_mobile_meram_cfg *meram_cfg;
> +
> + struct platform_device *tx_dev; /* HDMI/MIPI transmitter device */
"MIPI" is too generic, IMHO
Hm, could we, maybe, have different names for sh_mobile_lcdc_chan::tx_dev
and sh_mobile_lcdc_chan_cfg::tx_dev?;-)
> };
>
> struct sh_mobile_lcdc_info {
> --
> 1.7.3.4
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 33/57] fbdev: sh_mobile_lcdc: Add sh_mobile_format_info()
From: Damian Hobson-Garcia @ 2011-12-14 3:04 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-34-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Laurent,
On 2011/12/13 23:02, Laurent Pinchart wrote:
> --- a/drivers/video/sh_mobile_lcdcfb.c
> +++ b/drivers/video/sh_mobile_lcdcfb.c
> @@ -447,6 +447,75 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
> * Format helpers
> */
>
> +struct sh_mobile_lcdc_format_info {
> + u32 fourcc;
> + unsigned int bpp;
> + bool yuv;
> + u32 lddfr;
> +};
> +
> +static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = {
> + {
> + .fourcc = V4L2_PIX_FMT_RGB565,
> + .bpp = 12,
I think that this should be 16 instead of 12.
> @@ -665,37 +726,20 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
>
> /* Setup geometry, format, frame buffer memory and operation mode. */
> for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
> + const struct sh_mobile_lcdc_format_info *format;
> + u32 fourcc;
> +
> ch = &priv->ch[k];
> if (!ch->enabled)
> continue;
>
> sh_mobile_lcdc_geometry(ch);
>
> - switch (sh_mobile_format_fourcc(&ch->info->var)) {
> - case V4L2_PIX_FMT_RGB565:
> - tmp = LDDFR_PKF_RGB16;
> - break;
> - case V4L2_PIX_FMT_BGR24:
> - tmp = LDDFR_PKF_RGB24;
> - break;
> - case V4L2_PIX_FMT_BGR32:
> - tmp = LDDFR_PKF_ARGB32;
> - break;
> - case V4L2_PIX_FMT_NV12:
> - case V4L2_PIX_FMT_NV21:
> - tmp = LDDFR_CC | LDDFR_YF_420;
> - break;
> - case V4L2_PIX_FMT_NV16:
> - case V4L2_PIX_FMT_NV61:
> - tmp = LDDFR_CC | LDDFR_YF_422;
> - break;
> - case V4L2_PIX_FMT_NV24:
> - case V4L2_PIX_FMT_NV42:
> - tmp = LDDFR_CC | LDDFR_YF_444;
> - break;
> - }
> + fourcc = sh_mobile_format_fourcc(&ch->info->var);
> + format = sh_mobile_format_info(fourcc);
> + tmp = format->lddfr;
Do you need to check if format is NULL here?
Damian
^ permalink raw reply
* [PATCH 0/2] OMAPDSS: DISPC: Peformance improvement of DISPC Scaling
From: Chandrabhanu Mahapatra @ 2011-12-14 4:53 UTC (permalink / raw)
To: =tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
Hi everyone,
the following patch set directs to improve the scaling performance of DISPC
module which consists of two pacthes.
The first patch is based on code of Lajos Molnar <lajos@ti.com> from Android
Kernel, which updates the code with new set of coefficients to improve the
scaling performance.
The second patch is based on some very valuable suggestions by
Sebastien Fagard <s-fagard@ti.com> and directs to modify the clock
requirements for scaling to support OMAP4 and avoid clock failure issues.
I have tested these patches on OMAP2, OMAP3 AND OMAP4. To test on 2430SDP
board I have created a patch to enable the display which will follow later.
All your comments and suggestions are welcome.
Regards,
Chandrabhanu
Chandrabhanu Mahapatra (2):
OMAPDSS: DISPC: Update Fir Coefficients
OMAPDSS: DISPC: Update Scaling Clock Logic
drivers/video/omap2/dss/Makefile | 2 +-
drivers/video/omap2/dss/dispc.c | 203 +++++++--------------
drivers/video/omap2/dss/dispc.h | 11 +
drivers/video/omap2/dss/dispc_coefs.c | 327 ++++++++++++++++++++++++++++++++
drivers/video/omap2/dss/dss_features.c | 7 +
drivers/video/omap2/dss/dss_features.h | 1 +
6 files changed, 412 insertions(+), 139 deletions(-)
create mode 100644 drivers/video/omap2/dss/dispc_coefs.c
^ permalink raw reply
* [PATCH 1/2] OMAPDSS: DISPC: Update Fir Coefficients
From: Chandrabhanu Mahapatra @ 2011-12-14 4:53 UTC (permalink / raw)
To: =tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
The FIR coefficients present in kernel are being updated to new coefficients
consisting of 24 coefficient tables, with 12 each for 3 tap and 5 tap scenario,
which are chosen on the basis of DISPC up/downsampling filters M value. M is
the inverse of low pass cut off frequency of the sampling filter. For vertical
scaling 3 tap or 5 tap tables are used based on the clock rate and width of
the line buffer whereas in OMAP2 3 tap is always used. For horizontal scaling
however 5 tap tables are always used.
New coefficients and the corresponding logic have been tested on OMAP2, OMAP3
and OMAP4. Horizontal and vertical scaling worked fine except for some 3 tap
vs 5 tap issue during vertical upscaling and clock failing issues which is
acknowledged in the next patch. Vertical upscaling was found to perform better
under 5 taps. The 24 coefficient tables have been moved to another file
dispc_coefs.c for proper maintainance.
This code is written based on code written by Lajos Molnar <lajos@ti.com> in
Android Kernel for scaling. Lajos Molnar <lajos@ti.com> had fine tuned the FIR
coefficient selection process and reduced outliness and blockiness around
images when upscaling more than 2 times.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/Makefile | 2 +-
drivers/video/omap2/dss/dispc.c | 135 ++------------
drivers/video/omap2/dss/dispc.h | 11 +
drivers/video/omap2/dss/dispc_coefs.c | 327 +++++++++++++++++++++++++++++++++
4 files changed, 357 insertions(+), 118 deletions(-)
create mode 100644 drivers/video/omap2/dss/dispc_coefs.c
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index bd34ac5..f10d56f 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o manager.o overlay.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 6892cfd..b981983 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -63,22 +63,6 @@ struct omap_dispc_isr_data {
u32 mask;
};
-struct dispc_h_coef {
- s8 hc4;
- s8 hc3;
- u8 hc2;
- s8 hc1;
- s8 hc0;
-};
-
-struct dispc_v_coef {
- s8 vc22;
- s8 vc2;
- u8 vc1;
- s8 vc0;
- s8 vc00;
-};
-
enum omap_burst_size {
BURST_SIZE_X2 = 0,
BURST_SIZE_X4 = 1,
@@ -532,105 +516,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
}
-static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup,
- int vscaleup, int five_taps,
- enum omap_color_component color_comp)
-{
- /* Coefficients for horizontal up-sampling */
- static const struct dispc_h_coef coef_hup[8] = {
- { 0, 0, 128, 0, 0 },
- { -1, 13, 124, -8, 0 },
- { -2, 30, 112, -11, -1 },
- { -5, 51, 95, -11, -2 },
- { 0, -9, 73, 73, -9 },
- { -2, -11, 95, 51, -5 },
- { -1, -11, 112, 30, -2 },
- { 0, -8, 124, 13, -1 },
- };
-
- /* Coefficients for vertical up-sampling */
- static const struct dispc_v_coef coef_vup_3tap[8] = {
- { 0, 0, 128, 0, 0 },
- { 0, 3, 123, 2, 0 },
- { 0, 12, 111, 5, 0 },
- { 0, 32, 89, 7, 0 },
- { 0, 0, 64, 64, 0 },
- { 0, 7, 89, 32, 0 },
- { 0, 5, 111, 12, 0 },
- { 0, 2, 123, 3, 0 },
- };
-
- static const struct dispc_v_coef coef_vup_5tap[8] = {
- { 0, 0, 128, 0, 0 },
- { -1, 13, 124, -8, 0 },
- { -2, 30, 112, -11, -1 },
- { -5, 51, 95, -11, -2 },
- { 0, -9, 73, 73, -9 },
- { -2, -11, 95, 51, -5 },
- { -1, -11, 112, 30, -2 },
- { 0, -8, 124, 13, -1 },
- };
-
- /* Coefficients for horizontal down-sampling */
- static const struct dispc_h_coef coef_hdown[8] = {
- { 0, 36, 56, 36, 0 },
- { 4, 40, 55, 31, -2 },
- { 8, 44, 54, 27, -5 },
- { 12, 48, 53, 22, -7 },
- { -9, 17, 52, 51, 17 },
- { -7, 22, 53, 48, 12 },
- { -5, 27, 54, 44, 8 },
- { -2, 31, 55, 40, 4 },
- };
-
- /* Coefficients for vertical down-sampling */
- static const struct dispc_v_coef coef_vdown_3tap[8] = {
- { 0, 36, 56, 36, 0 },
- { 0, 40, 57, 31, 0 },
- { 0, 45, 56, 27, 0 },
- { 0, 50, 55, 23, 0 },
- { 0, 18, 55, 55, 0 },
- { 0, 23, 55, 50, 0 },
- { 0, 27, 56, 45, 0 },
- { 0, 31, 57, 40, 0 },
- };
-
- static const struct dispc_v_coef coef_vdown_5tap[8] = {
- { 0, 36, 56, 36, 0 },
- { 4, 40, 55, 31, -2 },
- { 8, 44, 54, 27, -5 },
- { 12, 48, 53, 22, -7 },
- { -9, 17, 52, 51, 17 },
- { -7, 22, 53, 48, 12 },
- { -5, 27, 54, 44, 8 },
- { -2, 31, 55, 40, 4 },
- };
-
- const struct dispc_h_coef *h_coef;
- const struct dispc_v_coef *v_coef;
+static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
+ int fir_vinc, int five_taps,
+ enum omap_color_component color_comp)
+{
+ const struct dispc_coef *h_coef, *v_coef;
int i;
- if (hscaleup)
- h_coef = coef_hup;
- else
- h_coef = coef_hdown;
-
- if (vscaleup)
- v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap;
- else
- v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap;
+ h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
+ v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
for (i = 0; i < 8; i++) {
u32 h, hv;
- h = FLD_VAL(h_coef[i].hc0, 7, 0)
- | FLD_VAL(h_coef[i].hc1, 15, 8)
- | FLD_VAL(h_coef[i].hc2, 23, 16)
- | FLD_VAL(h_coef[i].hc3, 31, 24);
- hv = FLD_VAL(h_coef[i].hc4, 7, 0)
- | FLD_VAL(v_coef[i].vc0, 15, 8)
- | FLD_VAL(v_coef[i].vc1, 23, 16)
- | FLD_VAL(v_coef[i].vc2, 31, 24);
+ h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
+ | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
+ | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
+ | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
+ hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
+ | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
+ | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
+ | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
if (color_comp = DISPC_COLOR_COMPONENT_RGB_Y) {
dispc_ovl_write_firh_reg(plane, i, h);
@@ -645,8 +551,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup,
if (five_taps) {
for (i = 0; i < 8; i++) {
u32 v;
- v = FLD_VAL(v_coef[i].vc00, 7, 0)
- | FLD_VAL(v_coef[i].vc22, 15, 8);
+ v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
+ | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
if (color_comp = DISPC_COLOR_COMPONENT_RGB_Y)
dispc_ovl_write_firv_reg(plane, i, v);
else
@@ -1168,17 +1074,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane,
enum omap_color_component color_comp)
{
int fir_hinc, fir_vinc;
- int hscaleup, vscaleup;
-
- hscaleup = orig_width <= out_width;
- vscaleup = orig_height <= out_height;
-
- dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps,
- color_comp);
fir_hinc = 1024 * orig_width / out_width;
fir_vinc = 1024 * orig_height / out_height;
+ dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
+ color_comp);
dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
}
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
index c06efc3..5836bd1 100644
--- a/drivers/video/omap2/dss/dispc.h
+++ b/drivers/video/omap2/dss/dispc.h
@@ -97,6 +97,17 @@
#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
DISPC_PRELOAD_OFFSET(n))
+/* DISPC up/downsampling FIR filter coefficient structure */
+struct dispc_coef {
+ s8 hc4_vc22;
+ s8 hc3_vc2;
+ u8 hc2_vc1;
+ s8 hc1_vc0;
+ s8 hc0_vc00;
+};
+
+const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
+
/* DISPC manager/channel specific registers */
static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
{
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c
new file mode 100644
index 0000000..e87b94f
--- /dev/null
+++ b/drivers/video/omap2/dss/dispc_coefs.c
@@ -0,0 +1,327 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc_coefs.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <video/omapdss.h>
+#include "dispc.h"
+
+#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
+
+static const struct dispc_coef coef3_M8[8] = {
+ { 0, 0, 128, 0, 0 },
+ { 0, -4, 123, 9, 0 },
+ { 0, -4, 108, 87, 0 },
+ { 0, -2, 87, 43, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 43, 87, -2, 0 },
+ { 0, 24, 108, -4, 0 },
+ { 0, 9, 123, -4, 0 },
+};
+
+static const struct dispc_coef coef3_M9[8] = {
+ { 0, 6, 116, 6, 0 },
+ { 0, 0, 112, 16, 0 },
+ { 0, -2, 100, 30, 0 },
+ { 0, -2, 83, 47, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 47, 83, -2, 0 },
+ { 0, 30, 100, -2, 0 },
+ { 0, 16, 112, 0, 0 },
+};
+
+static const struct dispc_coef coef3_M10[8] = {
+ { 0, 10, 108, 10, 0 },
+ { 0, 3, 104, 21, 0 },
+ { 0, 0, 94, 34, 0 },
+ { 0, -1, 80, 49, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 49, 80, -1, 0 },
+ { 0, 34, 94, 0, 0 },
+ { 0, 21, 104, 3, 0 },
+};
+
+static const struct dispc_coef coef3_M11[8] = {
+ { 0, 14, 100, 14, 0 },
+ { 0, 6, 98, 24, 0 },
+ { 0, 2, 90, 36, 0 },
+ { 0, 0, 78, 50, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 50, 78, 0, 0 },
+ { 0, 36, 90, 2, 0 },
+ { 0, 24, 98, 6, 0 },
+};
+
+static const struct dispc_coef coef3_M12[8] = {
+ { 0, 16, 96, 16, 0 },
+ { 0, 9, 93, 26, 0 },
+ { 0, 4, 86, 38, 0 },
+ { 0, 1, 76, 51, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 51, 76, 1, 0 },
+ { 0, 38, 86, 4, 0 },
+ { 0, 26, 93, 9, 0 },
+};
+
+static const struct dispc_coef coef3_M13[8] = {
+ { 0, 18, 92, 18, 0 },
+ { 0, 10, 90, 28, 0 },
+ { 0, 5, 83, 40, 0 },
+ { 0, 1, 75, 52, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 52, 75, 1, 0 },
+ { 0, 40, 83, 5, 0 },
+ { 0, 28, 90, 10, 0 },
+};
+
+static const struct dispc_coef coef3_M14[8] = {
+ { 0, 20, 88, 20, 0 },
+ { 0, 12, 86, 30, 0 },
+ { 0, 6, 81, 41, 0 },
+ { 0, 2, 74, 52, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 52, 74, 2, 0 },
+ { 0, 41, 81, 6, 0 },
+ { 0, 30, 86, 12, 0 },
+};
+
+static const struct dispc_coef coef3_M16[8] = {
+ { 0, 22, 84, 22, 0 },
+ { 0, 14, 82, 32, 0 },
+ { 0, 8, 78, 42, 0 },
+ { 0, 3, 72, 53, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 53, 72, 3, 0 },
+ { 0, 42, 78, 8, 0 },
+ { 0, 32, 82, 14, 0 },
+};
+
+static const struct dispc_coef coef3_M19[8] = {
+ { 0, 24, 80, 24, 0 },
+ { 0, 16, 79, 33, 0 },
+ { 0, 9, 76, 43, 0 },
+ { 0, 4, 70, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 70, 4, 0 },
+ { 0, 43, 76, 9, 0 },
+ { 0, 33, 79, 16, 0 },
+};
+
+static const struct dispc_coef coef3_M22[8] = {
+ { 0, 25, 78, 25, 0 },
+ { 0, 17, 77, 34, 0 },
+ { 0, 10, 74, 44, 0 },
+ { 0, 5, 69, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 69, 5, 0 },
+ { 0, 44, 74, 10, 0 },
+ { 0, 34, 77, 17, 0 },
+};
+
+static const struct dispc_coef coef3_M26[8] = {
+ { 0, 26, 76, 26, 0 },
+ { 0, 19, 74, 35, 0 },
+ { 0, 11, 72, 45, 0 },
+ { 0, 5, 69, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 69, 5, 0 },
+ { 0, 45, 72, 11, 0 },
+ { 0, 35, 74, 19, 0 },
+};
+
+static const struct dispc_coef coef3_M32[8] = {
+ { 0, 27, 74, 27, 0 },
+ { 0, 19, 73, 36, 0 },
+ { 0, 12, 71, 45, 0 },
+ { 0, 6, 68, 54, 0 },
+ { 0, 64, 64, 0, 0 },
+ { 0, 54, 68, 6, 0 },
+ { 0, 45, 71, 12, 0 },
+ { 0, 36, 73, 19, 0 },
+};
+
+static const struct dispc_coef coef5_M8[8] = {
+ { 0, 0, 128, 0, 0 },
+ { -2, 14, 125, -10, 1 },
+ { -6, 33, 114, -15, 2 },
+ { -10, 55, 98, -16, 1 },
+ { 0, -14, 78, 78, -14 },
+ { 1, -16, 98, 55, -10 },
+ { 2, -15, 114, 33, -6 },
+ { 1, -10, 125, 14, -2 },
+};
+
+static const struct dispc_coef coef5_M9[8] = {
+ { -3, 10, 114, 10, -3 },
+ { -6, 24, 110, 0, -1 },
+ { -8, 40, 103, -7, 0 },
+ { -11, 58, 91, -11, 1 },
+ { 0, -12, 76, 76, -12 },
+ { 1, -11, 91, 58, -11 },
+ { 0, -7, 103, 40, -8 },
+ { -1, 0, 111, 24, -6 },
+};
+
+static const struct dispc_coef coef5_M10[8] = {
+ { -4, 18, 100, 18, -4 },
+ { -6, 30, 99, 8, -3 },
+ { -8, 44, 93, 0, -1 },
+ { -9, 58, 84, -5, 0 },
+ { 0, -8, 72, 72, -8 },
+ { 0, -5, 84, 58, -9 },
+ { -1, 0, 93, 44, -8 },
+ { -3, 8, 99, 30, -6 },
+};
+
+static const struct dispc_coef coef5_M11[8] = {
+ { -5, 23, 92, 23, -5 },
+ { -6, 34, 90, 13, -3 },
+ { -6, 45, 85, 6, -2 },
+ { -6, 57, 78, 0, -1 },
+ { 0, -4, 68, 68, -4 },
+ { -1, 0, 78, 57, -6 },
+ { -2, 6, 85, 45, -6 },
+ { -3, 13, 90, 34, -6 },
+};
+
+static const struct dispc_coef coef5_M12[8] = {
+ { -4, 26, 84, 26, -4 },
+ { -5, 36, 82, 18, -3 },
+ { -4, 46, 78, 10, -2 },
+ { -3, 55, 72, 5, -1 },
+ { 0, 0, 64, 64, 0 },
+ { -1, 5, 72, 55, -3 },
+ { -2, 10, 78, 46, -4 },
+ { -3, 18, 82, 36, -5 },
+};
+
+static const struct dispc_coef coef5_M13[8] = {
+ { -3, 28, 78, 28, -3 },
+ { -3, 37, 76, 21, -3 },
+ { -2, 45, 73, 14, -2 },
+ { 0, 53, 68, 8, -1 },
+ { 0, 3, 61, 61, 3 },
+ { -1, 8, 68, 53, 0 },
+ { -2, 14, 73, 45, -2 },
+ { -3, 21, 76, 37, -3 },
+};
+
+static const struct dispc_coef coef5_M14[8] = {
+ { -2, 30, 72, 30, -2 },
+ { -1, 37, 71, 23, -2 },
+ { 0, 45, 69, 16, -2 },
+ { 3, 52, 64, 10, -1 },
+ { 0, 6, 58, 58, 6 },
+ { -1, 10, 64, 52, 3 },
+ { -2, 16, 69, 45, 0 },
+ { -2, 23, 71, 37, -1 },
+};
+
+static const struct dispc_coef coef5_M16[8] = {
+ { 0, 31, 66, 31, 0 },
+ { 1, 38, 65, 25, -1 },
+ { 3, 44, 62, 20, -1 },
+ { 6, 49, 59, 14, 0 },
+ { 0, 10, 54, 54, 10 },
+ { 0, 14, 59, 49, 6 },
+ { -1, 20, 62, 44, 3 },
+ { -1, 25, 65, 38, 1 },
+};
+
+static const struct dispc_coef coef5_M19[8] = {
+ { 3, 32, 58, 32, 3 },
+ { 4, 38, 58, 27, 1 },
+ { 7, 42, 55, 23, 1 },
+ { 10, 46, 54, 18, 0 },
+ { 0, 14, 50, 50, 14 },
+ { 0, 18, 54, 46, 10 },
+ { 1, 23, 55, 42, 7 },
+ { 1, 27, 58, 38, 4 },
+};
+
+static const struct dispc_coef coef5_M22[8] = {
+ { 4, 33, 54, 33, 4 },
+ { 6, 37, 54, 28, 3 },
+ { 9, 41, 53, 24, 1 },
+ { 12, 45, 51, 20, 0 },
+ { 0, 16, 48, 48, 16 },
+ { 0, 20, 51, 45, 12 },
+ { 1, 24, 53, 41, 9 },
+ { 3, 28, 54, 37, 6 },
+};
+
+static const struct dispc_coef coef5_M26[8] = {
+ { 6, 33, 50, 33, 6 },
+ { 8, 36, 51, 29, 4 },
+ { 11, 40, 50, 25, 2 },
+ { 14, 43, 48, 22, 1 },
+ { 0, 18, 46, 46, 18 },
+ { 1, 22, 48, 43, 14 },
+ { 2, 25, 50, 40, 11 },
+ { 4, 29, 51, 36, 8 },
+};
+
+static const struct dispc_coef coef5_M32[8] = {
+ { 7, 33, 48, 33, 7 },
+ { 10, 36, 48, 29, 5 },
+ { 13, 39, 47, 26, 3 },
+ { 16, 42, 46, 23, 1 },
+ { 0, 19, 45, 45, 19 },
+ { 1, 23, 46, 42, 16 },
+ { 3, 26, 47, 39, 13 },
+ { 5, 29, 48, 36, 10 },
+};
+
+const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
+{
+ int i;
+ static const struct {
+ int Mmin;
+ int Mmax;
+ const struct dispc_coef *coef_3;
+ const struct dispc_coef *coef_5;
+ } coefs[] = {
+ { 26, 32, coef3_M32, coef5_M32 },
+ { 22, 26, coef3_M26, coef5_M26 },
+ { 19, 22, coef3_M22, coef5_M22 },
+ { 16, 19, coef3_M19, coef5_M19 },
+ { 14, 16, coef3_M16, coef5_M16 },
+ { 13, 14, coef3_M14, coef5_M14 },
+ { 12, 13, coef3_M13, coef5_M13 },
+ { 11, 12, coef3_M12, coef5_M12 },
+ { 10, 11, coef3_M11, coef5_M11 },
+ { 9, 10, coef3_M10, coef5_M10 },
+ { 8, 9, coef3_M9, coef5_M9 },
+ { 3, 8, coef3_M8, coef5_M8 },
+ /*
+ * When upscaling more than two times, blockiness and outlines
+ * around the image are observed when M8 tables are used. M11,
+ * M16 and M19 tables are used to prevent this.
+ */
+ { 2, 3, coef3_M11, coef5_M11 },
+ { 1, 2, coef3_M16, coef5_M16 },
+ };
+
+ inc /= 128;
+ for (i = 0; i < ARRAY_LEN(coefs); ++i)
+ if (inc > coefs[i].Mmin && inc <= coefs[i].Mmax)
+ return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
+ if (inc = 1)
+ return five_taps ? coef3_M19 : coef5_M19;
+ return NULL;
+}
--
1.7.1
^ permalink raw reply related
* [PATCH 2/2] OMAPDSS: DISPC: Update Scaling Clock Logic
From: Chandrabhanu Mahapatra @ 2011-12-14 4:53 UTC (permalink / raw)
To: =tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
Clock requirements for scaling in OMAP2, OMAP3 and OMAP4 are different. In
OMAP2 and OMAP3 the required clock rate is a function of pixel clock, vertical
downscale ratio and horizontal downscale ratio whereas in OMAP4 it is a
function of pixel clock and horizontal downscale ratio only. Selection of 3-tap
vs 5-tap coefficients depends on clock rate line buffer width in OMAP3 whereas
in OMAP4 it is independent of clock rate and line buffer width. In OMAP2 3-tap
for vertical and 5-tap for horizontal scaling is used. In OMAP4 5-tap is used
both for horizontal and vertical scaling for better performance. Also, the
number and width of line buffers differs in OMAP3 and OMAP4.
So, clock functions have been fined tuned for OMAP3 and support has been added
added for OMAP4. This code has been tested on OMAP2, OMAP3 and OMAP4, and
scaling issues due to clock errors have been resolved.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dispc.c | 66 ++++++++++++++++++++++----------
drivers/video/omap2/dss/dss_features.c | 7 +++
drivers/video/omap2/dss/dss_features.h | 1 +
3 files changed, 54 insertions(+), 20 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index b981983..6c3feb4 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -1554,6 +1554,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
u32 fclk = 0;
u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
+ if (height <= out_height && width <= out_width)
+ return (unsigned long) pclk;
+
if (height > out_height) {
struct omap_dss_device *dssdev = dispc_mgr_get_device(channel);
unsigned int ppl = dssdev->panel.timings.x_res;
@@ -1608,7 +1611,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
else
vf = 1;
- return dispc_mgr_pclk_rate(channel) * vf * hf;
+ if (cpu_is_omap24xx()) {
+ if (vf > 1 && hf > 1)
+ return dispc_mgr_pclk_rate(channel) * 4;
+ else
+ return dispc_mgr_pclk_rate(channel) * 2;
+ } else if (cpu_is_omap34xx()) {
+ return dispc_mgr_pclk_rate(channel) * vf * hf;
+ } else {
+ return dispc_mgr_pclk_rate(channel) * hf;
+ }
}
static int dispc_ovl_calc_scaling(enum omap_plane plane,
@@ -1618,6 +1630,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
unsigned long fclk = 0;
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) = 0) {
@@ -1635,28 +1649,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
out_height > height * 8)
return -EINVAL;
- /* Must use 5-tap filter? */
- *five_taps = height > out_height * 2;
-
- if (!*five_taps) {
+ if (cpu_is_omap24xx()) {
+ if (width > maxsinglelinewidth)
+ DSSERR("Cannot scale max input width exceeded");
+ *five_taps = false;
+ fclk = calc_fclk(channel, width, height, out_width,
+ out_height);
+ } else if (cpu_is_omap34xx()) {
+ if (width > (maxsinglelinewidth * 2)) {
+ DSSERR("Cannot setup scaling");
+ DSSERR("width exceeds maximum width possible");
+ return -EINVAL;
+ }
+ fclk = calc_fclk_five_taps(channel, width, height, out_width,
+ out_height, color_mode);
+ if (width > maxsinglelinewidth) {
+ if (height > out_height && height < out_height * 2)
+ *five_taps = false;
+ else {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
+ }
+ }
+ if (!*five_taps)
+ fclk = calc_fclk(channel, width, height, out_width,
+ out_height);
+ } else {
+ if (width > maxsinglelinewidth) {
+ DSSERR("Cannot scale width exceeds max line width");
+ return -EINVAL;
+ }
fclk = calc_fclk(channel, width, height, out_width,
out_height);
-
- /* Try 5-tap filter if 3-tap fclk is too high */
- if (cpu_is_omap34xx() && height > out_height &&
- fclk > dispc_fclk_rate())
- *five_taps = true;
}
- if (width > (2048 >> *five_taps)) {
- DSSERR("failed to set up scaling, fclk too low\n");
- return -EINVAL;
- }
-
- if (*five_taps)
- fclk = calc_fclk_five_taps(channel, width, height,
- out_width, out_height, color_mode);
-
DSSDBG("required fclk rate = %lu Hz\n", fclk);
DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
@@ -1676,7 +1702,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
u32 fifo_low, u32 fifo_high)
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
- bool five_taps = false;
+ bool five_taps = true;
bool fieldmode = 0;
int r, cconv = 0;
unsigned offset0, offset1;
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index b402699..5e4b829 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
[FEAT_PARAM_DOWNSCALE] = { 1, 2 },
+ /*
+ * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
+ * scaler cannot scale a image with width more than 768.
+ */
+ [FEAT_PARAM_LINEWIDTH] = { 1, 768 },
};
static const struct dss_param_range omap3_dss_param_range[] = {
@@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
};
static const struct dss_param_range omap4_dss_param_range[] = {
@@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
};
/* OMAP2 DSS Features */
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 6a6c05d..cd833bb 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -86,6 +86,7 @@ enum dss_range_param {
FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV,
FEAT_PARAM_DOWNSCALE,
+ FEAT_PARAM_LINEWIDTH,
};
/* DSS Feature Functions */
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 02/57] fbdev: sh_mobile_lcdc: Mark init-only symbols with __devinit(const)
From: Laurent Pinchart @ 2011-12-14 10:40 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-3-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Guennadi,
On Tuesday 13 December 2011 23:23:32 Guennadi Liakhovetski wrote:
> On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> > default_720p and sh_mobile_lcdc_check_interface are used at device
> > initialization time only. Mark them as __devinitconst and __devinit
> > respectively.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >
> > drivers/video/sh_mobile_lcdcfb.c | 5 +++--
> > 1 files changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/video/sh_mobile_lcdcfb.c
> > b/drivers/video/sh_mobile_lcdcfb.c index 8b18360..a6bf4fb 100644
> > --- a/drivers/video/sh_mobile_lcdcfb.c
> > +++ b/drivers/video/sh_mobile_lcdcfb.c
> > @@ -1459,7 +1459,7 @@ static int sh_mobile_lcdc_notify(struct
> > notifier_block *nb,
> >
> > * Probe/remove and driver init/exit
> > */
> >
> > -static const struct fb_videomode default_720p = {
> > +static const struct fb_videomode default_720p __devinitconst = {
> >
> > .name = "HDMI 720p",
> > .xres = 1280,
> > .yres = 720,
> >
> > @@ -1528,7 +1528,8 @@ static int sh_mobile_lcdc_remove(struct
> > platform_device *pdev)
> >
> > return 0;
> >
> > }
> >
> > -static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan
> > *ch) +static int __devinit
> > +sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
>
> Personally, I don't like this type of line splitting very much, I prefer
> the grep output to show the function type and all attributes, but this,
> certainly, would not be the reason to change this specific hunk:-) But
> this might be: the whole file so far has all function definitions at least
> up to and including the first parameter on one line, so, I find, this
> change would introduce an inconsistency in the file style. The line would
> __only__ be 83 characters long if you put it all on one line. I think, it
> would look better then:-)
It's a matter of limits, as usual... I find 80 to be a nice limit, although in
some cases I'm fine with exceeding it (one example is a long list of #defines
with a small comment describing each macro, as in the list of FOURCCs in
linux/videodev2.h for instance). For code I try to respect the 80 characters
limit. Another reason is that it produces checkpatch.pl warnings, which force
me to manually look at all the warnings to check which ones are acceptable.
Regarding consistency, other patches in this series use the same style, so
that function won't feel alone anymore ;-)
I can change this (and other instances of the same coding style) if you
insist. BTW, a possible improvement would be to shorten the sh_mobile_lcdc_
prefix. I find it too long, and I was thinking about reducing it to shm_lcdc_
(although shm reffers to shared memory, so that might not be the best idea).
> > {
> >
> > int interface_type = ch->cfg.interface_type;
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 06/57] fbdev: sh_mobile_hdmi: Don't access LCDC channel in notifier callback
From: Laurent Pinchart @ 2011-12-14 10:41 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-7-git-send-email-laurent.pinchart@ideasonboard.com>
On Wednesday 14 December 2011 00:02:11 Guennadi Liakhovetski wrote:
> On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> > Instead of relying on info->par being a pointer to an LCDC channel, cast
> > the notifier block pointer to an sh_hdmi pointer.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >
> > drivers/video/sh_mobile_hdmi.c | 6 +++---
> > 1 files changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/video/sh_mobile_hdmi.c
> > b/drivers/video/sh_mobile_hdmi.c index 647ba98..b1e90f5 100644
> > --- a/drivers/video/sh_mobile_hdmi.c
> > +++ b/drivers/video/sh_mobile_hdmi.c
> > @@ -225,6 +225,8 @@ struct sh_hdmi {
> >
> > struct notifier_block notifier;
> >
> > };
> >
> > +#define notifier_to_hdmi(n) container_of(n, struct sh_hdmi, notifier)
> > +
> >
> > static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
> > {
> >
> > iowrite8(data, hdmi->base + reg);
> >
> > @@ -1204,9 +1206,7 @@ static int sh_hdmi_notify(struct notifier_block
> > *nb,
> >
> > {
> >
> > struct fb_event *event = data;
> > struct fb_info *info = event->info;
> >
> > - struct sh_mobile_lcdc_chan *ch = info->par;
> > - struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
> > - struct sh_hdmi *hdmi = board_cfg->board_data;
> > + struct sh_hdmi *hdmi = notifier_to_hdmi(nb);
> >
> > if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
>
> Then you also can drop the first two of the three checks above. If I'm not
> mistaken, in a HDMI / LCD set up, if this notifier is called for the LCD
> panel, hdmi will wtill point to the HDMI-related sh_hdmi object, whose
> ->info will then mismatch the info pointer, derived from the notifier
> "data" pointer.
>
> > return NOTIFY_DONE;
>
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 06/57] fbdev: sh_mobile_hdmi: Don't access LCDC channel in notifier callback
From: Laurent Pinchart @ 2011-12-14 10:47 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-7-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Guennadi,
On Wednesday 14 December 2011 00:02:11 Guennadi Liakhovetski wrote:
> On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> > Instead of relying on info->par being a pointer to an LCDC channel, cast
> > the notifier block pointer to an sh_hdmi pointer.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >
> > drivers/video/sh_mobile_hdmi.c | 6 +++---
> > 1 files changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/video/sh_mobile_hdmi.c
> > b/drivers/video/sh_mobile_hdmi.c index 647ba98..b1e90f5 100644
> > --- a/drivers/video/sh_mobile_hdmi.c
> > +++ b/drivers/video/sh_mobile_hdmi.c
> > @@ -225,6 +225,8 @@ struct sh_hdmi {
> >
> > struct notifier_block notifier;
> >
> > };
> >
> > +#define notifier_to_hdmi(n) container_of(n, struct sh_hdmi, notifier)
> > +
> >
> > static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
> > {
> >
> > iowrite8(data, hdmi->base + reg);
> >
> > @@ -1204,9 +1206,7 @@ static int sh_hdmi_notify(struct notifier_block
> > *nb,
> >
> > {
> >
> > struct fb_event *event = data;
> > struct fb_info *info = event->info;
> >
> > - struct sh_mobile_lcdc_chan *ch = info->par;
> > - struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
> > - struct sh_hdmi *hdmi = board_cfg->board_data;
> > + struct sh_hdmi *hdmi = notifier_to_hdmi(nb);
> >
> > if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
>
> Then you also can drop the first two of the three checks above. If I'm not
> mistaken, in a HDMI / LCD set up, if this notifier is called for the LCD
> panel, hdmi will wtill point to the HDMI-related sh_hdmi object, whose
> ->info will then mismatch the info pointer, derived from the notifier
> "data" pointer.
That's correct. The first two checks don't hurt, but will always be false.
I'll remove them.
> > return NOTIFY_DONE;
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 02/57] fbdev: sh_mobile_lcdc: Mark init-only symbols with
From: Guennadi Liakhovetski @ 2011-12-14 11:07 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-3-git-send-email-laurent.pinchart@ideasonboard.com>
On Wed, 14 Dec 2011, Laurent Pinchart wrote:
> Hi Guennadi,
>
> On Tuesday 13 December 2011 23:23:32 Guennadi Liakhovetski wrote:
> > On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> > > default_720p and sh_mobile_lcdc_check_interface are used at device
> > > initialization time only. Mark them as __devinitconst and __devinit
> > > respectively.
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > ---
> > >
> > > drivers/video/sh_mobile_lcdcfb.c | 5 +++--
> > > 1 files changed, 3 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/video/sh_mobile_lcdcfb.c
> > > b/drivers/video/sh_mobile_lcdcfb.c index 8b18360..a6bf4fb 100644
> > > --- a/drivers/video/sh_mobile_lcdcfb.c
> > > +++ b/drivers/video/sh_mobile_lcdcfb.c
> > > @@ -1459,7 +1459,7 @@ static int sh_mobile_lcdc_notify(struct
> > > notifier_block *nb,
> > >
> > > * Probe/remove and driver init/exit
> > > */
> > >
> > > -static const struct fb_videomode default_720p = {
> > > +static const struct fb_videomode default_720p __devinitconst = {
> > >
> > > .name = "HDMI 720p",
> > > .xres = 1280,
> > > .yres = 720,
> > >
> > > @@ -1528,7 +1528,8 @@ static int sh_mobile_lcdc_remove(struct
> > > platform_device *pdev)
> > >
> > > return 0;
> > >
> > > }
> > >
> > > -static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan
> > > *ch) +static int __devinit
> > > +sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
> >
> > Personally, I don't like this type of line splitting very much, I prefer
> > the grep output to show the function type and all attributes, but this,
> > certainly, would not be the reason to change this specific hunk:-) But
> > this might be: the whole file so far has all function definitions at least
> > up to and including the first parameter on one line, so, I find, this
> > change would introduce an inconsistency in the file style. The line would
> > __only__ be 83 characters long if you put it all on one line. I think, it
> > would look better then:-)
>
> It's a matter of limits, as usual... I find 80 to be a nice limit, although in
> some cases I'm fine with exceeding it (one example is a long list of #defines
> with a small comment describing each macro, as in the list of FOURCCs in
> linux/videodev2.h for instance). For code I try to respect the 80 characters
> limit. Another reason is that it produces checkpatch.pl warnings, which force
> me to manually look at all the warnings to check which ones are acceptable.
>
> Regarding consistency, other patches in this series use the same style, so
> that function won't feel alone anymore ;-)
>
> I can change this (and other instances of the same coding style) if you
> insist. BTW, a possible improvement would be to shorten the sh_mobile_lcdc_
> prefix. I find it too long, and I was thinking about reducing it to shm_lcdc_
> (although shm reffers to shared memory, so that might not be the best idea).
How about sh_lcdc?
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 11/57] fbdev: sh_mobile_lcdc: Handle HDMI/MIPI transmitter device directly
From: Laurent Pinchart @ 2011-12-14 11:10 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-12-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Guennadi,
On Wednesday 14 December 2011 01:03:06 Guennadi Liakhovetski wrote:
> On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> > Pass a pointer to the transmitter device through platform data, retrieve
> > the corresponding sh_mobile_lcdc_entity structure in the probe method
> > and call the transmitter display_on/off methods directly.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >
> > drivers/video/sh_mobile_lcdcfb.c | 33
> > ++++++++++++++++++++++++++++----- drivers/video/sh_mobile_lcdcfb.h |
> > 2 ++
> > include/video/sh_mobile_lcdc.h | 2 ++
> > 3 files changed, 32 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/video/sh_mobile_lcdcfb.c
> > b/drivers/video/sh_mobile_lcdcfb.c index afa1fac..f1bbae6 100644
> > --- a/drivers/video/sh_mobile_lcdcfb.c
> > +++ b/drivers/video/sh_mobile_lcdcfb.c
> > @@ -338,6 +338,13 @@ static void sh_mobile_lcdc_deferred_io_touch(struct
> > fb_info *info)
> >
> > static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
> > {
> >
> > struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
> >
> > + int ret;
> > +
> > + if (ch->tx_dev) {
> > + ret = ch->tx_dev->ops->display_on(ch->tx_dev, ch->info);
>
> ->ops or ->display_o{n,ff}() cannot be NULL?
They must be provided, at least with the transmitters we currently have. This
code will likely get reworked to support things like HDMI-on-DSI, so I don't
think adding a pre
> also
>
> + int ret = ch->tx_dev->ops->display_on(ch->tx_dev, ch->info);
>
> would suffice;-)
Or even if (ch->tx_dev->ops->display_on(ch->tx_dev, ch->info) < 0)
I'll fix that.
> > + if (ret < 0)
> > + return;
> > + }
> >
> > /* HDMI must be enabled before LCDC configuration */
> > if (board_cfg->display_on && try_module_get(board_cfg->owner)) {
> >
> > @@ -354,6 +361,9 @@ static void sh_mobile_lcdc_display_off(struct
> > sh_mobile_lcdc_chan *ch)
> >
> > board_cfg->display_off(board_cfg->board_data);
> > module_put(board_cfg->owner);
> >
> > }
> >
> > +
> > + if (ch->tx_dev)
> > + ch->tx_dev->ops->display_off(ch->tx_dev);
> >
> > }
> >
> > /*
> > -----------------------------------------------------------------------
> > ------
> >
> > @@ -1490,18 +1500,21 @@ static int sh_mobile_lcdc_remove(struct
> > platform_device *pdev)
> >
> > sh_mobile_lcdc_stop(priv);
> >
> > for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
> >
> > - info = priv->ch[i].info;
> > + struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
> >
> > + info = ch->info;
> >
> > if (!info || !info->device)
> >
> > continue;
> >
> > - if (priv->ch[i].sglist)
> > - vfree(priv->ch[i].sglist);
> > + if (ch->tx_dev)
> > + module_put(ch->cfg.tx_dev->dev.driver->owner);
>
> This is now the same ->owner, as the one taken in your
> sh_mobile_lcdc_display_o{n,ff}() functions? IIUC, you're now adding this
> new ->owner field to later (17/57) remove the original one?
It's the same owner, yes. The idea is to get a reference to the transmitter
device module at probe() time and release it at remove() time instead of doing
so in display_on() and display_off(), and to remove the owner field hack from
platform data.
> > +
> > + if (ch->sglist)
> > + vfree(ch->sglist);
> >
> > if (info->screen_base)
> >
> > dma_free_coherent(&pdev->dev, info->fix.smem_len,
> >
> > - info->screen_base,
> > - priv->ch[i].dma_handle);
> > + info->screen_base, ch->dma_handle);
> >
> > fb_dealloc_cmap(&info->cmap);
> > framebuffer_release(info);
> >
> > }
> >
> > @@ -1596,6 +1609,16 @@ sh_mobile_lcdc_channel_init(struct
> > sh_mobile_lcdc_priv *priv,
> >
> > info->pseudo_palette = &ch->pseudo_palette;
> > info->flags = FBINFO_FLAG_DEFAULT;
> >
> > + if (cfg->tx_dev) {
> > + if (!cfg->tx_dev->dev.driver ||
> > + !try_module_get(cfg->tx_dev->dev.driver->owner)) {
> > + dev_warn(priv->dev, "unable to get transmitter "
> > + "device\n");
>
> Grrr... Pleeeease, don't split strings. If you really have to program on
> vt220;-) at least do
>
> + dev_warn(priv->dev,
> + "unable to get transmitter device\n");
Sorry about that. Will fix.
> > + return -EINVAL;
> > + }
> > + ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
> > + }
> > +
> >
> > /* Iterate through the modes to validate them and find the highest
> >
> > * resolution.
> > */
> >
> > diff --git a/drivers/video/sh_mobile_lcdcfb.h
> > b/drivers/video/sh_mobile_lcdcfb.h index d79e5aa..9601b92 100644
> > --- a/drivers/video/sh_mobile_lcdcfb.h
> > +++ b/drivers/video/sh_mobile_lcdcfb.h
> > @@ -41,6 +41,8 @@ struct sh_mobile_lcdc_entity {
> >
> > */
> >
> > struct sh_mobile_lcdc_chan {
> >
> > struct sh_mobile_lcdc_priv *lcdc;
> >
> > + struct sh_mobile_lcdc_entity *tx_dev;
> > +
> >
> > unsigned long *reg_offs;
> > unsigned long ldmt1r_value;
> > unsigned long enabled; /* ME and SE in LDCNT2R */
> >
> > diff --git a/include/video/sh_mobile_lcdc.h
> > b/include/video/sh_mobile_lcdc.h index fe30b75..0ec59e1 100644
> > --- a/include/video/sh_mobile_lcdc.h
> > +++ b/include/video/sh_mobile_lcdc.h
> > @@ -186,6 +186,8 @@ struct sh_mobile_lcdc_chan_cfg {
> >
> > struct sh_mobile_lcdc_bl_info bl_info;
> > struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
> > struct sh_mobile_meram_cfg *meram_cfg;
> >
> > +
> > + struct platform_device *tx_dev; /* HDMI/MIPI transmitter device */
>
> "MIPI" is too generic, IMHO
Will HDMI/DSI do ?
> Hm, could we, maybe, have different names for sh_mobile_lcdc_chan::tx_dev
> and sh_mobile_lcdc_chan_cfg::tx_dev?;-)
Sure. Do you have any suggestion ? :-)
> > };
> >
> > struct sh_mobile_lcdc_info {
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 33/57] fbdev: sh_mobile_lcdc: Add sh_mobile_format_info() function
From: Laurent Pinchart @ 2011-12-14 11:30 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-34-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Damian,
On Wednesday 14 December 2011 04:04:52 Damian Hobson-Garcia wrote:
> On 2011/12/13 23:02, Laurent Pinchart wrote:
> > --- a/drivers/video/sh_mobile_lcdcfb.c
> > +++ b/drivers/video/sh_mobile_lcdcfb.c
> > @@ -447,6 +447,75 @@ static int sh_mobile_lcdc_display_notify(struct
> > sh_mobile_lcdc_chan *ch,
> >
> > * Format helpers
> > */
> >
> > +struct sh_mobile_lcdc_format_info {
> > + u32 fourcc;
> > + unsigned int bpp;
> > + bool yuv;
> > + u32 lddfr;
> > +};
> > +
> > +static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[]
> > = { + {
> > + .fourcc = V4L2_PIX_FMT_RGB565,
> > + .bpp = 12,
>
> I think that this should be 16 instead of 12.
Oops, you're right. Thanks. I'll fix that.
> > @@ -665,37 +726,20 @@ static void __sh_mobile_lcdc_start(struct
> > sh_mobile_lcdc_priv *priv)
> >
> > /* Setup geometry, format, frame buffer memory and operation mode. */
> > for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
> >
> > + const struct sh_mobile_lcdc_format_info *format;
> > + u32 fourcc;
> > +
> >
> > ch = &priv->ch[k];
> > if (!ch->enabled)
> >
> > continue;
> >
> > sh_mobile_lcdc_geometry(ch);
> >
> > - switch (sh_mobile_format_fourcc(&ch->info->var)) {
> > - case V4L2_PIX_FMT_RGB565:
> > - tmp = LDDFR_PKF_RGB16;
> > - break;
> > - case V4L2_PIX_FMT_BGR24:
> > - tmp = LDDFR_PKF_RGB24;
> > - break;
> > - case V4L2_PIX_FMT_BGR32:
> > - tmp = LDDFR_PKF_ARGB32;
> > - break;
> > - case V4L2_PIX_FMT_NV12:
> > - case V4L2_PIX_FMT_NV21:
> > - tmp = LDDFR_CC | LDDFR_YF_420;
> > - break;
> > - case V4L2_PIX_FMT_NV16:
> > - case V4L2_PIX_FMT_NV61:
> > - tmp = LDDFR_CC | LDDFR_YF_422;
> > - break;
> > - case V4L2_PIX_FMT_NV24:
> > - case V4L2_PIX_FMT_NV42:
> > - tmp = LDDFR_CC | LDDFR_YF_444;
> > - break;
> > - }
> > + fourcc = sh_mobile_format_fourcc(&ch->info->var);
> > + format = sh_mobile_format_info(fourcc);
> > + tmp = format->lddfr;
>
> Do you need to check if format is NULL here?
The fourcc is validated in both sh_mobile_lcdc_channel_init() (for the value
passed to the driver through platform data) and sh_mobile_check_var() (for the
value requested by userspace). format should thus never be NULL here.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 02/57] fbdev: sh_mobile_lcdc: Mark init-only symbols with __devinit(const)
From: Laurent Pinchart @ 2011-12-14 12:30 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-3-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Guennadi,
On Wednesday 14 December 2011 12:07:26 Guennadi Liakhovetski wrote:
> On Wed, 14 Dec 2011, Laurent Pinchart wrote:
> > On Tuesday 13 December 2011 23:23:32 Guennadi Liakhovetski wrote:
> > > On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> > > > default_720p and sh_mobile_lcdc_check_interface are used at device
> > > > initialization time only. Mark them as __devinitconst and __devinit
> > > > respectively.
> > > >
> > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > ---
> > > >
> > > > drivers/video/sh_mobile_lcdcfb.c | 5 +++--
> > > > 1 files changed, 3 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/drivers/video/sh_mobile_lcdcfb.c
> > > > b/drivers/video/sh_mobile_lcdcfb.c index 8b18360..a6bf4fb 100644
> > > > --- a/drivers/video/sh_mobile_lcdcfb.c
> > > > +++ b/drivers/video/sh_mobile_lcdcfb.c
> > > > @@ -1459,7 +1459,7 @@ static int sh_mobile_lcdc_notify(struct
> > > > notifier_block *nb,
> > > >
> > > > * Probe/remove and driver init/exit
> > > > */
> > > >
> > > > -static const struct fb_videomode default_720p = {
> > > > +static const struct fb_videomode default_720p __devinitconst = {
> > > >
> > > > .name = "HDMI 720p",
> > > > .xres = 1280,
> > > > .yres = 720,
> > > >
> > > > @@ -1528,7 +1528,8 @@ static int sh_mobile_lcdc_remove(struct
> > > > platform_device *pdev)
> > > >
> > > > return 0;
> > > >
> > > > }
> > > >
> > > > -static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan
> > > > *ch) +static int __devinit
> > > > +sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
> > >
> > > Personally, I don't like this type of line splitting very much, I
> > > prefer the grep output to show the function type and all attributes,
> > > but this, certainly, would not be the reason to change this specific
> > > hunk:-) But this might be: the whole file so far has all function
> > > definitions at least up to and including the first parameter on one
> > > line, so, I find, this change would introduce an inconsistency in the
> > > file style. The line would __only__ be 83 characters long if you put
> > > it all on one line. I think, it would look better then:-)
> >
> > It's a matter of limits, as usual... I find 80 to be a nice limit,
> > although in some cases I'm fine with exceeding it (one example is a long
> > list of #defines with a small comment describing each macro, as in the
> > list of FOURCCs in linux/videodev2.h for instance). For code I try to
> > respect the 80 characters limit. Another reason is that it produces
> > checkpatch.pl warnings, which force me to manually look at all the
> > warnings to check which ones are acceptable.
> >
> > Regarding consistency, other patches in this series use the same style,
> > so that function won't feel alone anymore ;-)
> >
> > I can change this (and other instances of the same coding style) if you
> > insist. BTW, a possible improvement would be to shorten the
> > sh_mobile_lcdc_ prefix. I find it too long, and I was thinking about
> > reducing it to shm_lcdc_ (although shm reffers to shared memory, so that
> > might not be the best idea).
>
> How about sh_lcdc?
Sounds good to me. Does anyone have an objection ?
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH 1/2] offb: Fix bug in calculating requested vram size
From: Benjamin Herrenschmidt @ 2011-12-14 23:58 UTC (permalink / raw)
To: linux-fbdev; +Cc: linuxppc-dev, kvm-ppc
From 448820776363da565f221c020f4ccb3c610faec3 Mon Sep 17 00:00:00 2001
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Wed, 14 Dec 2011 16:52:02 +1100
Subject:
We used to try to request 8 times more vram than needed, which would
fail if the card has a too small BAR (observed with qemu).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/video/offb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
(I'm happy to carry that in the powerpc tree)
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index cb163a5..915acae 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -381,7 +381,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
int pitch, unsigned long address,
int foreign_endian, struct device_node *dp)
{
- unsigned long res_size = pitch * height * (depth + 7) / 8;
+ unsigned long res_size = pitch * height;
struct offb_par *par = &default_par;
unsigned long res_start = address;
struct fb_fix_screeninfo *fix;
^ permalink raw reply related
* [PATCH 2/2] offb: Add palette hack for qemu "standard vga"
From: Benjamin Herrenschmidt @ 2011-12-14 23:58 UTC (permalink / raw)
To: linux-fbdev; +Cc: linuxppc-dev, kvm-ppc
We rename the mach64 hack to "simple" since that's also applicable
to anything using VGA-style DAC IO ports (set to 8-bit DAC) and we
use it for qemu vga.
Note that this is keyed on a device-tree "compatible" property that
is currently only set by an upcoming version of SLOF when using the
qemu "pseries" platform. This is on purpose as other qemu ppc platforms
using OpenBIOS aren't properly setting the DAC to 8-bit at the time of
the writing of this patch.
We can fix OpenBIOS later to do that and add the required property, in
which case it will be matched by this change.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
drivers/video/offb.c | 19 +++++++++++++++----
1 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 915acae..da7cf79 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -41,13 +41,14 @@
/* Supported palette hacks */
enum {
cmap_unknown,
- cmap_m64, /* ATI Mach64 */
+ cmap_simple, /* ATI Mach64 */
cmap_r128, /* ATI Rage128 */
cmap_M3A, /* ATI Rage Mobility M3 Head A */
cmap_M3B, /* ATI Rage Mobility M3 Head B */
cmap_radeon, /* ATI Radeon */
cmap_gxt2000, /* IBM GXT2000 */
cmap_avivo, /* ATI R5xx */
+ cmap_qemu, /* qemu vga */
};
struct offb_par {
@@ -138,7 +139,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
return 0;
switch (par->cmap_type) {
- case cmap_m64:
+ case cmap_simple:
writeb(regno, par->cmap_adr);
writeb(red, par->cmap_data);
writeb(green, par->cmap_data);
@@ -208,7 +209,7 @@ static int offb_blank(int blank, struct fb_info *info)
if (blank)
for (i = 0; i < 256; i++) {
switch (par->cmap_type) {
- case cmap_m64:
+ case cmap_simple:
writeb(i, par->cmap_adr);
for (j = 0; j < 3; j++)
writeb(0, par->cmap_data);
@@ -350,7 +351,7 @@ static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp
par->cmap_adr ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
par->cmap_data = par->cmap_adr + 1;
- par->cmap_type = cmap_m64;
+ par->cmap_type = cmap_simple;
} else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
of_device_is_compatible(dp, "pci1014,21c"))) {
par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
@@ -371,6 +372,16 @@ static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp
par->cmap_type = cmap_avivo;
}
of_node_put(pciparent);
+ } else if (dp && of_device_is_compatible(dp, "qemu,std-vga")) {
+ const u32 io_of_addr[3] = { 0x01000000, 0x0, 0x0 };
+ u64 io_addr = of_translate_address(dp, io_of_addr);
+ if (io_addr != OF_BAD_ADDR) {
+ par->cmap_adr = ioremap(io_addr + 0x3c8, 2);
+ if (par->cmap_adr) {
+ par->cmap_type = cmap_simple;
+ par->cmap_data = par->cmap_adr + 1;
+ }
+ }
}
info->fix.visual = (par->cmap_type != cmap_unknown) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
^ permalink raw reply related
* Re: [PATCH 47/57] fbdev: sh_mobile_meram: Use genalloc to manage
From: Damian Hobson-Garcia @ 2011-12-15 2:43 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-48-git-send-email-laurent.pinchart@ideasonboard.com>
On 2011/12/13 23:02, Laurent Pinchart wrote:
> @@ -195,43 +196,40 @@ static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
> test_bit(new->cache_icb, &priv->used_icb))
> return 1;
>
> - for (i = 0; i < MERAM_ICB_NUM; i++) {
> - if (!test_bit(i, &priv->used_icb))
> - continue;
> -
> - used_start = MERAM_CACHE_START(priv->icbs[i].region);
> - used_end = MERAM_CACHE_END(priv->icbs[i].region);
> - meram_start = new->meram_offset;
> - meram_end = new->meram_offset + new->meram_size;
> -
> - if ((meram_start >= used_start && meram_start < used_end) ||
> - (meram_end > used_start && meram_end < used_end))
> - return 1;
> - }
> -
> return 0;
> }
>
> -/* Mark the specified ICB as used. */
> -static void meram_mark(struct sh_mobile_meram_priv *priv,
> +/* Allocate memory for the ICBs and mark them as used. */
> +static int meram_alloc(struct sh_mobile_meram_priv *priv,
> const struct sh_mobile_meram_icb_cfg *new,
> int pixelformat)
> {
> + struct sh_mobile_meram_icb *marker = &priv->icbs[new->marker_icb];
> + unsigned long mem;
> +
> + mem = gen_pool_alloc(priv->pool, new->meram_size * 1024);
> + if (mem = 0)
> + return -ENOMEM;
> +
> __set_bit(new->marker_icb, &priv->used_icb);
> __set_bit(new->cache_icb, &priv->used_icb);
>
> - priv->icbs[new->marker_icb].region = MERAM_CACHE_SET(new->meram_offset,
> - new->meram_size);
> - priv->icbs[new->cache_icb].region = MERAM_CACHE_SET(new->meram_offset,
> - new->meram_size);
> - priv->icbs[new->marker_icb].current_reg = 1;
> - priv->icbs[new->marker_icb].pixelformat = pixelformat;
> + marker->offset = mem - priv->meram;
I might have missed this somewhere, but it doesn't look like priv->meram
is assigned anywhere.
Damian
--
Damian Hobson-Garcia
IGEL Co.,Ltd
http://www.igel.co.jp
^ permalink raw reply
* Re: [PATCH 48/57] fbdev: sh_mobile_meram: Allocate ICBs automatically
From: Damian Hobson-Garcia @ 2011-12-15 2:58 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-49-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Laurent,
On 2011/12/13 23:02, Laurent Pinchart wrote:
> Instead of manually specifying the ICBs to use in platform data,
> allocate them automatically at runtime.
>
> The MERAM registration function now returns a pointer to an opaque MERAM
> object, which is passed to the update and unregistration functions.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
So one concern that I have about this is in regards to sharing ICBs with
user-space drivers. Since there are user space drivers (via UIO) for
blocks like the VEU, that may want to have access to MERAM, we need
a way to communicate which ICBs are free to user space. With the
hard-coded platform data we could easily assume that kernel drivers
would use, for example, the upper 16 ICBs and so user-space drivers were
free to use the lower 16.
One simple temporary workaround might be to provide a range of useable
ICBs in the platform data. The MERAM memory allocation range can always
easily be tweaked by using the meram_resources structure.
Thanks,
Damian
^ permalink raw reply
* [PATCH 3/15] i810: fix module_param bool abuse.
From: Rusty Russell @ 2011-12-15 3:15 UTC (permalink / raw)
To: lkml - Kernel Mailing List; +Cc: Antonino Daplas
The driver says "module_param(ddc3, bool, 0);". But it's not a used
as a bool, it's used as a count.
Make it a bool.
Cc: Antonino Daplas <adaplas@gmail.com>
Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
drivers/video/i810/i810_main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -147,7 +147,7 @@ static int vyres __devinitdata;
static int sync __devinitdata;
static int extvga __devinitdata;
static int dcolor __devinitdata;
-static int ddc3 __devinitdata = 2;
+static bool ddc3 __devinitdata;
/*------------------------------------------------------------*/
@@ -1776,7 +1776,7 @@ static void __devinit i810_init_defaults
if (sync)
par->dev_flags |= ALWAYS_SYNC;
- par->ddc_num = ddc3;
+ par->ddc_num = (ddc3 ? 3 : 2);
if (bpp < 8)
bpp = 8;
@@ -1999,7 +1999,7 @@ static int __devinit i810fb_setup(char *
else if (!strncmp(this_opt, "dcolor", 6))
dcolor = 1;
else if (!strncmp(this_opt, "ddc3", 4))
- ddc3 = 3;
+ ddc3 = true;
else
mode_option = this_opt;
}
^ permalink raw reply
* Re: [PATCH 2/2] offb: Add palette hack for qemu "standard vga" framebuffer
From: Andreas Färber @ 2011-12-15 7:49 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linux-fbdev, linuxppc-dev, kvm-ppc
In-Reply-To: <1323907109.21839.28.camel@pasglop>
Am 15.12.2011 00:58, schrieb Benjamin Herrenschmidt:
> We rename the mach64 hack to "simple" since that's also applicable
> to anything using VGA-style DAC IO ports (set to 8-bit DAC) and we
> use it for qemu vga.
>
> Note that this is keyed on a device-tree "compatible" property that
> is currently only set by an upcoming version of SLOF when using the
> qemu "pseries" platform. This is on purpose as other qemu ppc platforms
> using OpenBIOS aren't properly setting the DAC to 8-bit at the time of
> the writing of this patch.
>
> We can fix OpenBIOS later to do that and add the required property, in
> which case it will be matched by this change.
Just let me know what's needed for OpenBIOS.
Is this just for -vga std as opposed to the default cirrus?
Cheers,
Andreas
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply
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