* [PATCHv2 0/8] *** ARM: Update arch-vt8500 to Devicetree ***
From: Tony Prisk @ 2012-08-09 1:54 UTC (permalink / raw)
To: linux-arm-kernel
This patchset updates arch-vt8500 to devicetree and removes all the old-style
code. Support for WM8650 has also been added.
Example dts/dtsi files are given for the three currently supported models.
Major changes:
GPIO code has been converted to a platform_device and rewritten as WM8505
support was broken. Add support for WM8650 gpio controller.
UHCI support was missing. Added this as a generic non-pci uhci controller as
it doesn't require anything special. Should be usable by any system that doesn't
have special requirements to get the UHCI controller working.
Framebuffer code patched to support WM8650. The bindings for this are of concern
but there doesn't seem to be a formalized binding yet. This patch is based off
Sascha Hauer's current patch on the dri-devel mailing list and should be easily
patched out when its finalized.
Patchset based on Arnd's arm-soc/for-next branch.
Could I get this reviewed, hopefully for inclusion into v3.7.
Regards
Tony Prisk
Changes
v2:
Cleanup style/formatting errors
Removed erroneous commit message about GPIO not being converted to devicetree
Corrected arch-vt8500/irq.c header to correct filename
Changed GPIO driver to use module_platform_driver()
Renamed vt8500_gpio_bank_regs -> vt8500_gpio_bank_regoffsets
Changed vt8500_gpio_bank_regoffset fields to unsigned int
Changed bit-setting code to use BIT() macro
Removed of_find_compatible() and use pdev->dev.of_node in _probe()
Removed regoff field and related code - leftover from old design
Added kerneldoc regarding struct vt8500_gpio_bank_regoffsets fields
Update MODULE_LICENSE on all platform devices to "GPL v2" to match their headers
Renamed dts board files to clarify product names
Tony Prisk (8):
arm: vt8500: Add device tree files for VIA/Wondermedia SoC's
rtc: vt8500: Add devicetree support for vt8500-rtc
serial: vt8500: Add devicetree support for vt8500-serial
usb: vt8500: Add devicetree support for vt8500-ehci and -uhci.
video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb
arm: vt8500: Update arch-vt8500 to devicetree support.
arm: vt8500: doc: Add device tree bindings for arch-vt8500 devices
ARM: vt8500: gpio: Devicetree support for arch-vt8500
Documentation/devicetree/bindings/arm/vt8500.txt | 15 +
.../bindings/arm/vt8500/via,vt8500-intc.txt | 16 +
.../bindings/arm/vt8500/via,vt8500-pmc.txt | 13 +
.../bindings/arm/vt8500/via,vt8500-timer.txt | 15 +
.../devicetree/bindings/gpio/gpio_vt8500.txt | 24 ++
.../devicetree/bindings/rtc/via,vt8500-rtc.txt | 15 +
.../bindings/tty/serial/via,vt8500-uart.txt | 15 +
.../devicetree/bindings/usb/platform-uhci.txt | 15 +
.../devicetree/bindings/usb/via,vt8500-ehci.txt | 15 +
.../devicetree/bindings/vendor-prefixes.txt | 2 +
.../devicetree/bindings/video/via,vt8500-fb.txt | 46 +++
.../devicetree/bindings/video/wm,prizm-ge-rops.txt | 13 +
.../devicetree/bindings/video/wm,wm8505-fb.txt | 20 ++
arch/arm/Kconfig | 2 +
arch/arm/boot/dts/vt8500.dtsi | 99 ++++++
arch/arm/boot/dts/vt8500_ref.dts | 31 ++
arch/arm/boot/dts/wm8505.dtsi | 125 ++++++++
arch/arm/boot/dts/wm8505_ref.dts | 31 ++
arch/arm/boot/dts/wm8650.dtsi | 95 ++++++
arch/arm/boot/dts/wm8650_ref.dts | 31 ++
arch/arm/mach-vt8500/Kconfig | 72 +----
arch/arm/mach-vt8500/Makefile | 9 +-
arch/arm/mach-vt8500/bv07.c | 80 -----
arch/arm/mach-vt8500/common.h | 25 ++
arch/arm/mach-vt8500/devices-vt8500.c | 91 ------
arch/arm/mach-vt8500/devices-wm8505.c | 99 ------
arch/arm/mach-vt8500/devices.c | 270 -----------------
arch/arm/mach-vt8500/devices.h | 88 ------
arch/arm/mach-vt8500/gpio.c | 240 ---------------
arch/arm/mach-vt8500/include/mach/restart.h | 4 +-
arch/arm/mach-vt8500/include/mach/vt8500_irqs.h | 88 ------
arch/arm/mach-vt8500/include/mach/vt8500_regs.h | 79 -----
arch/arm/mach-vt8500/include/mach/wm8505_irqs.h | 115 -------
arch/arm/mach-vt8500/include/mach/wm8505_regs.h | 78 -----
arch/arm/mach-vt8500/irq.c | 160 +++++-----
arch/arm/mach-vt8500/restart.c | 54 ----
arch/arm/mach-vt8500/timer.c | 56 +++-
arch/arm/mach-vt8500/vt8500.c | 192 ++++++++++++
arch/arm/mach-vt8500/wm8505_7in.c | 79 -----
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-vt8500.c | 318 ++++++++++++++++++++
drivers/rtc/rtc-vt8500.c | 7 +
drivers/tty/serial/vt8500_serial.c | 7 +
drivers/usb/host/Kconfig | 4 +-
drivers/usb/host/ehci-vt8500.c | 24 +-
drivers/usb/host/uhci-hcd.c | 5 +
drivers/usb/host/uhci-platform.c | 166 ++++++++++
drivers/video/Kconfig | 6 +-
drivers/video/vt8500lcdfb.c | 77 ++++-
drivers/video/wm8505fb.c | 95 +++++-
drivers/video/wmt_ge_rops.c | 7 +
52 files changed, 1674 insertions(+), 1566 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/vt8500.txt
create mode 100644 Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt
create mode 100644 Documentation/devicetree/bindings/arm/vt8500/via,vt8500-pmc.txt
create mode 100644 Documentation/devicetree/bindings/arm/vt8500/via,vt8500-timer.txt
create mode 100644 Documentation/devicetree/bindings/gpio/gpio_vt8500.txt
create mode 100644 Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt
create mode 100644 Documentation/devicetree/bindings/tty/serial/via,vt8500-uart.txt
create mode 100644 Documentation/devicetree/bindings/usb/platform-uhci.txt
create mode 100644 Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
create mode 100644 Documentation/devicetree/bindings/video/via,vt8500-fb.txt
create mode 100644 Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt
create mode 100644 Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
create mode 100644 arch/arm/boot/dts/vt8500.dtsi
create mode 100644 arch/arm/boot/dts/vt8500_ref.dts
create mode 100644 arch/arm/boot/dts/wm8505.dtsi
create mode 100644 arch/arm/boot/dts/wm8505_ref.dts
create mode 100644 arch/arm/boot/dts/wm8650.dtsi
create mode 100644 arch/arm/boot/dts/wm8650_ref.dts
delete mode 100644 arch/arm/mach-vt8500/bv07.c
create mode 100644 arch/arm/mach-vt8500/common.h
delete mode 100644 arch/arm/mach-vt8500/devices-vt8500.c
delete mode 100644 arch/arm/mach-vt8500/devices-wm8505.c
delete mode 100644 arch/arm/mach-vt8500/devices.c
delete mode 100644 arch/arm/mach-vt8500/devices.h
delete mode 100644 arch/arm/mach-vt8500/gpio.c
delete mode 100644 arch/arm/mach-vt8500/include/mach/vt8500_irqs.h
delete mode 100644 arch/arm/mach-vt8500/include/mach/vt8500_regs.h
delete mode 100644 arch/arm/mach-vt8500/include/mach/wm8505_irqs.h
delete mode 100644 arch/arm/mach-vt8500/include/mach/wm8505_regs.h
delete mode 100644 arch/arm/mach-vt8500/restart.c
create mode 100644 arch/arm/mach-vt8500/vt8500.c
delete mode 100644 arch/arm/mach-vt8500/wm8505_7in.c
create mode 100644 drivers/gpio/gpio-vt8500.c
create mode 100644 drivers/usb/host/uhci-platform.c
--
1.7.9.5
^ permalink raw reply
* Re: [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
From: Arnd Bergmann @ 2012-08-08 19:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5022B242.1050001@wwwdotorg.org>
On Wednesday 08 August 2012, Stephen Warren wrote:
> I think that's all just:
>
> module_platform_driver(vt8500_gpio_driver);
>
> (except that _init uses platform_driver_probe() rather than
> platform_driver_register(), which seems unusual. I guess that explains
> the of_find_matching_node() above too.)
Ah, I totally missed both of these. Using platform_driver_register
is definitely preferred over platform_driver_probe in cases like
this, so using module_platform_driver is the right simplification.
Arnd
^ permalink raw reply
* Re: [PATCH 6/8] arm: vt8500: Update arch-vt8500 to devicetree support.
From: Stephen Warren @ 2012-08-08 18:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1344389967-8465-7-git-send-email-linux@prisktech.co.nz>
On 08/07/2012 07:39 PM, Tony Prisk wrote:
> Merged existing board files to a single dt-capable file.
> Converted irq and timer code to devicetree.
> Removed existing device files that are no longer required with
> devicetree support.
>
> All existing platform devices are converted to devicetree nodes
> except GPIO and PWM.
Perhaps that also explains what I was commenting on in the GPIO driver
patch. Why not convert GPIO too?
> diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c
> /*
> - * arch/arm/mach-vt8500/irq.c
> + * arch/arm/mach-vt8500/irq_dt.c
This file didn't get renamed?
> diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c
> +void __init vt8500_init(void)
> +{
> + struct device_node *np, *fb;
> + void __iomem *gpio_base;
> +
> +#ifdef CONFIG_FB_VT8500
> + fb = of_find_compatible_node(NULL, NULL, "via,vt8500-fb");
> + if (fb) {
> + np = of_find_compatible_node(NULL, NULL, "via,vt8500-gpio");
> + if (np) {
> + gpio_base = of_iomap(np, 0);
> +
> + if (!gpio_base)
> + pr_err("%s:of_iomap(gpio_mux) failed\n", __func__);
> +
> + of_node_put(np);
> + } else {
> + gpio_base = ioremap(LEGACY_GPIO_BASE, 0x1000);
> + if (!gpio_base)
> + pr_err("%s:ioremap(legacy_gpio_mux) failed\n", __func__);
> + }
> + if (gpio_base) {
> + writel(readl(gpio_base + VT8500_GPIO_MUX_REG) | 1,
> + gpio_base + VT8500_GPIO_MUX_REG);
> + iounmap(gpio_base);
> + } else
> + pr_err("%s: Could not remap GPIO mux\n", __func__);
> +
> + of_node_put(fb);
> + }
> +#endif
That looks quite suspicious. What's it doing? Is this something that
should be part of a pinctrl driver, or the GPIO driver?
^ permalink raw reply
* Re: [PATCH 5/8] video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb
From: Stephen Warren @ 2012-08-08 18:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1344389967-8465-6-git-send-email-linux@prisktech.co.nz>
On 08/07/2012 07:39 PM, Tony Prisk wrote:
> Update vt8500-fb, wm8505-fb and wmt-ge-rops to support device
> tree bindings.
> Small change in wm8505-fb.c to support WM8650 framebuffer color
> format.
That might warrant a separate patch?
> diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
> + np = of_find_node_by_name(NULL, "display");
> + if (!np) {
> + pr_err("%s: No display description in Device Tree\n", __func__);
> + ret = -EINVAL;
> + goto failed_free_res;
> + }
I believe that using hard-coded node names is frowned upon. Better would
be to put a phandle into the display controller's node that points at
the node representing the display, e.g.:
fb@d800e400 {
compatible = "via,vt8500-fb";
reg = <0xd800e400 0x400>;
interrupts = <12>;
via,display = <&display>;
};
display: display {
...
};
^ permalink raw reply
* Re: [PATCH 1/8] arm: vt8500: Add device tree files for VIA/Wondermedia SoC's
From: Stephen Warren @ 2012-08-08 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1344389967-8465-2-git-send-email-linux@prisktech.co.nz>
On 08/07/2012 07:39 PM, Tony Prisk wrote:
> Add device tree files for VT8500, WM8505 and WM8650 SoC's and
> reference boards.
> diff --git a/arch/arm/boot/dts/vt8500_ref.dts b/arch/arm/boot/dts/vt8500_ref.dts
It appears more typical to use "-" rather than "_" in the filename to
join SoC and board names.
I guess "_ref" means "reference". Is that how the boards are commonly
known? Are you sure there will never be another reference board for
these SoCs? Given the "model" values in the file, something more like
vt8500-bv07.dts might be more appropriate?
> + /*
> + * Display node is based on Sascha Hauer's patch on dri-devel.
> + * Added a bpp property to calculate the size of the framebuffer
> + * until the binding is formalized.
> + */
> + display {
Maybe it's better to just hold off on adding this node, to wait until
the binding is complete so this file doesn't churn? Certainly it sounded
like Sascha was going to change the binding a little in response to
comments it received.
^ permalink raw reply
* Re: [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
From: Stephen Warren @ 2012-08-08 18:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1344389967-8465-9-git-send-email-linux@prisktech.co.nz>
On 08/07/2012 07:39 PM, Tony Prisk wrote:
> Converted the existing arch-vt8500 gpio to a platform_device.
> Added support for WM8505 and WM8650 GPIO controllers.
> diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
> +static struct of_device_id vt8500_gpio_dt_ids[] = {
> + { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
> + { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
> + { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
> + { /* Sentinel */ },
> +};
> +
> +static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
> +{
> + void __iomem *gpio_base;
> + struct device_node *np;
> + const struct of_device_id *of_id > + of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
> +
> + if (!of_id) {
> + dev_err(&pdev->dev, "Failed to find gpio controller\n");
> + return -ENODEV;
> + }
> +
> + np = of_find_matching_node(NULL, vt8500_gpio_dt_ids);
Can't you use pdev->dev.of_node instead of searching for it again?
...
> + of_node_put(np);
If so, you could also remove that.
> +static int __init vt8500_gpio_init(void)
> +{
> + return platform_driver_probe(&vt8500_gpio_driver, &vt8500_gpio_probe);
> +}
> +
> +static void __exit vt8500_gpio_exit(void)
> +{
> + return platform_driver_unregister(&vt8500_gpio_driver);
> +}
> +
> +module_init(vt8500_gpio_init);
> +module_exit(vt8500_gpio_exit);
I think that's all just:
module_platform_driver(vt8500_gpio_driver);
(except that _init uses platform_driver_probe() rather than
platform_driver_register(), which seems unusual. I guess that explains
the of_find_matching_node() above too.)
> +MODULE_LICENSE("GPL");
That should be "GPL v2" given the license header.
^ permalink raw reply
* Re: [PATCH] video: move CNVT_TOHW to a common place
From: Geert Uytterhoeven @ 2012-08-08 17:02 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1344426866-8789-1-git-send-email-prakash.pm@ti.com>
On Wed, Aug 8, 2012 at 1:54 PM, Manjunathappa, Prakash
<prakash.pm@ti.com> wrote:
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -397,6 +397,11 @@ struct fb_cursor {
> struct fb_image image; /* Cursor image */
> };
>
> +static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
"__u32" is a bit misleading, as "val" is actually an unsigned 16-bit value.
> +{
> + return ((val << width) + 0x7FFF - val) >> 16;
> +}
Also, if you move it to a public header, perhaps the function needs a more
descriptive name? What it does is remap a 16-bit value "val" onto a value with
"width" bits of resolution, where "width" must be smaller than 16.
"reduce_resolution()"?
Also, it can become more generic, not limiting to 16-bit input values.
The "0x7fff" part is "(1 << (width -1)) - 1". But I'm not sure it's
worth the effort
(are there places where this is needed?).
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v4] da8xx-fb: add 24bpp LCD configuration support
From: Sergei Shtylyov @ 2012-08-08 16:14 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1344440145-27117-1-git-send-email-prakash.pm@ti.com>
Hello.
On 08-08-2012 19:35, Manjunathappa, Prakash wrote:
> LCD controller on am335x supports 24bpp raster configuration in addition
> to ones on da850. LCDC also supports 24bpp in unpacked format having
> ARGB:8888 32bpp format data in DDR, but it doesn't interpret alpha
> component of the data.
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
> Cc: Anatolij Gustschin <agust@denx.de>
[...]
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 7ae9d53..1abcfa9 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
[...]
> @@ -499,6 +501,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
> {
> u32 reg;
>
> + if ((bpp > 16) && (lcd_revision = LCD_VERSION_1))
Parens around operands of && not necessary.
> @@ -542,6 +547,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
> reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
> if (raster_order)
> reg |= LCD_RASTER_ORDER;
> +
> + if (bpp = 24)
> + reg |= LCD_V2_TFT_24BPP_MODE;
> + else if (bpp = 32)
> + reg |= (LCD_V2_TFT_24BPP_MODE | LCD_V2_TFT_24BPP_UNPACK);
> +
This asks to be a *switch* statement.
> lcdc_write(reg, LCD_RASTER_CTRL_REG);
>
> switch (bpp) {
> @@ -549,6 +560,8 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
> case 2:
> case 4:
> case 16:
> + case 24:
> + case 32:
> par->palette_sz = 16 * 2;
> break;
>
> @@ -578,13 +591,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
> if (info->fix.visual = FB_VISUAL_DIRECTCOLOR)
> return 1;
>
> - if (info->var.bits_per_pixel = 4) {
> - if (regno > 15)
> - return 1;
> + if ((info->var.bits_per_pixel > 16) && (lcd_revision = LCD_VERSION_1))
Parens around operands of && not necessary.
> + switch (info->fix.visual) {
> + case FB_VISUAL_TRUECOLOR:
> + red = CNVT_TOHW(red, info->var.red.length);
> + green = CNVT_TOHW(green, info->var.green.length);
> + blue = CNVT_TOHW(blue, info->var.blue.length);
> + break;
> + case FB_VISUAL_PSEUDOCOLOR:
> + if (info->var.bits_per_pixel = 4) {
> + if (regno > 15)
> + return -EINVAL;
> +
> + if (info->var.grayscale) {
> + pal = regno;
> + } else {
> + red >>= 4;
> + green >>= 8;
> + blue >>= 12;
> +
> + pal = (red & 0x0f00);
> + pal |= (green & 0x00f0);
> + pal |= (blue & 0x000f);
Parens not needed.
> + }
> + if (regno = 0)
> + pal |= 0x2000;
> + palette[regno] = pal;
> +
> + } else if (info->var.bits_per_pixel = 8) {
This asks to be a *switch* statement.
> @@ -842,6 +877,9 @@ static int fb_check_var(struct fb_var_screeninfo *var,
> {
> int err = 0;
>
> + if ((var->bits_per_pixel > 16) && (lcd_revision = LCD_VERSION_1))
Parens around operands of && not necessary.
WBR, Sergei
^ permalink raw reply
* [PATCH v4] da8xx-fb: add 24bpp LCD configuration support
From: Manjunathappa, Prakash @ 2012-08-08 15:47 UTC (permalink / raw)
To: linux-fbdev
LCD controller on am335x supports 24bpp raster configuration in addition
to ones on da850. LCDC also supports 24bpp in unpacked format having
ARGB:8888 32bpp format data in DDR, but it doesn't interpret alpha
component of the data.
Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Cc: Anatolij Gustschin <agust@denx.de>
---
Patch is dependent on earlier submitted patch "video: move CNVT_TOHW to a common place"[1]
Since v3:
Minor nit, declare pseudo_palette as u32 type.
Since v2:
Fixed additional configurations for 24bpp support.
Since v1:
Simplified calculation of pseudopalette for FB_VISUAL_TRUECOLOR type.
[1] http://marc.info/?l=linux-fbdev&m\x134442816627846&w=2
drivers/video/da8xx-fb.c | 124 +++++++++++++++++++++++++++++++++------------
1 files changed, 91 insertions(+), 33 deletions(-)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 7ae9d53..1abcfa9 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -86,6 +86,8 @@
#define LCD_V2_LIDD_CLK_EN BIT(1)
#define LCD_V2_CORE_CLK_EN BIT(0)
#define LCD_V2_LPP_B10 26
+#define LCD_V2_TFT_24BPP_MODE BIT(25)
+#define LCD_V2_TFT_24BPP_UNPACK BIT(26)
/* LCD Raster Timing 2 Register */
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
@@ -156,7 +158,6 @@ struct da8xx_fb_par {
unsigned int dma_end;
struct clk *lcdc_clk;
int irq;
- unsigned short pseudo_palette[16];
unsigned int palette_sz;
unsigned int pxl_clk;
int blank;
@@ -175,6 +176,7 @@ struct da8xx_fb_par {
unsigned int lcd_fck_rate;
#endif
void (*panel_power_ctrl)(int);
+ u32 pseudo_palette[16];
};
/* Variable Screen Information */
@@ -499,6 +501,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
{
u32 reg;
+ if ((bpp > 16) && (lcd_revision = LCD_VERSION_1))
+ return -EINVAL;
+
/* Set the Panel Width */
/* Pixels per line = (PPL + 1)*16 */
if (lcd_revision = LCD_VERSION_1) {
@@ -542,6 +547,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
if (raster_order)
reg |= LCD_RASTER_ORDER;
+
+ if (bpp = 24)
+ reg |= LCD_V2_TFT_24BPP_MODE;
+ else if (bpp = 32)
+ reg |= (LCD_V2_TFT_24BPP_MODE | LCD_V2_TFT_24BPP_UNPACK);
+
lcdc_write(reg, LCD_RASTER_CTRL_REG);
switch (bpp) {
@@ -549,6 +560,8 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
case 2:
case 4:
case 16:
+ case 24:
+ case 32:
par->palette_sz = 16 * 2;
break;
@@ -578,13 +591,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (info->fix.visual = FB_VISUAL_DIRECTCOLOR)
return 1;
- if (info->var.bits_per_pixel = 4) {
- if (regno > 15)
- return 1;
+ if ((info->var.bits_per_pixel > 16) && (lcd_revision = LCD_VERSION_1))
+ return -EINVAL;
- if (info->var.grayscale) {
- pal = regno;
- } else {
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ break;
+ case FB_VISUAL_PSEUDOCOLOR:
+ if (info->var.bits_per_pixel = 4) {
+ if (regno > 15)
+ return -EINVAL;
+
+ if (info->var.grayscale) {
+ pal = regno;
+ } else {
+ red >>= 4;
+ green >>= 8;
+ blue >>= 12;
+
+ pal = (red & 0x0f00);
+ pal |= (green & 0x00f0);
+ pal |= (blue & 0x000f);
+ }
+ if (regno = 0)
+ pal |= 0x2000;
+ palette[regno] = pal;
+
+ } else if (info->var.bits_per_pixel = 8) {
red >>= 4;
green >>= 8;
blue >>= 12;
@@ -592,36 +628,35 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
pal = (red & 0x0f00);
pal |= (green & 0x00f0);
pal |= (blue & 0x000f);
- }
- if (regno = 0)
- pal |= 0x2000;
- palette[regno] = pal;
-
- } else if (info->var.bits_per_pixel = 8) {
- red >>= 4;
- green >>= 8;
- blue >>= 12;
- pal = (red & 0x0f00);
- pal |= (green & 0x00f0);
- pal |= (blue & 0x000f);
-
- if (palette[regno] != pal) {
- update_hw = 1;
- palette[regno] = pal;
+ if (palette[regno] != pal) {
+ update_hw = 1;
+ palette[regno] = pal;
+ }
}
- } else if ((info->var.bits_per_pixel = 16) && regno < 16) {
- red >>= (16 - info->var.red.length);
- red <<= info->var.red.offset;
+ break;
+ }
- green >>= (16 - info->var.green.length);
- green <<= info->var.green.offset;
+ /* Truecolor has hardware independent palette */
+ if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
+ u32 v;
- blue >>= (16 - info->var.blue.length);
- blue <<= info->var.blue.offset;
+ if (regno > 15)
+ return -EINVAL;
- par->pseudo_palette[regno] = red | green | blue;
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ ((u16 *) (info->pseudo_palette))[regno] = v;
+ break;
+ case 24:
+ case 32:
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ break;
+ }
if (palette[0] != 0x4000) {
update_hw = 1;
palette[0] = 0x4000;
@@ -842,6 +877,9 @@ static int fb_check_var(struct fb_var_screeninfo *var,
{
int err = 0;
+ if ((var->bits_per_pixel > 16) && (lcd_revision = LCD_VERSION_1))
+ return -EINVAL;
+
switch (var->bits_per_pixel) {
case 1:
case 8:
@@ -877,6 +915,26 @@ static int fb_check_var(struct fb_var_screeninfo *var,
var->transp.length = 0;
var->nonstd = 0;
break;
+ case 24:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->nonstd = 0;
+ break;
+ case 32:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->nonstd = 0;
+ break;
default:
err = -EINVAL;
}
--
1.7.1
^ permalink raw reply related
* Re: [rtc-linux] [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
From: Linus Walleij @ 2012-08-08 14:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201208080919.52592.arnd@arndb.de>
On Wed, Aug 8, 2012 at 11:19 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> What on earth are all those magic numbers?
>>
>> I *guess* they're enabling some default GPIO settings etc.
>
> No, they are the register offsets you quoted above, per bank.
Aha I was fooled by this:
+struct vt8500_gpio_bank_regs {
+ int en;
+ int dir;
+ int data_out;
+ int data_in;
+ int ngpio;
+};
This needs to be named something intuitive like "vt8500_gpio_bank_regoffsets"
Some kerneldoc intsead of the opaque comment above will also improve
readability a lot:
/**
* struct vt8500_gpio_bank_regoffsets
* @en: offset to enable register in the bank
* ...
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH 1/6] OMAPDSS: DISPC: cleanup cpu_is_xxxx checks
From: Tomi Valkeinen @ 2012-08-08 13:25 UTC (permalink / raw)
To: Mahapatra, Chandrabhanu; +Cc: linux-omap, linux-fbdev
In-Reply-To: <CAF0AtAv3uuS_GDuYEk4mpUKieZqqBnLUpRcLBx0M4zjbsSq2Nw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1373 bytes --]
On Wed, 2012-08-08 at 18:31 +0530, Mahapatra, Chandrabhanu wrote:
> Yes, this sounds good, but I was just following general order of
> structure and function declarations, structures initializations
> followed by functions.
Yep, it's a good rule. But there are exceptions when we'll get bloated
code by following the rule =).
> > During runtime we only require one of these, others can be discarded.
> > This can be accomplished with the combination of "__initdata" for these,
> > and "__init" for dispc_init_features().
> >
>
> The same also applies for all structures in dss_features.c. Just a
> thought that __init and __initdata should have also been used there.
I agree. We should also see what things we can move from dss_features.c
into dss.c, dispc.c, etc. Some things in dss_features are quite global,
but some are really used only in one place in one file.
Although this also makes me wonder, is it better to have all the
hardware version information for all DSS modules in one place, as we
tried with dss_features, or is it better to have the HW information in
the respective DSS submodule, as you're doing with this patch.
Both have benefits. Even though with the latter method there's no one
place to look for DSS HW feature differences, I think it'll still give
us cleaner code. So let's continue on this track.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 3/6] OMAPDSS: DSS: Cleanup cpu_is_xxxx checks
From: Tomi Valkeinen @ 2012-08-08 13:16 UTC (permalink / raw)
To: Chandrabhanu Mahapatra; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1344425899-28267-1-git-send-email-cmahapatra@ti.com>
[-- Attachment #1: Type: text/plain, Size: 7972 bytes --]
On Wed, 2012-08-08 at 17:08 +0530, Chandrabhanu Mahapatra wrote:
> All the cpu_is checks have been moved to dss_init_features function providing a
> much more generic and cleaner interface. The OMAP version and revision specific
> functions are initialized by dss_features structure local to dss.c.
Most of the comments for the dispc patch apply also to this patch.
> Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
> ---
> drivers/video/omap2/dss/dss.c | 154 ++++++++++++++++++++++++++++++-----------
> 1 file changed, 114 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
> index 7b1c6ac..f5971ac 100644
> --- a/drivers/video/omap2/dss/dss.c
> +++ b/drivers/video/omap2/dss/dss.c
> @@ -65,6 +65,20 @@ struct dss_reg {
> static int dss_runtime_get(void);
> static void dss_runtime_put(void);
>
> +static bool check_dss_cinfo_fck(void);
> +static bool check_dss_cinfo_fck_34xx(void);
> +
> +static int dss_get_clk_24xx(struct clk *clk);
> +static int dss_get_clk_3xxx(struct clk *clk);
> +static int dss_get_clk_44xx(struct clk *clk);
> +
> +struct dss_features {
> + u16 fck_div_max;
> + int factor;
> + bool (*check_cinfo_fck) (void);
> + int (*get_clk) (struct clk *clk);
> +};
> +
> static struct {
> struct platform_device *pdev;
> void __iomem *base;
> @@ -83,6 +97,8 @@ static struct {
>
> bool ctx_valid;
> u32 ctx[DSS_SZ_REGS / sizeof(u32)];
> +
> + const struct dss_features *feat;
> } dss;
>
> static const char * const dss_generic_clk_source_names[] = {
> @@ -91,6 +107,34 @@ static const char * const dss_generic_clk_source_names[] = {
> [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
> };
>
> +static const struct dss_features omap2_dss_features = {
> + .fck_div_max = 16,
> + .factor = 2,
> + .check_cinfo_fck = check_dss_cinfo_fck,
> + .get_clk = dss_get_clk_24xx,
> +};
> +
> +static const struct dss_features omap34_dss_features = {
> + .fck_div_max = 16,
> + .factor = 2,
> + .check_cinfo_fck = check_dss_cinfo_fck_34xx,
> + .get_clk = dss_get_clk_3xxx,
> +};
> +
> +static const struct dss_features omap36_dss_features = {
> + .fck_div_max = 32,
> + .factor = 1,
> + .check_cinfo_fck = check_dss_cinfo_fck,
> + .get_clk = dss_get_clk_3xxx,
> +};
> +
> +static const struct dss_features omap4_dss_features = {
> + .fck_div_max = 32,
> + .factor = 1,
> + .check_cinfo_fck = check_dss_cinfo_fck,
> + .get_clk = dss_get_clk_44xx,
> +};
> +
> static inline void dss_write_reg(const struct dss_reg idx, u32 val)
> {
> __raw_writel(val, dss.base + idx.idx);
> @@ -236,7 +280,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
> return dss_generic_clk_source_names[clk_src];
> }
>
> -
> void dss_dump_clocks(struct seq_file *s)
> {
> unsigned long dpll4_ck_rate;
> @@ -259,18 +302,10 @@ void dss_dump_clocks(struct seq_file *s)
>
> seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
>
> - if (cpu_is_omap3630() || cpu_is_omap44xx())
> - seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
> - fclk_name, fclk_real_name,
> - dpll4_ck_rate,
> - dpll4_ck_rate / dpll4_m4_ck_rate,
> - fclk_rate);
> - else
> - seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
> - fclk_name, fclk_real_name,
> - dpll4_ck_rate,
> - dpll4_ck_rate / dpll4_m4_ck_rate,
> - fclk_rate);
> + seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
> + fclk_name, fclk_real_name, dpll4_ck_rate,
> + dpll4_ck_rate / dpll4_m4_ck_rate,
> + dss.feat->factor, fclk_rate);
> } else {
> seq_printf(s, "%s (%s) = %lu\n",
> fclk_name, fclk_real_name,
> @@ -461,6 +496,25 @@ unsigned long dss_get_dpll4_rate(void)
> return 0;
> }
>
> +static bool check_dss_cinfo_fck_34xx(void)
> +{
> + unsigned long prate = dss_get_dpll4_rate();
> + unsigned long fck = clk_get_rate(dss.dss_clk);
> +
> + if (prate == dss.cache_prate || dss.cache_dss_cinfo.fck == fck)
> + return true;
> + return false;
> +}
> +
> +static bool check_dss_cinfo_fck(void)
> +{
> + unsigned long fck = clk_get_rate(dss.dss_clk);
> +
> + if (dss.cache_dss_cinfo.fck == fck)
> + return true;
> + return false;
Often code like this is cleaner written as:
return dss.cache_dss_cinfo.fck == fck;
> +}
> +
> int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
> struct dispc_clock_info *dispc_cinfo)
> {
> @@ -470,7 +524,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
>
> unsigned long fck, max_dss_fck;
>
> - u16 fck_div, fck_div_max = 16;
> + u16 fck_div;
>
> int match = 0;
> int min_fck_per_pck;
> @@ -479,10 +533,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
>
> max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
>
> - fck = clk_get_rate(dss.dss_clk);
> - if (req_pck == dss.cache_req_pck &&
> - ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
> - dss.cache_dss_cinfo.fck == fck)) {
> + if (req_pck == dss.cache_req_pck && dss.feat->check_cinfo_fck()) {
This change, and the check_cinfo_fck() doesn't look correct. I mean,
looking at the code, I think it does the same thing as the old code, but
the line above does look very confusing =). Okay, the original code also
looks confusing.
I don't think the original code is even correct. I think it should
include omap4 also in the prate check... And why does it have || instead
of &&? Shouldn't we check both the prate _and_ the fck, instead of just
either one of those... Who writes this stuff without any clarifying
comments! (I think I wrote the code)
If I'm not mistaken, the whole cpu check could be just discarded. On
OMAP2, where prate does not exist/matter, prate should be always 0. If
it's always 0 in the dss.cache_prate also, we can compare them without
any cpu checks.
Can you verify this, and if I'm right, just get rid of the cpu check
there, and we don't even need the feat thing here.
> DSSDBG("dispc clock info found from cache.\n");
> *dss_cinfo = dss.cache_dss_cinfo;
> *dispc_cinfo = dss.cache_dispc_cinfo;
> @@ -519,13 +570,10 @@ retry:
>
> goto found;
> } else {
> - if (cpu_is_omap3630() || cpu_is_omap44xx())
> - fck_div_max = 32;
> -
> - for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
> + for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
> struct dispc_clock_info cur_dispc;
>
> - if (fck_div_max == 32)
> + if (dss.feat->fck_div_max == 32)
> fck = prate / fck_div;
> else
> fck = prate / fck_div * 2;
Hmm, I think this one should use the "factor" field for the multiply.
> @@ -619,6 +667,32 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
> return REG_GET(DSS_CONTROL, 15, 15);
> }
>
> +static int dss_get_clk_24xx(struct clk *clk)
> +{
> + clk = NULL;
> + return true;
> +}
> +
> +static int dss_get_clk_3xxx(struct clk *clk)
> +{
> + clk = clk_get(NULL, "dpll4_m4_ck");
> + if (IS_ERR(clk)) {
> + DSSERR("Failed to get dpll4_m4_ck\n");
> + return PTR_ERR(clk);
> + }
> + return true;
> +}
> +
> +static int dss_get_clk_44xx(struct clk *clk)
> +{
> + clk = clk_get(NULL, "dpll_per_m5x2_ck");
> + if (IS_ERR(clk)) {
> + DSSERR("Failed to get dpll_per_m5x2_ck\n");
> + return PTR_ERR(clk);
> + }
> + return true;
> +}
These are almost the same functions. Rather than having separate
functions, perhaps add the clock name into the feat struct. And NULL for
omap2.
The clock name shouldn't really even be in dss, it should come as
parameter, or even better, we wouldn't need it an we could use the clk
framework without this clock. But that was not possible the last time I
looked at it, so let's have it in dss feat struct for now.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 1/6] OMAPDSS: DISPC: cleanup cpu_is_xxxx checks
From: Mahapatra, Chandrabhanu @ 2012-08-08 13:13 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1344429360.4932.58.camel@deskari>
On Wed, Aug 8, 2012 at 6:06 PM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> On Wed, 2012-08-08 at 17:07 +0530, Chandrabhanu Mahapatra wrote:
>> All the cpu_is checks have been moved to dispc_init_features function providing
>> a much more generic and cleaner interface. The OMAP version and revision
>> specific functions are initialized by dispc_features structure local to dispc.c.
>>
>> Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
>> ---
>> drivers/video/omap2/dss/dispc.c | 476 ++++++++++++++++++++++++++-------------
>> 1 file changed, 315 insertions(+), 161 deletions(-)
>>
>> diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
>> index 5b289c5..7e0b080 100644
>> --- a/drivers/video/omap2/dss/dispc.c
>> +++ b/drivers/video/omap2/dss/dispc.c
>> @@ -75,12 +75,60 @@ enum omap_burst_size {
>> #define REG_FLD_MOD(idx, val, start, end) \
>> dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
>>
>> +static int dispc_ovl_calc_scaling_24xx(enum omap_channel channel,
>> + const struct omap_video_timings *mgr_timings, u16 width, u16 height,
>> + u16 out_width, u16 out_height, enum omap_color_mode color_mode,
>> + bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
>> + int *decim_y, u16 pos_x, unsigned long *core_clk);
>> +static int dispc_ovl_calc_scaling_34xx(enum omap_channel channel,
>> + const struct omap_video_timings *mgr_timings, u16 width, u16 height,
>> + u16 out_width, u16 out_height, enum omap_color_mode color_mode,
>> + bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
>> + int *decim_y, u16 pos_x, unsigned long *core_clk);
>> +static int dispc_ovl_calc_scaling_44xx(enum omap_channel channel,
>> + const struct omap_video_timings *mgr_timings, u16 width, u16 height,
>> + u16 out_width, u16 out_height, enum omap_color_mode color_mode,
>> + bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
>> + int *decim_y, u16 pos_x, unsigned long *core_clk);
>> +
>> +static unsigned long calc_core_clk_24xx(enum omap_channel channel, u16 width,
>> + u16 height, u16 out_width, u16 out_height);
>> +static unsigned long calc_core_clk_34xx(enum omap_channel channel, u16 width,
>> + u16 height, u16 out_width, u16 out_height);
>> +static unsigned long calc_core_clk_44xx(enum omap_channel channel, u16 width,
>> + u16 height, u16 out_width, u16 out_height);
>> +
>> +static bool _dispc_lcd_timings_ok_24xx(int hsw, int hfp, int hbp,
>> + int vsw, int vfp, int vbp);
>> +static bool _dispc_lcd_timings_ok_44xx(int hsw, int hfp, int hbp,
>> + int vsw, int vfp, int vbp);
>> +
>> +static void _dispc_mgr_set_lcd_timings_hv_24xx(enum omap_channel channel,
>> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp);
>> +static void _dispc_mgr_set_lcd_timings_hv_44xx(enum omap_channel channel,
>> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp);
>
> While it's nice to have the initialization of struct dispc_features in
> the beginning of dispc.c, it requires the above prototypes. And in the
> future we may require more. For that reason I think it's better to
> initialize the dispc_features at the end of dispc.c, just above
> dispc_init_features(). This would be kinda similar to how drivers often
> initialize their ops.
>
Yes, this sounds good, but I was just following general order of
structure and function declarations, structures initializations
followed by functions.
>> +static const struct dispc_features omap2_dispc_features = {
>> + .calc_scaling = dispc_ovl_calc_scaling_24xx,
>> + .calc_core_clk = calc_core_clk_24xx,
>> + .lcd_timings_ok = _dispc_lcd_timings_ok_24xx,
>> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_24xx,
>> +};
>> +
>> +static const struct dispc_features omap3_2_1_dispc_features = {
>> + .calc_scaling = dispc_ovl_calc_scaling_34xx,
>> + .calc_core_clk = calc_core_clk_34xx,
>> + .lcd_timings_ok = _dispc_lcd_timings_ok_24xx,
>> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_24xx,
>> +};
>> +
>> +static const struct dispc_features omap3_3_0_dispc_features = {
>> + .calc_scaling = dispc_ovl_calc_scaling_34xx,
>> + .calc_core_clk = calc_core_clk_34xx,
>> + .lcd_timings_ok = _dispc_lcd_timings_ok_44xx,
>> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_44xx,
>> +};
>> +
>> +static const struct dispc_features omap4_dispc_features = {
>> + .calc_scaling = dispc_ovl_calc_scaling_44xx,
>> + .calc_core_clk = calc_core_clk_44xx,
>> + .lcd_timings_ok = _dispc_lcd_timings_ok_44xx,
>> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_44xx,
>> +};
>
> During runtime we only require one of these, others can be discarded.
> This can be accomplished with the combination of "__initdata" for these,
> and "__init" for dispc_init_features().
>
The same also applies for all structures in dss_features.c. Just a
thought that __init and __initdata should have also been used there.
> However, because even the one we need will be discarded, we need to copy
> the values. This could be done either by having the dispc_features
> struct inside dispc struct (instead of a pointer), or allocating memory
> for it with devm_kzalloc(). The latter allows us to keep it const, but
> I'm not sure which approach is better (if either).
>
The latter approach seems better as we need to keep it const. I will
try out both anyways.
>> -static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
>> +static bool _dispc_lcd_timings_ok_24xx(int hsw, int hfp, int hbp,
>> int vsw, int vfp, int vbp)
>> {
>> - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
>> - if (hsw < 1 || hsw > 64 ||
>> - hfp < 1 || hfp > 256 ||
>> - hbp < 1 || hbp > 256 ||
>> - vsw < 1 || vsw > 64 ||
>> - vfp < 0 || vfp > 255 ||
>> - vbp < 0 || vbp > 255)
>> - return false;
>> - } else {
>> - if (hsw < 1 || hsw > 256 ||
>> - hfp < 1 || hfp > 4096 ||
>> - hbp < 1 || hbp > 4096 ||
>> - vsw < 1 || vsw > 256 ||
>> - vfp < 0 || vfp > 4095 ||
>> - vbp < 0 || vbp > 4095)
>> - return false;
>> - }
>> -
>> + if (hsw < 1 || hsw > 64 ||
>> + hfp < 1 || hfp > 256 ||
>> + hbp < 1 || hbp > 256 ||
>> + vsw < 1 || vsw > 64 ||
>> + vfp < 0 || vfp > 255 ||
>> + vbp < 0 || vbp > 255)
>> + return false;
>> + return true;
>> +}
>> +static bool _dispc_lcd_timings_ok_44xx(int hsw, int hfp, int hbp,
>> + int vsw, int vfp, int vbp)
>> +{
>> + if (hsw < 1 || hsw > 256 ||
>> + hfp < 1 || hfp > 4096 ||
>> + hbp < 1 || hbp > 4096 ||
>> + vsw < 1 || vsw > 256 ||
>> + vfp < 0 || vfp > 4095 ||
>> + vbp < 0 || vbp > 4095)
>> + return false;
>> return true;
>> }
>
> I think we should use separate functions only when the code is
> different. Here the code is the same, we just use different max values.
>
> So instead of these functions, I suggest to add those max values into
> struct dispc_features.
Ok.
>
>> @@ -2633,7 +2757,8 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
>> timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
>>
>> if (dss_mgr_is_lcd(channel))
>> - timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
>> + timings_ok = timings_ok &&
>> + dispc.feat->lcd_timings_ok(timings->hsw,
>> timings->hfp, timings->hbp,
>> timings->vsw, timings->vfp,
>> timings->vbp);
>> @@ -2641,6 +2766,34 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
>> return timings_ok;
>> }
>>
>> +static void _dispc_mgr_set_lcd_timings_hv_24xx(enum omap_channel channel,
>> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp)
>> +{
>> + u32 timing_h, timing_v;
>> +
>> + timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
>> + FLD_VAL(hbp-1, 27, 20);
>> + timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
>> + FLD_VAL(vbp, 27, 20);
>> +
>> + dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
>> + dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
>> +}
>> +
>> +static void _dispc_mgr_set_lcd_timings_hv_44xx(enum omap_channel channel,
>> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp)
>> +{
>> + u32 timing_h, timing_v;
>> +
>> + timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
>> + FLD_VAL(hbp-1, 31, 20);
>> + timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
>> + FLD_VAL(vbp, 31, 20);
>> +
>> + dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
>> + dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
>> +}
>
> Same thing here. The code is the same, only the bit fields are larger.
>
> Tomi
>
ok
--
Chandrabhanu Mahapatra
Texas Instruments India Pvt. Ltd.
^ permalink raw reply
* Re: [PATCH v2] of: Add videomode helper
From: Laurent Pinchart @ 2012-08-08 12:41 UTC (permalink / raw)
To: Sascha Hauer
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <20120705165029.GU30009-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Hi Sascha,
Sorry for the late reply.
On Thursday 05 July 2012 18:50:29 Sascha Hauer wrote:
> On Thu, Jul 05, 2012 at 04:08:07PM +0200, Laurent Pinchart wrote:
> > > +++ b/Documentation/devicetree/bindings/video/displaymode
> > > @@ -0,0 +1,40 @@
> > > +videomode bindings
> > > +=========
> > > +
> > > +Required properties:
> > > + - xres, yres: Display resolution
> > > + - left-margin, right-margin, hsync-len: Horizontal Display timing
> > > parameters + in pixels
> > > + upper-margin, lower-margin, vsync-len: Vertical display timing
> > > parameters in + lines
> > > + - clock: displayclock in Hz
> > > +
> > > +Optional properties:
> > > + - width-mm, height-mm: Display dimensions in mm
> >
> > I've always had mixed feelings about the physical display dimension being
> > part of the display mode. Those are properties of the panel/display
> > instead of the mode. Storing them as part of the mode can be convenient,
> > but we then run into consistency issues (developers have to remember in
> > which display mode instances the values are available, and in which
> > instances they're set to 0 for instance). If we want to clean this up,
> > this patch would be a good occasion.
>
> This sounds like a display node with one or more node subnodes, like:
>
> display {
> width_mm = <>;
> height_mm = <>;
> mode {
> xres = <>;
> yres = <>;
> ...
> };
> };
>
> Is that what you mean or are you thinking of something else?
Yes, that's exactly what I meant.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v2] of: Add videomode helper
From: Laurent Pinchart @ 2012-08-08 12:40 UTC (permalink / raw)
To: Sascha Hauer
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org
In-Reply-To: <20120803073844.GK1451-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Hi Sascha,
On Friday 03 August 2012 09:38:44 Sascha Hauer wrote:
> On Thu, Aug 02, 2012 at 01:35:40PM -0600, Stephen Warren wrote:
> > On 07/04/2012 01:56 AM, Sascha Hauer wrote:
> > > This patch adds a helper function for parsing videomodes from the
> > > devicetree. The videomode can be either converted to a struct
> > > drm_display_mode or a struct fb_videomode.
> > >
> > > diff --git a/Documentation/devicetree/bindings/video/displaymode
> > > b/Documentation/devicetree/bindings/video/displaymode
> > >
> > > +Required properties:
> > > + - xres, yres: Display resolution
> > > + - left-margin, right-margin, hsync-len: Horizontal Display timing
> > > parameters + in pixels
> > > + upper-margin, lower-margin, vsync-len: Vertical display timing
> > > parameters in + lines
> >
> > Perhaps bike-shedding, but...
> >
> > For the margin property names, wouldn't it be better to use terminology
> > more commonly used for video timings rather than Linux FB naming. In
> > other words naming like:
> >
> > hactive, hsync-len, hfront-porch, hback-porch?
>
> Can do. Just to make sure:
>
> hactive = xres
> hsync-len = hsync-len
> hfront-porch = right-margin
> hback-porch = left-margin
That's correct. On the vertical direction, vfront-porch = lower-margin and
vback-porch = upper-margin.
>
> ?
>
> > This node appears to describe a video mode, not a display, hence the
> > node name seems wrong.
> >
> > Many displays can support multiple different video modes. As mentioned
> > elsewhere, properties like display width/height are properties of the
> > display not the mode.
> >
> > So, I might expect something more like the following (various overhead
> > properties like reg/#address-cells etc. elided for simplicity):
> >
> > disp: display {
> >
> > width-mm = <...>;
> > height-mm = <...>;
> > modes {
> >
> > mode@0 {
> >
> > /* 1920x1080p24 */
> > clock = <52000000>;
> > xres = <1920>;
> > yres = <1080>;
> > left-margin = <25>;
> > right-margin = <25>;
> > hsync-len = <25>;
> > lower-margin = <2>;
> > upper-margin = <2>;
> > vsync-len = <2>;
> > hsync-active-high;
> >
> > };
> > mode@1 {
> > };
> >
> > };
> >
> > };
>
> Ok, we can do this.
>
> > display-connector {
> >
> > display = <&disp>;
> > // interface-specific properties such as pixel format here
> >
> > };
> >
> > Finally, have you considered just using an EDID instead of creating
> > something custom? I know that creating an EDID is harder than writing a
>
> > few simple properties into a DT, but EDIDs have the following advantages:
> I have considered using EDID and I also tried it. It's painful. There
> are no (open) tools available for creating EDID. That's something we
> could change of course. Then when generating a devicetree there is
> always an extra step involved creating the EDID blob. Once the EDID
> blob is in devicetree it is not parsable anymore by mere humans, so
> to see what we've got there is another tool involved to generate a
> readable form again.
>
> > a) They're already standardized and very common.
>
> Indeed, that's a big plus for EDID. I have no intention of removing EDID
> data from the devicetree. There are situations where EDID is handy, for
> example when you get EDID data provided by your vendor.
>
> > b) They allow other information such as a display's HDMI audio
> > capabilities to be represented, which can then feed into an ALSA driver.
> >
> > c) The few LCD panel datasheets I've seen actually quote their
> > specification as an EDID already, so deriving the EDID may actually be
> > easy.
> >
> > d) People familiar with displays are almost certainly familiar with
> > EDID's mode representation. There are many ways of representing display
> > modes (sync position vs. porch widths, htotal specified rather than
> > specifying all the components and hence htotal being calculated etc.).
> > Not everyone will be familiar with all representations. Conversion
> > errors are less likely if the target is EDID's familiar format.
>
> You seem to think about a different class of displays for which EDID
> indeed is a better way to handle. What I have to deal with here mostly
> are dumb displays which:
>
> - can only handle their native resolution
> - Have no audio capabilities at all
> - come with a datasheet which specify a min/typ/max triplet for
> xres,hsync,..., often enough they are scanned to pdf from some previously
> printed paper.
>
> These displays are very common on embedded devices, probably that's the
> reason I did not even think about the possibility that a single display
> might have different modes.
>
> > e) You'll end up with exactly the same data as if you have a DDC-based
> > external monitor rather than an internal panel, so you end up getting to
> > a common path in display handling code much more quickly.
>
> All we have in our display driver currently is:
>
> edidp = of_get_property(np, "edid", &imxpd->edid_len);
> if (edidp) {
> imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
> } else {
> ret = of_get_video_mode(np, &imxpd->mode, NULL);
> if (!ret)
> imxpd->mode_valid = 1;
> }
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 1/6] OMAPDSS: DISPC: cleanup cpu_is_xxxx checks
From: Tomi Valkeinen @ 2012-08-08 12:36 UTC (permalink / raw)
To: Chandrabhanu Mahapatra; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1344425874-28222-1-git-send-email-cmahapatra@ti.com>
[-- Attachment #1: Type: text/plain, Size: 7991 bytes --]
On Wed, 2012-08-08 at 17:07 +0530, Chandrabhanu Mahapatra wrote:
> All the cpu_is checks have been moved to dispc_init_features function providing
> a much more generic and cleaner interface. The OMAP version and revision
> specific functions are initialized by dispc_features structure local to dispc.c.
>
> Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
> ---
> drivers/video/omap2/dss/dispc.c | 476 ++++++++++++++++++++++++++-------------
> 1 file changed, 315 insertions(+), 161 deletions(-)
>
> diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
> index 5b289c5..7e0b080 100644
> --- a/drivers/video/omap2/dss/dispc.c
> +++ b/drivers/video/omap2/dss/dispc.c
> @@ -75,12 +75,60 @@ enum omap_burst_size {
> #define REG_FLD_MOD(idx, val, start, end) \
> dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
>
> +static int dispc_ovl_calc_scaling_24xx(enum omap_channel channel,
> + const struct omap_video_timings *mgr_timings, u16 width, u16 height,
> + u16 out_width, u16 out_height, enum omap_color_mode color_mode,
> + bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
> + int *decim_y, u16 pos_x, unsigned long *core_clk);
> +static int dispc_ovl_calc_scaling_34xx(enum omap_channel channel,
> + const struct omap_video_timings *mgr_timings, u16 width, u16 height,
> + u16 out_width, u16 out_height, enum omap_color_mode color_mode,
> + bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
> + int *decim_y, u16 pos_x, unsigned long *core_clk);
> +static int dispc_ovl_calc_scaling_44xx(enum omap_channel channel,
> + const struct omap_video_timings *mgr_timings, u16 width, u16 height,
> + u16 out_width, u16 out_height, enum omap_color_mode color_mode,
> + bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
> + int *decim_y, u16 pos_x, unsigned long *core_clk);
> +
> +static unsigned long calc_core_clk_24xx(enum omap_channel channel, u16 width,
> + u16 height, u16 out_width, u16 out_height);
> +static unsigned long calc_core_clk_34xx(enum omap_channel channel, u16 width,
> + u16 height, u16 out_width, u16 out_height);
> +static unsigned long calc_core_clk_44xx(enum omap_channel channel, u16 width,
> + u16 height, u16 out_width, u16 out_height);
> +
> +static bool _dispc_lcd_timings_ok_24xx(int hsw, int hfp, int hbp,
> + int vsw, int vfp, int vbp);
> +static bool _dispc_lcd_timings_ok_44xx(int hsw, int hfp, int hbp,
> + int vsw, int vfp, int vbp);
> +
> +static void _dispc_mgr_set_lcd_timings_hv_24xx(enum omap_channel channel,
> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp);
> +static void _dispc_mgr_set_lcd_timings_hv_44xx(enum omap_channel channel,
> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp);
While it's nice to have the initialization of struct dispc_features in
the beginning of dispc.c, it requires the above prototypes. And in the
future we may require more. For that reason I think it's better to
initialize the dispc_features at the end of dispc.c, just above
dispc_init_features(). This would be kinda similar to how drivers often
initialize their ops.
> +static const struct dispc_features omap2_dispc_features = {
> + .calc_scaling = dispc_ovl_calc_scaling_24xx,
> + .calc_core_clk = calc_core_clk_24xx,
> + .lcd_timings_ok = _dispc_lcd_timings_ok_24xx,
> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_24xx,
> +};
> +
> +static const struct dispc_features omap3_2_1_dispc_features = {
> + .calc_scaling = dispc_ovl_calc_scaling_34xx,
> + .calc_core_clk = calc_core_clk_34xx,
> + .lcd_timings_ok = _dispc_lcd_timings_ok_24xx,
> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_24xx,
> +};
> +
> +static const struct dispc_features omap3_3_0_dispc_features = {
> + .calc_scaling = dispc_ovl_calc_scaling_34xx,
> + .calc_core_clk = calc_core_clk_34xx,
> + .lcd_timings_ok = _dispc_lcd_timings_ok_44xx,
> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_44xx,
> +};
> +
> +static const struct dispc_features omap4_dispc_features = {
> + .calc_scaling = dispc_ovl_calc_scaling_44xx,
> + .calc_core_clk = calc_core_clk_44xx,
> + .lcd_timings_ok = _dispc_lcd_timings_ok_44xx,
> + .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_44xx,
> +};
During runtime we only require one of these, others can be discarded.
This can be accomplished with the combination of "__initdata" for these,
and "__init" for dispc_init_features().
However, because even the one we need will be discarded, we need to copy
the values. This could be done either by having the dispc_features
struct inside dispc struct (instead of a pointer), or allocating memory
for it with devm_kzalloc(). The latter allows us to keep it const, but
I'm not sure which approach is better (if either).
> -static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
> +static bool _dispc_lcd_timings_ok_24xx(int hsw, int hfp, int hbp,
> int vsw, int vfp, int vbp)
> {
> - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
> - if (hsw < 1 || hsw > 64 ||
> - hfp < 1 || hfp > 256 ||
> - hbp < 1 || hbp > 256 ||
> - vsw < 1 || vsw > 64 ||
> - vfp < 0 || vfp > 255 ||
> - vbp < 0 || vbp > 255)
> - return false;
> - } else {
> - if (hsw < 1 || hsw > 256 ||
> - hfp < 1 || hfp > 4096 ||
> - hbp < 1 || hbp > 4096 ||
> - vsw < 1 || vsw > 256 ||
> - vfp < 0 || vfp > 4095 ||
> - vbp < 0 || vbp > 4095)
> - return false;
> - }
> -
> + if (hsw < 1 || hsw > 64 ||
> + hfp < 1 || hfp > 256 ||
> + hbp < 1 || hbp > 256 ||
> + vsw < 1 || vsw > 64 ||
> + vfp < 0 || vfp > 255 ||
> + vbp < 0 || vbp > 255)
> + return false;
> + return true;
> +}
> +static bool _dispc_lcd_timings_ok_44xx(int hsw, int hfp, int hbp,
> + int vsw, int vfp, int vbp)
> +{
> + if (hsw < 1 || hsw > 256 ||
> + hfp < 1 || hfp > 4096 ||
> + hbp < 1 || hbp > 4096 ||
> + vsw < 1 || vsw > 256 ||
> + vfp < 0 || vfp > 4095 ||
> + vbp < 0 || vbp > 4095)
> + return false;
> return true;
> }
I think we should use separate functions only when the code is
different. Here the code is the same, we just use different max values.
So instead of these functions, I suggest to add those max values into
struct dispc_features.
> @@ -2633,7 +2757,8 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
> timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
>
> if (dss_mgr_is_lcd(channel))
> - timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
> + timings_ok = timings_ok &&
> + dispc.feat->lcd_timings_ok(timings->hsw,
> timings->hfp, timings->hbp,
> timings->vsw, timings->vfp,
> timings->vbp);
> @@ -2641,6 +2766,34 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
> return timings_ok;
> }
>
> +static void _dispc_mgr_set_lcd_timings_hv_24xx(enum omap_channel channel,
> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp)
> +{
> + u32 timing_h, timing_v;
> +
> + timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
> + FLD_VAL(hbp-1, 27, 20);
> + timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
> + FLD_VAL(vbp, 27, 20);
> +
> + dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
> + dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
> +}
> +
> +static void _dispc_mgr_set_lcd_timings_hv_44xx(enum omap_channel channel,
> + int hsw, int hfp, int hbp, int vsw, int vfp, int vbp)
> +{
> + u32 timing_h, timing_v;
> +
> + timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
> + FLD_VAL(hbp-1, 31, 20);
> + timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
> + FLD_VAL(vbp, 31, 20);
> +
> + dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
> + dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
> +}
Same thing here. The code is the same, only the bit fields are larger.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH] fbdev: Add Renesas vdc4 framebuffer driver
From: Phil Edworthy @ 2012-08-08 12:14 UTC (permalink / raw)
To: linux-fbdev
The vdc4 display hardware is found on the sh7269 device.
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/ren_vdc4fb.c | 653 ++++++++++++++++++++++++++++++++++++++++++++
include/video/ren_vdc4fb.h | 19 ++
4 files changed, 683 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/ren_vdc4fb.c
create mode 100644 include/video/ren_vdc4fb.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0217f74..89c9250 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1990,6 +1990,16 @@ config FB_W100
If unsure, say N.
+config FB_REN_VDC4FB
+ tristate "Renesas VDC4 framebuffer support"
+ depends on FB && CPU_SUBTYPE_SH7269
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ ---help---
+ Frame buffer driver for the Renesas VDC4.
+
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ee8dafb..ba69fcb 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -140,6 +140,7 @@ obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
+obj-$(CONFIG_FB_REN_VDC4FB) += ren_vdc4fb.o
obj-$(CONFIG_FB_OMAP) += omap/
obj-y += omap2/
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
diff --git a/drivers/video/ren_vdc4fb.c b/drivers/video/ren_vdc4fb.c
new file mode 100644
index 0000000..1a31e85
--- /dev/null
+++ b/drivers/video/ren_vdc4fb.c
@@ -0,0 +1,653 @@
+/*
+ * Renesas VDC4 Framebuffer
+ *
+ * Based on sh_mobile_lcdcfb.c
+ * Copyright (c) 2012 Renesas Electronics Europe Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <video/ren_vdc4fb.h>
+
+#define PALETTE_NR 16
+
+struct ren_vdc4_priv {
+ void __iomem *base;
+ int irq;
+ struct clk *dot_clk;
+ struct clk *clk;
+ struct fb_info *info;
+ dma_addr_t dma_handle;
+ struct ren_vdc4_info *cfg;
+ u32 pseudo_palette[PALETTE_NR];
+};
+
+/* Register offsets/reading and writing functions */
+enum {
+ SCL0_UPDATE, SCL0_FRC1, SCL0_FRC2, SCL0_FRC3,
+ SCL0_FRC4, SCL0_FRC5, SCL0_FRC6, SCL0_FRC7,
+ SCL0_DS1, SCL0_US1,
+
+ GR1_UPDATE, GR1_AB1,
+
+ GR2_UPDATE, GR2_AB1,
+
+ GR3_UPDATE, GR3_FLM_RD, GR3_FLM1, GR3_FLM2,
+ GR3_FLM3, GR3_FLM4, GR3_FLM5, GR3_FLM6, GR3_AB1,
+ GR3_AB2, GR3_AB3, GR3_AB4, GR3_AB5, GR3_AB6,
+ GR3_AB7, GR3_AB8, GR3_AB9, GR3_AB10, GR3_AB11,
+ GR3_BASE, GR3_CLUT_INT, GR3_MON,
+
+ TCON_UPDATE, TCON_TIM, TCON_TIM_STVA1, TCON_TIM_STVA2,
+ TCON_TIM_STVB1, TCON_TIM_STVB2, TCON_TIM_STH1,
+ TCON_TIM_STH2, TCON_TIM_STB1, TCON_TIM_STB2,
+ TCON_TIM_CPV1, TCON_TIM_CPV2, TCON_TIM_POLA1,
+ TCON_TIM_POLA2, TCON_TIM_POLB1, TCON_TIM_POLB2,
+ TCON_TIM_DE,
+
+ OUT_UPDATE, OUT_SET, OUT_BRIGHT1,
+ OUT_BRIGHT2, OUT_CONTRAST, OUT_PDTHA, OUT_CLK_PHASE,
+
+ SYSCNT_INT1, SYSCNT_INT2, SYSCNT_INT3, SYSCNT_INT4,
+ SYSCNT_PANEL_CLK, SYSCNT_CLUT
+};
+
+static unsigned long vdc4_offsets[] = {
+ [SCL0_UPDATE] = 0x0100,
+ [SCL0_FRC1] = 0x0104,
+ [SCL0_FRC2] = 0x0108,
+ [SCL0_FRC3] = 0x010C,
+ [SCL0_FRC4] = 0x0110,
+ [SCL0_FRC5] = 0x0114,
+ [SCL0_FRC6] = 0x0118,
+ [SCL0_FRC7] = 0x011C,
+ [SCL0_DS1] = 0x012C,
+ [SCL0_US1] = 0x0148,
+ [GR1_UPDATE] = 0x0200,
+ [GR1_AB1] = 0x0220,
+ [GR2_UPDATE] = 0x0300,
+ [GR2_AB1] = 0x0320,
+ [GR3_UPDATE] = 0x0380,
+ [GR3_FLM_RD] = 0x0384,
+ [GR3_FLM1] = 0x0388,
+ [GR3_FLM2] = 0x038C,
+ [GR3_FLM3] = 0x0390,
+ [GR3_FLM4] = 0x0394,
+ [GR3_FLM5] = 0x0398,
+ [GR3_FLM6] = 0x039C,
+ [GR3_AB1] = 0x03A0,
+ [GR3_AB2] = 0x03A4,
+ [GR3_AB3] = 0x03A8,
+ [GR3_AB4] = 0x03AC,
+ [GR3_AB5] = 0x03B0,
+ [GR3_AB6] = 0x03B4,
+ [GR3_AB7] = 0x03B8,
+ [GR3_AB8] = 0x03BC,
+ [GR3_AB9] = 0x03C0,
+ [GR3_AB10] = 0x03C4,
+ [GR3_AB11] = 0x03C8,
+ [GR3_BASE] = 0x03CC,
+ [GR3_CLUT_INT] = 0x03D0,
+ [GR3_MON] = 0x03D4,
+ [TCON_UPDATE] = 0x0580,
+ [TCON_TIM] = 0x0584,
+ [TCON_TIM_STVA1] = 0x0588,
+ [TCON_TIM_STVA2] = 0x058C,
+ [TCON_TIM_STVB1] = 0x0590,
+ [TCON_TIM_STVB2] = 0x0594,
+ [TCON_TIM_STH1] = 0x0598,
+ [TCON_TIM_STH2] = 0x059C,
+ [TCON_TIM_STB1] = 0x05A0,
+ [TCON_TIM_STB2] = 0x05A4,
+ [TCON_TIM_CPV1] = 0x05A8,
+ [TCON_TIM_CPV2] = 0x05AC,
+ [TCON_TIM_POLA1] = 0x05B0,
+ [TCON_TIM_POLA2] = 0x05B4,
+ [TCON_TIM_POLB1] = 0x05B8,
+ [TCON_TIM_POLB2] = 0x05BC,
+ [TCON_TIM_DE] = 0x05C0,
+ [OUT_UPDATE] = 0x0600,
+ [OUT_SET] = 0x0604,
+ [OUT_BRIGHT1] = 0x0608,
+ [OUT_BRIGHT2] = 0x060C,
+ [OUT_CONTRAST] = 0x0610,
+ [OUT_PDTHA] = 0x0614,
+ [OUT_CLK_PHASE] = 0x0624,
+ [SYSCNT_INT1] = 0x0680,
+ [SYSCNT_INT2] = 0x0684,
+ [SYSCNT_INT3] = 0x0688,
+ [SYSCNT_INT4] = 0x068C,
+ [SYSCNT_PANEL_CLK] = 0x0690, /* 16-bit */
+ [SYSCNT_CLUT] = 0x0692, /* 16-bit */
+};
+
+/* SYSCNT */
+#define ICKEN (1 << 8)
+
+/* SCL Syncs */
+#define FREE_RUN_VSYNC 0x0001
+
+/* OUTPUT */
+#define OUT_FMT_RGB666 (1 << 12)
+
+/* TCON Timings */
+#define STVB_SEL_BITS 0x0007
+#define STVB_HS_SEL 2
+
+#define STH2_SEL_BITS 0x0007
+#define STH2_DE_SEL 7
+
+/* OUTCLK */
+#define LCD_DATA_EDGE 0x0100
+#define STVB_EDGE 0x0020
+#define STH_EDGE 0x0010
+
+/* SCL_UPDATE */
+#define SCL0_UPDATE_BIT 0x0100
+#define SCL0_VEN_BIT 0x0010
+
+/* TCON_UPDATE */
+#define TCON_VEN_BIT 0x0001
+
+/* OUT_UPDATE */
+#define OUTCNT_VEN_BIT 0x0001
+
+/* GR_UPDATE */
+#define P_VEN_UPDATE 0x0010
+#define IBUS_VEN_UPDATE 0x0001
+
+/* GR_AB1 */
+#define DISPSEL_BCKGND 0x0000
+#define DISPSEL_LOWER 0x0001
+#define DISPSEL_CUR 0x0002
+
+/* GR_FLM_RD */
+#define FB_R_ENB 0x01
+
+
+static void vdc4_write(struct ren_vdc4_priv *priv,
+ unsigned long reg_offs, unsigned long data)
+{
+ if ((SYSCNT_PANEL_CLK = reg_offs) || (SYSCNT_CLUT = reg_offs))
+ iowrite16(data, priv->base + vdc4_offsets[reg_offs]);
+ else
+ iowrite32(data, priv->base + vdc4_offsets[reg_offs]);
+}
+
+static unsigned long vdc4_read(struct ren_vdc4_priv *priv,
+ unsigned long reg_offs)
+{
+ if ((SYSCNT_PANEL_CLK = reg_offs) || (SYSCNT_CLUT = reg_offs))
+ return ioread16(priv->base + vdc4_offsets[reg_offs]);
+ else
+ return ioread32(priv->base + vdc4_offsets[reg_offs]);
+}
+
+static irqreturn_t ren_vdc4_irq(int irq, void *data)
+{
+ /* Not currently implemented/used */
+ return IRQ_HANDLED;
+}
+
+static void lcd_clear_display(struct ren_vdc4_priv *priv)
+{
+ unsigned char *pdest;
+ unsigned long size;
+
+ pdest = (unsigned char *)priv->dma_handle;
+ size = priv->cfg->lcd_cfg.xres * priv->cfg->lcd_cfg.yres * 2;
+
+ memset(pdest, 0, size);
+}
+
+static void restart_tft_display(struct ren_vdc4_priv *priv,
+ int clock_source)
+{
+ struct fb_videomode *lcd;
+ unsigned long h;
+ unsigned long v;
+ unsigned long tmp;
+
+ /* FB setup */
+ lcd = &priv->cfg->lcd_cfg;
+ lcd_clear_display(priv);
+
+ /* VDC clock Setup */
+ tmp = priv->cfg->clock_divider;
+ tmp |= clock_source << 12;
+ tmp |= ICKEN;
+ vdc4_write(priv, SYSCNT_PANEL_CLK, tmp);
+
+ /* Clear and Disable all interrupts */
+ vdc4_write(priv, SYSCNT_INT1, 0);
+ vdc4_write(priv, SYSCNT_INT2, 0);
+ vdc4_write(priv, SYSCNT_INT3, 0);
+ vdc4_write(priv, SYSCNT_INT4, 0);
+
+ /* Setup free-running syncs */
+ vdc4_write(priv, SCL0_FRC3, FREE_RUN_VSYNC);
+
+ /* Disable scale up/down */
+ vdc4_write(priv, SCL0_DS1, 0);
+ vdc4_write(priv, SCL0_US1, 0);
+
+ /* Timing registers */
+ h = lcd->hsync_len + lcd->left_margin + lcd->xres + lcd->right_margin;
+ v = lcd->vsync_len + lcd->upper_margin + lcd->yres + lcd->lower_margin;
+ tmp = (v - 1) << 16;
+ tmp |= h - 1;
+ vdc4_write(priv, SCL0_FRC4, tmp);
+
+ vdc4_write(priv, TCON_TIM, (((h - 1) / 2) << 16));
+
+ tmp = (lcd->vsync_len + lcd->upper_margin) << 16;
+ tmp |= lcd->yres;
+ vdc4_write(priv, SCL0_FRC6, tmp);
+ vdc4_write(priv, TCON_TIM_STVB1, tmp);
+ vdc4_write(priv, GR3_AB2, tmp);
+
+ tmp = lcd->left_margin << 16;
+ tmp |= lcd->xres;
+ vdc4_write(priv, SCL0_FRC7, tmp);
+ vdc4_write(priv, TCON_TIM_STB1, tmp);
+ vdc4_write(priv, GR3_AB3, tmp);
+
+ vdc4_write(priv, SCL0_FRC1, 0);
+ vdc4_write(priv, SCL0_FRC2, 0);
+ vdc4_write(priv, SCL0_FRC5, 0);
+
+ /* Set output format */
+ vdc4_write(priv, OUT_SET, OUT_FMT_RGB666);
+
+ /* STH TCON Timing */
+ tmp = priv->cfg->hs_pulse_width;
+ tmp |= priv->cfg->hs_start_pos << 16;
+ vdc4_write(priv, TCON_TIM_STH1, tmp);
+
+ /* Setup STVB as HSYNC */
+ tmp = vdc4_read(priv, TCON_TIM_STVB2);
+ tmp &= ~STVB_SEL_BITS;
+ tmp |= STVB_HS_SEL;
+ vdc4_write(priv, TCON_TIM_STVB2, tmp);
+
+ tmp = vdc4_read(priv, OUT_CLK_PHASE);
+ tmp &= ~STVB_EDGE;
+ vdc4_write(priv, OUT_CLK_PHASE, tmp);
+
+ /* Setup STH as DE */
+ tmp = vdc4_read(priv, TCON_TIM_STH2);
+ tmp &= ~STH2_SEL_BITS;
+ tmp |= STH2_DE_SEL;
+ vdc4_write(priv, TCON_TIM_STH2, tmp);
+
+ tmp = vdc4_read(priv, OUT_CLK_PHASE);
+ tmp &= ~STH_EDGE;
+ vdc4_write(priv, OUT_CLK_PHASE, tmp);
+
+ /* Output clock rising edge */
+ tmp = vdc4_read(priv, OUT_CLK_PHASE);
+ tmp &= ~LCD_DATA_EDGE;
+ vdc4_write(priv, OUT_CLK_PHASE, tmp);
+
+ /* Setup graphics buffers and update all registers */
+ vdc4_write(priv, GR1_AB1, DISPSEL_BCKGND);
+ vdc4_write(priv, GR2_AB1, DISPSEL_LOWER);
+ vdc4_write(priv, GR3_AB1, DISPSEL_CUR);
+
+ /* Setup framebuffer base/output */
+ vdc4_write(priv, GR3_FLM_RD, FB_R_ENB);
+
+ vdc4_write(priv, GR3_FLM2, (unsigned long)priv->info->screen_base);
+
+ vdc4_write(priv, GR3_FLM3, (lcd->xres * 2) << 16);
+
+ tmp = vdc4_read(priv, GR3_FLM5);
+ tmp |= lcd->yres << 16;
+ vdc4_write(priv, GR3_FLM5, tmp);
+
+ tmp = lcd->xres << 16;
+ vdc4_write(priv, GR3_FLM6, tmp);
+
+ /* Apply all register settings */
+ vdc4_write(priv, SCL0_UPDATE, SCL0_VEN_BIT | SCL0_UPDATE_BIT);
+ vdc4_write(priv, GR1_UPDATE, P_VEN_UPDATE);
+ vdc4_write(priv, GR2_UPDATE, P_VEN_UPDATE);
+ vdc4_write(priv, GR3_UPDATE, P_VEN_UPDATE | IBUS_VEN_UPDATE);
+ vdc4_write(priv, OUT_UPDATE, OUTCNT_VEN_BIT);
+ vdc4_write(priv, TCON_UPDATE, TCON_VEN_BIT);
+}
+
+static int ren_vdc4_setup_clocks(struct platform_device *pdev,
+ int clock_source,
+ struct ren_vdc4_priv *priv)
+{
+ priv->clk = clk_get(&pdev->dev, "vdc4");
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"vdc4\"\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ if (clock_source = VDC4_PERI_CLK) {
+ priv->dot_clk = clk_get(&pdev->dev, "peripheral_clk");
+ if (IS_ERR(priv->dot_clk)) {
+ dev_err(&pdev->dev, "cannot get peripheral clock\n");
+ clk_put(priv->clk);
+ return PTR_ERR(priv->dot_clk);
+ }
+ }
+
+ return 0;
+}
+
+static int ren_vdc4_setcolreg(u_int regno,
+ u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ u32 *palette = info->pseudo_palette;
+
+ if (regno >= PALETTE_NR)
+ return -EINVAL;
+
+ /* only FB_VISUAL_TRUECOLOR supported */
+
+ red >>= 16 - info->var.red.length;
+ green >>= 16 - info->var.green.length;
+ blue >>= 16 - info->var.blue.length;
+ transp >>= 16 - info->var.transp.length;
+
+ palette[regno] = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ return 0;
+}
+
+static struct fb_fix_screeninfo ren_vdc4_fix = {
+ .id = "Renesas VDC4FB",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .accel = FB_ACCEL_NONE,
+};
+
+static struct fb_ops ren_vdc4_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = ren_vdc4_setcolreg,
+ .fb_read = fb_sys_read,
+ .fb_write = fb_sys_write,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+};
+
+static int ren_vdc4_set_bpp(struct fb_var_screeninfo *var, int bpp)
+{
+ switch (bpp) {
+ case 16: /* RGB 565 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ var->bits_per_pixel = bpp;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+ return 0;
+}
+
+/* PM Functions */
+static int ren_vdc4_start(struct ren_vdc4_priv *priv,
+ int clock_source)
+{
+ int ret;
+
+ ret = clk_enable(priv->clk);
+ if (ret < 0)
+ return ret;
+
+ if (priv->dot_clk) {
+ ret = clk_enable(priv->dot_clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ restart_tft_display(priv, clock_source);
+
+ return ret;
+}
+
+static void ren_vdc4_stop(struct ren_vdc4_priv *priv)
+{
+ if (priv->dot_clk)
+ clk_disable(priv->dot_clk);
+ clk_disable(priv->clk);
+}
+
+static int ren_vdc4_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ ren_vdc4_stop(platform_get_drvdata(pdev));
+ return 0;
+}
+
+static int ren_vdc4_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ren_vdc4_info *pdata = pdev->dev.platform_data;
+
+ return ren_vdc4_start(platform_get_drvdata(pdev), pdata->clock_source);
+}
+
+static const struct dev_pm_ops ren_vdc4_dev_pm_ops = {
+ .suspend = ren_vdc4_suspend,
+ .resume = ren_vdc4_resume,
+};
+
+static int ren_vdc4_remove(struct platform_device *pdev);
+
+static int __devinit ren_vdc4_probe(struct platform_device *pdev)
+{
+ struct fb_info *info;
+ struct ren_vdc4_priv *priv;
+ struct ren_vdc4_info *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ void *buf;
+ int irq, error;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || irq < 0) {
+ dev_err(&pdev->dev, "cannot get platform resources\n");
+ return -ENOENT;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "cannot allocate device data\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ error = request_irq(irq, ren_vdc4_irq, 0, dev_name(&pdev->dev), priv);
+ if (error) {
+ dev_err(&pdev->dev, "unable to request irq\n");
+ goto err1;
+ }
+
+ priv->irq = irq;
+ pdata = pdev->dev.platform_data;
+
+ priv->cfg = pdata;
+
+ error = ren_vdc4_setup_clocks(pdev, pdata->clock_source, priv);
+ if (error) {
+ dev_err(&pdev->dev, "unable to setup clocks\n");
+ goto err1;
+ }
+
+ priv->base = ioremap_nocache(res->start, resource_size(res));
+ if (!priv->base) {
+ dev_err(&pdev->dev, "unable to ioremap\n");
+ goto err1;
+ }
+
+ priv->info = framebuffer_alloc(0, &pdev->dev);
+ if (!priv->info) {
+ dev_err(&pdev->dev, "unable to allocate fb_info\n");
+ goto err1;
+ }
+
+ info = priv->info;
+ info->fbops = &ren_vdc4_ops;
+ info->var.xres = info->var.xres_virtual = pdata->lcd_cfg.xres;
+ info->var.yres = info->var.yres_virtual = pdata->lcd_cfg.yres;
+ info->var.width = pdata->panel_width;
+ info->var.height = pdata->panel_height;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->pseudo_palette = priv->pseudo_palette;
+ error = ren_vdc4_set_bpp(&info->var, pdata->bpp);
+ if (error)
+ goto err1;
+
+ info->fix = ren_vdc4_fix;
+ info->fix.line_length = pdata->lcd_cfg.xres * (pdata->bpp / 8);
+ info->fix.smem_len = info->fix.line_length * pdata->lcd_cfg.yres;
+
+ buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
+ &priv->dma_handle, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&pdev->dev, "unable to allocate buffer\n");
+ goto err1;
+ }
+
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
+ if (error < 0) {
+ dev_err(&pdev->dev, "unable to allocate cmap\n");
+ goto err1;
+ }
+
+ memset(buf, 0, info->fix.smem_len);
+ info->fix.smem_start = priv->dma_handle;
+ info->screen_base = buf;
+ info->device = &pdev->dev;
+ info->par = priv;
+
+ if (error)
+ goto err1;
+
+ ren_vdc4_start(priv, pdata->clock_source);
+ if (error) {
+ dev_err(&pdev->dev, "unable to start hardware\n");
+ goto err1;
+ }
+
+ info = priv->info;
+
+ error = register_framebuffer(info);
+ if (error < 0)
+ goto err1;
+
+ dev_info(info->dev,
+ "registered %s as %udx%ud %dbpp.\n",
+ pdev->name,
+ (int) pdata->lcd_cfg.xres,
+ (int) pdata->lcd_cfg.yres,
+ pdata->bpp);
+
+ return 0;
+
+err1:
+ ren_vdc4_remove(pdev);
+ return error;
+}
+
+static int ren_vdc4_remove(struct platform_device *pdev)
+{
+ struct ren_vdc4_priv *priv = platform_get_drvdata(pdev);
+ struct fb_info *info;
+
+ if (priv->info->dev)
+ unregister_framebuffer(priv->info);
+
+ ren_vdc4_stop(priv);
+
+ info = priv->info;
+
+ if (!info || !info->device) {
+ dev_err(&pdev->dev, "Failed to dealloc/release fb_info\n");
+ } else {
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ if (priv->dot_clk)
+ clk_put(priv->dot_clk);
+ clk_put(priv->clk);
+
+ if (priv->base)
+ iounmap(priv->base);
+
+ if (priv->irq)
+ free_irq(priv->irq, priv);
+
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver ren_vdc4_driver = {
+ .driver = {
+ .name = "ren_vdc4fb",
+ .owner = THIS_MODULE,
+ .pm = &ren_vdc4_dev_pm_ops,
+ },
+ .probe = ren_vdc4_probe,
+ .remove = ren_vdc4_remove,
+};
+
+static int __init ren_vdc4_init(void)
+{
+ return platform_driver_register(&ren_vdc4_driver);
+}
+
+static void __exit ren_vdc4_exit(void)
+{
+ platform_driver_unregister(&ren_vdc4_driver);
+}
+
+module_init(ren_vdc4_init);
+module_exit(ren_vdc4_exit);
+
+MODULE_DESCRIPTION("Renesas VDC4 Framebuffer driver");
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/video/ren_vdc4fb.h b/include/video/ren_vdc4fb.h
new file mode 100644
index 0000000..e91a515
--- /dev/null
+++ b/include/video/ren_vdc4fb.h
@@ -0,0 +1,19 @@
+#ifndef __REN_VDC4_H__
+#define __REN_VDC4_H__
+
+#include <linux/fb.h>
+
+enum { VDC4_EXTCLK = 1, VDC4_PERI_CLK };
+
+struct ren_vdc4_info {
+ int bpp;
+ int clock_source;
+ int clock_divider;
+ int hs_pulse_width;
+ int hs_start_pos;
+ struct fb_videomode lcd_cfg;
+ unsigned long panel_width;
+ unsigned long panel_height;
+};
+
+#endif
--
1.7.5.4
^ permalink raw reply related
* [PATCH] video: move CNVT_TOHW to a common place
From: Manjunathappa, Prakash @ 2012-08-08 12:06 UTC (permalink / raw)
To: linux-fbdev
Replace macro "CNVT_TOHW" by inline function. Also moving it to a
common place linux/fb.h so that it can be accessed from all framebuffer
drivers.
Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
---
Applies on top of fbdev tree[1].
[1] git://github.com/schandinat/linux-2.6.git fbdev-next
drivers/video/68328fb.c | 2 --
drivers/video/fb-puv3.c | 2 --
drivers/video/fsl-diu-fb.c | 5 -----
drivers/video/grvga.c | 6 ------
drivers/video/imxfb.c | 1 -
drivers/video/matrox/matroxfb_base.h | 2 --
drivers/video/pm2fb.c | 2 --
drivers/video/pm3fb.c | 2 --
drivers/video/skeletonfb.c | 2 --
drivers/video/tdfxfb.c | 3 ---
drivers/video/vfb.c | 2 --
drivers/video/xen-fbfront.c | 2 --
include/linux/fb.h | 5 +++++
13 files changed, 5 insertions(+), 31 deletions(-)
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index a425d65..5a1f360 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -318,7 +318,6 @@ static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* (blue << blue.offset) | (transp << transp.offset)
* RAMDAC does not exist
*/
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_PSEUDOCOLOR:
@@ -335,7 +334,6 @@ static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
transp = CNVT_TOHW(transp, 8);
break;
}
-#undef CNVT_TOHW
/* Truecolor has hardware independent palette */
if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
u32 v;
diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c
index 60a787f..c84a907 100644
--- a/drivers/video/fb-puv3.c
+++ b/drivers/video/fb-puv3.c
@@ -565,7 +565,6 @@ static int unifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
(red * 77 + green * 151 + blue * 28) >> 8;
}
-#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_PSEUDOCOLOR:
@@ -582,7 +581,6 @@ static int unifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
transp = CNVT_TOHW(transp, 8);
break;
}
-#undef CNVT_TOHW
/* Truecolor has hardware independent palette */
if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
u32 v;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 458c006..878c588 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1008,11 +1008,6 @@ static int fsl_diu_set_par(struct fb_info *info)
return 0;
}
-static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
-{
- return ((val << width) + 0x7FFF - val) >> 16;
-}
-
/*
* Set a single color register. The values supplied have a 16 bit magnitude
* which needs to be scaled in this function for the hardware. Things to take
diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
index 5245f9a..452038f 100644
--- a/drivers/video/grvga.c
+++ b/drivers/video/grvga.c
@@ -203,17 +203,11 @@ static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigne
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
}
-
-
-#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
-
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
-#undef CNVT_TOHW
-
/* In PSEUDOCOLOR we use the hardware CLUT */
if (info->fix.visual = FB_VISUAL_PSEUDOCOLOR)
__raw_writel((regno << 24) | (red << 16) | (green << 8) | blue,
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index caad368..b008fde 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -224,7 +224,6 @@ static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
struct imxfb_info *fbi = info->par;
u_int val, ret = 1;
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
if (regno < fbi->palette_size) {
val = (CNVT_TOHW(red, 4) << 8) |
(CNVT_TOHW(green,4) << 4) |
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index 11ed57b..ace1e12 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -116,8 +116,6 @@
#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR
#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
-
/* G-series and Mystique have (almost) same DAC */
#undef NEED_DAC1064
#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G)
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index df31a24..85e810c 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -908,7 +908,6 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
* (blue << blue.offset) | (transp << transp.offset)
* RAMDAC does not exist
*/
-#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_PSEUDOCOLOR:
@@ -927,7 +926,6 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
transp = CNVT_TOHW(transp, 8);
break;
}
-#undef CNVT_TOHW
/* Truecolor has hardware independent palette */
if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
u32 v;
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 055e527..8cb30f8 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1109,12 +1109,10 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
* This is the point where the color is converted to something that
* is acceptable by the hardware.
*/
-#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
-#undef CNVT_TOHW
if (info->fix.visual = FB_VISUAL_TRUECOLOR ||
info->fix.visual = FB_VISUAL_DIRECTCOLOR) {
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 5b6abc6..fbf8b75 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -359,12 +359,10 @@ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
* This is the point where the color is converted to something that
* is acceptable by the hardware.
*/
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
-#undef CNVT_TOHW
/*
* This is the point where the function feeds the color to the hardware
* palette after converting the colors to something acceptable by
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index e026724..2eb6c63 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -752,9 +752,6 @@ static int tdfxfb_set_par(struct fb_info *info)
return 0;
}
-/* A handy macro shamelessly pinched from matroxfb */
-#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
-
static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 501a922..bec437c 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -335,7 +335,6 @@ static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* (blue << blue.offset) | (transp << transp.offset)
* RAMDAC does not exist
*/
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_PSEUDOCOLOR:
@@ -352,7 +351,6 @@ static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
transp = CNVT_TOHW(transp, 8);
break;
}
-#undef CNVT_TOHW
/* Truecolor has hardware independent palette */
if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
u32 v;
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index b7f5173..6896744 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -217,12 +217,10 @@ static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (regno > info->cmap.len)
return 1;
-#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
-#undef CNVT_TOHW
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
diff --git a/include/linux/fb.h b/include/linux/fb.h
index ac3f1c6..8a2b3ca 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -397,6 +397,11 @@ struct fb_cursor {
struct fb_image image; /* Cursor image */
};
+static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
+{
+ return ((val << width) + 0x7FFF - val) >> 16;
+}
+
#ifdef CONFIG_FB_BACKLIGHT
/* Settings for the generic backlight code */
#define FB_BACKLIGHT_LEVELS 128
--
1.7.1
^ permalink raw reply related
* [PATCH 3/6] OMAPDSS: DSS: Cleanup cpu_is_xxxx checks
From: Chandrabhanu Mahapatra @ 2012-08-08 11:50 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <19a46cc15dc7add0671dd8c32f5398249c0420ab.1343912533.git.cmahapatra@ti.com>
All the cpu_is checks have been moved to dss_init_features function providing a
much more generic and cleaner interface. The OMAP version and revision specific
functions are initialized by dss_features structure local to dss.c.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dss.c | 154 ++++++++++++++++++++++++++++++-----------
1 file changed, 114 insertions(+), 40 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 7b1c6ac..f5971ac 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -65,6 +65,20 @@ struct dss_reg {
static int dss_runtime_get(void);
static void dss_runtime_put(void);
+static bool check_dss_cinfo_fck(void);
+static bool check_dss_cinfo_fck_34xx(void);
+
+static int dss_get_clk_24xx(struct clk *clk);
+static int dss_get_clk_3xxx(struct clk *clk);
+static int dss_get_clk_44xx(struct clk *clk);
+
+struct dss_features {
+ u16 fck_div_max;
+ int factor;
+ bool (*check_cinfo_fck) (void);
+ int (*get_clk) (struct clk *clk);
+};
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -83,6 +97,8 @@ static struct {
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
+
+ const struct dss_features *feat;
} dss;
static const char * const dss_generic_clk_source_names[] = {
@@ -91,6 +107,34 @@ static const char * const dss_generic_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
};
+static const struct dss_features omap2_dss_features = {
+ .fck_div_max = 16,
+ .factor = 2,
+ .check_cinfo_fck = check_dss_cinfo_fck,
+ .get_clk = dss_get_clk_24xx,
+};
+
+static const struct dss_features omap34_dss_features = {
+ .fck_div_max = 16,
+ .factor = 2,
+ .check_cinfo_fck = check_dss_cinfo_fck_34xx,
+ .get_clk = dss_get_clk_3xxx,
+};
+
+static const struct dss_features omap36_dss_features = {
+ .fck_div_max = 32,
+ .factor = 1,
+ .check_cinfo_fck = check_dss_cinfo_fck,
+ .get_clk = dss_get_clk_3xxx,
+};
+
+static const struct dss_features omap4_dss_features = {
+ .fck_div_max = 32,
+ .factor = 1,
+ .check_cinfo_fck = check_dss_cinfo_fck,
+ .get_clk = dss_get_clk_44xx,
+};
+
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
{
__raw_writel(val, dss.base + idx.idx);
@@ -236,7 +280,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
return dss_generic_clk_source_names[clk_src];
}
-
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
@@ -259,18 +302,10 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
- else
- seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
+ seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
+ fclk_name, fclk_real_name, dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss.feat->factor, fclk_rate);
} else {
seq_printf(s, "%s (%s) = %lu\n",
fclk_name, fclk_real_name,
@@ -461,6 +496,25 @@ unsigned long dss_get_dpll4_rate(void)
return 0;
}
+static bool check_dss_cinfo_fck_34xx(void)
+{
+ unsigned long prate = dss_get_dpll4_rate();
+ unsigned long fck = clk_get_rate(dss.dss_clk);
+
+ if (prate = dss.cache_prate || dss.cache_dss_cinfo.fck = fck)
+ return true;
+ return false;
+}
+
+static bool check_dss_cinfo_fck(void)
+{
+ unsigned long fck = clk_get_rate(dss.dss_clk);
+
+ if (dss.cache_dss_cinfo.fck = fck)
+ return true;
+ return false;
+}
+
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo)
{
@@ -470,7 +524,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
unsigned long fck, max_dss_fck;
- u16 fck_div, fck_div_max = 16;
+ u16 fck_div;
int match = 0;
int min_fck_per_pck;
@@ -479,10 +533,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
- fck = clk_get_rate(dss.dss_clk);
- if (req_pck = dss.cache_req_pck &&
- ((cpu_is_omap34xx() && prate = dss.cache_prate) ||
- dss.cache_dss_cinfo.fck = fck)) {
+ if (req_pck = dss.cache_req_pck && dss.feat->check_cinfo_fck()) {
DSSDBG("dispc clock info found from cache.\n");
*dss_cinfo = dss.cache_dss_cinfo;
*dispc_cinfo = dss.cache_dispc_cinfo;
@@ -519,13 +570,10 @@ retry:
goto found;
} else {
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
+ for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- if (fck_div_max = 32)
+ if (dss.feat->fck_div_max = 32)
fck = prate / fck_div;
else
fck = prate / fck_div * 2;
@@ -619,6 +667,32 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
return REG_GET(DSS_CONTROL, 15, 15);
}
+static int dss_get_clk_24xx(struct clk *clk)
+{
+ clk = NULL;
+ return true;
+}
+
+static int dss_get_clk_3xxx(struct clk *clk)
+{
+ clk = clk_get(NULL, "dpll4_m4_ck");
+ if (IS_ERR(clk)) {
+ DSSERR("Failed to get dpll4_m4_ck\n");
+ return PTR_ERR(clk);
+ }
+ return true;
+}
+
+static int dss_get_clk_44xx(struct clk *clk)
+{
+ clk = clk_get(NULL, "dpll_per_m5x2_ck");
+ if (IS_ERR(clk)) {
+ DSSERR("Failed to get dpll_per_m5x2_ck\n");
+ return PTR_ERR(clk);
+ }
+ return true;
+}
+
static int dss_get_clocks(void)
{
struct clk *clk;
@@ -633,23 +707,9 @@ static int dss_get_clocks(void)
dss.dss_clk = clk;
- if (cpu_is_omap34xx()) {
- clk = clk_get(NULL, "dpll4_m4_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else if (cpu_is_omap44xx()) {
- clk = clk_get(NULL, "dpll_per_m5x2_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll_per_m5x2_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else { /* omap24xx */
- clk = NULL;
- }
+ r = dss.feat->get_clk(clk);
+ if (r != true)
+ goto err;
dss.dpll4_m4_ck = clk;
@@ -704,6 +764,18 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
+static void dss_init_features(void)
+{
+ if (cpu_is_omap24xx())
+ dss.feat = &omap2_dss_features;
+ else if (cpu_is_omap34xx())
+ dss.feat = &omap34_dss_features;
+ else if (cpu_is_omap3630())
+ dss.feat = &omap36_dss_features;
+ else
+ dss.feat = &omap4_dss_features;
+}
+
/* DSS HW IP initialisation */
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
@@ -750,6 +822,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+ dss_init_features();
+
rev = dss_read_reg(DSS_REVISION);
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
--
1.7.10
^ permalink raw reply related
* [PATCH 1/6] OMAPDSS: DISPC: cleanup cpu_is_xxxx checks
From: Chandrabhanu Mahapatra @ 2012-08-08 11:49 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <5344e530a125ef5c5dfeb00e54b7d32df6169aa9.1343912532.git.cmahapatra@ti.com>
All the cpu_is checks have been moved to dispc_init_features function providing
a much more generic and cleaner interface. The OMAP version and revision
specific functions are initialized by dispc_features structure local to dispc.c.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dispc.c | 476 ++++++++++++++++++++++++++-------------
1 file changed, 315 insertions(+), 161 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 5b289c5..7e0b080 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -75,12 +75,60 @@ enum omap_burst_size {
#define REG_FLD_MOD(idx, val, start, end) \
dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
+static int dispc_ovl_calc_scaling_24xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings, u16 width, u16 height,
+ u16 out_width, u16 out_height, enum omap_color_mode color_mode,
+ bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
+ int *decim_y, u16 pos_x, unsigned long *core_clk);
+static int dispc_ovl_calc_scaling_34xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings, u16 width, u16 height,
+ u16 out_width, u16 out_height, enum omap_color_mode color_mode,
+ bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
+ int *decim_y, u16 pos_x, unsigned long *core_clk);
+static int dispc_ovl_calc_scaling_44xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings, u16 width, u16 height,
+ u16 out_width, u16 out_height, enum omap_color_mode color_mode,
+ bool *five_taps, int *x_predecim, int *y_predecim, int *decim_x,
+ int *decim_y, u16 pos_x, unsigned long *core_clk);
+
+static unsigned long calc_core_clk_24xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height);
+static unsigned long calc_core_clk_34xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height);
+static unsigned long calc_core_clk_44xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height);
+
+static bool _dispc_lcd_timings_ok_24xx(int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp);
+static bool _dispc_lcd_timings_ok_44xx(int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp);
+
+static void _dispc_mgr_set_lcd_timings_hv_24xx(enum omap_channel channel,
+ int hsw, int hfp, int hbp, int vsw, int vfp, int vbp);
+static void _dispc_mgr_set_lcd_timings_hv_44xx(enum omap_channel channel,
+ int hsw, int hfp, int hbp, int vsw, int vfp, int vbp);
+
struct dispc_irq_stats {
unsigned long last_reset;
unsigned irq_count;
unsigned irqs[32];
};
+struct dispc_features {
+ int (*calc_scaling) (enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk);
+ unsigned long (*calc_core_clk) (enum omap_channel channel,
+ u16 width, u16 height, u16 out_width, u16 out_height);
+ bool (*lcd_timings_ok) (int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp);
+ void (*set_lcd_timings_hv) (enum omap_channel channel, int hsw, int hfp,
+ int hbp, int vsw, int vfp, int vbp);
+};
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -101,6 +149,8 @@ static struct {
bool ctx_valid;
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
+ const struct dispc_features *feat;
+
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock;
struct dispc_irq_stats irq_stats;
@@ -210,6 +260,34 @@ static const struct {
},
};
+static const struct dispc_features omap2_dispc_features = {
+ .calc_scaling = dispc_ovl_calc_scaling_24xx,
+ .calc_core_clk = calc_core_clk_24xx,
+ .lcd_timings_ok = _dispc_lcd_timings_ok_24xx,
+ .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_24xx,
+};
+
+static const struct dispc_features omap3_2_1_dispc_features = {
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .lcd_timings_ok = _dispc_lcd_timings_ok_24xx,
+ .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_24xx,
+};
+
+static const struct dispc_features omap3_3_0_dispc_features = {
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .lcd_timings_ok = _dispc_lcd_timings_ok_44xx,
+ .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_44xx,
+};
+
+static const struct dispc_features omap4_dispc_features = {
+ .calc_scaling = dispc_ovl_calc_scaling_44xx,
+ .calc_core_clk = calc_core_clk_44xx,
+ .lcd_timings_ok = _dispc_lcd_timings_ok_44xx,
+ .set_lcd_timings_hv = _dispc_mgr_set_lcd_timings_hv_44xx,
+};
+
static void _omap_dispc_set_irqs(void);
static inline void dispc_write_reg(const u16 idx, u32 val)
@@ -1939,7 +2017,18 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
return core_clk;
}
-static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
+static unsigned long calc_core_clk_24xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height)
+{
+ unsigned long pclk = dispc_mgr_pclk_rate(channel);
+
+ if (height > out_height && width > out_width)
+ return pclk * 4;
+ else
+ return pclk * 2;
+}
+
+static unsigned long calc_core_clk_34xx(enum omap_channel channel, u16 width,
u16 height, u16 out_width, u16 out_height)
{
unsigned int hf, vf;
@@ -1958,25 +2047,163 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
hf = 2;
else
hf = 1;
-
if (height > out_height)
vf = 2;
else
vf = 1;
- if (cpu_is_omap24xx()) {
- if (vf > 1 && hf > 1)
- return pclk * 4;
- else
- return pclk * 2;
- } else if (cpu_is_omap34xx()) {
- return pclk * vf * hf;
- } else {
- if (hf > 1)
- return DIV_ROUND_UP(pclk, out_width) * width;
- else
- return pclk;
+ return pclk * vf * hf;
+}
+
+static unsigned long calc_core_clk_44xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height)
+{
+ unsigned long pclk = dispc_mgr_pclk_rate(channel);
+
+ if (width > out_width)
+ return DIV_ROUND_UP(pclk, out_width) * width;
+ else
+ return pclk;
+}
+
+static int dispc_ovl_calc_scaling_24xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ *five_taps = false;
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = dispc.feat->calc_core_clk(channel, in_width,
+ in_height, out_width, out_height);
+ error = (in_width > maxsinglelinewidth || !*core_clk ||
+ *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x = *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale max input width exceeded");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_34xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = calc_core_clk_five_taps(channel, mgr_timings,
+ in_width, in_height, out_width, out_height, color_mode);
+
+ error = check_horiz_timing_omap3(channel, mgr_timings, pos_x,
+ in_width, in_height, out_width, out_height);
+
+ if (in_width > maxsinglelinewidth)
+ if (in_height > out_height &&
+ in_height < out_height * 2)
+ *five_taps = false;
+ if (!*five_taps)
+ *core_clk = dispc.feat->calc_core_clk(channel, in_width,
+ in_height, out_width, out_height);
+
+ error = (error || in_width > maxsinglelinewidth * 2 ||
+ (in_width > maxsinglelinewidth && *five_taps) ||
+ !*core_clk || *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x = *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, height,
+ out_width, out_height)){
+ DSSERR("horizontal timing too tight\n");
+ return -EINVAL;
+ }
+
+ if (in_width > (maxsinglelinewidth * 2)) {
+ DSSERR("Cannot setup scaling");
+ DSSERR("width exceeds maximum width possible");
+ return -EINVAL;
+ }
+
+ if (in_width > maxsinglelinewidth && *five_taps) {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_44xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk)
+{
+ u16 in_width, in_width_max;
+ int decim_x_min = *decim_x;
+ u16 in_height = DIV_ROUND_UP(height, *decim_y);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ in_width_max = dispc_core_clk_rate() /
+ DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), out_width);
+ *decim_x = DIV_ROUND_UP(width, in_width_max);
+
+ *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
+ if (*decim_x > *x_predecim)
+ return -EINVAL;
+
+ do {
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ } while (*decim_x <= *x_predecim &&
+ in_width > maxsinglelinewidth && ++*decim_x);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale width exceeds max line width");
+ return -EINVAL;
}
+
+ *core_clk = dispc.feat->calc_core_clk(channel, in_width, in_height,
+ out_width, out_height);
+ return 0;
}
static int dispc_ovl_calc_scaling(enum omap_plane plane,
@@ -1988,12 +2215,9 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
- const int maxsinglelinewidth - dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
const int max_decim_limit = 16;
unsigned long core_clk = 0;
- int decim_x, decim_y, error, min_factor;
- u16 in_width, in_height, in_width_max = 0;
+ int decim_x, decim_y, ret;
if (width = out_width && height = out_height)
return 0;
@@ -2017,118 +2241,17 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
- min_factor = min(decim_x, decim_y);
-
if (decim_x > *x_predecim || out_width > width * 8)
return -EINVAL;
if (decim_y > *y_predecim || out_height > height * 8)
return -EINVAL;
- if (cpu_is_omap24xx()) {
- *five_taps = false;
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- error = (in_width > maxsinglelinewidth || !core_clk ||
- core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x = decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim &&
- error);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale max input width exceeded");
- return -EINVAL;
- }
- } else if (cpu_is_omap34xx()) {
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk_five_taps(channel, mgr_timings,
- in_width, in_height, out_width, out_height,
- color_mode);
-
- error = check_horiz_timing_omap3(channel, mgr_timings,
- pos_x, in_width, in_height, out_width,
- out_height);
-
- if (in_width > maxsinglelinewidth)
- if (in_height > out_height &&
- in_height < out_height * 2)
- *five_taps = false;
- if (!*five_taps)
- core_clk = calc_core_clk(channel, in_width,
- in_height, out_width, out_height);
- error = (error || in_width > maxsinglelinewidth * 2 ||
- (in_width > maxsinglelinewidth && *five_taps) ||
- !core_clk || core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x = decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim
- && error);
-
- if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width,
- height, out_width, out_height)){
- DSSERR("horizontal timing too tight\n");
- return -EINVAL;
- }
-
- if (in_width > (maxsinglelinewidth * 2)) {
- DSSERR("Cannot setup scaling");
- DSSERR("width exceeds maximum width possible");
- return -EINVAL;
- }
-
- if (in_width > maxsinglelinewidth && *five_taps) {
- DSSERR("cannot setup scaling with five taps");
- return -EINVAL;
- }
- } else {
- int decim_x_min = decim_x;
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width_max = dispc_core_clk_rate() /
- DIV_ROUND_UP(dispc_mgr_pclk_rate(channel),
- out_width);
- decim_x = DIV_ROUND_UP(width, in_width_max);
-
- decim_x = decim_x > decim_x_min ? decim_x : decim_x_min;
- if (decim_x > *x_predecim)
- return -EINVAL;
-
- do {
- in_width = DIV_ROUND_UP(width, decim_x);
- } while (decim_x <= *x_predecim &&
- in_width > maxsinglelinewidth && decim_x++);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale width exceeds max line width");
- return -EINVAL;
- }
-
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- }
+ ret = dispc.feat->calc_scaling(channel, mgr_timings, width, height,
+ out_width, out_height, color_mode, five_taps, x_predecim,
+ y_predecim, &decim_x, &decim_y, pos_x, &core_clk);
+ if (ret)
+ return ret;
DSSDBG("required core clk rate = %lu Hz\n", core_clk);
DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
@@ -2601,27 +2724,28 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height)
height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT);
}
-static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
+static bool _dispc_lcd_timings_ok_24xx(int hsw, int hfp, int hbp,
int vsw, int vfp, int vbp)
{
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- if (hsw < 1 || hsw > 64 ||
- hfp < 1 || hfp > 256 ||
- hbp < 1 || hbp > 256 ||
- vsw < 1 || vsw > 64 ||
- vfp < 0 || vfp > 255 ||
- vbp < 0 || vbp > 255)
- return false;
- } else {
- if (hsw < 1 || hsw > 256 ||
- hfp < 1 || hfp > 4096 ||
- hbp < 1 || hbp > 4096 ||
- vsw < 1 || vsw > 256 ||
- vfp < 0 || vfp > 4095 ||
- vbp < 0 || vbp > 4095)
- return false;
- }
-
+ if (hsw < 1 || hsw > 64 ||
+ hfp < 1 || hfp > 256 ||
+ hbp < 1 || hbp > 256 ||
+ vsw < 1 || vsw > 64 ||
+ vfp < 0 || vfp > 255 ||
+ vbp < 0 || vbp > 255)
+ return false;
+ return true;
+}
+static bool _dispc_lcd_timings_ok_44xx(int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp)
+{
+ if (hsw < 1 || hsw > 256 ||
+ hfp < 1 || hfp > 4096 ||
+ hbp < 1 || hbp > 4096 ||
+ vsw < 1 || vsw > 256 ||
+ vfp < 0 || vfp > 4095 ||
+ vbp < 0 || vbp > 4095)
+ return false;
return true;
}
@@ -2633,7 +2757,8 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
if (dss_mgr_is_lcd(channel))
- timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
+ timings_ok = timings_ok &&
+ dispc.feat->lcd_timings_ok(timings->hsw,
timings->hfp, timings->hbp,
timings->vsw, timings->vfp,
timings->vbp);
@@ -2641,6 +2766,34 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
return timings_ok;
}
+static void _dispc_mgr_set_lcd_timings_hv_24xx(enum omap_channel channel,
+ int hsw, int hfp, int hbp, int vsw, int vfp, int vbp)
+{
+ u32 timing_h, timing_v;
+
+ timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
+ FLD_VAL(hbp-1, 27, 20);
+ timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
+ FLD_VAL(vbp, 27, 20);
+
+ dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
+ dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
+}
+
+static void _dispc_mgr_set_lcd_timings_hv_44xx(enum omap_channel channel,
+ int hsw, int hfp, int hbp, int vsw, int vfp, int vbp)
+{
+ u32 timing_h, timing_v;
+
+ timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
+ FLD_VAL(hbp-1, 31, 20);
+ timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
+ FLD_VAL(vbp, 31, 20);
+
+ dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
+ dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
+}
+
static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
int hfp, int hbp, int vsw, int vfp, int vbp,
enum omap_dss_signal_level vsync_level,
@@ -2650,25 +2803,10 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
enum omap_dss_signal_edge sync_pclk_edge)
{
- u32 timing_h, timing_v, l;
+ u32 l;
bool onoff, rf, ipc;
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
- FLD_VAL(hbp-1, 27, 20);
-
- timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
- FLD_VAL(vbp, 27, 20);
- } else {
- timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
- FLD_VAL(hbp-1, 31, 20);
-
- timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
- FLD_VAL(vbp, 31, 20);
- }
-
- dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
- dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
+ dispc.feat->set_lcd_timings_hv(channel, hsw, hfp, hbp, vsw, vfp, vbp);
switch (data_pclk_edge) {
case OMAPDSS_DRIVE_SIG_RISING_EDGE:
@@ -3671,6 +3809,20 @@ static void _omap_dispc_initial_config(void)
dispc_ovl_enable_zorder_planes();
}
+static void dispc_init_features(void)
+{
+ if (cpu_is_omap24xx()) {
+ dispc.feat = &omap2_dispc_features;
+ } else if (cpu_is_omap34xx()) {
+ if (omap_rev() < OMAP3430_REV_ES3_0)
+ dispc.feat = &omap3_2_1_dispc_features;
+ else
+ dispc.feat = &omap3_3_0_dispc_features;
+ } else {
+ dispc.feat = &omap4_dispc_features;
+ }
+}
+
/* DISPC HW IP initialisation */
static int __init omap_dispchw_probe(struct platform_device *pdev)
{
@@ -3725,6 +3877,8 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
dispc.dss_clk = clk;
+ dispc_init_features();
+
pm_runtime_enable(&pdev->dev);
r = dispc_runtime_get();
--
1.7.10
^ permalink raw reply related
* Re: [PATCH 1/2] ARM: pgtable: add pgprot_writethrough() macro
From: Grazvydas Ignotas @ 2012-08-08 11:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1337716444-30139-2-git-send-email-siarhei.siamashka@gmail.com>
On Tue, May 22, 2012 at 10:54 PM, Siarhei Siamashka
<siarhei.siamashka@gmail.com> wrote:
> Needed for remapping pages with write-through cacheable
> attribute. May be useful for framebuffers.
With this series applied, some of my framebuffer programs get over 70%
performance improvement, could we get this patch in? OMAP DSS
maintainer agreed to take the second patch if this can be merged.
> Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
> ---
> arch/arm/include/asm/pgtable.h | 3 +++
> 1 files changed, 3 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
> index f66626d..04297fa 100644
> --- a/arch/arm/include/asm/pgtable.h
> +++ b/arch/arm/include/asm/pgtable.h
> @@ -103,6 +103,9 @@ extern pgprot_t pgprot_kernel;
> #define pgprot_stronglyordered(prot) \
> __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
>
> +#define pgprot_writethrough(prot) \
> + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITETHROUGH)
> +
> #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
> #define pgprot_dmacoherent(prot) \
> __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN)
> --
> 1.7.3.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Gražvydas
^ permalink raw reply
* Re: [RFC 00/17] OMAPDSS: Change way of passing timings from panel driver to interface
From: Archit Taneja @ 2012-08-08 9:36 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-fbdev, linux-omap, sumit.semwal, rob
In-Reply-To: <1344415685.4932.14.camel@deskari>
On Wednesday 08 August 2012 02:18 PM, Tomi Valkeinen wrote:
> On Wed, 2012-08-08 at 14:08 +0530, Archit Taneja wrote:
>> On Wednesday 08 August 2012 01:43 PM, Tomi Valkeinen wrote:
>>> On Wed, 2012-08-08 at 13:29 +0530, Archit Taneja wrote:
>>>
>>>> Okay, one thing which I want to align on is that most of these functions
>>>> don't really do the actual configurations. That is, they'll just update
>>>> the private data, and the actual configuration will only happen on enable.
>>>>
>>>> We would want set_timings() op to have a direct impact. But we wouldn't
>>>> want the same for setting the data lines, that could be clubbed with
>>>> other configurations at enable. That's okay, right?
>>>
>>> I'm not sure we want/need set_timings to have direct impact. Changing
>>> the timings on the fly has some problems, like the output size changing
>>> to smaller than the overlays, and we perhaps may need to adjust the
>>> clock dividers (dispc's, DSI PLL's or PRCM's).
>>>
>>> It feels just much easier and safer to require that the mgr is disabled
>>> when these changes are made. And as far as I can see, there shouldn't be
>>> any need to change the timings via the shadow registers, as quickly as
>>> possible and during vblank...
>>
>> That makes sense. But currently set_timings for DPI has a direct impact.
>> HDMI/VENC/SDI take the easier route of disabling and enabling the interface.
>>
>> I agree it's safer and easier to make sure things are disabled first,
>> but maybe it's good to have the capability set hdmi timings on the fly
>> in the future, it would make the switch faster, same goes for reading edid.
>
> When do we need to switch mode quickly? Reading edid should not require
> disabling the output for sure.
I think I'm just finding excuses to find a use for my work done in
APPLYing manager related registers.
You are right about edid. Changing HDMI timings take a couple of seconds
now, I was wondering how much that has to do with us completely
disabling/enabling hdmi. it may be just the slowness of the monitors
which causes this.
>
> HDMI is a bit broken currently, though. I think we first enable the
> whole stuff, including video output using VGA, then we read EDID, then
> we change the mode.
>
> We should just enable enough of HDMI to be able to read EDID, and start
> the video output with the correct mode. This needs some restructuring of
> the driver, though. I tried it once quickly, but it turned out not to be
> trivial.
Right. Most likely this restructuring would allow us to modify only the
hdmi timings part when setting a new timing. We could check how much
time we save then :)
>
>> What I meant to ask was whether we should do the same for something like
>> dpi_set_data_lines(), that is, disable dpi, update the data_lines
>> private data with a new value, and enable dpi again.
>
> Hmm, I think it's better to leave disabling and enabling the output to
> the panel driver. So when the panel driver wants to use
> dpi_set_data_lines(), it needs to first disable the DPI output. If it
> doesn't, dpi_set_data_lines() returns -EBUSY.
>
> Otherwise if the panel driver does something like:
>
> dpi_set_foo()
> dpi_set_bar()
>
> Both of those could first disable output, change setting, enable output.
> Instead the panel should first disable, then call those, and then
> enable.
Right, that makes sense.
Archit
^ permalink raw reply
* Re: [rtc-linux] [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
From: Arnd Bergmann @ 2012-08-08 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdbYxpN9RCu8j8KMBgrb=-DsYZHq7hx-ifmHhJ0ZZcRYjw@mail.gmail.com>
On Wednesday 08 August 2012, Linus Walleij wrote:
> On Wed, Aug 8, 2012 at 3:39 AM, Tony Prisk <linux@prisktech.co.nz> wrote:
>
> > Converted the existing arch-vt8500 gpio to a platform_device.
> > Added support for WM8505 and WM8650 GPIO controllers.
> (...)
> > +++ b/drivers/gpio/gpio-vt8500.c
>
> This driver looks very one-bit-per-gpio typed. Are you sure you cannot
> just reuse drivers/gpio/gpio-generic.c? Make a compelling case please...
>
> > +struct vt8500_gpio_bank_regs {
> > + int en;
> > + int dir;
> > + int data_out;
> > + int data_in;
>
> Why are all these members int? They should be u8 from reading your code.
>
> > + int ngpio;
> > +};
Not necessarily 8 bit, but definitely unsigned.
> > +static struct vt8500_gpio_data vt8500_data = {
> > + .num_banks = 7,
> > + .banks = {
> > + VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
> > + VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
> > + VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
> > + VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
> > + VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
> > + VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
> > + VT8500_BANK(-1, 0x3C, 0x5C, 0x7C, 9), /* external gpio */
>
> What on earth are all those magic numbers?
>
> I *guess* they're enabling some default GPIO settings etc.
No, they are the register offsets you quoted above, per bank. There
is no easy way to abstract these, and I suggested putting the
values into the source code rather than describing each bank
separately in the .dtsi file.
My feeling however is that the "vt8500_chip->regoff" is wrong, which
would mean only the first bank works. The code adds the same offsets
per bank once more that it sets in this bank table.
Arnd
^ permalink raw reply
* Re: [rtc-linux] [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
From: Linus Walleij @ 2012-08-08 9:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1344389967-8465-9-git-send-email-linux@prisktech.co.nz>
On Wed, Aug 8, 2012 at 3:39 AM, Tony Prisk <linux@prisktech.co.nz> wrote:
> Converted the existing arch-vt8500 gpio to a platform_device.
> Added support for WM8505 and WM8650 GPIO controllers.
(...)
> +++ b/drivers/gpio/gpio-vt8500.c
This driver looks very one-bit-per-gpio typed. Are you sure you cannot
just reuse drivers/gpio/gpio-generic.c? Make a compelling case please...
> +struct vt8500_gpio_bank_regs {
> + int en;
> + int dir;
> + int data_out;
> + int data_in;
Why are all these members int? They should be u8 from reading your code.
> + int ngpio;
> +};
> +static struct vt8500_gpio_data vt8500_data = {
> + .num_banks = 7,
> + .banks = {
> + VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
> + VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
> + VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
> + VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
> + VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
> + VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
> + VT8500_BANK(-1, 0x3C, 0x5C, 0x7C, 9), /* external gpio */
What on earth are all those magic numbers?
I *guess* they're enabling some default GPIO settings etc.
But it really needs better structure, #defines for each one or
atleast include <linux/bitops.h> and say:
= BIT(4) | /* Enable GPIO pin 5 on this bank */
BIT(5); /* Enable GPIO pin 6 on this bank */
However I suspect this is board specific and should
be taken from device tree. Please elaborate on this...
Ditto for the different instances.
(...)
> + unsigned val;
Looks like all of these should be u8.
> + val = readl(vt8500_chip->base + vt8500_chip->regs->en +
> + vt8500_chip->regoff);
val = (u8) readl(...);
usw
> + val |= (1 << offset);
Use <linux/bitops.h>
val |= BIT(offset);
Apart from these remarks it's looking good...
Yours,
Linus Walleij
^ permalink raw reply
* Re: [RFC 00/17] OMAPDSS: Change way of passing timings from panel driver to interface
From: Archit Taneja @ 2012-08-08 8:50 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-fbdev, linux-omap, sumit.semwal, rob
In-Reply-To: <1344413580.4932.5.camel@deskari>
On Wednesday 08 August 2012 01:43 PM, Tomi Valkeinen wrote:
> On Wed, 2012-08-08 at 13:29 +0530, Archit Taneja wrote:
>
>> Okay, one thing which I want to align on is that most of these functions
>> don't really do the actual configurations. That is, they'll just update
>> the private data, and the actual configuration will only happen on enable.
>>
>> We would want set_timings() op to have a direct impact. But we wouldn't
>> want the same for setting the data lines, that could be clubbed with
>> other configurations at enable. That's okay, right?
>
> I'm not sure we want/need set_timings to have direct impact. Changing
> the timings on the fly has some problems, like the output size changing
> to smaller than the overlays, and we perhaps may need to adjust the
> clock dividers (dispc's, DSI PLL's or PRCM's).
>
> It feels just much easier and safer to require that the mgr is disabled
> when these changes are made. And as far as I can see, there shouldn't be
> any need to change the timings via the shadow registers, as quickly as
> possible and during vblank...
That makes sense. But currently set_timings for DPI has a direct impact.
HDMI/VENC/SDI take the easier route of disabling and enabling the interface.
I agree it's safer and easier to make sure things are disabled first,
but maybe it's good to have the capability set hdmi timings on the fly
in the future, it would make the switch faster, same goes for reading edid.
What I meant to ask was whether we should do the same for something like
dpi_set_data_lines(), that is, disable dpi, update the data_lines
private data with a new value, and enable dpi again.
>
> This makes me also think that if the output related settings can only be
> changed when the output is off, the apply mechanism is not really needed
> at all for these. Not that it causes any harm, but just a point I
> realized.
Hmm, unfortunately you are right. It's still good to have all the DISPC
writes only in APPLY though, and it gives us the option to do some
operation on the fly if needed in the future.
Archit
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox