* Re: [PATCH RESEND] video: mxsfb: Fix colors display on lower color depth
From: Marek Vasut @ 2013-04-22 9:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366618310-7068-1-git-send-email-maxime.ripard@free-electrons.com>
Dear Maxime Ripard,
> The current code always registers as a 32 bits display, and uses the
> hardware to drop the MSB of each color to abjust to the interface width
> used by the panel.
>
> This results on 18 bits (and probably 16 bits display as well) in colors
> being displayed poorly, because the MSB are obviously the most important
> bits for each color definition.
>
> The default controller behaviour when using an interface width smaller
> than the color depth is to drop the LSBs of each color, which makes more
> sense because you lose the least important part of the color definition.
>
> So, to fix the colors display, just get back to the default controller
> behaviour.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Did you receive my latest email? Check M28EVK (imx28-m28evk.dts), it uses 18bit
LCD and works without this patch I think.
Best regards,
Marek Vasut
^ permalink raw reply
* Re: [PATCH RESEND] video: mxsfb: Fix colors display on lower color depth
From: Juergen Beisert @ 2013-04-22 9:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366618310-7068-1-git-send-email-maxime.ripard@free-electrons.com>
Hi Maxime,
Maxime Ripard wrote:
> The current code always registers as a 32 bits display, and uses the
> hardware to drop the MSB of each color to abjust to the interface width
> used by the panel.
>
> This results on 18 bits (and probably 16 bits display as well) in colors
> being displayed poorly, because the MSB are obviously the most important
> bits for each color definition.
But the "def_rgb666" bitfield description reports correctly to use bit 0..5
for each colour component in this mode. Maybe your userland program has a bug
and forgets to honor the bitfield description?
> The default controller behaviour when using an interface width smaller
> than the color depth is to drop the LSBs of each color, which makes more
> sense because you lose the least important part of the color definition.
>
> So, to fix the colors display, just get back to the default controller
> behaviour.
If you do this change, you also must adapt the "def_rgb666" bitfield
description.
This structure currently reports the lower 6 bits to be used for this mode:
blue -> 0..5 (skip 6/7)
green -> 8..13 (skip 14/15)
red -> 16..21 (skip 22/23).
> [...]
jbe
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | http://www.pengutronix.de/ |
^ permalink raw reply
* [PATCH RESEND] video: mxsfb: Fix colors display on lower color depth
From: Maxime Ripard @ 2013-04-22 8:11 UTC (permalink / raw)
To: linux-arm-kernel
The current code always registers as a 32 bits display, and uses the
hardware to drop the MSB of each color to abjust to the interface width
used by the panel.
This results on 18 bits (and probably 16 bits display as well) in colors
being displayed poorly, because the MSB are obviously the most important
bits for each color definition.
The default controller behaviour when using an interface width smaller
than the color depth is to drop the LSBs of each color, which makes more
sense because you lose the least important part of the color definition.
So, to fix the colors display, just get back to the default controller
behaviour.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
- Copied Sascha
drivers/video/mxsfb.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 755556c..2cfaf8b 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -424,11 +424,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
return -EINVAL;
case STMLCDIF_16BIT:
case STMLCDIF_18BIT:
- /* 24 bit to 18 bit mapping */
- ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
- * each colour component
- */
- break;
case STMLCDIF_24BIT:
/* real 24 bit */
break;
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] video: mxsfb: Fix colors display on lower color depth
From: Maxime Ripard @ 2013-04-22 8:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130418144838.GD2222@S2101-09.ap.freescale.net>
Hi Shawn,
Le 18/04/2013 16:48, Shawn Guo a écrit :
> Copy Sascha.
Ah, yes, sorry, I somehow got confused and thought you were the one that
wrote the driver.
I'll resend the patch.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH] uvesafb: Correct/simplify warning message
From: Wang YanQing @ 2013-04-22 1:19 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1366380325-2038-1-git-send-email-bp@alien8.de>
On Fri, Apr 19, 2013 at 04:05:25PM +0200, Borislav Petkov wrote:
> From: Borislav Petkov <bp@suse.de>
>
> Streamline it a bit. No functional change.
>
> Signed-off-by: Borislav Petkov <bp@suse.de>
> Cc: Wang YanQing <udknight@gmail.com>
> Cc: Michal Januszewski <spock@gentoo.org>
> Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
> Cc: linux-fbdev@vger.kernel.org
> ---
> drivers/video/uvesafb.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
> index d4284458377e..a309f9fabe8b 100644
> --- a/drivers/video/uvesafb.c
> +++ b/drivers/video/uvesafb.c
> @@ -819,8 +819,8 @@ static int uvesafb_vbe_init(struct fb_info *info)
> if (par->pmi_setpal || par->ypan) {
> if (__supported_pte_mask & _PAGE_NX) {
> par->pmi_setpal = par->ypan = 0;
> - printk(KERN_WARNING "uvesafb: NX protection is actively."
> - "We have better not to use the PMI.\n");
> + printk(KERN_WARNING "uvesafb: NX protection is active, "
> + "better not use the PMI.\n");
> } else {
> uvesafb_vbe_getpmi(task, par);
> }
> --
> 1.8.2.135.g7b592fa
Acked-by: Wang YanQing <udknight@gmail.com>
Thanks.
^ permalink raw reply
* [PATCH] MAINTAINERS: Add linux-samsung-soc list to all related entries
From: Tomasz Figa @ 2013-04-21 19:20 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-samsung-soc, linux-media, dri-devel, linux-fbdev,
alsa-devel, linux-mmc, kyungmin.park, k.debski, s.nawrocki,
jtp.park, t.stanislaws, inki.dae, jy0922.shim, sw0312.kim,
jg1.han, dh09.lee, sbkim73, linux, Tomasz Figa
Several entries in MAINTAINERS file related to Samsung SoCs do not point
to linux-samsung-soc mailing list, which is supposed to collect all
Samsung SoC-related threads, to ease following of Samsung SoC-related
work. This leads to a problem with people skipping this mailing list in
their posts, even though they are related to Samsung SoCs.
This patch adds pointers to linux-samsung-soc mailing list to affected
entries of MAINTAINERS file.
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6c0d68b..07cb8da 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1139,6 +1139,7 @@ F: arch/arm/mach-exynos*/
ARM/SAMSUNG MOBILE MACHINE SUPPORT
M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-s5pv210/mach-aquila.c
F: arch/arm/mach-s5pv210/mach-goni.c
@@ -1150,6 +1151,7 @@ M: Kyungmin Park <kyungmin.park@samsung.com>
M: Kamil Debski <k.debski@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/media/platform/s5p-g2d/
@@ -1158,6 +1160,7 @@ M: Kyungmin Park <kyungmin.park@samsung.com>
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/plat-samsung/include/plat/*fimc*
F: drivers/media/platform/s5p-fimc/
@@ -1168,6 +1171,7 @@ M: Kamil Debski <k.debski@samsung.com>
M: Jeongtae Park <jtp.park@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/plat-samsung/s5p-dev-mfc.c
F: drivers/media/platform/s5p-mfc/
@@ -1177,6 +1181,7 @@ M: Kyungmin Park <kyungmin.park@samsung.com>
M: Tomasz Stanislawski <t.stanislaws@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/media/platform/s5p-tv/
@@ -2679,6 +2684,7 @@ M: Joonyoung Shim <jy0922.shim@samsung.com>
M: Seung-Woo Kim <sw0312.kim@samsung.com>
M: Kyungmin Park <kyungmin.park@samsung.com>
L: dri-devel@lists.freedesktop.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
S: Supported
F: drivers/gpu/drm/exynos
@@ -3142,6 +3148,7 @@ F: Documentation/extcon/
EXYNOS DP DRIVER
M: Jingoo Han <jg1.han@samsung.com>
L: linux-fbdev@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/video/exynos/exynos_dp*
F: include/video/exynos_dp*
@@ -3151,6 +3158,7 @@ M: Inki Dae <inki.dae@samsung.com>
M: Donghwa Lee <dh09.lee@samsung.com>
M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-fbdev@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/video/exynos/exynos_mipi*
F: include/video/exynos_mipi*
@@ -6892,12 +6900,14 @@ F: drivers/platform/x86/samsung-laptop.c
SAMSUNG AUDIO (ASoC) DRIVERS
M: Sangbeom Kim <sbkim73@samsung.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Supported
F: sound/soc/samsung
SAMSUNG FRAMEBUFFER DRIVER
M: Jingoo Han <jg1.han@samsung.com>
L: linux-fbdev@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/video/s3c-fb.c
@@ -7087,6 +7097,7 @@ F: drivers/mmc/host/sdhci-pltfm.[ch]
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
M: Ben Dooks <ben-linux@fluff.org>
L: linux-mmc@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/mmc/host/sdhci-s3c.c
--
1.8.2.1
^ permalink raw reply related
* Re: [PATCH v4 2/2] video: imxfb: Add DT support
From: Markus Pargmann @ 2013-04-21 8:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130418160614.GF4998@game.jcrosoft.org>
On Thu, Apr 18, 2013 at 06:06:14PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 15:03 Thu 18 Apr , Markus Pargmann wrote:
> > Add devicetree support for imx framebuffer driver. It uses the generic
> > display bindings and helper functions.
> >
> > Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
> > Cc: Fabio Estevam <festevam@gmail.com>
> > Cc: Mark Rutland <mark.rutland@arm.com>
> > ---
> >
> > Notes:
> > Changes in v4:
> > - Remove eukrea specific dmacr property.
> > - Add optional dmacr property. If not present, the dmacr reset value is not
> > changed.
> >
> > Changes in v3:
> > - Fix returncodes of of_read_mode function and print error messages
> > - Introduce a lower bound check for bits per pixel
> > - Calculate correct bytes per pixel value before using it for the calculation of
> > memory size
> > - Change DT property names
> >
> > Changes in v2:
> > - Removed pwmr register property
> > - Cleanup of devicetree binding documentation
> > - Use default values for pwmr and lscr1
> >
> > .../devicetree/bindings/video/fsl,imx-fb.txt | 51 ++++++
> > drivers/video/imxfb.c | 194 +++++++++++++++++----
> > 2 files changed, 210 insertions(+), 35 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> >
> > diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > new file mode 100644
> > index 0000000..aff16a4
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > @@ -0,0 +1,51 @@
> > +Freescale imx21 Framebuffer
> > +
> > +This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
> > +
> > +Required properties:
> > +- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
> > +- reg : Should contain 1 register ranges(address and length)
> > +- interrupts : One interrupt of the fb dev
> > +
> > +Required nodes:
> > +- display: Phandle to a display node as described in
> > + Documentation/devicetree/bindings/video/display-timing.txt
> > + Additional, the display node has to define properties:
> > + - fsl,bpp: Bits per pixel
> > + - fsl,pcr: LCDC PCR value
> > +
> > +Optional properties:
> > +- fsl,dmacr: DMA Control Register value. This is optional. By default, the
> > + register is not modified as recommended by the datasheet.
> > +- fsl,lscr1: LCDC Sharp Configuration Register value.
> > +
> > +Example:
> > +
> > + imxfb: fb@10021000 {
> > + compatible = "fsl,imx27-fb", "fsl,imx21-fb";
> you put both when in the doc you request one
Thanks, fixed.
> > + interrupts = <61>;
> > + reg = <0x10021000 0x1000>;
> > + display = <&display0>;
> > + };
> > +
> > + ...
> > +
> > + display0: display0 {
> > + model = "Primeview-PD050VL1";
> > + native-mode = <&timing_disp0>;
> > + fsl,bpp = <16>; /* non-standard but required */
> there is a generic binding bit-per-pixel use a cross other IP
I can't find a generic binding for that. There are only 2 other drivers
using a "bpp" property, but they both use it within different contexts.
tilcdc panel uses it within a "panel-info" property and via,vt8500-fb
within modes. So I think it would be better to use a clear distinction
because there is no generic binding. That was also suggested in comments
on version 2 of this patch:
https://patchwork.kernel.org/patch/2220511/
Regards,
Markus
> > + fsl,pcr = <0xf0c88080>; /* non-standard but required */
> > + display-timings {
> > + timing_disp0: 640x480 {
> > + hactive = <640>;
> > + vactive = <480>;
> > + hback-porch = <112>;
> > + hfront-porch = <36>;
> > + hsync-len = <32>;
> > + vback-porch = <33>;
> > + vfront-porch = <33>;
> > + vsync-len = <2>;
> > + clock-frequency = <25000000>;
> > + };
> > + };
> > + };
> > diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
> > index ef2b587..e0230f8 100644
> > --- a/drivers/video/imxfb.c
> > +++ b/drivers/video/imxfb.c
> > @@ -32,6 +32,12 @@
> > #include <linux/io.h>
> > #include <linux/math64.h>
> > #include <linux/uaccess.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +
> > +#include <video/of_display_timing.h>
> > +#include <video/of_videomode.h>
> > +#include <video/videomode.h>
> >
> > #include <linux/platform_data/video-imxfb.h>
> >
> > @@ -117,10 +123,11 @@
> > #define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
> > #define LGWCR_GWE (1 << 22)
> >
> > +#define IMXFB_LSCR1_DEFAULT 0x00120300
> > +
> > /* Used fb-mode. Can be set on kernel command line, therefore file-static. */
> > static const char *fb_mode;
> >
> > -
> > /*
> > * These are the bitfields for each
> > * display depth that we support.
> > @@ -192,6 +199,19 @@ static struct platform_device_id imxfb_devtype[] = {
> > };
> > MODULE_DEVICE_TABLE(platform, imxfb_devtype);
> >
> > +static struct of_device_id imxfb_of_dev_id[] = {
> > + {
> > + .compatible = "fsl,imx1-fb",
> > + .data = &imxfb_devtype[IMX1_FB],
> > + }, {
> > + .compatible = "fsl,imx21-fb",
> > + .data = &imxfb_devtype[IMX21_FB],
> > + }, {
> > + /* sentinel */
> > + }
> > +};
> > +MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
> > +
> > static inline int is_imx1_fb(struct imxfb_info *fbi)
> > {
> > return fbi->devtype = IMX1_FB;
> > @@ -324,6 +344,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
> > struct imx_fb_videomode *m;
> > int i;
> >
> > + if (!fb_mode)
> > + return &fbi->mode[0];
> > +
> > for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
> > if (!strcmp(m->mode.name, fb_mode))
> > return m;
> > @@ -479,6 +502,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
> > struct imxfb_info *fbi = bl_get_data(bl);
> > int brightness = bl->props.brightness;
> >
> > + if (!fbi->pwmr)
> > + return 0;
> > +
> > if (bl->props.power != FB_BLANK_UNBLANK)
> > brightness = 0;
> > if (bl->props.fb_blank != FB_BLANK_UNBLANK)
> > @@ -719,10 +745,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
> >
> > writel(fbi->pcr, fbi->regs + LCDC_PCR);
> > #ifndef PWMR_BACKLIGHT_AVAILABLE
> > - writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
> > + if (fbi->pwmr)
> > + writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
> > #endif
> > writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
> > - writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
> > +
> > + /* dmacr = 0 is no valid value, as we need DMA control marks. */
> > + if (fbi->dmacr)
> > + writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
> >
> > return 0;
> > }
> > @@ -758,13 +788,12 @@ static int imxfb_resume(struct platform_device *dev)
> > #define imxfb_resume NULL
> > #endif
> >
> > -static int __init imxfb_init_fbinfo(struct platform_device *pdev)
> > +static int imxfb_init_fbinfo(struct platform_device *pdev)
> > {
> > struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
> > struct fb_info *info = dev_get_drvdata(&pdev->dev);
> > struct imxfb_info *fbi = info->par;
> > - struct imx_fb_videomode *m;
> > - int i;
> > + struct device_node *np;
> >
> > pr_debug("%s\n",__func__);
> >
> > @@ -795,41 +824,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
> > info->fbops = &imxfb_ops;
> > info->flags = FBINFO_FLAG_DEFAULT |
> > FBINFO_READS_FAST;
> > - info->var.grayscale = pdata->cmap_greyscale;
> > - fbi->cmap_inverse = pdata->cmap_inverse;
> > - fbi->cmap_static = pdata->cmap_static;
> > - fbi->lscr1 = pdata->lscr1;
> > - fbi->dmacr = pdata->dmacr;
> > - fbi->pwmr = pdata->pwmr;
> > - fbi->lcd_power = pdata->lcd_power;
> > - fbi->backlight_power = pdata->backlight_power;
> > -
> > - for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
> > - info->fix.smem_len = max_t(size_t, info->fix.smem_len,
> > - m->mode.xres * m->mode.yres * m->bpp / 8);
> > + if (pdata) {
> > + info->var.grayscale = pdata->cmap_greyscale;
> > + fbi->cmap_inverse = pdata->cmap_inverse;
> > + fbi->cmap_static = pdata->cmap_static;
> > + fbi->lscr1 = pdata->lscr1;
> > + fbi->dmacr = pdata->dmacr;
> > + fbi->pwmr = pdata->pwmr;
> > + fbi->lcd_power = pdata->lcd_power;
> > + fbi->backlight_power = pdata->backlight_power;
> > + } else {
> > + np = pdev->dev.of_node;
> > + info->var.grayscale = of_property_read_bool(np,
> > + "cmap-greyscale");
> > + fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
> > + fbi->cmap_static = of_property_read_bool(np, "cmap-static");
> > +
> > + fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
> > + of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
> > +
> > + of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
> > +
> > + /* These two function pointers could be used by some specific
> > + * platforms. */
> > + fbi->lcd_power = NULL;
> > + fbi->backlight_power = NULL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
> > + struct imx_fb_videomode *imxfb_mode)
> > +{
> > + int ret;
> > + struct fb_videomode *of_mode = &imxfb_mode->mode;
> > + u32 bpp;
> > + u32 pcr;
> > +
> > + ret = of_property_read_string(np, "model", &of_mode->name);
> > + if (ret)
> > + of_mode->name = NULL;
> > +
> > + ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
> > + if (ret) {
> > + dev_err(dev, "Failed to get videomode from DT\n");
> > + return ret;
> > + }
> > +
> > + ret = of_property_read_u32(np, "fsl,bpp", &bpp);
> > + ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
> > +
> > + if (ret) {
> > + dev_err(dev, "Failed to read bpp and pcr from DT\n");
> > + return -EINVAL;
> > + }
> > +
> > + if (bpp < 1 || bpp > 255) {
> > + dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
> > + return -EINVAL;
> > + }
> > +
> > + imxfb_mode->bpp = bpp;
> > + imxfb_mode->pcr = pcr;
> >
> > return 0;
> > }
> >
> > -static int __init imxfb_probe(struct platform_device *pdev)
> > +static int imxfb_probe(struct platform_device *pdev)
> > {
> > struct imxfb_info *fbi;
> > struct fb_info *info;
> > struct imx_fb_platform_data *pdata;
> > struct resource *res;
> > + struct imx_fb_videomode *m;
> > + const struct of_device_id *of_id;
> > int ret, i;
> > + int bytes_per_pixel;
> >
> > dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
> >
> > + of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
> > + if (of_id)
> > + pdev->id_entry = of_id->data;
> > +
> > res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > if (!res)
> > return -ENODEV;
> >
> > pdata = pdev->dev.platform_data;
> > - if (!pdata) {
> > - dev_err(&pdev->dev,"No platform_data available\n");
> > - return -ENOMEM;
> > - }
> >
> > info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
> > if (!info)
> > @@ -837,15 +920,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
> >
> > fbi = info->par;
> >
> > - if (!fb_mode)
> > - fb_mode = pdata->mode[0].mode.name;
> > -
> > platform_set_drvdata(pdev, info);
> >
> > ret = imxfb_init_fbinfo(pdev);
> > if (ret < 0)
> > goto failed_init;
> >
> > + if (pdata) {
> > + if (!fb_mode)
> > + fb_mode = pdata->mode[0].mode.name;
> > +
> > + fbi->mode = pdata->mode;
> > + fbi->num_modes = pdata->num_modes;
> > + } else {
> > + struct device_node *display_np;
> > + fb_mode = NULL;
> > +
> > + display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
> > + if (!display_np) {
> > + dev_err(&pdev->dev, "No display defined in devicetree\n");
> > + ret = -EINVAL;
> > + goto failed_of_parse;
> > + }
> > +
> > + /*
> > + * imxfb does not support more modes, we choose only the native
> > + * mode.
> > + */
> > + fbi->num_modes = 1;
> > +
> > + fbi->mode = devm_kzalloc(&pdev->dev,
> > + sizeof(struct imx_fb_videomode), GFP_KERNEL);
> > + if (!fbi->mode) {
> > + ret = -ENOMEM;
> > + goto failed_of_parse;
> > + }
> > +
> > + ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
> > + if (ret)
> > + goto failed_of_parse;
> > + }
> > +
> > + /* Calculate maximum bytes used per pixel. In most cases this should
> > + * be the same as m->bpp/8 */
> > + m = &fbi->mode[0];
> > + bytes_per_pixel = (m->bpp + 7) / 8;
> > + for (i = 0; i < fbi->num_modes; i++, m++)
> > + info->fix.smem_len = max_t(size_t, info->fix.smem_len,
> > + m->mode.xres * m->mode.yres * bytes_per_pixel);
> > +
> > res = request_mem_region(res->start, resource_size(res),
> > DRIVER_NAME);
> > if (!res) {
> > @@ -878,7 +1001,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > goto failed_ioremap;
> > }
> >
> > - if (!pdata->fixed_screen_cpu) {
> > + /* Seems not being used by anyone, so no support for oftree */
> > + if (!pdata || !pdata->fixed_screen_cpu) {
> > fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
> > fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
> > fbi->map_size, &fbi->map_dma, GFP_KERNEL);
> > @@ -903,18 +1027,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > info->fix.smem_start = fbi->screen_dma;
> > }
> >
> > - if (pdata->init) {
> > + if (pdata && pdata->init) {
> > ret = pdata->init(fbi->pdev);
> > if (ret)
> > goto failed_platform_init;
> > }
> >
> > - fbi->mode = pdata->mode;
> > - fbi->num_modes = pdata->num_modes;
> >
> > INIT_LIST_HEAD(&info->modelist);
> > - for (i = 0; i < pdata->num_modes; i++)
> > - fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
> > + for (i = 0; i < fbi->num_modes; i++)
> > + fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
> >
> > /*
> > * This makes sure that our colour bitfield
> > @@ -944,10 +1066,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > failed_register:
> > fb_dealloc_cmap(&info->cmap);
> > failed_cmap:
> > - if (pdata->exit)
> > + if (pdata && pdata->exit)
> > pdata->exit(fbi->pdev);
> > failed_platform_init:
> > - if (!pdata->fixed_screen_cpu)
> > + if (pdata && !pdata->fixed_screen_cpu)
> > dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
> > fbi->map_dma);
> > failed_map:
> > @@ -956,6 +1078,7 @@ failed_ioremap:
> > failed_getclock:
> > release_mem_region(res->start, resource_size(res));
> > failed_req:
> > +failed_of_parse:
> > kfree(info->pseudo_palette);
> > failed_init:
> > platform_set_drvdata(pdev, NULL);
> > @@ -980,7 +1103,7 @@ static int imxfb_remove(struct platform_device *pdev)
> > unregister_framebuffer(info);
> >
> > pdata = pdev->dev.platform_data;
> > - if (pdata->exit)
> > + if (pdata && pdata->exit)
> > pdata->exit(fbi->pdev);
> >
> > fb_dealloc_cmap(&info->cmap);
> > @@ -1009,6 +1132,7 @@ static struct platform_driver imxfb_driver = {
> > .shutdown = imxfb_shutdown,
> > .driver = {
> > .name = DRIVER_NAME,
> > + .of_match_table = imxfb_of_dev_id,
> > },
> > .id_table = imxfb_devtype,
> > };
> > --
> > 1.8.1.5
> >
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Darlehen anbieten
From: jordan.buechler @ 2013-04-19 21:59 UTC (permalink / raw)
To: linux-fbdev
Sehr geehrter Kunde,
Sie benötigen Darlehen zu zahlen Sie Ihre Schulden oder begleichen Sie Ihre Rechnung? Sind Sie in irgendeiner finanziellen Schlamassel oder benötigen Sie Fonds zu starten Ihr eigenes Geschäft? NORTON FINANCE
ist bereit, Ihnen Kredit zu 3% Zins. wenn interessiert füllen das Anmeldeformular unten für die dringende Bearbeitung Ihres Darlehens. Kontakt: nortonfinan@blumail.org
Vorname: ........................
Adresse: ...........................
Land: ...........................
Telefonnummer: ......................
Beruf: .............. .........
Monatliches Einkommen: ...................
Zweck des Darlehens: ...................
Benötigte Menge ....................
Dauer der Ausleihe: .....................
Alter: ...............................
Mit freundlichen Grüßen,
Sarah Bell-
Loan Officer
E-Mail: nortonfinan@blumail.org
Tells: Tell: +447035958575
Fax: +448447742385
^ permalink raw reply
* [PATCH] uvesafb: Correct/simplify warning message
From: Borislav Petkov @ 2013-04-19 14:05 UTC (permalink / raw)
To: linux-fbdev
From: Borislav Petkov <bp@suse.de>
Streamline it a bit. No functional change.
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Wang YanQing <udknight@gmail.com>
Cc: Michal Januszewski <spock@gentoo.org>
Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: linux-fbdev@vger.kernel.org
---
drivers/video/uvesafb.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index d4284458377e..a309f9fabe8b 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -819,8 +819,8 @@ static int uvesafb_vbe_init(struct fb_info *info)
if (par->pmi_setpal || par->ypan) {
if (__supported_pte_mask & _PAGE_NX) {
par->pmi_setpal = par->ypan = 0;
- printk(KERN_WARNING "uvesafb: NX protection is actively."
- "We have better not to use the PMI.\n");
+ printk(KERN_WARNING "uvesafb: NX protection is active, "
+ "better not use the PMI.\n");
} else {
uvesafb_vbe_getpmi(task, par);
}
--
1.8.2.135.g7b592fa
^ permalink raw reply related
* [RFC v2] video: ARM CLCD: Add DT & CDF support
From: Pawel Moll @ 2013-04-18 17:33 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel, Laurent Pinchart, Linus Walleij, Pawel Moll
In-Reply-To: <20130418102444.GL14496@n2100.arm.linux.org.uk>
This patch adds basic DT bindings for the PL11x CLCD cells
and make their fbdev driver use them, together with the
Common Display Framework.
The DT provides information about the hardware configuration
and limitations (eg. the largest supported resolution)
but the video modes come exclusively from the Common
Display Framework drivers, referenced to by the standard CDF
binding.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
.../devicetree/bindings/video/arm,pl11x.txt | 35 +++
drivers/video/Kconfig | 1 +
drivers/video/amba-clcd.c | 247 ++++++++++++++++++++
include/linux/amba/clcd.h | 2 +
4 files changed, 285 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/arm,pl11x.txt
diff --git a/Documentation/devicetree/bindings/video/arm,pl11x.txt b/Documentation/devicetree/bindings/video/arm,pl11x.txt
new file mode 100644
index 0000000..ee9534a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/arm,pl11x.txt
@@ -0,0 +1,35 @@
+* ARM PrimeCell Color LCD Controller (CLCD) PL110/PL111
+
+Required properties:
+
+- compatible : must be one of:
+ "arm,pl110", "arm,primecell"
+ "arm,pl111", "arm,primecell"
+- reg : base address and size of the control registers block
+- interrupts : the combined interrupt
+- clocks : phandles to the CLCD (pixel) clock and the APB clocks
+- clock-names : "clcdclk", "apb_pclk"
+- display : phandle to the display entity connected to the controller
+
+Optional properties:
+
+- label : string describing the controller location and/or usage
+- video-ram : phandle to DT node of the specialized video RAM to be used
+- max-hactive : maximum frame buffer width in pixels
+- max-vactive : maximum frame buffer height in pixels
+- max-bpp : maximum number of bits per pixel
+- big-endian-pixels : defining this property makes the pixel bytes being
+ accessed in Big Endian organization
+
+Example:
+
+ clcd@1f0000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x1f0000 0x1000>;
+ interrupts = <14>;
+ clocks = <&v2m_oscclk1>, <&smbclk>;
+ clock-names = "clcdclk", "apb_pclk";
+ label = "IOFPGA CLCD";
+ video-ram = <&v2m_vram>;
+ display = <&v2m_muxfpga>;
+ };
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 281e548..bad8166 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -340,6 +340,7 @@ config FB_ARMCLCD
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS if OF
help
This framebuffer device driver is for the ARM PrimeCell PL110
Colour LCD controller. ARM PrimeCells provide the building
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0a2cce7..853f74c 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -25,6 +25,11 @@
#include <linux/amba/clcd.h>
#include <linux/clk.h>
#include <linux/hardirq.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <video/display.h>
+#include <video/videomode.h>
#include <asm/sizes.h>
@@ -62,6 +67,10 @@ static void clcdfb_disable(struct clcd_fb *fb)
{
u32 val;
+ if (fb->panel->display)
+ display_entity_set_state(fb->panel->display,
+ DISPLAY_ENTITY_STATE_OFF);
+
if (fb->board->disable)
fb->board->disable(fb);
@@ -115,6 +124,11 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
*/
if (fb->board->enable)
fb->board->enable(fb);
+
+ if (fb->panel->display)
+ display_entity_set_state(fb->panel->display,
+ DISPLAY_ENTITY_STATE_ON);
+
}
static int
@@ -304,6 +318,13 @@ static int clcdfb_set_par(struct fb_info *info)
clcdfb_enable(fb, regs.cntl);
+ if (fb->panel->display) {
+ struct videomode mode;
+
+ videomode_from_fb_var_screeninfo(&fb->fb.var, &mode);
+ display_entity_update(fb->panel->display, &mode);
+ }
+
#ifdef DEBUG
printk(KERN_INFO
"CLCD: Registers set to\n"
@@ -542,6 +563,229 @@ static int clcdfb_register(struct clcd_fb *fb)
return ret;
}
+#if defined(CONFIG_OF)
+static int clcdfb_of_get_tft_parallel_panel(struct clcd_panel *panel,
+ struct display_entity_interface_params *params)
+{
+ int r = params->p.tft_parallel.r_bits;
+ int g = params->p.tft_parallel.g_bits;
+ int b = params->p.tft_parallel.b_bits;
+
+ /* Bypass pixel clock divider, data output on the falling edge */
+ panel->tim2 = TIM2_BCD | TIM2_IPC;
+
+ /* TFT display, vert. comp. interrupt at the start of the back porch */
+ panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
+
+ if (r >= 4 && g >= 4 && b >= 4)
+ panel->caps |= CLCD_CAP_444;
+ if (r >= 5 && g >= 5 && b >= 5)
+ panel->caps |= CLCD_CAP_5551;
+ if (r >= 5 && g >= 6 && b >= 5)
+ panel->caps |= CLCD_CAP_565;
+ if (r >= 8 && g >= 8 && b >= 8)
+ panel->caps |= CLCD_CAP_888;
+
+ if (params->p.tft_parallel.r_b_swapped)
+ panel->caps &= ~CLCD_CAP_RGB;
+ else
+ panel->caps &= ~CLCD_CAP_BGR;
+
+ return 0;
+}
+
+static int clcdfb_of_init_display(struct clcd_fb *fb)
+{
+ struct device_node *node = fb->dev->dev.of_node;
+ struct display_entity_interface_params params;
+ const struct videomode *modes;
+ int modes_num;
+ int best_mode = -1;
+ u32 max_bpp = 32;
+ u32 max_hactive = (u32)~0UL;
+ u32 max_vactive = (u32)~0UL;
+ unsigned int width, height;
+ char *mode_name;
+ int i, err;
+
+ fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
+ if (!fb->panel)
+ return -ENOMEM;
+
+ fb->panel->display = of_display_entity_get(node, 0);
+ if (!fb->panel->display)
+ return -EPROBE_DEFER;
+
+ modes_num = display_entity_get_modes(fb->panel->display, &modes);
+ if (modes_num < 0)
+ return modes_num;
+
+ /* Pick the "best" (the widest, then the highest) mode from the list */
+ of_property_read_u32(node, "max-hactive", &max_hactive);
+ of_property_read_u32(node, "max-vactive", &max_vactive);
+ for (i = 0; i < modes_num; i++) {
+ if (modes[i].hactive > max_hactive ||
+ modes[i].vactive > max_vactive)
+ continue;
+ if (best_mode < 0 ||
+ (modes[i].hactive >= modes[best_mode].hactive &&
+ modes[i].vactive > modes[best_mode].vactive))
+ best_mode = i;
+ }
+ if (best_mode < 0)
+ return -ENODEV;
+
+ err = fb_videomode_from_videomode(&modes[best_mode], &fb->panel->mode);
+ if (err)
+ return err;
+
+ i = snprintf(NULL, 0, "%ux%u@%u", fb->panel->mode.xres,
+ fb->panel->mode.yres, fb->panel->mode.refresh);
+ mode_name = devm_kzalloc(&fb->dev->dev, i + 1, GFP_KERNEL);
+ snprintf(mode_name, i + 1, "%ux%u@%u", fb->panel->mode.xres,
+ fb->panel->mode.yres, fb->panel->mode.refresh);
+ fb->panel->mode.name = mode_name;
+
+ of_property_read_u32(node, "max-bpp", &max_bpp);
+ fb->panel->bpp = max_bpp;
+
+ if (of_property_read_bool(node, "big-endian-pixels"))
+ fb->panel->cntl |= CNTL_BEBO;
+
+ if (display_entity_get_size(fb->panel->display, &width, &height) != 0)
+ width = height = -1;
+ fb->panel->width = width;
+ fb->panel->height = height;
+
+ err = display_entity_get_params(fb->panel->display, ¶ms);
+ if (err)
+ return err;
+
+ switch (params.type) {
+ case DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL:
+ return clcdfb_of_get_tft_parallel_panel(fb->panel, ¶ms);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int clcdfb_of_vram_setup(struct clcd_fb *fb)
+{
+ const __be32 *prop = of_get_property(fb->dev->dev.of_node, "video-ram",
+ NULL);
+ struct device_node *node = of_find_node_by_phandle(be32_to_cpup(prop));
+ u64 size;
+ int err;
+
+ if (!node)
+ return -ENODEV;
+
+ err = clcdfb_of_init_display(fb);
+ if (err)
+ return err;
+
+ fb->fb.screen_base = of_iomap(node, 0);
+ if (!fb->fb.screen_base)
+ return -ENOMEM;
+
+ fb->fb.fix.smem_start = of_translate_address(node,
+ of_get_address(node, 0, &size, NULL));
+ fb->fb.fix.smem_len = size;
+
+ return 0;
+}
+
+static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ unsigned long off, user_size, kernel_size;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ user_size = vma->vm_end - vma->vm_start;
+ kernel_size = fb->fb.fix.smem_len;
+
+ if (off >= kernel_size || user_size > (kernel_size - off))
+ return -ENXIO;
+
+ return remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
+ user_size,
+ pgprot_writecombine(vma->vm_page_prot));
+}
+
+static void clcdfb_of_vram_remove(struct clcd_fb *fb)
+{
+ iounmap(fb->fb.screen_base);
+}
+
+static int clcdfb_of_dma_setup(struct clcd_fb *fb)
+{
+ unsigned long framesize;
+ dma_addr_t dma;
+ int err;
+
+ err = clcdfb_of_init_display(fb);
+ if (err)
+ return err;
+
+ framesize = fb->panel->mode.xres * fb->panel->mode.yres *
+ fb->panel->bpp / 8;
+ fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
+ &dma, GFP_KERNEL);
+ if (!fb->fb.screen_base)
+ return -ENOMEM;
+
+ fb->fb.fix.smem_start = dma;
+ fb->fb.fix.smem_len = framesize;
+
+ return 0;
+}
+
+static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base,
+ fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+}
+
+static void clcdfb_of_dma_remove(struct clcd_fb *fb)
+{
+ dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+ fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
+{
+ struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
+ GFP_KERNEL);
+ struct device_node *node = dev->dev.of_node;
+
+ if (!board)
+ return NULL;
+
+ board->name = of_get_property(node, "label", NULL);
+ if (!board->name)
+ board->name = of_node_full_name(node);
+ board->caps = CLCD_CAP_ALL;
+ board->check = clcdfb_check;
+ board->decode = clcdfb_decode;
+ if (of_find_property(node, "video-ram", NULL)) {
+ board->setup = clcdfb_of_vram_setup;
+ board->mmap = clcdfb_of_vram_mmap;
+ board->remove = clcdfb_of_vram_remove;
+ } else {
+ board->setup = clcdfb_of_dma_setup;
+ board->mmap = clcdfb_of_dma_mmap;
+ board->remove = clcdfb_of_dma_remove;
+ }
+
+ return board;
+}
+#else
+static struct clcd_board *clcdfb_of_get_board(struct amba_dev *dev)
+{
+ return NULL;
+}
+#endif
+
static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
{
struct clcd_board *board = dev->dev.platform_data;
@@ -549,6 +793,9 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
int ret;
if (!board)
+ board = clcdfb_of_get_board(dev);
+
+ if (!board)
return -EINVAL;
ret = amba_request_regions(dev, NULL);
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
index e82e3ee..73b199b 100644
--- a/include/linux/amba/clcd.h
+++ b/include/linux/amba/clcd.h
@@ -10,6 +10,7 @@
* for more details.
*/
#include <linux/fb.h>
+#include <video/display.h>
/*
* CLCD Controller Internal Register addresses
@@ -105,6 +106,7 @@ struct clcd_panel {
fixedtimings:1,
grayscale:1;
unsigned int connector;
+ struct display_entity *display;
};
struct clcd_regs {
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH v4 2/2] video: imxfb: Add DT support
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-18 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366290183-367-3-git-send-email-mpa@pengutronix.de>
On 15:03 Thu 18 Apr , Markus Pargmann wrote:
> Add devicetree support for imx framebuffer driver. It uses the generic
> display bindings and helper functions.
>
> Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> ---
>
> Notes:
> Changes in v4:
> - Remove eukrea specific dmacr property.
> - Add optional dmacr property. If not present, the dmacr reset value is not
> changed.
>
> Changes in v3:
> - Fix returncodes of of_read_mode function and print error messages
> - Introduce a lower bound check for bits per pixel
> - Calculate correct bytes per pixel value before using it for the calculation of
> memory size
> - Change DT property names
>
> Changes in v2:
> - Removed pwmr register property
> - Cleanup of devicetree binding documentation
> - Use default values for pwmr and lscr1
>
> .../devicetree/bindings/video/fsl,imx-fb.txt | 51 ++++++
> drivers/video/imxfb.c | 194 +++++++++++++++++----
> 2 files changed, 210 insertions(+), 35 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
>
> diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> new file mode 100644
> index 0000000..aff16a4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> @@ -0,0 +1,51 @@
> +Freescale imx21 Framebuffer
> +
> +This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
> +
> +Required properties:
> +- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
> +- reg : Should contain 1 register ranges(address and length)
> +- interrupts : One interrupt of the fb dev
> +
> +Required nodes:
> +- display: Phandle to a display node as described in
> + Documentation/devicetree/bindings/video/display-timing.txt
> + Additional, the display node has to define properties:
> + - fsl,bpp: Bits per pixel
> + - fsl,pcr: LCDC PCR value
> +
> +Optional properties:
> +- fsl,dmacr: DMA Control Register value. This is optional. By default, the
> + register is not modified as recommended by the datasheet.
> +- fsl,lscr1: LCDC Sharp Configuration Register value.
> +
> +Example:
> +
> + imxfb: fb@10021000 {
> + compatible = "fsl,imx27-fb", "fsl,imx21-fb";
you put both when in the doc you request one
> + interrupts = <61>;
> + reg = <0x10021000 0x1000>;
> + display = <&display0>;
> + };
> +
> + ...
> +
> + display0: display0 {
> + model = "Primeview-PD050VL1";
> + native-mode = <&timing_disp0>;
> + fsl,bpp = <16>; /* non-standard but required */
there is a generic binding bit-per-pixel use a cross other IP
> + fsl,pcr = <0xf0c88080>; /* non-standard but required */
> + display-timings {
> + timing_disp0: 640x480 {
> + hactive = <640>;
> + vactive = <480>;
> + hback-porch = <112>;
> + hfront-porch = <36>;
> + hsync-len = <32>;
> + vback-porch = <33>;
> + vfront-porch = <33>;
> + vsync-len = <2>;
> + clock-frequency = <25000000>;
> + };
> + };
> + };
> diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
> index ef2b587..e0230f8 100644
> --- a/drivers/video/imxfb.c
> +++ b/drivers/video/imxfb.c
> @@ -32,6 +32,12 @@
> #include <linux/io.h>
> #include <linux/math64.h>
> #include <linux/uaccess.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +#include <video/of_display_timing.h>
> +#include <video/of_videomode.h>
> +#include <video/videomode.h>
>
> #include <linux/platform_data/video-imxfb.h>
>
> @@ -117,10 +123,11 @@
> #define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
> #define LGWCR_GWE (1 << 22)
>
> +#define IMXFB_LSCR1_DEFAULT 0x00120300
> +
> /* Used fb-mode. Can be set on kernel command line, therefore file-static. */
> static const char *fb_mode;
>
> -
> /*
> * These are the bitfields for each
> * display depth that we support.
> @@ -192,6 +199,19 @@ static struct platform_device_id imxfb_devtype[] = {
> };
> MODULE_DEVICE_TABLE(platform, imxfb_devtype);
>
> +static struct of_device_id imxfb_of_dev_id[] = {
> + {
> + .compatible = "fsl,imx1-fb",
> + .data = &imxfb_devtype[IMX1_FB],
> + }, {
> + .compatible = "fsl,imx21-fb",
> + .data = &imxfb_devtype[IMX21_FB],
> + }, {
> + /* sentinel */
> + }
> +};
> +MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
> +
> static inline int is_imx1_fb(struct imxfb_info *fbi)
> {
> return fbi->devtype = IMX1_FB;
> @@ -324,6 +344,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
> struct imx_fb_videomode *m;
> int i;
>
> + if (!fb_mode)
> + return &fbi->mode[0];
> +
> for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
> if (!strcmp(m->mode.name, fb_mode))
> return m;
> @@ -479,6 +502,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
> struct imxfb_info *fbi = bl_get_data(bl);
> int brightness = bl->props.brightness;
>
> + if (!fbi->pwmr)
> + return 0;
> +
> if (bl->props.power != FB_BLANK_UNBLANK)
> brightness = 0;
> if (bl->props.fb_blank != FB_BLANK_UNBLANK)
> @@ -719,10 +745,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
>
> writel(fbi->pcr, fbi->regs + LCDC_PCR);
> #ifndef PWMR_BACKLIGHT_AVAILABLE
> - writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
> + if (fbi->pwmr)
> + writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
> #endif
> writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
> - writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
> +
> + /* dmacr = 0 is no valid value, as we need DMA control marks. */
> + if (fbi->dmacr)
> + writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
>
> return 0;
> }
> @@ -758,13 +788,12 @@ static int imxfb_resume(struct platform_device *dev)
> #define imxfb_resume NULL
> #endif
>
> -static int __init imxfb_init_fbinfo(struct platform_device *pdev)
> +static int imxfb_init_fbinfo(struct platform_device *pdev)
> {
> struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
> struct fb_info *info = dev_get_drvdata(&pdev->dev);
> struct imxfb_info *fbi = info->par;
> - struct imx_fb_videomode *m;
> - int i;
> + struct device_node *np;
>
> pr_debug("%s\n",__func__);
>
> @@ -795,41 +824,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
> info->fbops = &imxfb_ops;
> info->flags = FBINFO_FLAG_DEFAULT |
> FBINFO_READS_FAST;
> - info->var.grayscale = pdata->cmap_greyscale;
> - fbi->cmap_inverse = pdata->cmap_inverse;
> - fbi->cmap_static = pdata->cmap_static;
> - fbi->lscr1 = pdata->lscr1;
> - fbi->dmacr = pdata->dmacr;
> - fbi->pwmr = pdata->pwmr;
> - fbi->lcd_power = pdata->lcd_power;
> - fbi->backlight_power = pdata->backlight_power;
> -
> - for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
> - info->fix.smem_len = max_t(size_t, info->fix.smem_len,
> - m->mode.xres * m->mode.yres * m->bpp / 8);
> + if (pdata) {
> + info->var.grayscale = pdata->cmap_greyscale;
> + fbi->cmap_inverse = pdata->cmap_inverse;
> + fbi->cmap_static = pdata->cmap_static;
> + fbi->lscr1 = pdata->lscr1;
> + fbi->dmacr = pdata->dmacr;
> + fbi->pwmr = pdata->pwmr;
> + fbi->lcd_power = pdata->lcd_power;
> + fbi->backlight_power = pdata->backlight_power;
> + } else {
> + np = pdev->dev.of_node;
> + info->var.grayscale = of_property_read_bool(np,
> + "cmap-greyscale");
> + fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
> + fbi->cmap_static = of_property_read_bool(np, "cmap-static");
> +
> + fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
> + of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
> +
> + of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
> +
> + /* These two function pointers could be used by some specific
> + * platforms. */
> + fbi->lcd_power = NULL;
> + fbi->backlight_power = NULL;
> + }
> +
> + return 0;
> +}
> +
> +static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
> + struct imx_fb_videomode *imxfb_mode)
> +{
> + int ret;
> + struct fb_videomode *of_mode = &imxfb_mode->mode;
> + u32 bpp;
> + u32 pcr;
> +
> + ret = of_property_read_string(np, "model", &of_mode->name);
> + if (ret)
> + of_mode->name = NULL;
> +
> + ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
> + if (ret) {
> + dev_err(dev, "Failed to get videomode from DT\n");
> + return ret;
> + }
> +
> + ret = of_property_read_u32(np, "fsl,bpp", &bpp);
> + ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
> +
> + if (ret) {
> + dev_err(dev, "Failed to read bpp and pcr from DT\n");
> + return -EINVAL;
> + }
> +
> + if (bpp < 1 || bpp > 255) {
> + dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
> + return -EINVAL;
> + }
> +
> + imxfb_mode->bpp = bpp;
> + imxfb_mode->pcr = pcr;
>
> return 0;
> }
>
> -static int __init imxfb_probe(struct platform_device *pdev)
> +static int imxfb_probe(struct platform_device *pdev)
> {
> struct imxfb_info *fbi;
> struct fb_info *info;
> struct imx_fb_platform_data *pdata;
> struct resource *res;
> + struct imx_fb_videomode *m;
> + const struct of_device_id *of_id;
> int ret, i;
> + int bytes_per_pixel;
>
> dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
>
> + of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
> + if (of_id)
> + pdev->id_entry = of_id->data;
> +
> res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (!res)
> return -ENODEV;
>
> pdata = pdev->dev.platform_data;
> - if (!pdata) {
> - dev_err(&pdev->dev,"No platform_data available\n");
> - return -ENOMEM;
> - }
>
> info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
> if (!info)
> @@ -837,15 +920,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
>
> fbi = info->par;
>
> - if (!fb_mode)
> - fb_mode = pdata->mode[0].mode.name;
> -
> platform_set_drvdata(pdev, info);
>
> ret = imxfb_init_fbinfo(pdev);
> if (ret < 0)
> goto failed_init;
>
> + if (pdata) {
> + if (!fb_mode)
> + fb_mode = pdata->mode[0].mode.name;
> +
> + fbi->mode = pdata->mode;
> + fbi->num_modes = pdata->num_modes;
> + } else {
> + struct device_node *display_np;
> + fb_mode = NULL;
> +
> + display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
> + if (!display_np) {
> + dev_err(&pdev->dev, "No display defined in devicetree\n");
> + ret = -EINVAL;
> + goto failed_of_parse;
> + }
> +
> + /*
> + * imxfb does not support more modes, we choose only the native
> + * mode.
> + */
> + fbi->num_modes = 1;
> +
> + fbi->mode = devm_kzalloc(&pdev->dev,
> + sizeof(struct imx_fb_videomode), GFP_KERNEL);
> + if (!fbi->mode) {
> + ret = -ENOMEM;
> + goto failed_of_parse;
> + }
> +
> + ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
> + if (ret)
> + goto failed_of_parse;
> + }
> +
> + /* Calculate maximum bytes used per pixel. In most cases this should
> + * be the same as m->bpp/8 */
> + m = &fbi->mode[0];
> + bytes_per_pixel = (m->bpp + 7) / 8;
> + for (i = 0; i < fbi->num_modes; i++, m++)
> + info->fix.smem_len = max_t(size_t, info->fix.smem_len,
> + m->mode.xres * m->mode.yres * bytes_per_pixel);
> +
> res = request_mem_region(res->start, resource_size(res),
> DRIVER_NAME);
> if (!res) {
> @@ -878,7 +1001,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
> goto failed_ioremap;
> }
>
> - if (!pdata->fixed_screen_cpu) {
> + /* Seems not being used by anyone, so no support for oftree */
> + if (!pdata || !pdata->fixed_screen_cpu) {
> fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
> fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
> fbi->map_size, &fbi->map_dma, GFP_KERNEL);
> @@ -903,18 +1027,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
> info->fix.smem_start = fbi->screen_dma;
> }
>
> - if (pdata->init) {
> + if (pdata && pdata->init) {
> ret = pdata->init(fbi->pdev);
> if (ret)
> goto failed_platform_init;
> }
>
> - fbi->mode = pdata->mode;
> - fbi->num_modes = pdata->num_modes;
>
> INIT_LIST_HEAD(&info->modelist);
> - for (i = 0; i < pdata->num_modes; i++)
> - fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
> + for (i = 0; i < fbi->num_modes; i++)
> + fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
>
> /*
> * This makes sure that our colour bitfield
> @@ -944,10 +1066,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
> failed_register:
> fb_dealloc_cmap(&info->cmap);
> failed_cmap:
> - if (pdata->exit)
> + if (pdata && pdata->exit)
> pdata->exit(fbi->pdev);
> failed_platform_init:
> - if (!pdata->fixed_screen_cpu)
> + if (pdata && !pdata->fixed_screen_cpu)
> dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
> fbi->map_dma);
> failed_map:
> @@ -956,6 +1078,7 @@ failed_ioremap:
> failed_getclock:
> release_mem_region(res->start, resource_size(res));
> failed_req:
> +failed_of_parse:
> kfree(info->pseudo_palette);
> failed_init:
> platform_set_drvdata(pdev, NULL);
> @@ -980,7 +1103,7 @@ static int imxfb_remove(struct platform_device *pdev)
> unregister_framebuffer(info);
>
> pdata = pdev->dev.platform_data;
> - if (pdata->exit)
> + if (pdata && pdata->exit)
> pdata->exit(fbi->pdev);
>
> fb_dealloc_cmap(&info->cmap);
> @@ -1009,6 +1132,7 @@ static struct platform_driver imxfb_driver = {
> .shutdown = imxfb_shutdown,
> .driver = {
> .name = DRIVER_NAME,
> + .of_match_table = imxfb_of_dev_id,
> },
> .id_table = imxfb_devtype,
> };
> --
> 1.8.1.5
>
^ permalink raw reply
* Re: [PATCH] video: mxsfb: Fix colors display on lower color depth
From: Shawn Guo @ 2013-04-18 14:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366277032-671-1-git-send-email-maxime.ripard@free-electrons.com>
Copy Sascha.
Shawn
On Thu, Apr 18, 2013 at 11:23:52AM +0200, Maxime Ripard wrote:
> The current code always registers as a 32 bits display, and uses the
> hardware to drop the MSB of each color to abjust to the interface width
> used by the panel.
>
> This results on 18 bits (and probably 16 bits display as well) in colors
> being displayed poorly, because the MSB are obviously the most important
> bits for each color definition.
>
> The default controller behaviour when using an interface width smaller
> than the color depth is to drop the LSBs of each color, which makes more
> sense because you lose the least important part of the color definition.
>
> So, to fix the colors display, just get back to the default controller
> behaviour.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> drivers/video/mxsfb.c | 5 -----
> 1 file changed, 5 deletions(-)
>
> diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
> index 755556c..2cfaf8b 100644
> --- a/drivers/video/mxsfb.c
> +++ b/drivers/video/mxsfb.c
> @@ -424,11 +424,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
> return -EINVAL;
> case STMLCDIF_16BIT:
> case STMLCDIF_18BIT:
> - /* 24 bit to 18 bit mapping */
> - ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
> - * each colour component
> - */
> - break;
> case STMLCDIF_24BIT:
> /* real 24 bit */
> break;
> --
> 1.7.10.4
>
^ permalink raw reply
* Re: [PATCH] video: mxsfb: Fix colors display on lower color depth
From: Marek Vasut @ 2013-04-18 14:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366277032-671-1-git-send-email-maxime.ripard@free-electrons.com>
Dear Maxime Ripard,
> The current code always registers as a 32 bits display, and uses the
> hardware to drop the MSB of each color to abjust to the interface width
> used by the panel.
>
> This results on 18 bits (and probably 16 bits display as well) in colors
> being displayed poorly, because the MSB are obviously the most important
> bits for each color definition.
>
> The default controller behaviour when using an interface width smaller
> than the color depth is to drop the LSBs of each color, which makes more
> sense because you lose the least important part of the color definition.
>
> So, to fix the colors display, just get back to the default controller
> behaviour.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Isn't this what M28EVK is doing already? This was last tested on 3.9-rc3 I
think:
bits-per-pixel = <16>;
bus-width = <18>;
But it's also true we have all 24 data lines routed to the LCD.
Best regards,
Marek Vasut
^ permalink raw reply
* [PATCH v4 2/2] video: imxfb: Add DT support
From: Markus Pargmann @ 2013-04-18 13:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366290183-367-1-git-send-email-mpa@pengutronix.de>
Add devicetree support for imx framebuffer driver. It uses the generic
display bindings and helper functions.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
---
Notes:
Changes in v4:
- Remove eukrea specific dmacr property.
- Add optional dmacr property. If not present, the dmacr reset value is not
changed.
Changes in v3:
- Fix returncodes of of_read_mode function and print error messages
- Introduce a lower bound check for bits per pixel
- Calculate correct bytes per pixel value before using it for the calculation of
memory size
- Change DT property names
Changes in v2:
- Removed pwmr register property
- Cleanup of devicetree binding documentation
- Use default values for pwmr and lscr1
.../devicetree/bindings/video/fsl,imx-fb.txt | 51 ++++++
drivers/video/imxfb.c | 194 +++++++++++++++++----
2 files changed, 210 insertions(+), 35 deletions(-)
create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
new file mode 100644
index 0000000..aff16a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
@@ -0,0 +1,51 @@
+Freescale imx21 Framebuffer
+
+This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
+
+Required properties:
+- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : One interrupt of the fb dev
+
+Required nodes:
+- display: Phandle to a display node as described in
+ Documentation/devicetree/bindings/video/display-timing.txt
+ Additional, the display node has to define properties:
+ - fsl,bpp: Bits per pixel
+ - fsl,pcr: LCDC PCR value
+
+Optional properties:
+- fsl,dmacr: DMA Control Register value. This is optional. By default, the
+ register is not modified as recommended by the datasheet.
+- fsl,lscr1: LCDC Sharp Configuration Register value.
+
+Example:
+
+ imxfb: fb@10021000 {
+ compatible = "fsl,imx27-fb", "fsl,imx21-fb";
+ interrupts = <61>;
+ reg = <0x10021000 0x1000>;
+ display = <&display0>;
+ };
+
+ ...
+
+ display0: display0 {
+ model = "Primeview-PD050VL1";
+ native-mode = <&timing_disp0>;
+ fsl,bpp = <16>; /* non-standard but required */
+ fsl,pcr = <0xf0c88080>; /* non-standard but required */
+ display-timings {
+ timing_disp0: 640x480 {
+ hactive = <640>;
+ vactive = <480>;
+ hback-porch = <112>;
+ hfront-porch = <36>;
+ hsync-len = <32>;
+ vback-porch = <33>;
+ vfront-porch = <33>;
+ vsync-len = <2>;
+ clock-frequency = <25000000>;
+ };
+ };
+ };
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index ef2b587..e0230f8 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -32,6 +32,12 @@
#include <linux/io.h>
#include <linux/math64.h>
#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
#include <linux/platform_data/video-imxfb.h>
@@ -117,10 +123,11 @@
#define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
#define LGWCR_GWE (1 << 22)
+#define IMXFB_LSCR1_DEFAULT 0x00120300
+
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
-
/*
* These are the bitfields for each
* display depth that we support.
@@ -192,6 +199,19 @@ static struct platform_device_id imxfb_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, imxfb_devtype);
+static struct of_device_id imxfb_of_dev_id[] = {
+ {
+ .compatible = "fsl,imx1-fb",
+ .data = &imxfb_devtype[IMX1_FB],
+ }, {
+ .compatible = "fsl,imx21-fb",
+ .data = &imxfb_devtype[IMX21_FB],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
+
static inline int is_imx1_fb(struct imxfb_info *fbi)
{
return fbi->devtype = IMX1_FB;
@@ -324,6 +344,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
struct imx_fb_videomode *m;
int i;
+ if (!fb_mode)
+ return &fbi->mode[0];
+
for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
if (!strcmp(m->mode.name, fb_mode))
return m;
@@ -479,6 +502,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
struct imxfb_info *fbi = bl_get_data(bl);
int brightness = bl->props.brightness;
+ if (!fbi->pwmr)
+ return 0;
+
if (bl->props.power != FB_BLANK_UNBLANK)
brightness = 0;
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
@@ -719,10 +745,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
writel(fbi->pcr, fbi->regs + LCDC_PCR);
#ifndef PWMR_BACKLIGHT_AVAILABLE
- writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+ if (fbi->pwmr)
+ writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
#endif
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
- writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
+
+ /* dmacr = 0 is no valid value, as we need DMA control marks. */
+ if (fbi->dmacr)
+ writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
return 0;
}
@@ -758,13 +788,12 @@ static int imxfb_resume(struct platform_device *dev)
#define imxfb_resume NULL
#endif
-static int __init imxfb_init_fbinfo(struct platform_device *pdev)
+static int imxfb_init_fbinfo(struct platform_device *pdev)
{
struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
struct fb_info *info = dev_get_drvdata(&pdev->dev);
struct imxfb_info *fbi = info->par;
- struct imx_fb_videomode *m;
- int i;
+ struct device_node *np;
pr_debug("%s\n",__func__);
@@ -795,41 +824,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
info->fbops = &imxfb_ops;
info->flags = FBINFO_FLAG_DEFAULT |
FBINFO_READS_FAST;
- info->var.grayscale = pdata->cmap_greyscale;
- fbi->cmap_inverse = pdata->cmap_inverse;
- fbi->cmap_static = pdata->cmap_static;
- fbi->lscr1 = pdata->lscr1;
- fbi->dmacr = pdata->dmacr;
- fbi->pwmr = pdata->pwmr;
- fbi->lcd_power = pdata->lcd_power;
- fbi->backlight_power = pdata->backlight_power;
-
- for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
- info->fix.smem_len = max_t(size_t, info->fix.smem_len,
- m->mode.xres * m->mode.yres * m->bpp / 8);
+ if (pdata) {
+ info->var.grayscale = pdata->cmap_greyscale;
+ fbi->cmap_inverse = pdata->cmap_inverse;
+ fbi->cmap_static = pdata->cmap_static;
+ fbi->lscr1 = pdata->lscr1;
+ fbi->dmacr = pdata->dmacr;
+ fbi->pwmr = pdata->pwmr;
+ fbi->lcd_power = pdata->lcd_power;
+ fbi->backlight_power = pdata->backlight_power;
+ } else {
+ np = pdev->dev.of_node;
+ info->var.grayscale = of_property_read_bool(np,
+ "cmap-greyscale");
+ fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
+ fbi->cmap_static = of_property_read_bool(np, "cmap-static");
+
+ fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
+ of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
+
+ of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
+
+ /* These two function pointers could be used by some specific
+ * platforms. */
+ fbi->lcd_power = NULL;
+ fbi->backlight_power = NULL;
+ }
+
+ return 0;
+}
+
+static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
+ struct imx_fb_videomode *imxfb_mode)
+{
+ int ret;
+ struct fb_videomode *of_mode = &imxfb_mode->mode;
+ u32 bpp;
+ u32 pcr;
+
+ ret = of_property_read_string(np, "model", &of_mode->name);
+ if (ret)
+ of_mode->name = NULL;
+
+ ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
+ if (ret) {
+ dev_err(dev, "Failed to get videomode from DT\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "fsl,bpp", &bpp);
+ ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
+
+ if (ret) {
+ dev_err(dev, "Failed to read bpp and pcr from DT\n");
+ return -EINVAL;
+ }
+
+ if (bpp < 1 || bpp > 255) {
+ dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
+ return -EINVAL;
+ }
+
+ imxfb_mode->bpp = bpp;
+ imxfb_mode->pcr = pcr;
return 0;
}
-static int __init imxfb_probe(struct platform_device *pdev)
+static int imxfb_probe(struct platform_device *pdev)
{
struct imxfb_info *fbi;
struct fb_info *info;
struct imx_fb_platform_data *pdata;
struct resource *res;
+ struct imx_fb_videomode *m;
+ const struct of_device_id *of_id;
int ret, i;
+ int bytes_per_pixel;
dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
+ of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev,"No platform_data available\n");
- return -ENOMEM;
- }
info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
if (!info)
@@ -837,15 +920,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
fbi = info->par;
- if (!fb_mode)
- fb_mode = pdata->mode[0].mode.name;
-
platform_set_drvdata(pdev, info);
ret = imxfb_init_fbinfo(pdev);
if (ret < 0)
goto failed_init;
+ if (pdata) {
+ if (!fb_mode)
+ fb_mode = pdata->mode[0].mode.name;
+
+ fbi->mode = pdata->mode;
+ fbi->num_modes = pdata->num_modes;
+ } else {
+ struct device_node *display_np;
+ fb_mode = NULL;
+
+ display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
+ if (!display_np) {
+ dev_err(&pdev->dev, "No display defined in devicetree\n");
+ ret = -EINVAL;
+ goto failed_of_parse;
+ }
+
+ /*
+ * imxfb does not support more modes, we choose only the native
+ * mode.
+ */
+ fbi->num_modes = 1;
+
+ fbi->mode = devm_kzalloc(&pdev->dev,
+ sizeof(struct imx_fb_videomode), GFP_KERNEL);
+ if (!fbi->mode) {
+ ret = -ENOMEM;
+ goto failed_of_parse;
+ }
+
+ ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
+ if (ret)
+ goto failed_of_parse;
+ }
+
+ /* Calculate maximum bytes used per pixel. In most cases this should
+ * be the same as m->bpp/8 */
+ m = &fbi->mode[0];
+ bytes_per_pixel = (m->bpp + 7) / 8;
+ for (i = 0; i < fbi->num_modes; i++, m++)
+ info->fix.smem_len = max_t(size_t, info->fix.smem_len,
+ m->mode.xres * m->mode.yres * bytes_per_pixel);
+
res = request_mem_region(res->start, resource_size(res),
DRIVER_NAME);
if (!res) {
@@ -878,7 +1001,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
goto failed_ioremap;
}
- if (!pdata->fixed_screen_cpu) {
+ /* Seems not being used by anyone, so no support for oftree */
+ if (!pdata || !pdata->fixed_screen_cpu) {
fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
fbi->map_size, &fbi->map_dma, GFP_KERNEL);
@@ -903,18 +1027,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
info->fix.smem_start = fbi->screen_dma;
}
- if (pdata->init) {
+ if (pdata && pdata->init) {
ret = pdata->init(fbi->pdev);
if (ret)
goto failed_platform_init;
}
- fbi->mode = pdata->mode;
- fbi->num_modes = pdata->num_modes;
INIT_LIST_HEAD(&info->modelist);
- for (i = 0; i < pdata->num_modes; i++)
- fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
+ for (i = 0; i < fbi->num_modes; i++)
+ fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
/*
* This makes sure that our colour bitfield
@@ -944,10 +1066,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
failed_register:
fb_dealloc_cmap(&info->cmap);
failed_cmap:
- if (pdata->exit)
+ if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
failed_platform_init:
- if (!pdata->fixed_screen_cpu)
+ if (pdata && !pdata->fixed_screen_cpu)
dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
fbi->map_dma);
failed_map:
@@ -956,6 +1078,7 @@ failed_ioremap:
failed_getclock:
release_mem_region(res->start, resource_size(res));
failed_req:
+failed_of_parse:
kfree(info->pseudo_palette);
failed_init:
platform_set_drvdata(pdev, NULL);
@@ -980,7 +1103,7 @@ static int imxfb_remove(struct platform_device *pdev)
unregister_framebuffer(info);
pdata = pdev->dev.platform_data;
- if (pdata->exit)
+ if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
fb_dealloc_cmap(&info->cmap);
@@ -1009,6 +1132,7 @@ static struct platform_driver imxfb_driver = {
.shutdown = imxfb_shutdown,
.driver = {
.name = DRIVER_NAME,
+ .of_match_table = imxfb_of_dev_id,
},
.id_table = imxfb_devtype,
};
--
1.8.1.5
^ permalink raw reply related
* [PATCH v4 1/2] imxfb: Set alpha value of the framebuffer
From: Markus Pargmann @ 2013-04-18 13:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366290183-367-1-git-send-email-mpa@pengutronix.de>
From: Christian Hemp <c.hemp@phytec.de>
Based on Sascha Hauer's patch i.MX27 clock: Do not disable lcd clocks during
startup.
This patch gives a interface to chance the alphavalue of the framebuffer.
Signed-off-by: Christian Hemp <c.hemp@phytec.de>
rebased to 3.7
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
drivers/video/imxfb.c | 35 +++++++++++++++++++++++++++++++
include/linux/platform_data/video-imxfb.h | 3 +++
2 files changed, 38 insertions(+)
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 0abf2bf..ef2b587 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/math64.h>
+#include <linux/uaccess.h>
#include <linux/platform_data/video-imxfb.h>
@@ -112,6 +113,10 @@
#define LCDISR_EOF (1<<1)
#define LCDISR_BOF (1<<0)
+#define LCDC_LGWCR 0x64
+#define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
+#define LGWCR_GWE (1 << 22)
+
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
@@ -610,6 +615,35 @@ static int imxfb_blank(int blank, struct fb_info *info)
return 0;
}
+static int imxfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct imxfb_info *fbi = info->par;
+ int alpha, ret = 0;
+ unsigned int tmp;
+
+ switch (cmd) {
+ case IMXFB_ALPHA:
+ if (get_user(alpha, (int __user *)arg)) {
+ ret = -EFAULT;
+ } else {
+ tmp = readl(fbi->regs + LCDC_LGWCR);
+ tmp &= ~LGWCR_GWAV(0xff);
+ tmp |= LGWCR_GWAV(alpha);
+ if (!alpha)
+ tmp &= ~LGWCR_GWE;
+ else
+ tmp |= LGWCR_GWE;
+ writel(tmp , fbi->regs + LCDC_LGWCR);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static struct fb_ops imxfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = imxfb_check_var,
@@ -619,6 +653,7 @@ static struct fb_ops imxfb_ops = {
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = imxfb_blank,
+ .fb_ioctl = imxfb_ioctl,
};
/*
diff --git a/include/linux/platform_data/video-imxfb.h b/include/linux/platform_data/video-imxfb.h
index 9de8f06..ce3875f 100644
--- a/include/linux/platform_data/video-imxfb.h
+++ b/include/linux/platform_data/video-imxfb.h
@@ -51,6 +51,9 @@
#define DMACR_HM(x) (((x) & 0xf) << 16)
#define DMACR_TM(x) ((x) & 0xf)
+#define IMXFB_IOW(num, dtype) _IOW('I', num, dtype)
+#define IMXFB_ALPHA IMXFB_IOW(31, int)
+
struct imx_fb_videomode {
struct fb_videomode mode;
u32 pcr;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v4 0/2] video: imxfb DT support
From: Markus Pargmann @ 2013-04-18 13:03 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds DT support for imxfb. Changes are listed in the notes section
of each patch.
Regards,
Markus
Christian Hemp (1):
imxfb: Set alpha value of the framebuffer
Markus Pargmann (1):
video: imxfb: Add DT support
Documentation/devicetree/bindings/video/fsl,imx-fb.txt | 51 ++++++++++++++++++
drivers/video/imxfb.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
include/linux/platform_data/video-imxfb.h | 3 ++
3 files changed, 248 insertions(+), 35 deletions(-)
create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
^ permalink raw reply
* Re: [RFC 06/10] video: ARM CLCD: Add DT & CDF support
From: Russell King - ARM Linux @ 2013-04-18 10:24 UTC (permalink / raw)
To: Pawel Moll
Cc: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel, Laurent Pinchart, Linus Walleij
In-Reply-To: <1366211842-21497-7-git-send-email-pawel.moll@arm.com>
On Wed, Apr 17, 2013 at 04:17:18PM +0100, Pawel Moll wrote:
> +#if defined(CONFIG_OF)
> +static int clcdfb_of_get_tft_parallel_panel(struct clcd_panel *panel,
> + struct display_entity_interface_params *params)
> +{
> + int r = params->p.tft_parallel.r_bits;
> + int g = params->p.tft_parallel.g_bits;
> + int b = params->p.tft_parallel.b_bits;
> +
> + /* Bypass pixel clock divider, data output on the falling edge */
> + panel->tim2 = TIM2_BCD | TIM2_IPC;
> +
> + /* TFT display, vert. comp. interrupt at the start of the back porch */
> + panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
> +
> + if (params->p.tft_parallel.r_b_swapped)
> + panel->cntl |= CNTL_BGR;
NAK. Do not set this explicitly. Note the driver talks about this being
"the old way" - this should not be used with the panel capabilities - and
in fact it will be overwritten.
Instead, you need to encode this into the capabilities by masking the
below with CLCD_CAP_RGB or CLCD_CAP_BGR depending on the ordering.
^ permalink raw reply
* [PATCH] video: mxsfb: Fix colors display on lower color depth
From: Maxime Ripard @ 2013-04-18 9:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <516EBCA4.1020609@free-electrons.com>
The current code always registers as a 32 bits display, and uses the
hardware to drop the MSB of each color to abjust to the interface width
used by the panel.
This results on 18 bits (and probably 16 bits display as well) in colors
being displayed poorly, because the MSB are obviously the most important
bits for each color definition.
The default controller behaviour when using an interface width smaller
than the color depth is to drop the LSBs of each color, which makes more
sense because you lose the least important part of the color definition.
So, to fix the colors display, just get back to the default controller
behaviour.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/video/mxsfb.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 755556c..2cfaf8b 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -424,11 +424,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
return -EINVAL;
case STMLCDIF_16BIT:
case STMLCDIF_18BIT:
- /* 24 bit to 18 bit mapping */
- ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
- * each colour component
- */
- break;
case STMLCDIF_24BIT:
/* real 24 bit */
break;
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH 00/33] OMAPDSS: platform_enable/disable callback removal from panel drivers
From: Tomi Valkeinen @ 2013-04-18 3:40 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Archit Taneja, linux-omap, linux-fbdev
In-Reply-To: <20130418003419.GB10155@atomide.com>
[-- Attachment #1: Type: text/plain, Size: 641 bytes --]
On 2013-04-18 03:34, Tony Lindgren wrote:
> Just one request: Let's do branches like this early on before -rc6,
> not what might be five days before the merge window potentially
> opens..
Agreed, it got a bit late. But the branch itself has been stable and in
linux-next for some time.
Perhaps it would've been better to merge it to l-o earlier, instead of
me pushing it to linux-next via my tree. Any possible found problems
(there weren't any this time) could've been fixed with a new fixes branch.
> I've pulled them into omap-for-v3.10/dss and will send a pull
> request for Arnd and Olof.
Ok, thanks!
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]
^ permalink raw reply
* Re: [PATCH 00/33] OMAPDSS: platform_enable/disable callback removal from panel drivers
From: Tony Lindgren @ 2013-04-18 0:34 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev
In-Reply-To: <516CD17A.5050403@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com> [130415 21:25]:
> On 2013-04-16 00:20, Tony Lindgren wrote:
>
> >> So, to recap, the common header changes are located in:
> >>
> >> git://gitorious.org/linux-omap-dss2/linux.git 3.10/0-dss-headers
> >>
> >> And the branch for linux-omap is:
> >>
> >> git://gitorious.org/linux-omap-dss2/linux.git 3.10-lo/board-cleanup
> >>
> >> After merging those, some displays won't start anymore until the omapdss
> >> changes are in, but things should still compile.
> >
> > Sounds like it's best that you merge those branches via your
> > tree as the conflicts have been already resolved in linux next.
>
> The dss changes are going through drm tree this time, as there are some
> drm dependencies also, and I've already sent the pull request for those.
> And when I asked Dave Airlie if he can merge the dss changes, I didn't
> talk about a big chunk of arch file changes getting included.
OK sorry I did not know that and was assuming you will be sending
a pull request to Linus.
> Also, the whole division to two independent branches was done only to
> make it possible for the arch changes to go through l-o tree.
Yup. That probably caused you to fix up few other things while doing
it though ;)
> There will probably be more these kind of changes in the future, so I
> think we should agree how to handle those and stick to the plan.
> Dividing the arch file changes to a separate branch is often quite
> laborious, and I'd rather not do that for nothing.
Thanks for doing all that. And yes, let's plan on always separating
driver changes from arch/arm changes to cut away the dependencies.
Just one request: Let's do branches like this early on before -rc6,
not what might be five days before the merge window potentially
opens..
I've pulled them into omap-for-v3.10/dss and will send a pull
request for Arnd and Olof.
Regards,
Tony
^ permalink raw reply
* [RFC 10/10] ARM: vexpress: Add CLCD Device Tree properties
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel
Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi | 17 +++++++++++++----
arch/arm/boot/dts/vexpress-v2m.dtsi | 17 +++++++++++++----
arch/arm/boot/dts/vexpress-v2p-ca9.dts | 5 +++++
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index ac870fb..aac9459 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -41,7 +41,7 @@
bank-width = <4>;
};
- vram@2,00000000 {
+ v2m_vram: vram@2,00000000 {
compatible = "arm,vexpress-vram";
reg = <2 0x00000000 0x00800000>;
};
@@ -233,6 +233,12 @@
interrupts = <14>;
clocks = <&v2m_oscclk1>, <&smbclk>;
clock-names = "clcdclk", "apb_pclk";
+ label = "IOFPGA CLCD";
+ video-ram = <&v2m_vram>;
+ display = <&v2m_muxfpga 0>;
+ max-hactive = <640>;
+ max-vactive = <480>;
+ max-bpp = <16>;
};
};
@@ -282,7 +288,7 @@
/* CLCD clock */
compatible = "arm,vexpress-osc";
arm,vexpress-sysreg,func = <1 1>;
- freq-range = <23750000 63500000>;
+ freq-range = <23750000 65000000>;
#clock-cells = <0>;
clock-output-names = "v2m:oscclk1";
};
@@ -317,9 +323,11 @@
arm,vexpress-sysreg,func = <5 0>;
};
- muxfpga@0 {
+ v2m_muxfpga: muxfpga@0 {
compatible = "arm,vexpress-muxfpga";
arm,vexpress-sysreg,func = <7 0>;
+ #display-cells = <1>;
+ display = <&v2m_dvimode>;
};
shutdown@0 {
@@ -332,9 +340,10 @@
arm,vexpress-sysreg,func = <9 0>;
};
- dvimode@0 {
+ v2m_dvimode: dvimode@0 {
compatible = "arm,vexpress-dvimode";
arm,vexpress-sysreg,func = <11 0>;
+ #display-cells = <0>;
};
};
};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index f142036..4d080d0 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -40,7 +40,7 @@
bank-width = <4>;
};
- vram@3,00000000 {
+ v2m_vram: vram@3,00000000 {
compatible = "arm,vexpress-vram";
reg = <3 0x00000000 0x00800000>;
};
@@ -232,6 +232,12 @@
interrupts = <14>;
clocks = <&v2m_oscclk1>, <&smbclk>;
clock-names = "clcdclk", "apb_pclk";
+ label = "IOFPGA CLCD";
+ video-ram = <&v2m_vram>;
+ display = <&v2m_muxfpga 0>;
+ max-hactive = <640>;
+ max-vactive = <480>;
+ max-bpp = <16>;
};
};
@@ -281,7 +287,7 @@
/* CLCD clock */
compatible = "arm,vexpress-osc";
arm,vexpress-sysreg,func = <1 1>;
- freq-range = <23750000 63500000>;
+ freq-range = <23750000 65000000>;
#clock-cells = <0>;
clock-output-names = "v2m:oscclk1";
};
@@ -316,9 +322,11 @@
arm,vexpress-sysreg,func = <5 0>;
};
- muxfpga@0 {
+ v2m_muxfpga: muxfpga@0 {
compatible = "arm,vexpress-muxfpga";
arm,vexpress-sysreg,func = <7 0>;
+ #display-cells = <1>;
+ display = <&v2m_dvimode>;
};
shutdown@0 {
@@ -331,9 +339,10 @@
arm,vexpress-sysreg,func = <9 0>;
};
- dvimode@0 {
+ v2m_dvimode: dvimode@0 {
compatible = "arm,vexpress-dvimode";
arm,vexpress-sysreg,func = <11 0>;
+ #display-cells = <0>;
};
};
};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 1420bb1..2a63510 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -73,6 +73,11 @@
interrupts = <0 44 4>;
clocks = <&oscclk1>, <&oscclk2>;
clock-names = "clcdclk", "apb_pclk";
+ label = "V2P-CA9 CLCD";
+ display = <&v2m_muxfpga 0xf>;
+ max-hactive = <1024>;
+ max-vactive = <768>;
+ max-bpp = <16>;
};
memory-controller@100e0000 {
--
1.7.10.4
^ permalink raw reply related
* [RFC 09/10] video: Versatile Express DVI mode driver
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel
Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>
Versatile Express DVI output is driven by a Sii9022 chip. It can be
controller to a limited extend by the Motherboard Config Controller,
and that's what the driver is doing now. It is a temporary measure
till there's a full I2C driver for the chip.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
drivers/video/Makefile | 1 +
drivers/video/vexpress-dvimode.c | 158 ++++++++++++++++++++++++++++++++++++++
2 files changed, 159 insertions(+)
create mode 100644 drivers/video/vexpress-dvimode.c
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 84c6083..9347e00 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -179,3 +179,4 @@ obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
# platform specific output drivers
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-muxfpga.o
+obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-dvimode.o
diff --git a/drivers/video/vexpress-dvimode.c b/drivers/video/vexpress-dvimode.c
new file mode 100644
index 0000000..85d5608
--- /dev/null
+++ b/drivers/video/vexpress-dvimode.c
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-dvimode: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+#include <video/display.h>
+#include <video/videomode.h>
+
+
+static struct vexpress_config_func *vexpress_dvimode_func;
+
+
+static int vexpress_dvimode_display_update(struct display_entity *display,
+ const struct videomode *mode)
+{
+ static const struct {
+ u32 hactive, vactive, dvimode;
+ } dvimodes[] = {
+ { 640, 480, 0 }, /* VGA */
+ { 800, 600, 1 }, /* SVGA */
+ { 1024, 768, 2 }, /* XGA */
+ { 1280, 1024, 3 }, /* SXGA */
+ { 1600, 1200, 4 }, /* UXGA */
+ { 1920, 1080, 5 }, /* HD1080 */
+ };
+ int err = -ENOENT;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dvimodes); i++) {
+ if (dvimodes[i].hactive == mode->hactive &&
+ dvimodes[i].vactive == mode->vactive) {
+ pr_debug("mode: %ux%u = %d\n", mode->hactive,
+ mode->vactive, dvimodes[i].dvimode);
+ err = vexpress_config_write(vexpress_dvimode_func, 0,
+ dvimodes[i].dvimode);
+ break;
+ }
+ }
+
+ if (err)
+ pr_warn("Failed to set %ux%u mode! (%d)\n", mode->hactive,
+ mode->vactive, err);
+
+ return err;
+}
+
+static int vexpress_dvimode_display_get_modes(struct display_entity *display,
+ const struct videomode **modes)
+{
+ static const struct videomode m[] = {
+ {
+ /* VGA */
+ .pixelclock = 25175000,
+ .hactive = 640,
+ .hback_porch = 40,
+ .hfront_porch = 24,
+ .vfront_porch = 11,
+ .hsync_len = 96,
+ .vactive = 480,
+ .vback_porch = 32,
+ .vsync_len = 2,
+ }, {
+ /* XGA */
+ .pixelclock = 63500127,
+ .hactive = 1024,
+ .hback_porch = 152,
+ .hfront_porch = 48,
+ .hsync_len = 104,
+ .vactive = 768,
+ .vback_porch = 23,
+ .vfront_porch = 3,
+ .vsync_len = 4,
+ }, {
+ /* SXGA */
+ .pixelclock = 108000000,
+ .hactive = 1280,
+ .hback_porch = 248,
+ .hfront_porch = 48,
+ .hsync_len = 112,
+ .vactive = 1024,
+ .vback_porch = 38,
+ .vfront_porch = 1,
+ .vsync_len = 3,
+ },
+ };
+
+ *modes = m;
+
+ return ARRAY_SIZE(m);
+}
+
+static int vexpress_dvimode_display_get_params(struct display_entity *display,
+ struct display_entity_interface_params *params)
+{
+ params->type = DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL;
+ params->p.tft_parallel.r_bits = 8;
+ params->p.tft_parallel.g_bits = 8;
+ params->p.tft_parallel.b_bits = 8;
+ params->p.tft_parallel.r_b_swapped = 0;
+
+ return 0;
+}
+
+static const struct display_entity_control_ops vexpress_dvimode_display_ops = {
+ .update = vexpress_dvimode_display_update,
+ .get_modes = vexpress_dvimode_display_get_modes,
+ .get_params = vexpress_dvimode_display_get_params,
+};
+
+static struct display_entity vexpress_dvimode_display = {
+ .ops.ctrl = &vexpress_dvimode_display_ops,
+};
+
+static struct of_device_id vexpress_dvimode_of_match[] = {
+ { .compatible = "arm,vexpress-dvimode", },
+ {}
+};
+
+static int vexpress_dvimode_probe(struct platform_device *pdev)
+{
+ vexpress_dvimode_func = vexpress_config_func_get_by_dev(&pdev->dev);
+
+ vexpress_dvimode_display.dev = &pdev->dev;
+ display_entity_register(&vexpress_dvimode_display);
+ of_display_entity_add_provider(pdev->dev.of_node,
+ of_display_entity_provider_simple_get,
+ &vexpress_dvimode_display);
+
+ return 0;
+}
+
+static struct platform_driver vexpress_dvimode_driver = {
+ .probe = vexpress_dvimode_probe,
+ .driver = {
+ .name = "vexpress-dvimode",
+ .of_match_table = vexpress_dvimode_of_match,
+ },
+};
+
+static int __init vexpress_dvimode_init(void)
+{
+ return platform_driver_register(&vexpress_dvimode_driver);
+}
+device_initcall(vexpress_dvimode_init);
--
1.7.10.4
^ permalink raw reply related
* [RFC 08/10] video: Versatile Express MUXFPGA driver
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel
Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>
Versatile Express' DVI video output can be connected to one the three
sources - motherboard's CLCD controller or a video signal generated
by one of the daughterboards.
This driver provides a Common Display Framework driver for the
muxer FPGA, which acts as a switch selecting one of the video data
sources. The default source is selected basing on the priority
list (which itself can be modified via module paramter), but
the user can make his own decision about it using the device's
sysfs "source" attribute.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
.../testing/sysfs-driver-video-vexpress-muxfpga | 5 +
drivers/video/Makefile | 3 +
drivers/video/vexpress-muxfpga.c | 228 ++++++++++++++++++++
3 files changed, 236 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
create mode 100644 drivers/video/vexpress-muxfpga.c
diff --git a/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga b/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
new file mode 100644
index 0000000..bfd568d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
@@ -0,0 +1,5 @@
+What: /sys/bus/platform/drivers/vexpress-muxfpga/<muxfpga device>/source
+Date: April 2013
+Contant: Pawel Moll <pawel.moll@arm.com>
+Description: This file stores the id of the video signal source
+ supposed to be routed to the board's DVI output.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index b989e8e..84c6083 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -176,3 +176,6 @@ obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
obj-$(CONFIG_VIDEOMODE) += videomode.o
obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
+
+# platform specific output drivers
+obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-muxfpga.o
diff --git a/drivers/video/vexpress-muxfpga.c b/drivers/video/vexpress-muxfpga.c
new file mode 100644
index 0000000..1731ad0
--- /dev/null
+++ b/drivers/video/vexpress-muxfpga.c
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-muxfpga: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+#include <video/display.h>
+#include <video/videomode.h>
+
+
+static struct vexpress_config_func *vexpress_muxfpga_func;
+static struct display_entity *vexpress_muxfpga_output;
+
+
+static struct vexpress_muxfpga_source {
+ struct display_entity display;
+ struct videomode mode;
+ bool updated;
+} vexpress_muxfpga_sources[__VEXPRESS_SITE_LAST];
+static u32 vexpress_muxfpga_source_site = VEXPRESS_SITE_MB;
+static bool vexpress_muxfpga_source_stored;
+
+
+static int vexpress_muxfpga_set_site(u32 site)
+{
+ int err;
+
+ if (site >= ARRAY_SIZE(vexpress_muxfpga_sources))
+ return -EINVAL;
+
+ err = vexpress_config_write(vexpress_muxfpga_func, 0, site);
+ if (!err) {
+ pr_debug("Selected site %d as source\n", site);
+ vexpress_muxfpga_source_site = site;
+ } else {
+ pr_warn("Failed to select site %d as source! (%d)\n",
+ site, err);
+ }
+
+ return err;
+}
+
+static unsigned int vexpress_muxfpga_preferred_sites[] = {
+ VEXPRESS_SITE_MASTER,
+ VEXPRESS_SITE_DB1,
+ VEXPRESS_SITE_DB2,
+ VEXPRESS_SITE_MB,
+};
+static unsigned int vexpress_muxfpga_preferred_sites_num =
+ ARRAY_SIZE(vexpress_muxfpga_preferred_sites);
+module_param_array_named(preferred_sites, vexpress_muxfpga_preferred_sites,
+ uint, &vexpress_muxfpga_preferred_sites_num, S_IRUGO);
+MODULE_PARM_DESC(preferred_sites, "Preferred order of MUXFPGA (DVI output) "
+ "sources; values can be a daughterboard site ID (1-2), the "
+ "motherboard ID (0) or a value describing the master site "
+ "(0xf).");
+
+static int vexpress_muxfpga_get_priority(u32 site)
+{
+ int i;
+
+ for (i = 0; i < vexpress_muxfpga_preferred_sites_num; i++) {
+ u32 preference = vexpress_muxfpga_preferred_sites[i];
+
+ if (site == vexpress_get_site(preference))
+ return i;
+ }
+
+ return INT_MAX;
+}
+
+static void vexpress_muxfpga_set_preffered_site(u32 site)
+{
+ int current_priority = vexpress_muxfpga_get_priority(
+ vexpress_muxfpga_source_site);
+ int new_priority = vexpress_muxfpga_get_priority(site);
+
+ if (new_priority <= current_priority)
+ vexpress_muxfpga_set_site(site);
+}
+
+
+static int vexpress_muxfpga_display_update(struct display_entity *display,
+ const struct videomode *mode)
+{
+ int err = display_entity_update(vexpress_muxfpga_output, mode);
+
+ if (!err) {
+ struct vexpress_muxfpga_source *source = container_of(display,
+ struct vexpress_muxfpga_source, display);
+
+ source->updated = true;
+ source->mode = *mode;
+ }
+
+ return err;
+}
+
+static int vexpress_muxfpga_display_get_modes(struct display_entity *display,
+ const struct videomode **modes)
+{
+ return display_entity_get_modes(vexpress_muxfpga_output, modes);
+}
+
+static int vexpress_muxfpga_display_get_params(struct display_entity *display,
+ struct display_entity_interface_params *params)
+{
+ return display_entity_get_params(vexpress_muxfpga_output, params);
+}
+
+static const struct display_entity_control_ops vexpress_muxfpga_display_ops = {
+ .update = vexpress_muxfpga_display_update,
+ .get_modes = vexpress_muxfpga_display_get_modes,
+ .get_params = vexpress_muxfpga_display_get_params,
+};
+
+
+static ssize_t vexpress_muxfpga_show_source(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ return sprintf(buf, "%u\n", vexpress_muxfpga_source_site);
+}
+
+static ssize_t vexpress_muxfpga_store_source(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u32 site;
+ int err = kstrtou32(buf, 0, &site);
+
+ if (!err) {
+ site = vexpress_get_site(site);
+ err = vexpress_muxfpga_set_site(site);
+ }
+
+ if (!err)
+ vexpress_muxfpga_source_stored = true;
+
+ if (!err && vexpress_muxfpga_sources[site].updated)
+ vexpress_muxfpga_display_update(
+ &vexpress_muxfpga_sources[site].display,
+ &vexpress_muxfpga_sources[site].mode);
+
+ return err ? err : count;
+}
+
+DEVICE_ATTR(source, S_IRUGO | S_IWUSR, vexpress_muxfpga_show_source,
+ vexpress_muxfpga_store_source);
+
+static struct display_entity *vexpress_muxfpga_display_get(
+ struct of_phandle_args *spec, void *data)
+{
+ u32 site = vexpress_get_site(spec->args[0]);
+
+ if (WARN_ON(spec->args_count != 1 ||
+ site >= ARRAY_SIZE(vexpress_muxfpga_sources)))
+ return NULL;
+
+ /* Skip source selection if the user made his choice */
+ if (!vexpress_muxfpga_source_stored)
+ vexpress_muxfpga_set_preffered_site(site);
+
+ return &vexpress_muxfpga_sources[site].display;
+}
+
+
+static struct of_device_id vexpress_muxfpga_of_match[] = {
+ { .compatible = "arm,vexpress-muxfpga", },
+ {}
+};
+
+static int vexpress_muxfpga_probe(struct platform_device *pdev)
+{
+ struct display_entity_interface_params params;
+ int i;
+
+ vexpress_muxfpga_output = of_display_entity_get(pdev->dev.of_node, 0);
+ if (!vexpress_muxfpga_output)
+ return -EPROBE_DEFER;
+
+ if (display_entity_get_params(vexpress_muxfpga_output, ¶ms) != 0 ||
+ params.type != DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL)
+ return -EINVAL;
+
+ vexpress_muxfpga_func = vexpress_config_func_get_by_dev(&pdev->dev);
+
+ for (i = 0; i < ARRAY_SIZE(vexpress_muxfpga_sources); i++) {
+ struct vexpress_muxfpga_source *source =
+ &vexpress_muxfpga_sources[i];
+
+ source->display.dev = &pdev->dev;
+ source->display.ops.ctrl = &vexpress_muxfpga_display_ops;
+ WARN_ON(display_entity_register(&source->display));
+ of_display_entity_add_provider(pdev->dev.of_node,
+ vexpress_muxfpga_display_get, NULL);
+ }
+
+ device_create_file(&pdev->dev, &dev_attr_source);
+
+ return 0;
+}
+
+static struct platform_driver vexpress_muxfpga_driver = {
+ .probe = vexpress_muxfpga_probe,
+ .driver = {
+ .name = "vexpress-muxfpga",
+ .of_match_table = vexpress_muxfpga_of_match,
+ },
+};
+
+static int __init vexpress_muxfpga_init(void)
+{
+ return platform_driver_register(&vexpress_muxfpga_driver);
+}
+device_initcall(vexpress_muxfpga_init);
--
1.7.10.4
^ permalink raw reply related
* [RFC 07/10] mfd: vexpress: Allow external drivers to parse site ids
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel
Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>
... by providing a function translating the MASTER
value into the currently valid site number and
a _LAST constant providing all possible site id values.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
drivers/mfd/vexpress-sysreg.c | 5 +++++
include/linux/vexpress.h | 2 ++
2 files changed, 7 insertions(+)
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index bf75e96..4158e26 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -81,6 +81,11 @@ void vexpress_flags_set(u32 data)
writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
}
+u32 vexpress_get_site(int site)
+{
+ return site == VEXPRESS_SITE_MASTER ? vexpress_master_site : site;
+}
+
u32 vexpress_get_procid(int site)
{
if (site == VEXPRESS_SITE_MASTER)
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 7581874..1ebbcf5 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -19,6 +19,7 @@
#define VEXPRESS_SITE_MB 0
#define VEXPRESS_SITE_DB1 1
#define VEXPRESS_SITE_DB2 2
+#define __VEXPRESS_SITE_LAST 3
#define VEXPRESS_SITE_MASTER 0xf
#define VEXPRESS_CONFIG_STATUS_DONE 0
@@ -103,6 +104,7 @@ int vexpress_config_write(struct vexpress_config_func *func, int offset,
/* Platform control */
+u32 vexpress_get_site(int site);
u32 vexpress_get_procid(int site);
u32 vexpress_get_hbi(int site);
void *vexpress_get_24mhz_clock_base(void);
--
1.7.10.4
^ permalink raw reply related
* [RFC 06/10] video: ARM CLCD: Add DT & CDF support
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
linux-arm-kernel
Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>
This patch adds basic DT bindings for the PL11x CLCD cells
and make their fbdev driver use them, together with the
Common Display Framework.
The DT provides information about the hardware configuration
and limitations (eg. the largest supported resolution)
but the video modes come exclusively from the Common
Display Framework drivers, referenced to by the standard CDF
binding.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
.../devicetree/bindings/video/arm,pl11x.txt | 35 +++
drivers/video/Kconfig | 1 +
drivers/video/amba-clcd.c | 244 ++++++++++++++++++++
include/linux/amba/clcd.h | 2 +
4 files changed, 282 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/arm,pl11x.txt
diff --git a/Documentation/devicetree/bindings/video/arm,pl11x.txt b/Documentation/devicetree/bindings/video/arm,pl11x.txt
new file mode 100644
index 0000000..ee9534a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/arm,pl11x.txt
@@ -0,0 +1,35 @@
+* ARM PrimeCell Color LCD Controller (CLCD) PL110/PL111
+
+Required properties:
+
+- compatible : must be one of:
+ "arm,pl110", "arm,primecell"
+ "arm,pl111", "arm,primecell"
+- reg : base address and size of the control registers block
+- interrupts : the combined interrupt
+- clocks : phandles to the CLCD (pixel) clock and the APB clocks
+- clock-names : "clcdclk", "apb_pclk"
+- display : phandle to the display entity connected to the controller
+
+Optional properties:
+
+- label : string describing the controller location and/or usage
+- video-ram : phandle to DT node of the specialized video RAM to be used
+- max-hactive : maximum frame buffer width in pixels
+- max-vactive : maximum frame buffer height in pixels
+- max-bpp : maximum number of bits per pixel
+- big-endian-pixels : defining this property makes the pixel bytes being
+ accessed in Big Endian organization
+
+Example:
+
+ clcd@1f0000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x1f0000 0x1000>;
+ interrupts = <14>;
+ clocks = <&v2m_oscclk1>, <&smbclk>;
+ clock-names = "clcdclk", "apb_pclk";
+ label = "IOFPGA CLCD";
+ video-ram = <&v2m_vram>;
+ display = <&v2m_muxfpga>;
+ };
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 281e548..bad8166 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -340,6 +340,7 @@ config FB_ARMCLCD
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS if OF
help
This framebuffer device driver is for the ARM PrimeCell PL110
Colour LCD controller. ARM PrimeCells provide the building
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0a2cce7..778dc03 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -25,6 +25,11 @@
#include <linux/amba/clcd.h>
#include <linux/clk.h>
#include <linux/hardirq.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <video/display.h>
+#include <video/videomode.h>
#include <asm/sizes.h>
@@ -62,6 +67,10 @@ static void clcdfb_disable(struct clcd_fb *fb)
{
u32 val;
+ if (fb->panel->display)
+ display_entity_set_state(fb->panel->display,
+ DISPLAY_ENTITY_STATE_OFF);
+
if (fb->board->disable)
fb->board->disable(fb);
@@ -115,6 +124,11 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
*/
if (fb->board->enable)
fb->board->enable(fb);
+
+ if (fb->panel->display)
+ display_entity_set_state(fb->panel->display,
+ DISPLAY_ENTITY_STATE_ON);
+
}
static int
@@ -304,6 +318,13 @@ static int clcdfb_set_par(struct fb_info *info)
clcdfb_enable(fb, regs.cntl);
+ if (fb->panel->display) {
+ struct videomode mode;
+
+ videomode_from_fb_var_screeninfo(&fb->fb.var, &mode);
+ display_entity_update(fb->panel->display, &mode);
+ }
+
#ifdef DEBUG
printk(KERN_INFO
"CLCD: Registers set to\n"
@@ -542,6 +563,226 @@ static int clcdfb_register(struct clcd_fb *fb)
return ret;
}
+#if defined(CONFIG_OF)
+static int clcdfb_of_get_tft_parallel_panel(struct clcd_panel *panel,
+ struct display_entity_interface_params *params)
+{
+ int r = params->p.tft_parallel.r_bits;
+ int g = params->p.tft_parallel.g_bits;
+ int b = params->p.tft_parallel.b_bits;
+
+ /* Bypass pixel clock divider, data output on the falling edge */
+ panel->tim2 = TIM2_BCD | TIM2_IPC;
+
+ /* TFT display, vert. comp. interrupt at the start of the back porch */
+ panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
+
+ if (params->p.tft_parallel.r_b_swapped)
+ panel->cntl |= CNTL_BGR;
+
+ if (r >= 4 && g >= 4 && b >= 4)
+ panel->caps |= CLCD_CAP_444;
+ if (r >= 5 && g >= 5 && b >= 5)
+ panel->caps |= CLCD_CAP_5551;
+ if (r >= 5 && g >= 6 && b >= 5)
+ panel->caps |= CLCD_CAP_565;
+ if (r >= 8 && g >= 8 && b >= 8)
+ panel->caps |= CLCD_CAP_888;
+
+ return 0;
+}
+
+static int clcdfb_of_init_display(struct clcd_fb *fb)
+{
+ struct device_node *node = fb->dev->dev.of_node;
+ struct display_entity_interface_params params;
+ const struct videomode *modes;
+ int modes_num;
+ int best_mode = -1;
+ u32 max_bpp = 32;
+ u32 max_hactive = (u32)~0UL;
+ u32 max_vactive = (u32)~0UL;
+ unsigned int width, height;
+ char *mode_name;
+ int i, err;
+
+ fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
+ if (!fb->panel)
+ return -ENOMEM;
+
+ fb->panel->display = of_display_entity_get(node, 0);
+ if (!fb->panel->display)
+ return -EPROBE_DEFER;
+
+ modes_num = display_entity_get_modes(fb->panel->display, &modes);
+ if (modes_num < 0)
+ return modes_num;
+
+ /* Pick the "best" (the widest, then the highest) mode from the list */
+ of_property_read_u32(node, "max-hactive", &max_hactive);
+ of_property_read_u32(node, "max-vactive", &max_vactive);
+ for (i = 0; i < modes_num; i++) {
+ if (modes[i].hactive > max_hactive ||
+ modes[i].vactive > max_vactive)
+ continue;
+ if (best_mode < 0 ||
+ (modes[i].hactive >= modes[best_mode].hactive &&
+ modes[i].vactive > modes[best_mode].vactive))
+ best_mode = i;
+ }
+ if (best_mode < 0)
+ return -ENODEV;
+
+ err = fb_videomode_from_videomode(&modes[best_mode], &fb->panel->mode);
+ if (err)
+ return err;
+
+ i = snprintf(NULL, 0, "%ux%u@%u", fb->panel->mode.xres,
+ fb->panel->mode.yres, fb->panel->mode.refresh);
+ mode_name = devm_kzalloc(&fb->dev->dev, i + 1, GFP_KERNEL);
+ snprintf(mode_name, i + 1, "%ux%u@%u", fb->panel->mode.xres,
+ fb->panel->mode.yres, fb->panel->mode.refresh);
+ fb->panel->mode.name = mode_name;
+
+ of_property_read_u32(node, "max-bpp", &max_bpp);
+ fb->panel->bpp = max_bpp;
+
+ if (of_property_read_bool(node, "big-endian-pixels"))
+ fb->panel->cntl |= CNTL_BEBO;
+
+ if (display_entity_get_size(fb->panel->display, &width, &height) != 0)
+ width = height = -1;
+ fb->panel->width = width;
+ fb->panel->height = height;
+
+ err = display_entity_get_params(fb->panel->display, ¶ms);
+ if (err)
+ return err;
+
+ switch (params.type) {
+ case DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL:
+ return clcdfb_of_get_tft_parallel_panel(fb->panel, ¶ms);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int clcdfb_of_vram_setup(struct clcd_fb *fb)
+{
+ const __be32 *prop = of_get_property(fb->dev->dev.of_node, "video-ram",
+ NULL);
+ struct device_node *node = of_find_node_by_phandle(be32_to_cpup(prop));
+ u64 size;
+ int err;
+
+ if (!node)
+ return -ENODEV;
+
+ err = clcdfb_of_init_display(fb);
+ if (err)
+ return err;
+
+ fb->fb.screen_base = of_iomap(node, 0);
+ if (!fb->fb.screen_base)
+ return -ENOMEM;
+
+ fb->fb.fix.smem_start = of_translate_address(node,
+ of_get_address(node, 0, &size, NULL));
+ fb->fb.fix.smem_len = size;
+
+ return 0;
+}
+
+static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ unsigned long off, user_size, kernel_size;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ user_size = vma->vm_end - vma->vm_start;
+ kernel_size = fb->fb.fix.smem_len;
+
+ if (off >= kernel_size || user_size > (kernel_size - off))
+ return -ENXIO;
+
+ return remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
+ user_size,
+ pgprot_writecombine(vma->vm_page_prot));
+}
+
+static void clcdfb_of_vram_remove(struct clcd_fb *fb)
+{
+ iounmap(fb->fb.screen_base);
+}
+
+static int clcdfb_of_dma_setup(struct clcd_fb *fb)
+{
+ unsigned long framesize;
+ dma_addr_t dma;
+ int err;
+
+ err = clcdfb_of_init_display(fb);
+ if (err)
+ return err;
+
+ framesize = fb->panel->mode.xres * fb->panel->mode.yres *
+ fb->panel->bpp / 8;
+ fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
+ &dma, GFP_KERNEL);
+ if (!fb->fb.screen_base)
+ return -ENOMEM;
+
+ fb->fb.fix.smem_start = dma;
+ fb->fb.fix.smem_len = framesize;
+
+ return 0;
+}
+
+static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base,
+ fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+}
+
+static void clcdfb_of_dma_remove(struct clcd_fb *fb)
+{
+ dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+ fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
+{
+ struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
+ GFP_KERNEL);
+ struct device_node *node = dev->dev.of_node;
+
+ if (!board)
+ return NULL;
+
+ board->name = of_get_property(node, "label", NULL);
+ if (!board->name)
+ board->name = of_node_full_name(node);
+ board->check = clcdfb_check;
+ board->decode = clcdfb_decode;
+ if (of_find_property(node, "video-ram", NULL)) {
+ board->setup = clcdfb_of_vram_setup;
+ board->mmap = clcdfb_of_vram_mmap;
+ board->remove = clcdfb_of_vram_remove;
+ } else {
+ board->setup = clcdfb_of_dma_setup;
+ board->mmap = clcdfb_of_dma_mmap;
+ board->remove = clcdfb_of_dma_remove;
+ }
+
+ return board;
+}
+#else
+static struct clcd_board *clcdfb_of_get_board(struct amba_dev *dev)
+{
+ return NULL;
+}
+#endif
+
static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
{
struct clcd_board *board = dev->dev.platform_data;
@@ -549,6 +790,9 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
int ret;
if (!board)
+ board = clcdfb_of_get_board(dev);
+
+ if (!board)
return -EINVAL;
ret = amba_request_regions(dev, NULL);
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
index e82e3ee..73b199b 100644
--- a/include/linux/amba/clcd.h
+++ b/include/linux/amba/clcd.h
@@ -10,6 +10,7 @@
* for more details.
*/
#include <linux/fb.h>
+#include <video/display.h>
/*
* CLCD Controller Internal Register addresses
@@ -105,6 +106,7 @@ struct clcd_panel {
fixedtimings:1,
grayscale:1;
unsigned int connector;
+ struct display_entity *display;
};
struct clcd_regs {
--
1.7.10.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox