* Re: [PATCH] da8xx-fb: do not turn ON LCD backlight unless LCDC is enabled
From: Florian Tobias Schandinat @ 2012-07-29 21:16 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1343103325-7313-1-git-send-email-prakash.pm@ti.com>
On 07/24/2012 04:15 AM, Manjunathappa, Prakash wrote:
> LCD blink is observed during suspend/resume and blank/unblank
> operations as backlight is ON during LCDC disable and enable.
> So make sure to turn OFF backlight before disabling and turn
> it ON after enabling.
>
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/da8xx-fb.c | 9 +++++----
> 1 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 0fb4d7d..1a569ae 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -1056,10 +1056,10 @@ static int cfb_blank(int blank, struct fb_info *info)
> par->blank = blank;
> switch (blank) {
> case FB_BLANK_UNBLANK:
> + lcd_enable_raster();
> +
> if (par->panel_power_ctrl)
> par->panel_power_ctrl(1);
> -
> - lcd_enable_raster();
> break;
> case FB_BLANK_POWERDOWN:
> if (par->panel_power_ctrl)
> @@ -1417,11 +1417,12 @@ static int fb_resume(struct platform_device *dev)
> struct da8xx_fb_par *par = info->par;
>
> console_lock();
> + clk_enable(par->lcdc_clk);
> + lcd_enable_raster();
> +
> if (par->panel_power_ctrl)
> par->panel_power_ctrl(1);
>
> - clk_enable(par->lcdc_clk);
> - lcd_enable_raster();
> fb_set_suspend(info, 0);
> console_unlock();
>
^ permalink raw reply
* Re: [PATCH] video: exynos mipi dsi: Fix mipi dsi regulators handling issue
From: Florian Tobias Schandinat @ 2012-07-29 21:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <500CB61A.6000106@samsung.com>
On 07/23/2012 02:25 AM, Donghwa Lee wrote:
> When FB_BLANK_UNLANK event occured, exynos mipi dsi regulators have to turn on.
>
> Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/exynos/exynos_mipi_dsi.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
> index 6c1f5c3..9390640 100644
> --- a/drivers/video/exynos/exynos_mipi_dsi.c
> +++ b/drivers/video/exynos/exynos_mipi_dsi.c
> @@ -154,7 +154,7 @@ static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
> if (client_drv && client_drv->power_on)
> client_drv->power_on(client_dev, 1);
>
> - exynos_mipi_regulator_disable(dsim);
> + exynos_mipi_regulator_enable(dsim);
>
> /* enable MIPI-DSI PHY. */
> if (dsim->pd->phy_enable)
^ permalink raw reply
* Re: [PATCH] video: da8xx-fb: do clock reset of revision 2 LCDC before enabling
From: Florian Tobias Schandinat @ 2012-07-29 21:14 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1342799471-10729-1-git-send-email-prakash.pm@ti.com>
On 07/20/2012 03:51 PM, Manjunathappa, Prakash wrote:
> As in specification software reset should be applied for several
> cycles before bringing it out of reset. Without this patch
> particularly during suspend and resume clock reset is not guaranteed
> to happen.
>
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Applied. But it would be better if you made the patch dependencies
clear, as I didn't consider some of your patches mature enough for this
merge window. Now I had to figure out why my final build failed and
applied the patch below.
Best regards,
Florian Tobias Schandinat
---
commit a0239073fd75489d25575cf3aaf71ab55b416020
Author: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Date: Sun Jul 29 16:47:40 2012 +0000
da8xx-fb: fix compile issue due to missing include
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index ca9943a..7ae9d53 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -32,6 +32,7 @@
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/lcm.h>
#include <video/da8xx-fb.h>
#include <asm/div64.h>
> ---
> drivers/video/da8xx-fb.c | 12 ++++++++----
> 1 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 3d2d0d1..4440292 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -262,10 +262,18 @@ static inline void lcd_enable_raster(void)
> {
> u32 reg;
>
> + /* Put LCDC in reset for several cycles */
> + if (lcd_revision = LCD_VERSION_2)
> + /* Write 1 to reset LCDC */
> + lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
> + mdelay(1);
> +
> /* Bring LCDC out of reset */
> if (lcd_revision = LCD_VERSION_2)
> lcdc_write(0, LCD_CLK_RESET_REG);
> + mdelay(1);
>
> + /* Above reset sequence doesnot reset register context */
> reg = lcdc_read(LCD_RASTER_CTRL_REG);
> if (!(reg & LCD_RASTER_ENABLE))
> lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
> @@ -279,10 +287,6 @@ static inline void lcd_disable_raster(void)
> reg = lcdc_read(LCD_RASTER_CTRL_REG);
> if (reg & LCD_RASTER_ENABLE)
> lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
> -
> - if (lcd_revision = LCD_VERSION_2)
> - /* Write 1 to reset LCDC */
> - lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
> }
>
> static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
^ permalink raw reply related
* Re: [PATCH v2 1/2] video: da8xx-fb: configure FIFO threshold to reduce underflow errors
From: Florian Tobias Schandinat @ 2012-07-29 21:07 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1342625616-7393-1-git-send-email-prakash.pm@ti.com>
On 07/18/2012 03:33 PM, Manjunathappa, Prakash wrote:
> Patch works around the below silicon errata:
> During LCDC initialization, there is the potential for a FIFO
> underflow condition to occur. A FIFO underflow condition
> occurs when the input FIFO is completely empty and the LCDC
> raster controller logic that drives data to the output pins
> attempts to fetch data from the FIFO. When a FIFO underflow
> condition occurs, incorrect data will be driven out on the
> LCDC data pins.
>
> Software should poll the FUF bit field in the LCD_STAT register
> to check if an error condition has occurred or service the
> interrupt if FUF_EN is enabled when FUF occurs. If the FUF bit
> field has been set to 1, this will indicate an underflow
> condition has occurred and then the software should execute a
> reset of the LCDC via the LPSC.
>
> This problem may occur if the LCDC FIFO threshold size
> (LCDDMA_CTRL[TH_FIFO_READY]) is left at its default value after
> reset. Increasing the FIFO threshold size will reduce or
> eliminate underflows. Setting the threshold size to 256 double
> words or larger is recommended.
>
> Above issue is described in section 2.1.3 of silicon errata
> http://www.ti.com/lit/er/sprz313e/sprz313e.pdf
>
> Signed-off-by: Rajashekhara, Sudhakar <sudhakar.raj@ti.com>
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Applied both patches of this series.
Thanks,
Florian Tobias Schandinat
> ---
> Seems like version 1 of this patch did not reach fbdev mailing list.
> Since v1:
> Removed clk_disable/clk_enable from error interrupt handling code.
>
> drivers/video/da8xx-fb.c | 11 +++++++----
> include/video/da8xx-fb.h | 3 +++
> 2 files changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 183366d..186ab5a 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -353,8 +353,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
> lcd_enable_raster();
> }
>
> -/* Configure the Burst Size of DMA */
> -static int lcd_cfg_dma(int burst_size)
> +/* Configure the Burst Size and fifo threhold of DMA */
> +static int lcd_cfg_dma(int burst_size, int fifo_th)
> {
> u32 reg;
>
> @@ -378,6 +378,9 @@ static int lcd_cfg_dma(int burst_size)
> default:
> return -EINVAL;
> }
> +
> + reg |= (fifo_th << 8);
> +
> lcdc_write(reg, LCD_DMA_CTRL_REG);
>
> return 0;
> @@ -679,8 +682,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
> lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) &
> ~LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);
>
> - /* Configure the DMA burst size. */
> - ret = lcd_cfg_dma(cfg->dma_burst_sz);
> + /* Configure the DMA burst size and fifo threshold. */
> + ret = lcd_cfg_dma(cfg->dma_burst_sz, cfg->fifo_th);
> if (ret < 0)
> return ret;
>
> diff --git a/include/video/da8xx-fb.h b/include/video/da8xx-fb.h
> index 89d43b3..5a0e4f9 100644
> --- a/include/video/da8xx-fb.h
> +++ b/include/video/da8xx-fb.h
> @@ -82,6 +82,9 @@ struct lcd_ctrl_config {
>
> /* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */
> unsigned char raster_order;
> +
> + /* DMA FIFO threshold */
> + int fifo_th;
> };
>
> struct lcd_sync_arg {
^ permalink raw reply
* Re: [PATCH RESEND] video: da8xx-fb: fix flicker due to 1 frame delay in updated frame
From: Florian Tobias Schandinat @ 2012-07-29 21:06 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1342625516-7185-1-git-send-email-prakash.pm@ti.com>
On 07/18/2012 03:31 PM, Manjunathappa, Prakash wrote:
> Flicker/tearing effect is observed with current FB driver.
> Issue is because of 2 active DMA channels ping ponging among them
> along with usage of 2 DDR ping pong buffers in driver. Application
> unaware of active DMA channel keeps updating frame being displayed,
> this leads to tearing effect.
> Below steps describes the issue:
> 1)Initially assume both buffers FB0 and FB1 are programmed for buffer-0.
> 2)On EOF0: Program FB0 for buffer-1, indicate(wake up) application
> to fill up buffer-0. As FB1 is active and continues to DMA buffer-0
> (which is being filled), leading to tearing/flickering issue.
> 3)On EOF1: Program FB1 for buffer-0, indicate(wake up) application to
> fill up buffer-1. As FB0 is active and continues to DMA buffer-1(which
> is being filled), leading to tearing/flickering issue.
> 4)On EOF0: Program FB0 for buffer-1, indicate(wake up) application to
> fill up buffer-0. As FB1 is active and continues to DMA buffer-0(which is
> being filled), leading to tearing/flickering issue.
> ...
> Above steps depict that issue is because of 1 frame delay in frame
> panned by application.
>
> Patch fixes the issue by keeping track free DMA channel and configures
> it in drivers PAN callback so that panned frame from application gets
> displayed in next frame period.
>
> Wiki below describes the issue in detail and it also has link to
> application with which issue can be reproduced.
> http://processors.wiki.ti.com/index.php/DA8xx_LCDC_Linux_FB_FAQs
>
> Signed-off-by: Nellutla, Aditya <aditya.n@ti.com>
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> Resending as my earlier patch seems like not reached fbdev mailing list.
>
> drivers/video/da8xx-fb.c | 30 ++++++++++++++++++++++++++++++
> 1 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index e9d2f6e..183366d 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -30,6 +30,7 @@
> #include <linux/clk.h>
> #include <linux/cpufreq.h>
> #include <linux/console.h>
> +#include <linux/spinlock.h>
> #include <linux/slab.h>
> #include <video/da8xx-fb.h>
> #include <asm/div64.h>
> @@ -161,6 +162,13 @@ struct da8xx_fb_par {
> wait_queue_head_t vsync_wait;
> int vsync_flag;
> int vsync_timeout;
> + spinlock_t lock_for_chan_update;
> +
> + /*
> + * LCDC has 2 ping pong DMA channels, channel 0
> + * and channel 1.
> + */
> + unsigned int which_dma_channel_done;
> #ifdef CONFIG_CPU_FREQ
> struct notifier_block freq_transition;
> unsigned int lcd_fck_rate;
> @@ -741,6 +749,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
> lcdc_write(stat, LCD_MASKED_STAT_REG);
>
> if (stat & LCD_END_OF_FRAME0) {
> + par->which_dma_channel_done = 0;
> lcdc_write(par->dma_start,
> LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
> lcdc_write(par->dma_end,
> @@ -750,6 +759,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
> }
>
> if (stat & LCD_END_OF_FRAME1) {
> + par->which_dma_channel_done = 1;
> lcdc_write(par->dma_start,
> LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
> lcdc_write(par->dma_end,
> @@ -796,6 +806,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
> lcdc_write(stat, LCD_STAT_REG);
>
> if (stat & LCD_END_OF_FRAME0) {
> + par->which_dma_channel_done = 0;
> lcdc_write(par->dma_start,
> LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
> lcdc_write(par->dma_end,
> @@ -805,6 +816,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
> }
>
> if (stat & LCD_END_OF_FRAME1) {
> + par->which_dma_channel_done = 1;
> lcdc_write(par->dma_start,
> LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
> lcdc_write(par->dma_end,
> @@ -1050,6 +1062,7 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
> struct fb_fix_screeninfo *fix = &fbi->fix;
> unsigned int end;
> unsigned int start;
> + unsigned long irq_flags;
>
> if (var->xoffset != fbi->var.xoffset ||
> var->yoffset != fbi->var.yoffset) {
> @@ -1067,6 +1080,21 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
> end = start + fbi->var.yres * fix->line_length - 1;
> par->dma_start = start;
> par->dma_end = end;
> + spin_lock_irqsave(&par->lock_for_chan_update,
> + irq_flags);
> + if (par->which_dma_channel_done = 0) {
> + lcdc_write(par->dma_start,
> + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
> + lcdc_write(par->dma_end,
> + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
> + } else if (par->which_dma_channel_done = 1) {
> + lcdc_write(par->dma_start,
> + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
> + lcdc_write(par->dma_end,
> + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
> + }
> + spin_unlock_irqrestore(&par->lock_for_chan_update,
> + irq_flags);
> }
> }
>
> @@ -1294,6 +1322,8 @@ static int __devinit fb_probe(struct platform_device *device)
> /* initialize the vsync wait queue */
> init_waitqueue_head(&par->vsync_wait);
> par->vsync_timeout = HZ / 5;
> + par->which_dma_channel_done = -1;
> + spin_lock_init(&par->lock_for_chan_update);
>
> /* Register the Frame Buffer */
> if (register_framebuffer(da8xx_fb_info) < 0) {
^ permalink raw reply
* Re: [PATCH RESEND] video: da8xx-fb rev2: fix disabling of palette completion interrupt
From: Florian Tobias Schandinat @ 2012-07-29 21:05 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1342624871-5947-1-git-send-email-prakash.pm@ti.com>
On 07/18/2012 03:21 PM, Manjunathappa, Prakash wrote:
> Writing '1' to particular bit of IRQENABLE_CLEAR register disables the
> corresponding interrupt on revision 2 LCDC. This register was wrongly
> configured to disable all previous enabled interrupts instead of
> disabling only palette completion interrupt. Patch fixes it by clearing
> only palette completion interrupt bit.
>
> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> Resending as my earlier patch seems like not reached fbdev mailing list.
>
> drivers/video/da8xx-fb.c | 7 ++-----
> 1 files changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 47118c7..88e98ea 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -715,7 +715,6 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
> {
> struct da8xx_fb_par *par = arg;
> u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
> - u32 reg_int;
>
> if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
> lcd_disable_raster();
> @@ -732,10 +731,8 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
>
> lcdc_write(stat, LCD_MASKED_STAT_REG);
>
> - /* Disable PL completion inerrupt */
> - reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) |
> - (LCD_V2_PL_INT_ENA);
> - lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG);
> + /* Disable PL completion interrupt */
> + lcdc_write(LCD_V2_PL_INT_ENA, LCD_INT_ENABLE_CLR_REG);
>
> /* Setup and start data loading mode */
> lcd_blit(LOAD_DATA, par);
^ permalink raw reply
* Re: [PATCH v2] da8xx-fb: add missing FB_BLANK operations
From: Florian Tobias Schandinat @ 2012-07-29 21:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1341583288-30281-1-git-send-email-yegorslists@googlemail.com>
On 07/06/2012 02:01 PM, yegorslists@googlemail.com wrote:
> From: Yegor Yefremov <yegorslists@googlemail.com>
>
> add FB_BLANK_NORMAL, FB_BLANK_VSYNC_SUSPEND and FB_BLANK_HSYNC_SUSPEND
> modes (copy drivers/video/omap2/omapfb/omapfb-main.c implementation).
> Otherwise X-server will complain about invalid parameter.
>
> Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> v2: add linux-fbdev as recipient
>
> drivers/video/da8xx-fb.c | 3 +++
> 1 files changed, 3 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
> index 47118c7..8d745bf 100644
> --- a/drivers/video/da8xx-fb.c
> +++ b/drivers/video/da8xx-fb.c
> @@ -1026,6 +1026,9 @@ static int cfb_blank(int blank, struct fb_info *info)
>
> lcd_enable_raster();
> break;
> + case FB_BLANK_NORMAL:
> + case FB_BLANK_VSYNC_SUSPEND:
> + case FB_BLANK_HSYNC_SUSPEND:
> case FB_BLANK_POWERDOWN:
> if (par->panel_power_ctrl)
> par->panel_power_ctrl(0);
^ permalink raw reply
* Re: [RFC][PATCH v3 1/3] runtime interpreted power sequences
From: Greg Kroah-Hartman @ 2012-07-27 18:20 UTC (permalink / raw)
To: Alexandre Courbot
Cc: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Mark Brown, Arnd Bergmann,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1343390750-3642-2-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
On Fri, Jul 27, 2012 at 09:05:48PM +0900, Alexandre Courbot wrote:
> +++ b/include/linux/power_seq.h
> @@ -0,0 +1,139 @@
> +/*
> + * power_seq.h
> + *
> + * Simple interpreter for defining power sequences as platform data or device
> + * tree properties. Initially designed for use with backlight drivers.
> + *
> + * Power sequences are designed to replace the callbacks typically used in
> + * board-specific files that implement board-specific power sequences of devices
> + * such as backlights. A power sequence is an array of resources (which can a
> + * regulator, a GPIO, a PWM, ...) with an action to perform on it (enable or
> + * disable) and optional pre and post step delays. By having them interpreted
> + * instead of arbitrarily executed, it is possible to describe these in the
> + * device tree and thus remove board-specific code from the kernel.
> + *
> + * Author: Alexandre Courbot <acourbot@nvidia.com>
> + *
> + * Copyright (c) 2012 NVIDIA Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
As I always say:
Unless you want to track the office movements of the FSF for the
next 40 years, and keep this file up to date, drop that last
paragraph, it's pointless.
^ permalink raw reply
* Re: [RFC][PATCH v3 1/3] runtime interpreted power sequences
From: Greg Kroah-Hartman @ 2012-07-27 18:19 UTC (permalink / raw)
To: Alexandre Courbot
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Mark Brown, Stephen Warren,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
In-Reply-To: <1343390750-3642-2-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
On Fri, Jul 27, 2012 at 09:05:48PM +0900, Alexandre Courbot wrote:
> Some device drivers (panel backlights especially) need to follow precise
> sequences for powering on and off, involving gpios, regulators, PWMs
> with a precise powering order and delays to respect between each steps.
> These sequences are board-specific, and do not belong to a particular
> driver - therefore they have been performed by board-specific hook
> functions to far.
>
> With the advent of the device tree and of ARM kernels that are not
> board-tied, we cannot rely on these board-specific hooks anymore but
> need a way to implement these sequences in a portable manner. This patch
> introduces a simple interpreter that can execute such power sequences
> encoded either as platform data or within the device tree.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> Documentation/power/power_seq.txt | 120 +++++++++++++++
> drivers/base/Kconfig | 4 +
> drivers/base/Makefile | 1 +
> drivers/base/power_seq.c | 300 ++++++++++++++++++++++++++++++++++++++
> include/linux/power_seq.h | 139 ++++++++++++++++++
What's wrong with drivers/power/? I sure don't want to maintain this
code, and it seems to not be part of the "driver core" infrastructure.
thanks,
greg k-h
^ permalink raw reply
* [RFC][PATCH v3 3/3] tegra: add pwm backlight device tree nodes
From: Alexandre Courbot @ 2012-07-27 12:05 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Greg Kroah-Hartman, Mark Brown, Arnd Bergmann
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Alexandre Courbot
In-Reply-To: <1343390750-3642-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
arch/arm/boot/dts/tegra20-ventana.dts | 53 +++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/tegra20.dtsi | 2 +-
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index be90544..6acdb6d 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -317,6 +317,59 @@
bus-width = <8>;
};
+ backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>;
+ default-brightness-level = <12>;
+
+ pwms = <&pwm 2 5000000>;
+ pwm-names = "backlight";
+ power-supply = <&backlight_reg>;
+ enable-gpio = <&gpio 28 0>;
+
+ power-on-sequence {
+ regulator@0 {
+ id = "power";
+ enable;
+ post-delay = <10>;
+ };
+ pwm@1 {
+ id = "backlight";
+ enable;
+ };
+ gpio@2 {
+ id = "enable-gpio";
+ enable;
+ };
+ };
+ power-off-sequence {
+ gpio@0 {
+ id = "enable-gpio";
+ disable;
+ };
+ pwm@1 {
+ id = "backlight";
+ disable;
+ };
+ regulator@2 {
+ id = "power";
+ disable;
+ pre-delay = <10>;
+ };
+ };
+ };
+
+ backlight_reg: fixedregulator@176 {
+ compatible = "regulator-fixed";
+ regulator-name = "backlight_regulator";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio 176 0>;
+ startup-delay-us = <0>;
+ enable-active-high;
+ regulator-boot-off;
+ };
+
sound {
compatible = "nvidia,tegra-audio-wm8903-ventana",
"nvidia,tegra-audio-wm8903";
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 405d167..67a6cd9 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -123,7 +123,7 @@
status = "disabled";
};
- pwm {
+ pwm: pwm {
compatible = "nvidia,tegra20-pwm";
reg = <0x7000a000 0x100>;
#pwm-cells = <2>;
--
1.7.11.3
^ permalink raw reply related
* [RFC][PATCH v3 2/3] pwm_backlight: use power sequences
From: Alexandre Courbot @ 2012-07-27 12:05 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Greg Kroah-Hartman, Mark Brown, Arnd Bergmann
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Alexandre Courbot
In-Reply-To: <1343390750-3642-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Make use of the power sequences specified in the device tree or platform
data, if any.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
.../bindings/video/backlight/pwm-backlight.txt | 55 +++++-
drivers/video/backlight/Kconfig | 1 +
drivers/video/backlight/pwm_bl.c | 213 +++++++++++++++------
include/linux/pwm_backlight.h | 18 +-
4 files changed, 225 insertions(+), 62 deletions(-)
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
index 1e4fc72..59abeba 100644
--- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
@@ -2,7 +2,6 @@ pwm-backlight bindings
Required properties:
- compatible: "pwm-backlight"
- - pwms: OF device-tree PWM specification (see PWM binding[0])
- brightness-levels: Array of distinct brightness levels. Typically these
are in the range from 0 to 255, but any range starting at 0 will do.
The actual brightness level (PWM duty cycle) will be interpolated
@@ -10,10 +9,22 @@ Required properties:
last value in the array represents a 100% duty cycle (brightest).
- default-brightness-level: the default brightness level (index into the
array defined by the "brightness-levels" property)
+ - pwms: OF device-tree PWM specification (see PWM binding[0]). Exactly one PWM
+ must be specified
+ - pwm-names: a list of names for the PWM devices specified in the
+ "pwms" property (see PWM binding[0])
+ - power-on-sequence: Power sequence that will bring the backlight on. This
+ sequence must reference the PWM specified in the pwms property by its
+ name. It can also reference extra GPIOs or regulators, and introduce
+ delays between sequence steps
+ - power-off-sequence: Power sequence that will bring the backlight off. This
+ sequence must reference the PWM specified in the pwms property by its
+ name. It can also reference extra GPIOs or regulators, and introduce
+ delays between sequence steps
Optional properties:
- - pwm-names: a list of names for the PWM devices specified in the
- "pwms" property (see PWM binding[0])
+ - *-supply: regulators used within a power sequence
+ - *-gpio: GPIOs used within a power sequence
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
@@ -21,8 +32,42 @@ Example:
backlight {
compatible = "pwm-backlight";
- pwms = <&pwm 0 5000000>;
-
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
+
+ pwms = <&pwm 0 5000000>;
+ pwm-names = "backlight";
+ power-supply = <&backlight_reg>;
+ enable-gpio = <&gpio 6 0>;
+
+ power-on-sequence {
+ regulator@0 {
+ id = "power";
+ enable;
+ post-delay = <10>;
+ };
+ pwm@1 {
+ id = "backlight";
+ enable;
+ };
+ gpio@2 {
+ id = "enable-gpio";
+ enable;
+ };
+ };
+ power-off-sequence {
+ gpio@0 {
+ id = "enable-gpio";
+ disable;
+ };
+ pwm@1 {
+ id = "backlight";
+ disable;
+ };
+ regulator@2 {
+ id = "power";
+ disable;
+ pre-delay = <10>;
+ };
+ };
};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index cf28276..6fb8aa3 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -246,6 +246,7 @@ config BACKLIGHT_CARILLO_RANCH
config BACKLIGHT_PWM
tristate "Generic PWM based Backlight Driver"
depends on PWM
+ select POWER_SEQ
help
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 995f016..6e3a49e 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -27,6 +27,12 @@ struct pwm_bl_data {
unsigned int period;
unsigned int lth_brightness;
unsigned int *levels;
+ bool enabled;
+ power_seq_resources resources;
+ power_seq *power_on_seq;
+ power_seq *power_off_seq;
+
+ /* Legacy callbacks */
int (*notify)(struct device *,
int brightness);
void (*notify_after)(struct device *,
@@ -35,6 +41,34 @@ struct pwm_bl_data {
void (*exit)(struct device *);
};
+static void pwm_backlight_on(struct backlight_device *bl)
+{
+ struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+ int ret;
+
+ if (pb->enabled)
+ return;
+
+ if ((ret = power_seq_run(pb->dev, pb->power_on_seq)) < 0)
+ dev_err(&bl->dev, "cannot run power on sequence\n");
+
+ pb->enabled = true;
+}
+
+static void pwm_backlight_off(struct backlight_device *bl)
+{
+ struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+ int ret;
+
+ if (!pb->enabled)
+ return;
+
+ if ((ret = power_seq_run(pb->dev, pb->power_off_seq)) < 0)
+ dev_err(&bl->dev, "cannot run power off sequence\n");
+
+ pb->enabled = false;
+}
+
static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
@@ -51,8 +85,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
brightness = pb->notify(pb->dev, brightness);
if (brightness = 0) {
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ pwm_backlight_off(bl);
} else {
int duty_cycle;
@@ -66,7 +99,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
duty_cycle = pb->lth_brightness +
(duty_cycle * (pb->period - pb->lth_brightness) / max);
pwm_config(pb->pwm, duty_cycle, pb->period);
- pwm_enable(pb->pwm);
+ pwm_backlight_on(bl);
}
if (pb->notify_after)
@@ -145,12 +178,16 @@ static int pwm_backlight_parse_dt(struct device *dev,
data->max_brightness--;
}
- /*
- * TODO: Most users of this driver use a number of GPIOs to control
- * backlight power. Support for specifying these needs to be
- * added.
- */
+ data->power_on_seq = of_parse_power_seq(dev, of_find_node_by_name(node,
+ "power-on-sequence"));
+ if (IS_ERR(data->power_on_seq))
+ return PTR_ERR(data->power_on_seq);
+ data->power_off_seq = of_parse_power_seq(dev, of_find_node_by_name(node,
+ "power-off-sequence"));
+ if (IS_ERR(data->power_off_seq))
+ return PTR_ERR(data->power_off_seq);
+ data->use_power_sequences = true;
return 0;
}
@@ -168,73 +205,141 @@ static int pwm_backlight_parse_dt(struct device *dev,
}
#endif
+/**
+ * Construct the power sequences corresponding to the legacy platform data.
+ */
+static int pwm_backlight_legacy_probe(struct platform_device *pdev,
+ struct pwm_bl_data *pb)
+{
+ struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct power_seq_resource *res;
+ struct power_seq_step *step;
+
+ pb->pwm = pwm_get(dev, NULL);
+ if (IS_ERR(pb->pwm)) {
+ dev_warn(dev, "unable to request PWM, trying legacy API\n");
+
+ pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
+ if (IS_ERR(pb->pwm)) {
+ dev_err(dev, "unable to request legacy PWM\n");
+ return PTR_ERR(pb->pwm);
+ }
+ pwm_set_period(pb->pwm, data->pwm_period_ns);
+ }
+
+ pb->notify = data->notify;
+ pb->notify_after = data->notify_after;
+ pb->check_fb = data->check_fb;
+ pb->exit = data->exit;
+ pb->dev = dev;
+
+ /* Now build the resources and sequences corresponding to this PWM */
+ res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+ if (!res) return -ENOMEM;
+ res->type = POWER_SEQ_PWM;
+ res->id = "pwm-backlight";
+ res->pwm = pb->pwm;
+ list_add(&res->list, &pb->resources);
+
+ /* allocate both power on and off sequences at the same time */
+ step = devm_kzalloc(dev, sizeof(*step) * 4, GFP_KERNEL);
+ if (!step) return -ENOMEM;
+ step->resource = res;
+ memcpy(&step[2], &step[0], sizeof(*step));
+ step[0].params.enable = 1;
+ pb->power_on_seq = &step[0];
+ pb->power_off_seq = &step[2];
+
+ return 0;
+}
+
static int pwm_backlight_probe(struct platform_device *pdev)
{
struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
struct platform_pwm_backlight_data defdata;
+ struct power_seq_resource *res;
struct backlight_properties props;
struct backlight_device *bl;
struct pwm_bl_data *pb;
unsigned int max;
int ret;
+ pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
+ if (!pb) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&pb->resources);
+
+ /* using new interface or device tree */
if (!data) {
+ /* build platform data from device tree */
ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
- if (ret < 0) {
+ if (ret = -EPROBE_DEFER) {
+ return ret;
+ } else if (ret < 0) {
dev_err(&pdev->dev, "failed to find platform data\n");
return ret;
}
-
data = &defdata;
}
- if (data->init) {
- ret = data->init(&pdev->dev);
+ if (!data->use_power_sequences) {
+ /* using legacy interface */
+ ret = pwm_backlight_legacy_probe(pdev, pb);
if (ret < 0)
return ret;
+ } else {
+ /* build sequences and allocate resources from platform data */
+ if (data->power_on_seq) {
+ pb->power_on_seq = power_seq_build(&pdev->dev,
+ &pb->resources,
+ data->power_on_seq);
+ if (IS_ERR(pb->power_on_seq))
+ return PTR_ERR(pb->power_on_seq);
+ }
+ if (data->power_off_seq) {
+ pb->power_off_seq = power_seq_build(&pdev->dev,
+ &pb->resources,
+ data->power_off_seq);
+ if (IS_ERR(pb->power_off_seq))
+ return PTR_ERR(pb->power_off_seq);
+ }
+
+ /* we must have exactly one PWM for this driver */
+ list_for_each_entry(res, &pb->resources, list) {
+ if (res->type != POWER_SEQ_PWM)
+ continue;
+ if (pb->pwm) {
+ dev_err(&pdev->dev, "more than one PWM used\n");
+ return -EINVAL;
+ }
+ /* keep the pwm at hand */
+ pb->pwm = res->pwm;
+ }
}
- pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
- if (!pb) {
- dev_err(&pdev->dev, "no memory for state\n");
- ret = -ENOMEM;
- goto err_alloc;
+ /* from here we should have a PWM */
+ if (!pb->pwm) {
+ dev_err(&pdev->dev, "no PWM defined!\n");
+ return -EINVAL;
+ }
+
+ if (data->init) {
+ ret = data->init(&pdev->dev);
+ if (ret < 0)
+ goto err;
}
if (data->levels) {
max = data->levels[data->max_brightness];
pb->levels = data->levels;
- } else
+ } else {
max = data->max_brightness;
-
- pb->notify = data->notify;
- pb->notify_after = data->notify_after;
- pb->check_fb = data->check_fb;
- pb->exit = data->exit;
- pb->dev = &pdev->dev;
-
- pb->pwm = pwm_get(&pdev->dev, NULL);
- if (IS_ERR(pb->pwm)) {
- dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
-
- pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
- if (IS_ERR(pb->pwm)) {
- dev_err(&pdev->dev, "unable to request legacy PWM\n");
- ret = PTR_ERR(pb->pwm);
- goto err_alloc;
- }
}
- dev_dbg(&pdev->dev, "got pwm for backlight\n");
-
- /*
- * The DT case will set the pwm_period_ns field to 0 and store the
- * period, parsed from the DT, in the PWM device. For the non-DT case,
- * set the period from platform data.
- */
- if (data->pwm_period_ns > 0)
- pwm_set_period(pb->pwm, data->pwm_period_ns);
-
pb->period = pwm_get_period(pb->pwm);
pb->lth_brightness = data->lth_brightness * (pb->period / max);
@@ -246,20 +351,20 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
- goto err_bl;
+ goto err;
}
bl->props.brightness = data->dft_brightness;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
+
return 0;
-err_bl:
- pwm_put(pb->pwm);
-err_alloc:
+err:
if (data->exit)
data->exit(&pdev->dev);
+ power_seq_free_resources(&pb->resources);
return ret;
}
@@ -269,9 +374,9 @@ static int pwm_backlight_remove(struct platform_device *pdev)
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
backlight_device_unregister(bl);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
- pwm_put(pb->pwm);
+ pwm_backlight_off(bl);
+ power_seq_free_resources(&pb->resources);
+
if (pb->exit)
pb->exit(&pdev->dev);
return 0;
@@ -285,8 +390,7 @@ static int pwm_backlight_suspend(struct device *dev)
if (pb->notify)
pb->notify(pb->dev, 0);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ pwm_backlight_off(bl);
if (pb->notify_after)
pb->notify_after(pb->dev, 0);
return 0;
@@ -323,4 +427,3 @@ module_platform_driver(pwm_backlight_driver);
MODULE_DESCRIPTION("PWM based Backlight Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pwm-backlight");
-
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 56f4a86..3e8bd2c 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -5,14 +5,28 @@
#define __LINUX_PWM_BACKLIGHT_H
#include <linux/backlight.h>
+#include <linux/power_seq.h>
struct platform_pwm_backlight_data {
- int pwm_id;
unsigned int max_brightness;
unsigned int dft_brightness;
unsigned int lth_brightness;
- unsigned int pwm_period_ns;
unsigned int *levels;
+ /* Set this to true otherwise the legacy interface will be used */
+ bool use_power_sequences;
+ /*
+ * New interface - arrays of steps terminated by a STOP instance, or
+ * NULL if unused.
+ */
+ struct platform_power_seq_step *power_on_seq;
+ struct platform_power_seq_step *power_off_seq;
+ /*
+ * Legacy interface - single PWM and callback methods to control
+ * the power sequence. pwm_id and pwm_period_ns need only be specified
+ * if get_pwm(dev, NULL) will return NULL.
+ */
+ int pwm_id;
+ unsigned int pwm_period_ns;
int (*init)(struct device *dev);
int (*notify)(struct device *dev, int brightness);
void (*notify_after)(struct device *dev, int brightness);
--
1.7.11.3
^ permalink raw reply related
* [RFC][PATCH v3 1/3] runtime interpreted power sequences
From: Alexandre Courbot @ 2012-07-27 12:05 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Greg Kroah-Hartman, Mark Brown, Arnd Bergmann
Cc: linux-tegra, linux-kernel, linux-fbdev, devicetree-discuss,
Alexandre Courbot
In-Reply-To: <1343390750-3642-1-git-send-email-acourbot@nvidia.com>
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
With the advent of the device tree and of ARM kernels that are not
board-tied, we cannot rely on these board-specific hooks anymore but
need a way to implement these sequences in a portable manner. This patch
introduces a simple interpreter that can execute such power sequences
encoded either as platform data or within the device tree.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
Documentation/power/power_seq.txt | 120 +++++++++++++++
drivers/base/Kconfig | 4 +
drivers/base/Makefile | 1 +
drivers/base/power_seq.c | 300 ++++++++++++++++++++++++++++++++++++++
include/linux/power_seq.h | 139 ++++++++++++++++++
5 files changed, 564 insertions(+)
create mode 100644 Documentation/power/power_seq.txt
create mode 100644 drivers/base/power_seq.c
create mode 100644 include/linux/power_seq.h
diff --git a/Documentation/power/power_seq.txt b/Documentation/power/power_seq.txt
new file mode 100644
index 0000000..aa2ceb5
--- /dev/null
+++ b/Documentation/power/power_seq.txt
@@ -0,0 +1,120 @@
+Runtime Interpreted Power Sequences
+-----------------------------------
+
+Problem
+-------
+One very common board-dependent code is the out-of-driver code that is used to
+turn a device on or off. For instance, SoC boards very commonly use a GPIO
+(abstracted to a regulator or not) to control the power supply of a backlight,
+disabling it when the backlight is not used in order to save power. The GPIO
+that should be used, however, as well as the exact power sequence that may
+involve different resources, is board-dependent and thus unknown of the driver.
+
+This has been addressed so far by using hooks in the device's platform data that
+are called whenever the state of the device might reflect a power change. This
+approach, however, introduces board-dependant code into the kernel and is not
+compatible with the device tree.
+
+The Runtime Interpreted Power Sequences (or power sequences for short) aim at
+turning this code into platform data or device tree nodes. Power sequences are
+described using a simple format and run by a simple interpreter whenever needed.
+This allows to remove the callback mechanism and makes the kernel less
+board-dependant.
+
+Sequences Format
+----------------
+Power sequences are a series of sequential steps during which an action is
+performed on a resource. The supported resources so far are:
+- GPIOs
+- Regulators
+- PWMs
+
+Each step designates a resource and the following parameters:
+- Whether the step should enable or disable the resource,
+- Delay to wait before performing the action,
+- Delay to wait after performing the action.
+
+Both new resources and parameters can be introduced, but the goal is of course
+to keep things as simple and compact as possible.
+
+The platform data is a simple array of platform_power_seq_step instances, each
+instance describing a step. The type as well as one of id or gpio members
+(depending on the type) must be specified. The last step must be of type
+POWER_SEQ_STOP. Regulator and PWM resources are identified by name. GPIO are
+identified by number. For example, the following sequence will turn on the
+"power" regulator of the device, wait 10ms, and set GPIO number 110 to 1:
+
+struct platform_power_seq_step power_on_seq[] = {
+ {
+ .type = POWER_SEQ_REGULATOR,
+ .id = "power",
+ .params = {
+ .enable = 1,
+ .post_delay = 10,
+ },
+ },
+ {
+ .type = POWER_SEQ_GPIO,
+ .gpio = 110,
+ .params = {
+ .enable = 1,
+ },
+ },
+ {
+ .type = POWER_SEQ_STOP,
+ },
+};
+
+Usage by Drivers and Resources Management
+-----------------------------------------
+Power sequences make use of resources that must be properly allocated and
+managed. The power_seq_build() function takes care of resolving the resources as
+they are met in the sequence and to allocate them if needed:
+
+power_seq *power_seq_build(struct device *dev, power_seq_resources *ress,
+ platform_power_seq *pseq);
+
+You will need an instance of power_seq_resources to keep track of the resources
+that are already allocated. On success, the function returns a devm allocated
+resolved sequence that is ready to be passed to power_seq_run(). In case of
+failure, and error code is returned.
+
+A resolved power sequence returned by power_seq_build can be run by
+power_run_run():
+
+int power_seq_run(struct device *dev, power_seq *seq);
+
+It returns 0 if the sequence has successfully been run, or an error code if a
+problem occured.
+
+Finally, some resources that cannot be allocated through devm need to be freed
+manually. Therefore, be sure to call power_seq_free_resources() in your device
+remove function:
+
+void power_seq_free_resources(power_seq_resources *ress);
+
+Device tree
+-----------
+All the same, power sequences can be encoded as device tree nodes. The following
+properties and nodes are equivalent to the platform data defined previously:
+
+ power-supply = <&mydevice_reg>;
+ enable-gpio = <&gpio 6 0>;
+
+ power-on-sequence {
+ regulator@0 {
+ id = "power";
+ enable;
+ post-delay = <10>;
+ };
+ gpio@1 {
+ id = "enable-gpio";
+ enable;
+ };
+ };
+
+Note that first, the phandles of the regulator and gpio used in the sequences
+are defined as properties. Then the sequence references them through the id
+property of every step. The name of sub-properties defines the type of the step.
+Valid names are "regulator", "gpio" and "pwm". Steps must be numbered
+sequentially.
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 08b4c52..65bebfe 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -282,4 +282,8 @@ config CMA_AREAS
endif
+config POWER_SEQ
+ bool
+ default n
+
endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 5aa2d70..4c498c1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
ifeq ($(CONFIG_SYSFS),y)
obj-$(CONFIG_MODULES) += module.o
endif
+obj-$(CONFIG_POWER_SEQ) += power_seq.o
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
obj-$(CONFIG_REGMAP) += regmap/
obj-$(CONFIG_SOC_BUS) += soc.o
diff --git a/drivers/base/power_seq.c b/drivers/base/power_seq.c
new file mode 100644
index 0000000..6ccefa1
--- /dev/null
+++ b/drivers/base/power_seq.c
@@ -0,0 +1,300 @@
+/*
+ * power_seq.c - A simple power sequence interpreter for platform devices
+ * and device tree.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/power_seq.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#endif
+
+static int power_seq_step_run(struct power_seq_step *step)
+{
+ int err = 0;
+
+ if (step->params.pre_delay)
+ mdelay(step->params.pre_delay);
+
+ switch (step->resource->type) {
+#ifdef CONFIG_REGULATOR
+ case POWER_SEQ_REGULATOR:
+ if (step->params.enable)
+ err = regulator_enable(step->resource->regulator);
+ else
+ err = regulator_disable(step->resource->regulator);
+ break;
+#endif
+#ifdef CONFIG_PWM
+ case POWER_SEQ_PWM:
+ if (step->params.enable)
+ err = pwm_enable(step->resource->pwm);
+ else
+ pwm_disable(step->resource->pwm);
+ break;
+#endif
+#ifdef CONFIG_GPIOLIB
+ case POWER_SEQ_GPIO:
+ gpio_set_value_cansleep(step->resource->gpio,
+ step->params.enable);
+ break;
+#endif
+ /*
+ * should never happen unless the sequence includes a step which
+ * type does not have support compiled in
+ */
+ default:
+ return -EINVAL;
+ }
+
+ if (err < 0)
+ return err;
+
+ if (step->params.post_delay)
+ mdelay(step->params.post_delay);
+
+ return 0;
+}
+
+int power_seq_run(struct device *dev, power_seq *seq)
+{
+ int err;
+
+ if (!seq) return 0;
+
+ while (seq->resource) {
+ if ((err = power_seq_step_run(seq++))) {
+ dev_err(dev, "error %d while running power sequence!\n",
+ err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(power_seq_run);
+
+#ifdef CONFIG_OF
+static int of_parse_power_seq_step(struct device *dev, struct device_node *node,
+ struct platform_power_seq_step *step)
+{
+ if (of_property_read_string(node, "id", &step->id)) {
+ dev_err(dev, "missing id property!\n");
+ return -EINVAL;
+ }
+
+ if (!strcmp(node->name, "regulator")) {
+ step->type = POWER_SEQ_REGULATOR;
+#ifdef CONFIG_OF_GPIO
+ } else if (!strcmp(node->name, "gpio")) {
+ int gpio;
+
+ step->type = POWER_SEQ_GPIO;
+ gpio = of_get_named_gpio(dev->of_node, step->id, 0);
+ if (gpio < 0) {
+ dev_err(dev, "cannot resolve gpio \"%s\"\n", step->id);
+ return gpio;
+ }
+ step->gpio = gpio;
+#endif /* CONFIG_OF_GPIO */
+ } else if (!strcmp(node->name, "pwm")) {
+ step->type = POWER_SEQ_PWM;
+ } else {
+ dev_err(dev, "invalid power seq step type!\n");
+ return -EINVAL;
+ }
+
+ if (of_find_property(node, "enable", NULL)) {
+ step->params.enable = 1;
+ } else if (!of_find_property(node, "disable", NULL)) {
+ dev_err(dev, "missing enable or disable property!\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32(node, "pre-delay", &step->params.pre_delay);
+ of_property_read_u32(node, "post-delay", &step->params.post_delay);
+
+ return 0;
+}
+
+platform_power_seq *of_parse_power_seq(struct device *dev,
+ struct device_node *node)
+{
+ struct device_node *child = NULL;
+ platform_power_seq *ret;
+ int cpt = 0;
+ int err;
+
+ if (!node) return NULL;
+
+ while ((child = of_get_next_child(node, child)))
+ cpt++;
+
+ /* allocate one more step to signal end of sequence */
+ ret = devm_kzalloc(dev, sizeof(*ret) * (cpt + 1), GFP_KERNEL);
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+
+ cpt = 0;
+ while ((child = of_get_next_child(node, child))) {
+ if ((err = of_parse_power_seq_step(dev, child, &ret[cpt++])))
+ return ERR_PTR(err);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_parse_power_seq);
+#endif /* CONFIG_OF */
+
+static
+struct power_seq_resource * power_seq_find_resource(power_seq_resources *ress,
+ struct platform_power_seq_step *res)
+{
+ struct power_seq_resource *step;
+
+ list_for_each_entry(step, ress, list) {
+ if (step->type != res->type) continue;
+ switch (res->type) {
+ case POWER_SEQ_GPIO:
+ if (step->gpio = res->gpio)
+ return step;
+ break;
+ default:
+ if (!strcmp(step->id, res->id))
+ return step;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static int power_seq_allocate_resource(struct device *dev,
+ struct power_seq_resource *res)
+{
+ int err;
+
+ switch (res->type) {
+#ifdef CONFIG_REGULATOR
+ case POWER_SEQ_REGULATOR:
+ res->regulator = devm_regulator_get(dev, res->id);
+ if (IS_ERR(res->regulator)) {
+ dev_err(dev, "cannot get regulator \"%s\"\n", res->id);
+ return PTR_ERR(res->regulator);
+ }
+ break;
+#endif
+#ifdef CONFIG_PWM
+ case POWER_SEQ_PWM:
+ res->pwm = pwm_get(dev, res->id);
+ if (IS_ERR(res->pwm)) {
+ dev_err(dev, "cannot get pwm \"%s\"\n", res->id);
+ return PTR_ERR(res->pwm);
+ }
+ break;
+#endif
+#ifdef CONFIG_GPIOLIB
+ case POWER_SEQ_GPIO:
+ err = devm_gpio_request_one(dev, res->gpio, GPIOF_OUT_INIT_HIGH,
+ "backlight_gpio");
+ if (err) {
+ dev_err(dev, "cannot get gpio %d\n", res->gpio);
+ return err;
+ }
+ break;
+#endif
+ default:
+ dev_err(dev, "invalid resource type %d\n", res->type);
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+power_seq *power_seq_build(struct device *dev, power_seq_resources *ress,
+ platform_power_seq *pseq)
+{
+ struct power_seq_step *seq = NULL, *ret;
+ struct power_seq_resource *res;
+ int cpt, err;
+
+ /* first pass to count the number of steps to allocate */
+ for (cpt = 0; pseq[cpt].type != POWER_SEQ_STOP; cpt++);
+
+ if (!cpt)
+ return seq;
+
+ /* 1 more for the STOP step */
+ ret = seq = devm_kzalloc(dev, sizeof(*seq) * (cpt + 1), GFP_KERNEL);
+ if (!seq)
+ return ERR_PTR(-ENOMEM);
+
+ for (; pseq->type != POWER_SEQ_STOP; pseq++, seq++) {
+ /* create resource node if not referenced already */
+ if (!(res = power_seq_find_resource(ress, pseq))) {
+ res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return ERR_PTR(-ENOMEM);
+ res->type = pseq->type;
+
+ if (res->type = POWER_SEQ_GPIO)
+ res->gpio = pseq->gpio;
+ else
+ res->id = pseq->id;
+
+ if ((err = power_seq_allocate_resource(dev, res)) < 0)
+ return ERR_PTR(err);
+
+ list_add(&res->list, ress);
+ }
+ seq->resource = res;
+ memcpy(&seq->params, &pseq->params, sizeof(seq->params));
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(power_seq_build);
+
+void power_seq_free_resources(power_seq_resources *ress) {
+ struct power_seq_resource *res;
+
+#ifdef CONFIG_PWM
+ list_for_each_entry(res, ress, list) {
+ if (res->type = POWER_SEQ_PWM)
+ pwm_put(res->pwm);
+ }
+#endif
+}
+EXPORT_SYMBOL_GPL(power_seq_free_resources);
+
+MODULE_AUTHOR("Alexandre Courbot <acourbot@nvidia.com>");
+MODULE_DESCRIPTION("Runtime Interpreted Power Sequences");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
new file mode 100644
index 0000000..da0593a
--- /dev/null
+++ b/include/linux/power_seq.h
@@ -0,0 +1,139 @@
+/*
+ * power_seq.h
+ *
+ * Simple interpreter for defining power sequences as platform data or device
+ * tree properties. Initially designed for use with backlight drivers.
+ *
+ * Power sequences are designed to replace the callbacks typically used in
+ * board-specific files that implement board-specific power sequences of devices
+ * such as backlights. A power sequence is an array of resources (which can a
+ * regulator, a GPIO, a PWM, ...) with an action to perform on it (enable or
+ * disable) and optional pre and post step delays. By having them interpreted
+ * instead of arbitrarily executed, it is possible to describe these in the
+ * device tree and thus remove board-specific code from the kernel.
+ *
+ * Author: Alexandre Courbot <acourbot@nvidia.com>
+ *
+ * Copyright (c) 2012 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_POWER_SEQ_H
+#define __LINUX_POWER_SEQ_H
+
+#include <linux/types.h>
+
+struct device;
+struct regulator;
+struct pwm_device;
+struct device_node;
+
+/**
+ * The different kinds of resources that can be controlled during the sequences.
+ */
+typedef enum {
+ POWER_SEQ_STOP = 0,
+ POWER_SEQ_REGULATOR,
+ POWER_SEQ_PWM,
+ POWER_SEQ_GPIO,
+ POWER_SEQ_MAX,
+} power_res_type;
+
+struct power_seq_resource {
+ power_res_type type;
+ /* name to resolve for resources with a name (regulator, pwm) */
+ const char *id;
+ /* resolved resource */
+ union {
+ struct regulator *regulator;
+ struct pwm_device *pwm;
+ int gpio;
+ };
+ /* used to maintain the list of resources used by the driver */
+ struct list_head list;
+};
+typedef struct list_head power_seq_resources;
+
+struct power_step_params {
+ /* enable the resource if 1, disable if 0 */
+ bool enable;
+ /* delay (in ms) to wait before executing the step */
+ int pre_delay;
+ /* delay (in ms) to wait after executing the step */
+ int post_delay;
+};
+
+/**
+ * Platform definition of power sequences. A sequence is an array of these,
+ * terminated by a STOP instance.
+ */
+struct platform_power_seq_step {
+ power_res_type type;
+ union {
+ /* Used by REGULATOR and PWM types to name the resource */
+ const char *id;
+ /* Used by GPIO */
+ int gpio;
+ };
+ struct power_step_params params;
+};
+typedef struct platform_power_seq_step platform_power_seq;
+
+/**
+ * Power sequence steps resolved against their resource. Built by
+ * power_seq_build and used to run the sequence.
+ */
+struct power_seq_step {
+ struct power_seq_resource *resource;
+ struct power_step_params params;
+};
+typedef struct power_seq_step power_seq;
+
+#ifdef CONFIG_OF
+/**
+ * Build a platform data sequence from a device tree node. Memory for the
+ * sequence is allocated using devm_kzalloc on dev.
+ */
+platform_power_seq *of_parse_power_seq(struct device *dev,
+ struct device_node *node);
+#else
+platform_power_seq *of_parse_power_seq(struct device *dev,
+ struct device_node *node)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * Build a runnable power sequence from platform data, and add the resources
+ * it uses into ress. Memory for the sequence is allocated using devm_kzalloc
+ * on dev.
+ */
+power_seq *power_seq_build(struct device *dev, power_seq_resources *ress,
+ platform_power_seq *pseq);
+
+/**
+ * Free all the resources previously allocated by power_seq_allocate_resources.
+ */
+void power_seq_free_resources(power_seq_resources *ress);
+
+/**
+ * Run the given power sequence. Returns 0 on success, error code in case of
+ * failure.
+ */
+int power_seq_run(struct device *dev, power_seq *seq);
+
+#endif
--
1.7.11.3
^ permalink raw reply related
* [RFC][PATCH v3 0/3] Power sequences with PWM and DT support
From: Alexandre Courbot @ 2012-07-27 12:05 UTC (permalink / raw)
To: Stephen Warren, Thierry Reding, Simon Glass, Grant Likely,
Rob Herring, Greg Kroah-Hartman, Mark Brown, Arnd Bergmann
Cc: linux-tegra, linux-kernel, linux-fbdev, devicetree-discuss,
Alexandre Courbot
Widening audience for this version.
The issue addressed is that the power sequences for backlights (and probably
other devices), which were implemented using board-specific callbacks so far,
could not be used with the device tree. This series of patches adds a small
power sequence interpreter that allows to acquire and control regulators, GPIOs,
and PWMs during sequences defined in the device tree or as platform data. It is
easy to use, low-footprint, and takes care of managing the resources it
acquires. This should help making the kernel less board-dependant.
Comments are especially welcome about the DT bindings proposal, which most
certainly needs to be refined, if not completely redesigned. Documentation is
still incomplete and will consolidate once the implementation reaches a stable
state.
The tegra device tree nodes of patch 3 are just here as an example usage.
Changelog:
v3:
- Move to driver to base/
- Use sub-nodes to describe steps in the DT as suggested by Simon Glass
- Write some documentation
- Make the DT support optional
Alexandre Courbot (3):
runtime interpreted power sequences
pwm_backlight: use power sequences
tegra: add pwm backlight device tree nodes
.../bindings/video/backlight/pwm-backlight.txt | 55 +++-
Documentation/power/power_seq.txt | 120 +++++++++
arch/arm/boot/dts/tegra20-ventana.dts | 53 ++++
arch/arm/boot/dts/tegra20.dtsi | 2 +-
drivers/base/Kconfig | 4 +
drivers/base/Makefile | 1 +
drivers/base/power_seq.c | 300 +++++++++++++++++++++
drivers/video/backlight/Kconfig | 1 +
drivers/video/backlight/pwm_bl.c | 213 +++++++++++----
include/linux/power_seq.h | 139 ++++++++++
include/linux/pwm_backlight.h | 18 +-
11 files changed, 843 insertions(+), 63 deletions(-)
create mode 100644 Documentation/power/power_seq.txt
create mode 100644 drivers/base/power_seq.c
create mode 100644 include/linux/power_seq.h
--
1.7.11.3
^ permalink raw reply
* Re: [PATCH] video/smscufx: fix line counting in fb_write
From: Florian Tobias Schandinat @ 2012-07-26 17:26 UTC (permalink / raw)
To: Alexander Holler; +Cc: linux-kernel, linux-fbdev
In-Reply-To: <4FF211BD.8060203@ahsoftware.de>
On 07/02/2012 09:25 PM, Alexander Holler wrote:
> Hi Florian,
>
> sorry for the late answer.
>
> Am 13.05.2012 14:47, schrieb Florian Tobias Schandinat:
>> Hi Alexander,
>>
>> On 04/21/2012 11:26 AM, Alexander Holler wrote:
>>> Hello,
>>>
>>> as for the patch for udlfb, I forgot to mention that this is a candidate
>>> for all stable trees 3.2 and above.
>>>
>>> Btw., the address of the maintainer doesn't seem to be valid anymore.
>>
>> it is better to cc me on patches to the framebuffer subsystem for such
>> cases. I don't have much free time so it's rare that I come around to
>> dig in the mailing list.
>>
>>>
>>> Regards,
>>>
>>> Alexander
>>>
>>> Am 21.04.2012 00:11, schrieb Alexander Holler:
>>>> Line 0 and 1 were both written to line 0 (on the display) and all
>>>> subsequent
>>>> lines had an offset of -1. The result was that the last line on the
>>>> display
>>>> was never overwritten by writes to /dev/fbN.
>>>>
>>>> The origin of this bug seems to have been udlfb.
>>>>
>>>> Signed-off-by: Alexander Holler<holler@ahsoftware.de>
>>>
>>> Cc: stable@vger.kernel.org
>>
>> Patch looks good to me but can be made simpler.
>>
>>>
>>>> ---
>>>> drivers/video/smscufx.c | 2 +-
>>>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>>>
>>>> diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
>>>> index ccbfef5..1e1e2d2 100644
>>>> --- a/drivers/video/smscufx.c
>>>> +++ b/drivers/video/smscufx.c
>>>> @@ -904,7 +904,7 @@ static ssize_t ufx_ops_write(struct fb_info *info,
>>>> const char __user *buf,
>>>> result = fb_sys_write(info, buf, count, ppos);
>>>>
>>>> if (result> 0) {
>>>> - int start = max((int)(offset / info->fix.line_length) - 1, 0);
>>>> + int start = max((int)(offset / info->fix.line_length), 0);
>>
>> the cast to int as well as the max is superfluous without the -1 as the
>> value can no longer be negative.
>
> I had that impression too, but I wanted to change as less as possible,
> so I didn't had the need to check types and (their) sizes for possible
> overflows or such. I was lazy and just wanted to fix that one bug. ;)
Well, as this patch fixes a bug I applied it as is.
>
>>
>>>> int lines = min((u32)((result / info->fix.line_length) + 1),
>>>> (u32)info->var.yres);
>>>>
Best regards,
Florian Tobias Schandinat
^ permalink raw reply
* Re: [GIT PULL] SH Mobile LCDC and MERAM patches
From: Laurent Pinchart @ 2012-07-26 17:26 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <2980452.38e8VA4mF5@avalon>
Hi Florian,
On Thursday 26 July 2012 17:14:33 Florian Tobias Schandinat wrote:
> On 07/24/2012 09:16 AM, Laurent Pinchart wrote:
> > Hi Florian,
> >
> > The following changes since commit
6fcdbc0c3a683003a00f383fceac80da1b7852ff:
> > s3fb: Add Virge/MX (86C260) (2012-07-08 14:03:50 +0000)
> >
> > are available in the git repository at:
> > git://linuxtv.org/pinchartl/fbdev.git for-next
>
> Merged. Should I also apply your followup patch
> "[PATCH] fbdev: sh_mobile_lcdc: Fix vertical panning step"
> ?
I was planning to send a pull request for that one, but yes, please merge it
:-)
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH] video: exynos_dp: fix wrong DPCD address during Link Training
From: Florian Tobias Schandinat @ 2012-07-26 17:23 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <000901cd5ff4$fa2ffbc0$ee8ff340$%han@samsung.com>
On 07/12/2012 06:10 AM, Jingoo Han wrote:
> Wrong DPCD addresses were used for clock recovery during Link Training.
> The training pattern should be set by TRAINING_PATTERN_SET (0x102), while
> voltage swing and pre-emphasis should be set by TRAINING_LANE0_SET (0x103).
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/exynos/exynos_dp_core.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
> index 9db7b9f..bf55e51 100644
> --- a/drivers/video/exynos/exynos_dp_core.c
> +++ b/drivers/video/exynos/exynos_dp_core.c
> @@ -304,7 +304,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp)
> buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
> DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
> exynos_dp_write_bytes_to_dpcd(dp,
> - DPCD_ADDR_TRAINING_PATTERN_SET,
> + DPCD_ADDR_TRAINING_LANE0_SET,
> lane_count, buf);
> }
>
> @@ -504,7 +504,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
> buf[0] = DPCD_SCRAMBLING_DISABLED |
> DPCD_TRAINING_PATTERN_2;
> exynos_dp_write_byte_to_dpcd(dp,
> - DPCD_ADDR_TRAINING_LANE0_SET,
> + DPCD_ADDR_TRAINING_PATTERN_SET,
> buf[0]);
>
> for (lane = 0; lane < lane_count; lane++) {
^ permalink raw reply
* Re: [PATCH] fb: epson1355fb: Fix section mismatch
From: Florian Tobias Schandinat @ 2012-07-26 17:23 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1342337558-9912-1-git-send-email-shc_work@mail.ru>
On 07/15/2012 07:32 AM, Alexander Shiyan wrote:
> This patch fixes "section mismatch" warning in the epson1355fb driver.
>
> WARNING: vmlinux.o(.devinit.text+0x184): Section mismatch in reference from the function epson1355fb_probe() to the function .init.text:fetch_hw_state()
> The function __devinit epson1355fb_probe() references
> a function __init fetch_hw_state().
> If fetch_hw_state is only used by epson1355fb_probe then
> annotate fetch_hw_state with a matching annotation.
>
> Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/epson1355fb.c | 8 ++++----
> 1 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
> index a268cbf..68b9b51 100644
> --- a/drivers/video/epson1355fb.c
> +++ b/drivers/video/epson1355fb.c
> @@ -477,11 +477,11 @@ static __init unsigned int get_fb_size(struct fb_info *info)
> return size;
> }
>
> -static int epson1355_width_tab[2][4] __initdata > +static int epson1355_width_tab[2][4] __devinitdata > { {4, 8, 16, -1}, {9, 12, 16, -1} };
> -static int epson1355_bpp_tab[8] __initdata = { 1, 2, 4, 8, 15, 16 };
> +static int epson1355_bpp_tab[8] __devinitdata = { 1, 2, 4, 8, 15, 16 };
>
> -static void __init fetch_hw_state(struct fb_info *info, struct epson1355_par *par)
> +static void __devinit fetch_hw_state(struct fb_info *info, struct epson1355_par *par)
> {
> struct fb_var_screeninfo *var = &info->var;
> struct fb_fix_screeninfo *fix = &info->fix;
> @@ -601,7 +601,7 @@ static int epson1355fb_remove(struct platform_device *dev)
> return 0;
> }
>
> -int __devinit epson1355fb_probe(struct platform_device *dev)
> +static int __devinit epson1355fb_probe(struct platform_device *dev)
> {
> struct epson1355_par *default_par;
> struct fb_info *info;
^ permalink raw reply
* Re: [PATCH] video: exynos_dp: check the only INTERLANE_ALIGN_DONE bit during Link Training
From: Florian Tobias Schandinat @ 2012-07-26 17:22 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <000c01cd63f8$57550000$05ff0000$%han@samsung.com>
On 07/17/2012 08:44 AM, Jingoo Han wrote:
> The only INTERLANE_ALIGN_DONE bit should be checked for channel equalization
> during Link Training. Previously, the other bits such as LINK_STATUS_UPDATED
> were checked, and channel equalization procedure was repeated unnecessarily.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/exynos/exynos_dp_core.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
> index 9db7b9f..6ca8043 100644
> --- a/drivers/video/exynos/exynos_dp_core.c
> +++ b/drivers/video/exynos/exynos_dp_core.c
> @@ -336,7 +336,7 @@ static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count)
> u8 lane_status;
>
> lane_align = link_status[2];
> - if ((lane_align = DPCD_INTERLANE_ALIGN_DONE) = 0)
> + if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) = 0)
> return -EINVAL;
>
> for (lane = 0; lane < lane_count; lane++) {
^ permalink raw reply
* Re: [PATCH] video: exynos_dp: use usleep_range instead of delay
From: Florian Tobias Schandinat @ 2012-07-26 17:22 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <002201cd64ca$d5bbabb0$81330310$%han@samsung.com>
On 07/18/2012 09:50 AM, Jingoo Han wrote:
> This patch replaces udelay and mdelay with usleep_range to remove
> the busy loop waiting.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/exynos/exynos_dp_core.c | 14 +++++++-------
> drivers/video/exynos/exynos_dp_reg.c | 4 ++--
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
> index 9db7b9f..25907f4 100644
> --- a/drivers/video/exynos/exynos_dp_core.c
> +++ b/drivers/video/exynos/exynos_dp_core.c
> @@ -47,7 +47,7 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
>
> exynos_dp_init_hpd(dp);
>
> - udelay(200);
> + usleep_range(200, 210);
>
> while (exynos_dp_get_plug_in_status(dp) != 0) {
> timeout_loop++;
> @@ -55,7 +55,7 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
> dev_err(dp->dev, "failed to get hpd plug status\n");
> return -ETIMEDOUT;
> }
> - udelay(10);
> + usleep_range(10, 11);
> }
>
> return 0;
> @@ -486,7 +486,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
> u8 pre_emphasis;
> u8 training_lane;
>
> - udelay(100);
> + usleep_range(100, 101);
>
> exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
> 6, link_status);
> @@ -571,7 +571,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
>
> u8 adjust_request[2];
>
> - udelay(400);
> + usleep_range(400, 401);
>
> exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
> 6, link_status);
> @@ -739,7 +739,7 @@ static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
> if (retval = 0)
> break;
>
> - udelay(100);
> + usleep_range(100, 110);
> }
>
> return retval;
> @@ -773,7 +773,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp,
> return -ETIMEDOUT;
> }
>
> - udelay(1);
> + usleep_range(1, 2);
> }
>
> /* Set to use the register calculated M/N video */
> @@ -807,7 +807,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp,
> return -ETIMEDOUT;
> }
>
> - mdelay(1);
> + usleep_range(1000, 1001);
> }
>
> if (retval != 0)
> diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
> index 6ce76d5..ce401c8 100644
> --- a/drivers/video/exynos/exynos_dp_reg.c
> +++ b/drivers/video/exynos/exynos_dp_reg.c
> @@ -122,7 +122,7 @@ void exynos_dp_reset(struct exynos_dp_device *dp)
> LS_CLK_DOMAIN_FUNC_EN_N;
> writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
>
> - udelay(20);
> + usleep_range(20, 30);
>
> exynos_dp_lane_swap(dp, 0);
>
> @@ -988,7 +988,7 @@ void exynos_dp_reset_macro(struct exynos_dp_device *dp)
> writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
>
> /* 10 us is the minimum reset time. */
> - udelay(10);
> + usleep_range(10, 20);
>
> reg &= ~MACRO_RST;
> writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
^ permalink raw reply
* Re: [GIT PULL] OMAP DSS for v3.6
From: Florian Tobias Schandinat @ 2012-07-26 17:20 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev, Tony Lindgren, Archit Taneja
In-Reply-To: <1342980836.2284.20.camel@deskari>
Hi Tomi,
On 07/22/2012 06:13 PM, Tomi Valkeinen wrote:
> Hi Florian,
>
> Here are OMAP DSS changes for 3.6. The main changes are:
>
> - Patches from Archit, which reorganize the output side of omapdss. This
> is much cleaner in itself, but will also help us in the future to
> implement the missing omap4 features and omap5+ features.
>
> - LCD3 patches from Chandrabhanu, which implement the support for LCD3
> overlay manager (for omap5). His patches also generalize the code which
> accesses the overlay manager related registers.
>
> There hasn't been new patches applied to the DSS tree for 3 weeks, as
> I'm on vacation. The tree has been in linux-next for that period, and I
> haven't received any complaints so I hope the stuff works quite well.
> Archit also reported that he has tested the linux-next, and it seems to
> work fine.
>
> There is a small conflict, though. This was caused by the two fixes
> "OMAPDSS: fix warnings if CONFIG_PM_RUNTIME=n" and "OMAPDSS: Use PM
> notifiers for system suspend", as I had already applied them into my
> master branch before Archit sent them for you. And as you fixed the code
> formatting issue (sorry about that), we have a small conflict there.
>
> The conflict is trivial to resolve, and I also pushed for-florian-merged
> branch to the same git tree below, which has the conflict resolved.
>
> I'm still on vacation for the next week, but I'll check my email every
> now and then to see if there are any issues.
>
> Tomi
>
>
> The following changes since commit cfaf025112d3856637ff34a767ef785ef5cf2ca9:
>
> Linux 3.5-rc2 (2012-06-08 18:40:09 -0700)
>
> are available in the git repository at:
>
> git://gitorious.org/linux-omap-dss2/linux.git for-florian
Merged.
Thanks,
Florian Tobias Schandinat
>
> for you to fetch changes up to 974a65825e0b5fbda49605f0416a2c975d66e9e6:
>
> Merge "Apply LCD manager related parameters" from Archit (2012-06-29 14:13:07 +0300)
>
> ----------------------------------------------------------------
>
> Archit Taneja (27):
> OMAPDSS: Remove passive matrix LCD support (part 1)
> OMAPDSS: Remove passive matrix LCD support (part 2)
> OMAPDSS: Remove passive matrix LCD support (part 3)
> OMAPDSS: Remove passive matrix LCD support (part 4)
> OMAPDSS: Add some new fields to omap_video_timings
> OMAPDSS: DISPLAY: Ignore newly added omap_video_timings fields for display timings sysfs file
> OMAPDSS: DISPC: Configure newly added omap_video_timing fields
> OMAPDSS: DISPC: Remove dispc_mgr_set_pol_freq()
> OMAPFB: Map the newly added omap_video_timings fields with fb sync flags
> OMAPDSS: Remove omap_panel_config enum from omap_dss_device
> OMAPDSS: Add interlace parameter to omap_video_timings
> OMAPDSS: DISPC/APPLY: Use interlace info in manager timings for dispc_ovl_setup()
> OMAPFB: Map interlace field in omap_video_timings with fb vmode flags
> OMAPDSS: HDMI: Remove custom hdmi_video_timings struct
> OMAPDSS: DSI: Fix HSYNC, VSYNC and DE polarities between DISPC and DSI
> OMAPDSS: DISPC: Change return type of dispc_mgr_set_clock_div()
> OMAPDSS: Add struct to hold LCD overlay manager configuration
> OMAPDSS: DPI: Configure dss_lcd_mgr_config struct with lcd manager parameters
> OMAPDSS: RFBI: Configure dss_lcd_mgr_config struct with lcd manager parameters
> OMAPDSS: DSI: Configure dss_lcd_mgr_config struct with lcd manager parameters
> OMAPDSS: SDI: Configure dss_lcd_mgr_config struct with lcd manager parameters
> OMAPDSS: APPLY: Remove DISPC writes to manager's lcd parameters in interface drivers
> OMAPDSS: MANAGER: Check LCD related overlay manager parameters
> OMAPDSS: APPLY: Remove usage of omap_dss_device from manual/auto update checks
> OMAPDSS: DISPC: Remove a redundant function
> OMAPDSS: RFBI: Use dss_mgr_enable to enable the overlay manager
> OMAPDSS: OVERLAY: Clean up replication checking
>
> Chandrabhanu Mahapatra (5):
> OMAPDSS: Cleanup implementation of LCD channels
> OMAPDSS: Add support for LCD3 channel
> OMAPDSS: Add LCD3 overlay manager and Clock and IRQ support
> OMAPDSS: Add dump and debug support for LCD3
> ARM: OMAP2PLUS: DSS: Disable LCD3 output when resetting DSS
>
> Jassi Brar (2):
> OMAPDSS: HDMI: Discard phy_tx_enabled member
> OMAPDSS: HDMI: Replace spinlock with mutex in hdmi_check_hpd_state
>
> Peter Meerwald (1):
> OMAPDSS: fix specification spelling in Kconfig
>
> Rajendra Nayak (1):
> OMAPDSS: add clk_prepare_enable and clk_disable_unprepare
>
> Tomi Valkeinen (6):
> Merge tag 'v3.5-rc2'
> OMAPDSS: remove enum omap_dss_overlay_managers
> OMAPDSS: Use PM notifiers for system suspend
> OMAPDSS: fix warnings if CONFIG_PM_RUNTIME=n
> Merge Misc DSS clean ups from Archit
> Merge "Apply LCD manager related parameters" from Archit
>
> arch/arm/mach-omap2/display.c | 29 +-
> drivers/video/omap2/displays/panel-acx565akm.c | 10 +-
> drivers/video/omap2/displays/panel-generic-dpi.c | 179 ++++---
> .../omap2/displays/panel-lgphilips-lb035q02.c | 8 +-
> drivers/video/omap2/displays/panel-n8x0.c | 1 -
> .../omap2/displays/panel-nec-nl8048hl11-01b.c | 9 +-
> drivers/video/omap2/displays/panel-picodlp.c | 9 +-
> .../video/omap2/displays/panel-sharp-ls037v7dw01.c | 9 +-
> drivers/video/omap2/displays/panel-taal.c | 3 +-
> drivers/video/omap2/displays/panel-tfp410.c | 7 +-
> .../video/omap2/displays/panel-tpo-td043mtea1.c | 8 +-
> drivers/video/omap2/dss/Kconfig | 4 +-
> drivers/video/omap2/dss/apply.c | 91 +++-
> drivers/video/omap2/dss/core.c | 48 +-
> drivers/video/omap2/dss/dispc.c | 496 ++++++++++----------
> drivers/video/omap2/dss/dispc.h | 28 ++
> drivers/video/omap2/dss/display.c | 40 +-
> drivers/video/omap2/dss/dpi.c | 64 +--
> drivers/video/omap2/dss/dsi.c | 156 +++---
> drivers/video/omap2/dss/dss.c | 21 +-
> drivers/video/omap2/dss/dss.h | 54 ++-
> drivers/video/omap2/dss/dss_features.h | 5 +-
> drivers/video/omap2/dss/hdmi.c | 248 ++++++++--
> drivers/video/omap2/dss/hdmi_panel.c | 9 +-
> drivers/video/omap2/dss/manager.c | 51 +-
> drivers/video/omap2/dss/overlay.c | 33 +-
> drivers/video/omap2/dss/rfbi.c | 42 +-
> drivers/video/omap2/dss/sdi.c | 42 +-
> drivers/video/omap2/dss/ti_hdmi.h | 21 +-
> drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 26 +-
> drivers/video/omap2/dss/venc.c | 10 +-
> drivers/video/omap2/omapfb/omapfb-main.c | 51 +-
> include/video/omapdss.h | 51 +-
> 33 files changed, 1172 insertions(+), 691 deletions(-)
>
^ permalink raw reply
* Re: [GIT PULL] SH Mobile LCDC and MERAM patches
From: Florian Tobias Schandinat @ 2012-07-26 17:14 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <2980452.38e8VA4mF5@avalon>
Hi Laurent,
On 07/24/2012 09:16 AM, Laurent Pinchart wrote:
> Hi Florian,
>
> The following changes since commit 6fcdbc0c3a683003a00f383fceac80da1b7852ff:
>
> s3fb: Add Virge/MX (86C260) (2012-07-08 14:03:50 +0000)
>
> are available in the git repository at:
> git://linuxtv.org/pinchartl/fbdev.git for-next
Merged. Should I also apply your followup patch
"[PATCH] fbdev: sh_mobile_lcdc: Fix vertical panning step"
?
Best regards,
Florian Tobias Schandinat
>
> Laurent Pinchart (9):
> sh_mobile_meram: Rename operations to cache_[alloc|free|update]
> sh_mobile_meram: Use direct function calls for the public API
> sh_mobile_meram: Add direct MERAM allocation API
> fbdev: sh_mobile_lcdc: Destroy mutex at remove time
> fbdev: sh_mobile_lcdc: Fix line pitch computation
> fbdev: sh_mobile_lcdc: Use channel configuration to initialize fb device
> fbdev: sh_mobile_lcdc: Support horizontal panning
> fbdev: sh_mobile_lcdc: Fix overlay registers update during pan operation
> fbdev: sh_mobile_lcdc: Fix pan offset computation in YUV mode
>
> drivers/video/sh_mobile_lcdcfb.c | 209 +++++++++++++++++----------------
> drivers/video/sh_mobile_lcdcfb.h | 5 +-
> drivers/video/sh_mobile_meram.c | 235 ++++++++++++++++++++-----------------
> include/video/sh_mobile_meram.h | 71 ++++++++----
> 4 files changed, 293 insertions(+), 227 deletions(-)
>
^ permalink raw reply
* [PATCH] fbdev: sh_mobile_lcdc: Fix vertical panning step
From: Laurent Pinchart @ 2012-07-26 12:36 UTC (permalink / raw)
To: linux-fbdev
Commit 15dede882e564601947f2ce4b647742c0351be6d added support for
horizontal panning but accidentally computes the Y pan step value
incorrectly for NV12/21 and NV16/61 formats. Fix this.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 8cb653b..699487c 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1716,11 +1716,11 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
info->fix.visual = FB_VISUAL_TRUECOLOR;
switch (ovl->format->fourcc) {
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- info->fix.ypanstep = 2;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ info->fix.ypanstep = 2;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
info->fix.xpanstep = 2;
}
@@ -2215,11 +2215,11 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
info->fix.visual = FB_VISUAL_TRUECOLOR;
switch (ch->format->fourcc) {
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- info->fix.ypanstep = 2;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
+ info->fix.ypanstep = 2;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
info->fix.xpanstep = 2;
}
--
Regards,
Laurent Pinchart
^ permalink raw reply related
* Re: [PATCH v2 4/4] fbdev: sh_mobile_lcdc: use dma_mmap_coherent if available
From: Laurent Pinchart @ 2012-07-26 11:20 UTC (permalink / raw)
To: Hideki EIRAKU
Cc: alsa-devel, Katsuya MATSUBARA, linux-fbdev, Russell King,
linux-media, Pawel Osciak, Florian Tobias Schandinat,
Takashi Iwai, linux-kernel, Mauro Carvalho Chehab, Kyungmin Park,
linux-arm-kernel, Marek Szyprowski
In-Reply-To: <1343301191-26001-5-git-send-email-hdk@igel.co.jp>
Hi Eiraku-san,
On Thursday 26 July 2012 20:13:11 Hideki EIRAKU wrote:
> fb_mmap() implemented in fbmem.c uses smem_start as the physical
> address of the frame buffer. In the sh_mobile_lcdc driver, the
> smem_start is a dma_addr_t that is not a physical address when IOMMU is
> enabled. dma_mmap_coherent() maps the address correctly. It is
> available on ARM platforms.
>
> Signed-off-by: Hideki EIRAKU <hdk@igel.co.jp>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH v2 4/4] fbdev: sh_mobile_lcdc: use dma_mmap_coherent if available
From: Hideki EIRAKU @ 2012-07-26 11:13 UTC (permalink / raw)
To: Russell King, Pawel Osciak, Marek Szyprowski, Kyungmin Park,
Mauro Carvalho Chehab, Florian Tobias Schandinat, Jaroslav Kysela,
Takashi Iwai
Cc: linux-arm-kernel, linux-kernel, linux-media, linux-fbdev,
alsa-devel, Katsuya MATSUBARA, Hideki EIRAKU
In-Reply-To: <1343301191-26001-1-git-send-email-hdk@igel.co.jp>
fb_mmap() implemented in fbmem.c uses smem_start as the physical
address of the frame buffer. In the sh_mobile_lcdc driver, the
smem_start is a dma_addr_t that is not a physical address when IOMMU is
enabled. dma_mmap_coherent() maps the address correctly. It is
available on ARM platforms.
Signed-off-by: Hideki EIRAKU <hdk@igel.co.jp>
---
drivers/video/sh_mobile_lcdcfb.c | 28 ++++++++++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 8cb653b..c8cba7a 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1614,6 +1614,17 @@ static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info)
return 1;
}
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+static int
+sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct sh_mobile_lcdc_overlay *ovl = info->par;
+
+ return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,
+ ovl->dma_handle, ovl->fb_size);
+}
+#endif
+
static struct fb_ops sh_mobile_lcdc_overlay_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
@@ -1626,6 +1637,9 @@ static struct fb_ops sh_mobile_lcdc_overlay_ops = {
.fb_ioctl = sh_mobile_lcdc_overlay_ioctl,
.fb_check_var = sh_mobile_lcdc_overlay_check_var,
.fb_set_par = sh_mobile_lcdc_overlay_set_par,
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+ .fb_mmap = sh_mobile_lcdc_overlay_mmap,
+#endif
};
static void
@@ -2093,6 +2107,17 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info)
return 0;
}
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+static int
+sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+
+ return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,
+ ch->dma_handle, ch->fb_size);
+}
+#endif
+
static struct fb_ops sh_mobile_lcdc_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = sh_mobile_lcdc_setcolreg,
@@ -2108,6 +2133,9 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_release = sh_mobile_lcdc_release,
.fb_check_var = sh_mobile_lcdc_check_var,
.fb_set_par = sh_mobile_lcdc_set_par,
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+ .fb_mmap = sh_mobile_lcdc_mmap,
+#endif
};
static void
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 3/4] media: videobuf2-dma-contig: use dma_mmap_coherent if available
From: Hideki EIRAKU @ 2012-07-26 11:13 UTC (permalink / raw)
To: Russell King, Pawel Osciak, Marek Szyprowski, Kyungmin Park,
Mauro Carvalho Chehab, Florian Tobias Schandinat, Jaroslav Kysela,
Takashi Iwai
Cc: linux-arm-kernel, linux-kernel, linux-media, linux-fbdev,
alsa-devel, Katsuya MATSUBARA, Hideki EIRAKU
In-Reply-To: <1343301191-26001-1-git-send-email-hdk@igel.co.jp>
Previously the vb2_dma_contig_mmap() function was using a dma_addr_t as a
physical address. The two addressses are not necessarily the same.
For example, when using the IOMMU funtion on certain platforms, dma_addr_t
addresses are not directly mappable physical address.
dma_mmap_coherent() maps the address correctly.
It is available on ARM platforms.
Signed-off-by: Hideki EIRAKU <hdk@igel.co.jp>
---
drivers/media/video/videobuf2-dma-contig.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c
index 4b71326..4dc85ab 100644
--- a/drivers/media/video/videobuf2-dma-contig.c
+++ b/drivers/media/video/videobuf2-dma-contig.c
@@ -101,14 +101,32 @@ static unsigned int vb2_dma_contig_num_users(void *buf_priv)
static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
{
struct vb2_dc_buf *buf = buf_priv;
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+ int ret;
+#endif
if (!buf) {
printk(KERN_ERR "No buffer to map\n");
return -EINVAL;
}
+#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ ret = dma_mmap_coherent(buf->conf->dev, vma, buf->vaddr, buf->dma_addr,
+ buf->size);
+ if (ret) {
+ pr_err("Remapping memory failed, error: %d\n", ret);
+ return ret;
+ }
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = &buf->handler;
+ vma->vm_ops = &vb2_common_vm_ops;
+ vma->vm_ops->open(vma);
+ return 0;
+#else
return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size,
&vb2_common_vm_ops, &buf->handler);
+#endif
}
static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
--
1.7.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox