* [PATCH 4/4] ARM: shmobile: ag5evm, ap4: Name SDHI IRQ sources
From: Simon Horman @ 2011-08-19 7:57 UTC (permalink / raw)
To: linux-mmc, linux-sh
Cc: Chris Ball, Paul Mundt, Guennadi Liakhovetski, Magnus Damm,
Simon Horman
In-Reply-To: <1313740642-18307-1-git-send-email-horms@verge.net.au>
This allows specific (non-multiplexed) IRQ handlers to be used.
Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Magnus Damm <magnus.damm@gmail.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
Requires
"mmc: sdhi: Allow specific IRQ sources to use corresponding handlers."
v7
* Rework to use named IRQs
v4
* Update for corrected ordering of SH_MOBILE_SDHI_IRQ_SDCARD and
SH_MOBILE_SDHI_IRQ_CARD_DETECT
v2
* Initial release
---
arch/arm/mach-shmobile/board-ag5evm.c | 6 ++++++
arch/arm/mach-shmobile/board-mackerel.c | 6 ++++++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index ce5c251..e100cad 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -353,14 +353,17 @@ static struct resource sdhi0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
+ .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
.start = gic_spi(83),
.flags = IORESOURCE_IRQ,
},
[2] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDCARD,
.start = gic_spi(84),
.flags = IORESOURCE_IRQ,
},
[3] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDIO,
.start = gic_spi(85),
.flags = IORESOURCE_IRQ,
},
@@ -396,14 +399,17 @@ static struct resource sdhi1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
+ .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
.start = gic_spi(87),
.flags = IORESOURCE_IRQ,
},
[2] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDCARD,
.start = gic_spi(88),
.flags = IORESOURCE_IRQ,
},
[3] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDIO,
.start = gic_spi(89),
.flags = IORESOURCE_IRQ,
},
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index d41c01f..492274f 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1066,14 +1066,17 @@ static struct resource sdhi1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
+ .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
.start = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
.flags = IORESOURCE_IRQ,
},
[2] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDCARD,
.start = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
.flags = IORESOURCE_IRQ,
},
[3] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDIO,
.start = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
.flags = IORESOURCE_IRQ,
},
@@ -1117,14 +1120,17 @@ static struct resource sdhi2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
+ .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
.start = evt2irq(0x1200), /* SDHI2_SDHI2I0 */
.flags = IORESOURCE_IRQ,
},
[2] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDCARD,
.start = evt2irq(0x1220), /* SDHI2_SDHI2I1 */
.flags = IORESOURCE_IRQ,
},
[3] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDIO,
.start = evt2irq(0x1240), /* SDHI2_SDHI2I2 */
.flags = IORESOURCE_IRQ,
},
--
1.7.5.4
^ permalink raw reply related
* [PULL] SH mobile LCDC cleanups and fixes
From: Laurent Pinchart @ 2011-08-19 8:44 UTC (permalink / raw)
To: linux-fbdev
Hi Florian,
Here are the latest SH mobile LCDC and MERAM cleanups and fixes based on top
of v3.1-rc2. All the patches have been posted to the list. I've incorporated
acked-by and tested-by lines when available, but most of the patches received
no comment.
The following changes since commit 93ee7a9340d64f20295aacc3fb6a22b759323280:
Linux 3.1-rc2 (2011-08-14 15:09:08 -0700)
are available in the git repository at:
git://linuxtv.org/pinchartl/fbdev.git sh-mobile-lcdc
Damian Hobson-Garcia (5):
fbdev: sh_mobile_meram: Enable runtime PM
fbdev: sh_mobile_meram: Enable/disable MERAM along with LCDC
fbdev: sh_mobile_meram: Move private data from .h to .c
fbdev: sh_mobile_meram: Backup/restore device registers on shutdown/resume
fbdev: sh_mobile_meram: Assign meram to the SH7372_A4LC power domain
Laurent Pinchart (11):
fbdev: sh_mobile_lcdc: Turn dot clock on before resuming from runtime PM
fbdev: sh_mobile_lcdc: Replace hardcoded register values with macros
fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
fbdev: sh_mobile_lcdc: Compute clock pattern using divider denominator
fbdev: sh_mobile_lcdc: Split LCDC start code from sh_mobile_lcdc_start
fbdev: sh_mobile_lcdc: Store the frame buffer base address when panning
fbdev: sh_mobile_lcdc: Restart LCDC in runtime PM resume handler
fbdev: sh_mobile_meram: Replace hardcoded register values with macros
fbdev: sh_mobile_meram: Validate ICB configuration outside mutex
fbdev: sh_mobile_meram: Fix MExxCTL register save on runtime PM suspend
fbdev: sh_mobile_meram: Remove unneeded sh_mobile_meram.h
arch/arm/mach-shmobile/board-mackerel.c | 1 +
drivers/video/sh_mobile_lcdcfb.c | 592 ++++++++++++++-----------------
drivers/video/sh_mobile_lcdcfb.h | 12 +-
drivers/video/sh_mobile_meram.c | 202 +++++++++--
drivers/video/sh_mobile_meram.h | 41 ---
include/video/sh_mobile_lcdc.h | 135 ++++++-
6 files changed, 556 insertions(+), 427 deletions(-)
delete mode 100644 drivers/video/sh_mobile_meram.h
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH 0/7] sh_mobile_lcdc: Support format changes at runtime
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
Hi everybody,
This patch set add supports for the .fb_set_par() operation in the
sh_mobile_lcdc driver, allowing userspace to change the frame buffer format
and size at runtime. It applies on top of the latest SH mobile LCDC cleanups
and fixes patches posted to the linux-fbdev list and available at
http://git.linuxtv.org/pinchartl/fbdev.git/shortlog/refs/heads/sh-mobile-lcdc.
Frame buffer memory reallocation is currently not supported. You will need to
make sure platform data sets the maximum size and bpp to high enough values
for all formats and sizes you want to support at runtime.
The patches have been tested with the fbdev-test utility
(http://git.ideasonboard.org/?pûdev-test.git;a=summary) on a Mackerel board.
Laurent Pinchart (7):
fbdev: sh_mobile_lcdc: Adjust requested parameters in .fb_check_var
fbdev: sh_mobile_lcdc: Add support for format changes at runtime
fbdev: sh_mobile_lcdc: use display information in info for panning
fbdev: sh_mobile_lcdc: Update fix.line_length in .fb_set_par()
fbdev: sh_mobile_lcdc: Avoid forward declarations
fbdev: sh_mobile_lcdc: Split channel initialization from probe function
fbdev: sh_mobile_lcdc: Remove sh_mobile_lcdc_set_bpp()
drivers/video/sh_mobile_lcdcfb.c | 570 +++++++++++++++++++++-----------------
1 files changed, 309 insertions(+), 261 deletions(-)
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH 1/7] fbdev: sh_mobile_lcdc: Adjust requested parameters in .fb_check_var
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
Instead of failing when the requested fb_var_screeninfo parameters are
not supported, adjust the parameters according to the hardware
capabilities.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 103 ++++++++++++++++++++++++++++++++------
1 files changed, 88 insertions(+), 15 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 088cb17..33b0ff8 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1055,28 +1055,101 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
{
struct sh_mobile_lcdc_chan *ch = info->par;
struct sh_mobile_lcdc_priv *p = ch->lcdc;
+ unsigned int best_dist = (unsigned int)-1;
+ unsigned int best_xres = 0;
+ unsigned int best_yres = 0;
+ unsigned int i;
- if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
- var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
- dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n",
- var->left_margin, var->xres, var->right_margin, var->hsync_len,
- var->upper_margin, var->yres, var->lower_margin, var->vsync_len,
- PICOS2KHZ(var->pixclock));
+ if (var->xres > MAX_XRES || var->yres > MAX_YRES)
return -EINVAL;
+
+ /* If board code provides us with a list of available modes, make sure
+ * we use one of them. Find the mode closest to the requested one. The
+ * distance between two modes is defined as the size of the
+ * non-overlapping parts of the two rectangles.
+ */
+ for (i = 0; i < ch->cfg.num_cfg; ++i) {
+ const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i];
+ unsigned int dist;
+
+ /* We can only round up. */
+ if (var->xres > mode->xres || var->yres > mode->yres)
+ continue;
+
+ dist = var->xres * var->yres + mode->xres * mode->yres
+ - 2 * min(var->xres, mode->xres)
+ * min(var->yres, mode->yres);
+
+ if (dist < best_dist) {
+ best_xres = mode->xres;
+ best_yres = mode->yres;
+ best_dist = dist;
+ }
}
- /* only accept the forced_bpp for dual channel configurations */
- if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
+ /* If no available mode can be used, return an error. */
+ if (ch->cfg.num_cfg != 0) {
+ if (best_dist = (unsigned int)-1)
+ return -EINVAL;
+
+ var->xres = best_xres;
+ var->yres = best_yres;
+ }
+
+ /* Make sure the virtual resolution is at least as big as the visible
+ * resolution.
+ */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->bits_per_pixel <= 16) { /* RGB 565 */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ } else if (var->bits_per_pixel <= 24) { /* RGB 888 */
+ var->bits_per_pixel = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ } else
return -EINVAL;
- switch (var->bits_per_pixel) {
- case 16: /* PKF[4:0] = 00011 - RGB 565 */
- case 24: /* PKF[4:0] = 01011 - RGB 888 */
- case 32: /* PKF[4:0] = 00000 - RGBA 888 */
- break;
- default:
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ /* Make sure we don't exceed our allocated memory. */
+ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+ info->fix.smem_len)
+ return -EINVAL;
+
+ /* only accept the forced_bpp for dual channel configurations */
+ if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
return -EINVAL;
- }
return 0;
}
--
1.7.3.4
^ permalink raw reply related
* [PATCH 2/7] fbdev: sh_mobile_lcdc: Add support for format changes at runtime
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
Implement .fb_set_par to support frame buffer format changes at runtime.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 33b0ff8..f9f420d 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1154,6 +1154,19 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
return 0;
}
+static int sh_mobile_set_par(struct fb_info *info)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+ int ret;
+
+ sh_mobile_lcdc_stop(ch->lcdc);
+ ret = sh_mobile_lcdc_start(ch->lcdc);
+ if (ret < 0)
+ dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
+
+ return ret;
+}
+
/*
* Screen blanking. Behavior is as follows:
* FB_BLANK_UNBLANK: screen unblanked, clocks enabled
@@ -1211,6 +1224,7 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_open = sh_mobile_open,
.fb_release = sh_mobile_release,
.fb_check_var = sh_mobile_check_var,
+ .fb_set_par = sh_mobile_set_par,
};
static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
--
1.7.3.4
^ permalink raw reply related
* [PATCH 3/7] fbdev: sh_mobile_lcdc: use display information in info for panning
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
We must not use any information in the passed var besides xoffset,
yoffset and vmode as otherwise applications might abuse it.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 24 ++++++++++++------------
1 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index f9f420d..1ff215c 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -877,12 +877,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
unsigned long base_addr_y, base_addr_c;
unsigned long c_offset;
- if (!var->nonstd)
- new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * (info->var.bits_per_pixel / 8));
+ if (!info->var.nonstd)
+ new_pan_offset = var->yoffset * info->fix.line_length
+ + var->xoffset * (info->var.bits_per_pixel / 8);
else
- new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset);
+ new_pan_offset = var->yoffset * info->fix.line_length
+ + var->xoffset;
if (new_pan_offset = ch->pan_offset)
return 0; /* No change, do nothing */
@@ -891,13 +891,13 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
/* Set the source address for the next refresh */
base_addr_y = ch->dma_handle + new_pan_offset;
- if (var->nonstd) {
+ if (info->var.nonstd) {
/* Set y offset */
- c_offset = (var->yoffset *
- info->fix.line_length *
- (info->var.bits_per_pixel - 8)) / 8;
- base_addr_c = ch->dma_handle + var->xres * var->yres_virtual +
- c_offset;
+ c_offset = var->yoffset * info->fix.line_length
+ * (info->var.bits_per_pixel - 8) / 8;
+ base_addr_c = ch->dma_handle
+ + info->var.xres * info->var.yres_virtual
+ + c_offset;
/* Set x offset */
if (info->var.bits_per_pixel = 24)
base_addr_c += 2 * var->xoffset;
@@ -923,7 +923,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
ch->base_addr_c = base_addr_c;
lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
- if (var->nonstd)
+ if (info->var.nonstd)
lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
if (lcdc_chan_is_sublcd(ch))
--
1.7.3.4
^ permalink raw reply related
* [PATCH 4/7] fbdev: sh_mobile_lcdc: Update fix.line_length in .fb_set_par()
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
Instead of updating the fixed screen information line length manually
after calling fb_set_var() in sh_mobile_fb_reconfig(), update the field
in the .fb_set_par() operation handler.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 1ff215c..b6da1d6 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -998,11 +998,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
/* Couldn't reconfigure, hopefully, can continue as before */
return;
- if (info->var.nonstd)
- info->fix.line_length = mode1.xres;
- else
- info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8);
-
/*
* fb_set_var() calls the notifier change internally, only if
* FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
@@ -1157,12 +1152,22 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
static int sh_mobile_set_par(struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
+ u32 line_length = info->fix.line_length;
int ret;
sh_mobile_lcdc_stop(ch->lcdc);
+
+ if (info->var.nonstd)
+ info->fix.line_length = info->var.xres;
+ else
+ info->fix.line_length = info->var.xres
+ * info->var.bits_per_pixel / 8;
+
ret = sh_mobile_lcdc_start(ch->lcdc);
- if (ret < 0)
+ if (ret < 0) {
dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
+ info->fix.line_length = line_length;
+ }
return ret;
}
--
1.7.3.4
^ permalink raw reply related
* [PATCH 5/7] fbdev: sh_mobile_lcdc: Avoid forward declarations
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
Reorder probe/remove functions to avoid forward declarations.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 102 ++++++++++++++++++-------------------
1 files changed, 50 insertions(+), 52 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index b6da1d6..366315b 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1434,7 +1434,56 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
-static int sh_mobile_lcdc_remove(struct platform_device *pdev);
+static int sh_mobile_lcdc_remove(struct platform_device *pdev)
+{
+ struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
+ struct fb_info *info;
+ int i;
+
+ fb_unregister_client(&priv->notifier);
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
+ if (priv->ch[i].info && priv->ch[i].info->dev)
+ unregister_framebuffer(priv->ch[i].info);
+
+ sh_mobile_lcdc_stop(priv);
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+ info = priv->ch[i].info;
+
+ if (!info || !info->device)
+ continue;
+
+ if (priv->ch[i].sglist)
+ vfree(priv->ch[i].sglist);
+
+ if (info->screen_base)
+ dma_free_coherent(&pdev->dev, info->fix.smem_len,
+ info->screen_base,
+ priv->ch[i].dma_handle);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+ if (priv->ch[i].bl)
+ sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
+ }
+
+ if (priv->dot_clk)
+ clk_put(priv->dot_clk);
+
+ if (priv->dev)
+ pm_runtime_disable(priv->dev);
+
+ if (priv->base)
+ iounmap(priv->base);
+
+ if (priv->irq)
+ free_irq(priv->irq, priv);
+ kfree(priv);
+ return 0;
+}
static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
{
@@ -1691,57 +1740,6 @@ err1:
return error;
}
-static int sh_mobile_lcdc_remove(struct platform_device *pdev)
-{
- struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
- struct fb_info *info;
- int i;
-
- fb_unregister_client(&priv->notifier);
-
- for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
- if (priv->ch[i].info && priv->ch[i].info->dev)
- unregister_framebuffer(priv->ch[i].info);
-
- sh_mobile_lcdc_stop(priv);
-
- for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
- info = priv->ch[i].info;
-
- if (!info || !info->device)
- continue;
-
- if (priv->ch[i].sglist)
- vfree(priv->ch[i].sglist);
-
- if (info->screen_base)
- dma_free_coherent(&pdev->dev, info->fix.smem_len,
- info->screen_base,
- priv->ch[i].dma_handle);
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
-
- for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
- if (priv->ch[i].bl)
- sh_mobile_lcdc_bl_remove(priv->ch[i].bl);
- }
-
- if (priv->dot_clk)
- clk_put(priv->dot_clk);
-
- if (priv->dev)
- pm_runtime_disable(priv->dev);
-
- if (priv->base)
- iounmap(priv->base);
-
- if (priv->irq)
- free_irq(priv->irq, priv);
- kfree(priv);
- return 0;
-}
-
static struct platform_driver sh_mobile_lcdc_driver = {
.driver = {
.name = "sh_mobile_lcdc_fb",
--
1.7.3.4
^ permalink raw reply related
* [PATCH 6/7] fbdev: sh_mobile_lcdc: Split channel initialization from probe function
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
Move channel initialization to sh_mobile_lcdc_channel_init() and call
the function from sh_mobile_lcdc_probe(). This makes the code more
readable and prepares it for fix/var initialization rework.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 247 ++++++++++++++++++++------------------
1 files changed, 129 insertions(+), 118 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 366315b..d1576e2 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1485,15 +1485,129 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
return 0;
}
-static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
+ struct device *dev)
{
+ struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
+ const struct fb_videomode *max_mode;
+ const struct fb_videomode *mode;
+ struct fb_var_screeninfo *var;
struct fb_info *info;
- struct sh_mobile_lcdc_priv *priv;
+ unsigned int max_size;
+ int num_cfg;
+ void *buf;
+ int ret;
+ int i;
+
+ ch->info = framebuffer_alloc(0, dev);
+ if (!ch->info) {
+ dev_err(dev, "unable to allocate fb_info\n");
+ return -ENOMEM;
+ }
+
+ info = ch->info;
+ var = &info->var;
+ info->fbops = &sh_mobile_lcdc_ops;
+ info->par = ch;
+
+ mutex_init(&ch->open_lock);
+
+ /* Iterate through the modes to validate them and find the highest
+ * resolution.
+ */
+ max_mode = NULL;
+ max_size = 0;
+
+ for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
+ unsigned int size = mode->yres * mode->xres;
+
+ /* NV12 buffers must have even number of lines */
+ if ((cfg->nonstd) && cfg->bpp = 12 &&
+ (mode->yres & 0x1)) {
+ dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
+ "mode.\n");
+ return -EINVAL;
+ }
+
+ if (size > max_size) {
+ max_mode = mode;
+ max_size = size;
+ }
+ }
+
+ if (!max_size)
+ max_size = MAX_XRES * MAX_YRES;
+ else
+ dev_dbg(dev, "Found largest videomode %ux%u\n",
+ max_mode->xres, max_mode->yres);
+
+ info->fix = sh_mobile_lcdc_fix;
+ info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
+
+ /* Only pan in 2 line steps for NV12 */
+ if (cfg->nonstd && cfg->bpp = 12)
+ info->fix.ypanstep = 2;
+
+ if (cfg->lcd_cfg = NULL) {
+ mode = &default_720p;
+ num_cfg = 1;
+ } else {
+ mode = cfg->lcd_cfg;
+ num_cfg = cfg->num_cfg;
+ }
+
+ fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
+
+ fb_videomode_to_var(var, mode);
+ var->width = cfg->lcd_size_cfg.width;
+ var->height = cfg->lcd_size_cfg.height;
+ /* Default Y virtual resolution is 2x panel size */
+ var->yres_virtual = var->yres * 2;
+ var->activate = FB_ACTIVATE_NOW;
+
+ ret = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
+ if (ret)
+ return ret;
+
+ buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle,
+ GFP_KERNEL);
+ if (!buf) {
+ dev_err(dev, "unable to allocate buffer\n");
+ return -ENOMEM;
+ }
+
+ info->pseudo_palette = &ch->pseudo_palette;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
+ if (ret < 0) {
+ dev_err(dev, "unable to allocate cmap\n");
+ dma_free_coherent(dev, info->fix.smem_len,
+ buf, ch->dma_handle);
+ return ret;
+ }
+
+ info->fix.smem_start = ch->dma_handle;
+ if (var->nonstd)
+ info->fix.line_length = var->xres;
+ else
+ info->fix.line_length = var->xres * (cfg->bpp / 8);
+
+ info->screen_base = buf;
+ info->device = dev;
+ ch->display_var = *var;
+
+ return 0;
+}
+
+static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+{
struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
+ struct sh_mobile_lcdc_priv *priv;
struct resource *res;
+ int num_channels;
int error;
- void *buf;
- int i, j;
+ int i;
if (!pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
@@ -1525,9 +1639,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
priv->irq = i;
atomic_set(&priv->hw_usecnt, -1);
- j = 0;
- for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {
- struct sh_mobile_lcdc_chan *ch = priv->ch + j;
+ for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
+ struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
ch->lcdc = priv;
memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
@@ -1549,24 +1662,24 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
case LCDC_CHAN_MAINLCD:
ch->enabled = LDCNT2R_ME;
ch->reg_offs = lcdc_offs_mainlcd;
- j++;
+ num_channels++;
break;
case LCDC_CHAN_SUBLCD:
ch->enabled = LDCNT2R_SE;
ch->reg_offs = lcdc_offs_sublcd;
- j++;
+ num_channels++;
break;
}
}
- if (!j) {
+ if (!num_channels) {
dev_err(&pdev->dev, "no channels defined\n");
error = -EINVAL;
goto err1;
}
/* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
- if (j = 2)
+ if (num_channels = 2)
priv->forced_bpp = pdata->ch[0].bpp;
priv->base = ioremap_nocache(res->start, resource_size(res));
@@ -1581,125 +1694,23 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
priv->meram_dev = pdata->meram_dev;
- for (i = 0; i < j; i++) {
- struct fb_var_screeninfo *var;
- const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
+ for (i = 0; i < num_channels; i++) {
struct sh_mobile_lcdc_chan *ch = priv->ch + i;
- struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
- const struct fb_videomode *mode = cfg->lcd_cfg;
- unsigned long max_size = 0;
- int k;
- int num_cfg;
-
- ch->info = framebuffer_alloc(0, &pdev->dev);
- if (!ch->info) {
- dev_err(&pdev->dev, "unable to allocate fb_info\n");
- error = -ENOMEM;
- break;
- }
-
- info = ch->info;
- var = &info->var;
- info->fbops = &sh_mobile_lcdc_ops;
- info->par = ch;
-
- mutex_init(&ch->open_lock);
-
- for (k = 0, lcd_cfg = mode;
- k < cfg->num_cfg && lcd_cfg;
- k++, lcd_cfg++) {
- unsigned long size = lcd_cfg->yres * lcd_cfg->xres;
- /* NV12 buffers must have even number of lines */
- if ((cfg->nonstd) && cfg->bpp = 12 &&
- (lcd_cfg->yres & 0x1)) {
- dev_err(&pdev->dev, "yres must be multiple of 2"
- " for YCbCr420 mode.\n");
- error = -EINVAL;
- goto err1;
- }
-
- if (size > max_size) {
- max_cfg = lcd_cfg;
- max_size = size;
- }
- }
-
- if (!mode)
- max_size = MAX_XRES * MAX_YRES;
- else if (max_cfg)
- dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
- max_cfg->xres, max_cfg->yres);
-
- info->fix = sh_mobile_lcdc_fix;
- info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
-
- /* Only pan in 2 line steps for NV12 */
- if (cfg->nonstd && cfg->bpp = 12)
- info->fix.ypanstep = 2;
-
- if (!mode) {
- mode = &default_720p;
- num_cfg = 1;
- } else {
- num_cfg = cfg->num_cfg;
- }
-
- fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
- fb_videomode_to_var(var, mode);
- var->width = cfg->lcd_size_cfg.width;
- var->height = cfg->lcd_size_cfg.height;
- /* Default Y virtual resolution is 2x panel size */
- var->yres_virtual = var->yres * 2;
- var->activate = FB_ACTIVATE_NOW;
-
- error = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
+ error = sh_mobile_lcdc_channel_init(ch, &pdev->dev);
if (error)
- break;
-
- buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
- &ch->dma_handle, GFP_KERNEL);
- if (!buf) {
- dev_err(&pdev->dev, "unable to allocate buffer\n");
- error = -ENOMEM;
- break;
- }
-
- info->pseudo_palette = &ch->pseudo_palette;
- 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");
- dma_free_coherent(&pdev->dev, info->fix.smem_len,
- buf, ch->dma_handle);
- break;
- }
-
- info->fix.smem_start = ch->dma_handle;
- if (var->nonstd)
- info->fix.line_length = var->xres;
- else
- info->fix.line_length = var->xres * (cfg->bpp / 8);
-
- info->screen_base = buf;
- info->device = &pdev->dev;
- ch->display_var = *var;
+ goto err1;
}
- if (error)
- goto err1;
-
error = sh_mobile_lcdc_start(priv);
if (error) {
dev_err(&pdev->dev, "unable to start hardware\n");
goto err1;
}
- for (i = 0; i < j; i++) {
+ for (i = 0; i < num_channels; i++) {
struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-
- info = ch->info;
+ struct fb_info *info = ch->info;
if (info->fbdefio) {
ch->sglist = vmalloc(sizeof(struct scatterlist) *
--
1.7.3.4
^ permalink raw reply related
* [PATCH 7/7] fbdev: sh_mobile_lcdc: Remove sh_mobile_lcdc_set_bpp()
From: Laurent Pinchart @ 2011-08-19 9:16 UTC (permalink / raw)
To: linux-fbdev
The function duplicates code found in sh_mobile_check_var(). Remove
sh_mobile_lcdc_set_bpp() and call sh_mobile_check_var() instead.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/video/sh_mobile_lcdcfb.c | 87 +++++++------------------------------
1 files changed, 17 insertions(+), 70 deletions(-)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index d1576e2..97ab8ba 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1291,66 +1291,6 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
backlight_device_unregister(bdev);
}
-static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp,
- int nonstd)
-{
- if (nonstd) {
- switch (bpp) {
- case 12:
- case 16:
- case 24:
- var->bits_per_pixel = bpp;
- var->nonstd = nonstd;
- return 0;
- default:
- return -EINVAL;
- }
- }
-
- switch (bpp) {
- case 16: /* PKF[4:0] = 00011 - 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;
-
- case 24: /* PKF[4:0] = 01011 - RGB 888 */
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
-
- case 32: /* PKF[4:0] = 00000 - RGBA 888 */
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- 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;
-}
-
static int sh_mobile_lcdc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1499,6 +1439,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
int ret;
int i;
+ mutex_init(&ch->open_lock);
+
+ /* Allocate the frame buffer device. */
ch->info = framebuffer_alloc(0, dev);
if (!ch->info) {
dev_err(dev, "unable to allocate fb_info\n");
@@ -1506,11 +1449,10 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
}
info = ch->info;
- var = &info->var;
info->fbops = &sh_mobile_lcdc_ops;
info->par = ch;
-
- mutex_init(&ch->open_lock);
+ info->pseudo_palette = &ch->pseudo_palette;
+ info->flags = FBINFO_FLAG_DEFAULT;
/* Iterate through the modes to validate them and find the highest
* resolution.
@@ -1541,13 +1483,15 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
dev_dbg(dev, "Found largest videomode %ux%u\n",
max_mode->xres, max_mode->yres);
+ /* Initialize fixed screen information. Restrict pan to 2 lines steps
+ * for NV12.
+ */
info->fix = sh_mobile_lcdc_fix;
info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
-
- /* Only pan in 2 line steps for NV12 */
if (cfg->nonstd && cfg->bpp = 12)
info->fix.ypanstep = 2;
+ /* Create the mode list. */
if (cfg->lcd_cfg = NULL) {
mode = &default_720p;
num_cfg = 1;
@@ -1558,17 +1502,23 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
+ /* Initialize variable screen information using the first mode as
+ * default. The default Y virtual resolution is twice the panel size to
+ * allow for double-buffering.
+ */
+ var = &info->var;
fb_videomode_to_var(var, mode);
+ var->bits_per_pixel = cfg->bpp;
var->width = cfg->lcd_size_cfg.width;
var->height = cfg->lcd_size_cfg.height;
- /* Default Y virtual resolution is 2x panel size */
var->yres_virtual = var->yres * 2;
var->activate = FB_ACTIVATE_NOW;
- ret = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
+ ret = sh_mobile_check_var(var, info);
if (ret)
return ret;
+ /* Allocate frame buffer memory and color map. */
buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle,
GFP_KERNEL);
if (!buf) {
@@ -1576,9 +1526,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
return -ENOMEM;
}
- info->pseudo_palette = &ch->pseudo_palette;
- info->flags = FBINFO_FLAG_DEFAULT;
-
ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
if (ret < 0) {
dev_err(dev, "unable to allocate cmap\n");
--
1.7.3.4
^ permalink raw reply related
* Re: [PATCH] mmc: sdhi: initialise mmc_data->flags before use
From: Chris Ball @ 2011-08-19 17:18 UTC (permalink / raw)
To: Simon Horman; +Cc: linux-mmc, linux-sh, Guennadi Liakhovetski, Magnus Damm
In-Reply-To: <1313716027-19470-1-git-send-email-horms@verge.net.au>
Hi,
On Thu, Aug 18 2011, Simon Horman wrote:
> This corrects a logic error that I introduced in
> "mmc: sdhi: Add write16_hook"
>
> Reported-by: Magnus Damm <magnus.damm@gmail.com>
> Signed-off-by: Simon Horman <horms@verge.net.au>
> ---
> drivers/mmc/host/sh_mobile_sdhi.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
> index 2fa7bbc..68702e4 100644
> --- a/drivers/mmc/host/sh_mobile_sdhi.c
> +++ b/drivers/mmc/host/sh_mobile_sdhi.c
> @@ -121,11 +121,11 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
> mmc_data->hclk = clk_get_rate(priv->clk);
> mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
> mmc_data->get_cd = sh_mobile_sdhi_get_cd;
> - if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
> - mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
> mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
> if (p) {
> mmc_data->flags = p->tmio_flags;
> + if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
> + mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
> mmc_data->ocr_mask = p->tmio_ocr_mask;
> mmc_data->capabilities |= p->tmio_caps;
Thanks, Simon, pushed to mmc-next for 3.1-rc.
- Chris.
--
Chris Ball <cjb@laptop.org> <http://printf.net/>
One Laptop Per Child
^ permalink raw reply
* [PATCH] PM / Domains: Preliminary support for devices with power.irq_safe set
From: Rafael J. Wysocki @ 2011-08-20 19:24 UTC (permalink / raw)
To: Linux PM mailing list; +Cc: LKML, Magnus Damm, linux-sh
From: Rafael J. Wysocki <rjw@sisk.pl>
The generic PM domains framework currently doesn't work with devices
whose power.irq_safe flag is set, because runtime PM callbacks for
such devices are run with interrupts disabled and the callbacks
provided by the generic PM domains framework use domain mutexes
and may sleep. However, such devices very well may belong to
power domains on some systems, so the generic PM domains framework
should take them into account.
For this reason, make modify the generic PM domains framework so
that the domain .power_off() and .power_on() callbacks are never
executed for a domain containing devices with power.irq_safe set,
although the .stop_device() and .start_device() callbacks are
still run for them.
Additionally, introduce a flag allowing the creator of a
struct generic_pm_domain object to indicate that its .stop_device()
and .start_device() callbacks may be run in interrupt context
(might_sleep_if() triggers if that flag is not set and one of those
callbacks is run in interrupt context).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
arch/arm/mach-shmobile/pm-sh7372.c | 1 +
drivers/base/power/domain.c | 19 ++++++++++++++++++-
include/linux/pm_domain.h | 1 +
3 files changed, 20 insertions(+), 1 deletion(-)
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -309,7 +309,8 @@ static int pm_genpd_poweroff(struct gene
not_suspended = 0;
list_for_each_entry(pdd, &genpd->dev_list, list_node)
- if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev))
+ if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
+ || pdd->dev->power.irq_safe))
not_suspended++;
if (not_suspended > genpd->in_progress)
@@ -417,12 +418,21 @@ static int pm_genpd_runtime_suspend(stru
if (IS_ERR(genpd))
return -EINVAL;
+ might_sleep_if(!genpd->dev_irq_safe);
+
if (genpd->stop_device) {
int ret = genpd->stop_device(dev);
if (ret)
return ret;
}
+ /*
+ * If power.irq_safe is set, this routine will be run with interrupts
+ * off, so it can't use mutexes.
+ */
+ if (dev->power.irq_safe)
+ return 0;
+
mutex_lock(&genpd->lock);
genpd->in_progress++;
pm_genpd_poweroff(genpd);
@@ -452,6 +462,12 @@ static int pm_genpd_runtime_resume(struc
if (IS_ERR(genpd))
return -EINVAL;
+ might_sleep_if(!genpd->dev_irq_safe);
+
+ /* If power.irq_safe, the PM domain is never powered off. */
+ if (dev->power.irq_safe)
+ goto out;
+
mutex_lock(&genpd->lock);
ret = __pm_genpd_poweron(genpd);
if (ret) {
@@ -483,6 +499,7 @@ static int pm_genpd_runtime_resume(struc
wake_up_all(&genpd->status_wait_queue);
mutex_unlock(&genpd->lock);
+ out:
if (genpd->start_device)
genpd->start_device(dev);
Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -42,6 +42,7 @@ struct generic_pm_domain {
unsigned int suspended_count; /* System suspend device counter */
unsigned int prepared_count; /* Suspend counter of prepared devices */
bool suspend_power_off; /* Power status before system suspend */
+ bool dev_irq_safe; /* Device callbacks are IRQ-safe */
int (*power_off)(struct generic_pm_domain *domain);
int (*power_on)(struct generic_pm_domain *domain);
int (*start_device)(struct device *dev);
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -103,6 +103,7 @@ void sh7372_init_pm_domain(struct sh7372
pm_genpd_init(genpd, NULL, false);
genpd->stop_device = pm_clk_suspend;
genpd->start_device = pm_clk_resume;
+ genpd->dev_irq_safe = true;
genpd->active_wakeup = pd_active_wakeup;
genpd->power_off = pd_power_down;
genpd->power_on = pd_power_up;
^ permalink raw reply
* [PATCH 0/2] sh-sci / PM: Fix problem with runtime PM callbacks run with interrupts off
From: Rafael J. Wysocki @ 2011-08-20 19:31 UTC (permalink / raw)
To: linux-sh; +Cc: Linux PM mailing list, LKML, Magnus Damm
Hi,
The sh-sci driver uses pm_runtime_get/put_sync() in such a way
that they may be run with interrupts off and cause the (recently
added) might_sleep_if() to trigger in rpm_suspend/resume().
To avoid that, it's necessary to set the SCI device's power.irq_safe
flag to indicate that it's runtime PM callbacks may be executed with
interrupts off safely. However, the sh-sci driver needs to be able to
clear that flag sometimes, so a new runtime PM helper for doing that
is needed.
[1/2] - Add pm_runtime_irq_unsafe() for clearing the power.irq_safe device flag.
[2/2] - Make sh-sci use power.irq_safe to indicate that runtime PM callbacks
may be run with interrupts off.
Thanks,
Rafael
^ permalink raw reply
* [PATCH 1/2] PM / Runtime: Introduce pm_runtime_irq_unsafe()
From: Rafael J. Wysocki @ 2011-08-20 19:32 UTC (permalink / raw)
To: linux-sh; +Cc: Linux PM mailing list, LKML, Magnus Damm
In-Reply-To: <201108202131.19479.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Add a helper function allowing drivers and subsystems to clear
the power.irq_safe device flag.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
Documentation/power/runtime_pm.txt | 4 ++++
drivers/base/power/runtime.c | 9 +++++----
include/linux/pm_runtime.h | 13 ++++++++++++-
3 files changed, 21 insertions(+), 5 deletions(-)
Index: linux/include/linux/pm_runtime.h
=================================--- linux.orig/include/linux/pm_runtime.h
+++ linux/include/linux/pm_runtime.h
@@ -40,7 +40,7 @@ extern int pm_generic_runtime_idle(struc
extern int pm_generic_runtime_suspend(struct device *dev);
extern int pm_generic_runtime_resume(struct device *dev);
extern void pm_runtime_no_callbacks(struct device *dev);
-extern void pm_runtime_irq_safe(struct device *dev);
+extern void __pm_runtime_irq_safe(struct device *dev, bool irq_safe);
extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
@@ -102,6 +102,16 @@ static inline void pm_runtime_mark_last_
ACCESS_ONCE(dev->power.last_busy) = jiffies;
}
+static inline void pm_runtime_irq_safe(struct device *dev)
+{
+ __pm_runtime_irq_safe(dev, true);
+}
+
+static inline void pm_runtime_irq_unsafe(struct device *dev)
+{
+ __pm_runtime_irq_safe(dev, false);
+}
+
#else /* !CONFIG_PM_RUNTIME */
static inline int __pm_runtime_idle(struct device *dev, int rpmflags)
@@ -143,6 +153,7 @@ static inline int pm_generic_runtime_sus
static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
static inline void pm_runtime_no_callbacks(struct device *dev) {}
static inline void pm_runtime_irq_safe(struct device *dev) {}
+static inline void pm_runtime_irq_unsafe(struct device *dev) {}
static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; }
static inline void pm_runtime_mark_last_busy(struct device *dev) {}
Index: linux/drivers/base/power/runtime.c
=================================--- linux.orig/drivers/base/power/runtime.c
+++ linux/drivers/base/power/runtime.c
@@ -1109,22 +1109,23 @@ void pm_runtime_no_callbacks(struct devi
EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
/**
- * pm_runtime_irq_safe - Leave interrupts disabled during callbacks.
+ * __pm_runtime_irq_safe - Manipulate a device's power.irq_safe flag.
* @dev: Device to handle
+ * @irq_safe: Whether or not to leave interrupts disabled during callbacks.
*
- * Set the power.irq_safe flag, which tells the PM core that the
+ * Set or unset the power.irq_safe flag, which tells the PM core that the
* ->runtime_suspend() and ->runtime_resume() callbacks for this device should
* always be invoked with the spinlock held and interrupts disabled. It also
* causes the parent's usage counter to be permanently incremented, preventing
* the parent from runtime suspending -- otherwise an irq-safe child might have
* to wait for a non-irq-safe parent.
*/
-void pm_runtime_irq_safe(struct device *dev)
+void __pm_runtime_irq_safe(struct device *dev, bool irq_safe)
{
if (dev->parent)
pm_runtime_get_sync(dev->parent);
spin_lock_irq(&dev->power.lock);
- dev->power.irq_safe = 1;
+ dev->power.irq_safe = irq_safe;
spin_unlock_irq(&dev->power.lock);
}
EXPORT_SYMBOL_GPL(pm_runtime_irq_safe);
Index: linux/Documentation/power/runtime_pm.txt
=================================--- linux.orig/Documentation/power/runtime_pm.txt
+++ linux/Documentation/power/runtime_pm.txt
@@ -434,6 +434,10 @@ drivers/base/power/runtime.c and include
suspend and resume callbacks (but not the idle callback) to be invoked
with interrupts disabled
+ void pm_runtime_irq_unsafe(struct device *dev);
+ - clear the power.irq_safe flag for the device, causing the runtime-PM
+ callbacks to be invoked with interrupts enabled
+
void pm_runtime_mark_last_busy(struct device *dev);
- set the power.last_busy field to the current time
^ permalink raw reply
* [PATCH 2/2] sh-sci / PM: Use power.irq_safe
From: Rafael J. Wysocki @ 2011-08-20 19:33 UTC (permalink / raw)
To: linux-sh; +Cc: Linux PM mailing list, LKML, Magnus Damm
In-Reply-To: <201108202131.19479.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Since sci_port_enable() and sci_port_disable() may be run with
interrupts off and they execute pm_runtime_get_sync() and
pm_runtime_put_sync(), respectively, the SCI device's
power.irq_safe flags has to be used to indicate that it is safe
to execute runtime PM callbacks for this device with interrupts off.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/tty/serial/sh-sci.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
Index: linux/drivers/tty/serial/sh-sci.c
=================================--- linux.orig/drivers/tty/serial/sh-sci.c
+++ linux/drivers/tty/serial/sh-sci.c
@@ -1582,11 +1582,15 @@ static int sci_startup(struct uart_port
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ pm_runtime_irq_safe(port->dev);
+
sci_port_enable(s);
ret = sci_request_irq(s);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ pm_runtime_irq_unsafe(port->dev);
return ret;
+ }
sci_request_dma(port);
@@ -1609,6 +1613,8 @@ static void sci_shutdown(struct uart_por
sci_free_irq(s);
sci_port_disable(s);
+
+ pm_runtime_irq_unsafe(port->dev);
}
static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
^ permalink raw reply
* Re: [PATCH 4/4] ARM: shmobile: ag5evm, ap4: Make use of irq index
From: Simon Horman @ 2011-08-21 0:03 UTC (permalink / raw)
To: Guennadi Liakhovetski
Cc: Magnus Damm, linux-mmc, linux-sh, Chris Ball, Paul Mundt
In-Reply-To: <Pine.LNX.4.64.1108190945270.11363@axis700.grange>
On Fri, Aug 19, 2011 at 09:52:17AM +0200, Guennadi Liakhovetski wrote:
> On Fri, 19 Aug 2011, Simon Horman wrote:
>
> > On Fri, Aug 19, 2011 at 03:51:49PM +0900, Magnus Damm wrote:
> > > On Fri, Aug 19, 2011 at 3:39 PM, Simon Horman <horms@verge.net.au> wrote:
>
> [snip]
>
> > > > As we are already on the slippery slope of allowing combinations
> > > > other than 1 (legacy) or 3 (specific) IRQ sources I plan to implement
> > > > a variant of your flag idea. The variation being to use names instead
> > > > because a) that allows the use of platform_get_irq_byname() and b)
> > > > the flags bits seem to be full and not driver-specific.
> > >
> > > Great, platform_get_irq_byname() seems like a perfect match.
> > >
> > > May I suggest "hotplug", "data" and "sdio" as names? I don't care very
> > > much about names except keeping them short and precise to prevent
> > > errors that can only be caught during runtime.
> >
> > Earlier on in the life of this series Guennadi suggested
> > the names "card_detect", "sdcard" and "sdio". While I am
> > not particularly attached to those names the do seem
> > reasonable and are already used consistently by this series.
> > So I would prefer to use those names.
>
> Just one more thing I forgot to mention in the previous mail: using names
> also makes the transition simple: first patch all platforms with names (at
> least those with multiple IRQs, if your legacy fallback implementation
> will accept unnamed IRQs), and then patch sh_mobile_sdhi.c
Yes, I agree that is a nice feature of using names.
^ permalink raw reply
* Re: [linux-pm] [PATCH 1/2] PM / Runtime: Introduce pm_runtime_irq_unsafe()
From: Alan Stern @ 2011-08-21 14:55 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linux-sh, Linux PM mailing list, LKML
In-Reply-To: <201108202132.13304.rjw@sisk.pl>
On Sat, 20 Aug 2011, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> Add a helper function allowing drivers and subsystems to clear
> the power.irq_safe device flag.
> --- linux.orig/drivers/base/power/runtime.c
> +++ linux/drivers/base/power/runtime.c
> @@ -1109,22 +1109,23 @@ void pm_runtime_no_callbacks(struct devi
> EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
>
> /**
> - * pm_runtime_irq_safe - Leave interrupts disabled during callbacks.
> + * __pm_runtime_irq_safe - Manipulate a device's power.irq_safe flag.
> * @dev: Device to handle
> + * @irq_safe: Whether or not to leave interrupts disabled during callbacks.
> *
> - * Set the power.irq_safe flag, which tells the PM core that the
> + * Set or unset the power.irq_safe flag, which tells the PM core that the
> * ->runtime_suspend() and ->runtime_resume() callbacks for this device should
> * always be invoked with the spinlock held and interrupts disabled. It also
> * causes the parent's usage counter to be permanently incremented, preventing
> * the parent from runtime suspending -- otherwise an irq-safe child might have
> * to wait for a non-irq-safe parent.
> */
> -void pm_runtime_irq_safe(struct device *dev)
> +void __pm_runtime_irq_safe(struct device *dev, bool irq_safe)
> {
> if (dev->parent)
> pm_runtime_get_sync(dev->parent);
> spin_lock_irq(&dev->power.lock);
> - dev->power.irq_safe = 1;
> + dev->power.irq_safe = irq_safe;
> spin_unlock_irq(&dev->power.lock);
It's not quite this easy. There are two important aspects that must be
considered.
Firstly, I originally envisioned pm_runtime_irq_safe() being called
just once, before the device is enabled for runtime PM. If you allow
the flag to be turned on and off like this, you raise the possibility
of races with runtime PM callbacks. (That is, if a callback occurs at
about the same time as the irq_safe flag is changed, nobody can predict
whether the callback will be invoked with interrupts enabled.) Maybe
that's something the driver needs to take care of, but it should at
least be mentioned in the documentation.
Secondly, this doesn't manage the parent's usage counter correctly.
Do the pm_runtime_get_sync(dev->parent) at the beginning only when the
irq_safe flag was off and is being turned on. And at the end, if the
irq_safe flag was on and is being turned off, do
pm_runtime_put_sync(dev->parent). See pm_runtime_remove() for why this
matters. (Also update the documentation; the change to the parent
isn't necessarily permanent any more.)
Alan Stern
^ permalink raw reply
* INVITATION TO TENDER, PLEASE SEE THE ATTACHED PDF FILE AND GET BACK TO US
From: Dr. Raphael Donkor (DONKOR TRADING) @ 2011-08-21 15:16 UTC (permalink / raw)
To: linux-sctp
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: INVITATION TO TENDER.pdf --]
[-- Type: application/pdf, Size: 35795 bytes --]
^ permalink raw reply
* Re: [linux-pm] [PATCH 1/2] PM / Runtime: Introduce pm_runtime_irq_unsafe()
From: Rafael J. Wysocki @ 2011-08-21 18:09 UTC (permalink / raw)
To: Alan Stern; +Cc: linux-sh, Linux PM mailing list, LKML
In-Reply-To: <Pine.LNX.4.44L0.1108211048060.12143-100000@netrider.rowland.org>
On Sunday, August 21, 2011, Alan Stern wrote:
> On Sat, 20 Aug 2011, Rafael J. Wysocki wrote:
>
> > From: Rafael J. Wysocki <rjw@sisk.pl>
> >
> > Add a helper function allowing drivers and subsystems to clear
> > the power.irq_safe device flag.
>
> > --- linux.orig/drivers/base/power/runtime.c
> > +++ linux/drivers/base/power/runtime.c
> > @@ -1109,22 +1109,23 @@ void pm_runtime_no_callbacks(struct devi
> > EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
> >
> > /**
> > - * pm_runtime_irq_safe - Leave interrupts disabled during callbacks.
> > + * __pm_runtime_irq_safe - Manipulate a device's power.irq_safe flag.
> > * @dev: Device to handle
> > + * @irq_safe: Whether or not to leave interrupts disabled during callbacks.
> > *
> > - * Set the power.irq_safe flag, which tells the PM core that the
> > + * Set or unset the power.irq_safe flag, which tells the PM core that the
> > * ->runtime_suspend() and ->runtime_resume() callbacks for this device should
> > * always be invoked with the spinlock held and interrupts disabled. It also
> > * causes the parent's usage counter to be permanently incremented, preventing
> > * the parent from runtime suspending -- otherwise an irq-safe child might have
> > * to wait for a non-irq-safe parent.
> > */
> > -void pm_runtime_irq_safe(struct device *dev)
> > +void __pm_runtime_irq_safe(struct device *dev, bool irq_safe)
> > {
> > if (dev->parent)
> > pm_runtime_get_sync(dev->parent);
> > spin_lock_irq(&dev->power.lock);
> > - dev->power.irq_safe = 1;
> > + dev->power.irq_safe = irq_safe;
> > spin_unlock_irq(&dev->power.lock);
>
> It's not quite this easy. There are two important aspects that must be
> considered.
>
> Firstly, I originally envisioned pm_runtime_irq_safe() being called
> just once, before the device is enabled for runtime PM. If you allow
> the flag to be turned on and off like this, you raise the possibility
> of races with runtime PM callbacks. (That is, if a callback occurs at
> about the same time as the irq_safe flag is changed, nobody can predict
> whether the callback will be invoked with interrupts enabled.) Maybe
> that's something the driver needs to take care of, but it should at
> least be mentioned in the documentation.
Good point. Perhaps I should make it possible only if runtime PM is
disabled.
> Secondly, this doesn't manage the parent's usage counter correctly.
Right, I forgot about that.
> Do the pm_runtime_get_sync(dev->parent) at the beginning only when the
> irq_safe flag was off and is being turned on. And at the end, if the
> irq_safe flag was on and is being turned off, do
> pm_runtime_put_sync(dev->parent). See pm_runtime_remove() for why this
> matters. (Also update the documentation; the change to the parent
> isn't necessarily permanent any more.)
I'll try to figure out an alternative approach without the $subject change
first. If I can't, I'll revisit this idea.
Thanks,
Rafael
^ permalink raw reply
* [PATCH 0/2 v2] sh-sci / PM: Fix problem with runtime PM callbacks run with interrupts off
From: Rafael J. Wysocki @ 2011-08-21 19:09 UTC (permalink / raw)
To: linux-sh; +Cc: Linux PM mailing list, LKML, Magnus Damm, Alan Stern
In-Reply-To: <201108202131.19479.rjw@sisk.pl>
Hi,
> The sh-sci driver uses pm_runtime_get/put_sync() in such a way
> that they may be run with interrupts off and cause the (recently
> added) might_sleep_if() to trigger in rpm_suspend/resume().
>
> To avoid that, it's necessary to set the SCI device's power.irq_safe
> flag to indicate that it's runtime PM callbacks may be executed with
> interrupts off safely. However, the sh-sci driver needs to be able to
> clear that flag sometimes, so a new runtime PM helper for doing that
> is needed.
The previous version of this patchset was not very good as Alan pointed out,
so hopefully this one will be better.
[1/2] - Change PM subsys_data lock type into spinlock.
[2/2] - Make sh-sci use power.irq_safe to indicate that runtime PM callbacks
may be run with interrupts off.
Thanks,
Rafael
^ permalink raw reply
* [PATCH 1/2 v2] PM: Change PM subsys_data lock type into spinlock
From: Rafael J. Wysocki @ 2011-08-21 19:10 UTC (permalink / raw)
To: linux-sh; +Cc: Linux PM mailing list, LKML, Magnus Damm, Alan Stern
In-Reply-To: <201108212109.30399.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
The lock member of struct pm_subsys_data is of type struct mutex,
which is a problem, because the suspend and resume routines
defined in drivers/base/power/clock_ops.c cannot be executed
with interrupts disabled for this reason. Modify
struct pm_subsys_data so that its lock member is a spinlock.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/clock_ops.c | 35 +++++++++++++++++++++--------------
drivers/base/power/common.c | 2 +-
include/linux/pm.h | 2 +-
3 files changed, 23 insertions(+), 16 deletions(-)
Index: linux/include/linux/pm.h
=================================--- linux.orig/include/linux/pm.h
+++ linux/include/linux/pm.h
@@ -438,7 +438,7 @@ struct pm_domain_data {
};
struct pm_subsys_data {
- struct mutex lock;
+ spinlock_t lock;
unsigned int refcount;
#ifdef CONFIG_PM_CLK
struct list_head clock_list;
Index: linux/drivers/base/power/clock_ops.c
=================================--- linux.orig/drivers/base/power/clock_ops.c
+++ linux/drivers/base/power/clock_ops.c
@@ -43,6 +43,7 @@ int pm_clk_add(struct device *dev, const
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
if (!psd)
return -EINVAL;
@@ -63,9 +64,9 @@ int pm_clk_add(struct device *dev, const
}
}
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_add_tail(&ce->node, &psd->clock_list);
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -109,11 +110,12 @@ void pm_clk_remove(struct device *dev, c
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
if (!psd)
return;
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry(ce, &psd->clock_list, node) {
if (!con_id && !ce->con_id) {
@@ -127,7 +129,7 @@ void pm_clk_remove(struct device *dev, c
}
}
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
}
/**
@@ -169,16 +171,17 @@ void pm_clk_destroy(struct device *dev)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce, *c;
+ unsigned long flags;
if (!psd)
return;
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
__pm_clk_remove(ce);
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
dev_pm_put_subsys_data(dev);
}
@@ -212,13 +215,14 @@ int pm_clk_suspend(struct device *dev)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
if (!psd)
return 0;
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry_reverse(ce, &psd->clock_list, node) {
if (ce->status = PCE_STATUS_NONE)
@@ -230,7 +234,7 @@ int pm_clk_suspend(struct device *dev)
}
}
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -243,13 +247,14 @@ int pm_clk_resume(struct device *dev)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
if (!psd)
return 0;
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry(ce, &psd->clock_list, node) {
if (ce->status = PCE_STATUS_NONE)
@@ -261,7 +266,7 @@ int pm_clk_resume(struct device *dev)
}
}
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -336,6 +341,7 @@ int pm_clk_suspend(struct device *dev)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
@@ -343,12 +349,12 @@ int pm_clk_suspend(struct device *dev)
if (!psd || !dev->driver)
return 0;
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry_reverse(ce, &psd->clock_list, node)
clk_disable(ce->clk);
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -361,6 +367,7 @@ int pm_clk_resume(struct device *dev)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
@@ -368,12 +375,12 @@ int pm_clk_resume(struct device *dev)
if (!psd || !dev->driver)
return 0;
- mutex_lock(&psd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
list_for_each_entry(ce, &psd->clock_list, node)
clk_enable(ce->clk);
- mutex_unlock(&psd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
Index: linux/drivers/base/power/common.c
=================================--- linux.orig/drivers/base/power/common.c
+++ linux/drivers/base/power/common.c
@@ -34,7 +34,7 @@ int dev_pm_get_subsys_data(struct device
if (dev->power.subsys_data) {
dev->power.subsys_data->refcount++;
} else {
- mutex_init(&psd->lock);
+ spin_lock_init(&psd->lock);
psd->refcount = 1;
dev->power.subsys_data = psd;
pm_clk_init(dev);
^ permalink raw reply
* [PATCH 2/2 v2] sh-sci / PM: Use power.irq_safe
From: Rafael J. Wysocki @ 2011-08-21 19:11 UTC (permalink / raw)
To: linux-sh; +Cc: Linux PM mailing list, LKML, Magnus Damm, Alan Stern
In-Reply-To: <201108212109.30399.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Since sci_port_enable() and sci_port_disable() may be run with
interrupts off and they execute pm_runtime_get_sync() and
pm_runtime_put_sync(), respectively, the SCI device's
power.irq_safe flags has to be used to indicate that it is safe
to execute runtime PM callbacks for this device with interrupts off.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/tty/serial/sh-sci.c | 1 +
1 file changed, 1 insertion(+)
Index: linux/drivers/tty/serial/sh-sci.c
=================================--- linux.orig/drivers/tty/serial/sh-sci.c
+++ linux/drivers/tty/serial/sh-sci.c
@@ -1913,6 +1913,7 @@ static int __devinit sci_init_single(str
port->dev = &dev->dev;
+ pm_runtime_irq_safe(&dev->dev);
pm_runtime_enable(&dev->dev);
}
^ permalink raw reply
* Re: LCDC problem after commit 794d78fea51504bad3880d14f354a9847f318f25
From: Damian Hobson-Garcia @ 2011-08-22 1:36 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <201108080125.34329.rjw@sisk.pl>
Hi Laurent,
On 2011/08/19 15:24, Laurent Pinchart wrote:
> Hi Damian,
>
> On Friday 12 August 2011 11:59:10 Laurent Pinchart wrote:
>> On Thursday 11 August 2011 21:37:04 Rafael J. Wysocki wrote:
>>> On Thursday, August 11, 2011, Laurent Pinchart wrote:
>>>> On Tuesday 09 August 2011 12:48:44 Magnus Damm wrote:
>>>>> On Mon, Aug 8, 2011 at 10:46 AM, Magnus Damm wrote:
>>>>>> On Mon, Aug 8, 2011 at 8:25 AM, Rafael J. Wysocki wrote:
>>>>>>> Unfortunately, after commit
>>>>>>> 794d78fea51504bad3880d14f354a9847f318f25 (drivers: sh: late
>>>>>>> disabling of clocks V2) the LCDC screen on my Mackerel board goes
>>>>>>> off (late) during boot and cannot be turned on by any way AFAICS
>>>>>>> (the backlight remains on, though).
>>>>>>>
>>>>>>> It looks like the late disabling of clocks interacts badly with
>>>>>>> the clock management done by PM domains.
>>>>>>
>>>>>> This is most likely showing a so-far-not-handled clock dependency
>>>>>> for the LCDC hardware. I'll have a look.
>>>>>
>>>>> Further investigation shows that this only triggers when the MERAM is
>>>>> enabled in the kernel configuration using
>>>>> CONFIG_FB_SH_MOBILE_MERAM=y. So this seems more related to MERAM
>>>>> power management than LCDC.
>>>>>
>>>>> Digging a bit deeper makes it clear that the sh_mobile_meram.c driver
>>>>> in upstream doesn't seem to include any Runtime PM code. I recall
>>>>> seeing various versions posted to the mailing list.
>>>>>
>>>>> Laurent [CC], can you please provide us with a list of outstanding
>>>>> LCDC/MERAM patches to make this work as expected? I realize there are
>>>>> quite a few outstanding LCDC patches, but if possible please provide
>>>>> a list of the bare minimum to make this work with 3.1-rc.
>>>>
>>>> I've pushed my pending patches to
>>>> http://git.linuxtv.org/pinchartl/fbdev.git in the pm-domains branch.
>>>> The first 19 patches have been picked from mailing lists. Hopefully
>>>> they're the latest versions that have been posted. The next 11 patches
>>>> shouldn't be required to enable runtime PM with the MERAM, but they
>>>> provide code cleanup and bug fixes.
>>>>
>>>> Are Rafael' and Damian's patches ready for mainline ? If so, when will
>>>> they be pulled ? They're more than one month old, I was expecting them
>>>> to hit v3.1- rc1. The backlog is growing, which makes collaboration
>>>> more difficult.
>>>
>>> Which of my patches are you referring to in particular?
>>
>> My bad, your patches are in v3.1-rc1. I had rebased my branch on top of the
>> wrong tag. We still need to push Damian's MERAM runtime PM patches, as well
>> as mine.
>
> Do you plan to push your MERAM runtime PM patches (available at
> http://git.linuxtv.org/pinchartl/fbdev.git/shortlog/refs/heads/pm-domains
> rebased on top of v3.1-rc2) ?
>
Sorry for my late reply. Yes the plan was to push the MERAM runtime
patches. I see that you've already included them in a PULL request, cc:d
to the list, so that's fine by me.
Thanks,
Damian
^ permalink raw reply
* Re: [PATCH 01/07] ARM: mach-shmobile: Kota2 SCIFA2 and SMSC911X support
From: Paul Mundt @ 2011-08-22 3:43 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <20110818054407.23410.98641.sendpatchset@rxone.opensource.se>
On Thu, Aug 18, 2011 at 02:44:07PM +0900, Magnus Damm wrote:
> +static void __init kota2_timer_init(void)
> +{
> + sh73a0_clock_init();
> + shmobile_timer.init();
> + return;
> +}
> +
Pointless return.
> --- 0001/arch/arm/mach-shmobile/platsmp.c
> +++ work/arch/arm/mach-shmobile/platsmp.c 2011-08-18 13:38:02.000000000 +0900
> @@ -21,9 +21,11 @@
> #include <asm/mach-types.h>
> #include <mach/common.h>
>
> +#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
> +
> static unsigned int __init shmobile_smp_get_core_count(void)
> {
> - if (machine_is_ag5evm())
> + if (is_sh73a0())
> return sh73a0_get_core_count();
>
> return 1;
No. If you want to do this then simply do what the other platforms are
doing and construct a cpu.h, then you can centrally define things and use
cpu_is_xxx() outright. Making CPU inferences from mach type is just
asking for trouble.
^ permalink raw reply
* [PATCH] ARM: mach-shmobile: AG5EVM/Kota2 external Ethernet fix
From: Magnus Damm @ 2011-08-22 5:45 UTC (permalink / raw)
To: linux-sh
From: Magnus Damm <damm@opensource.se>
Keep the ZB clock enabled on sh73a0 to allow the BSC
to access external peripherals hooked up to CS signals.
This is needed to unbreak Ethernet support on sh73a0 boards
such as AG5EVM and Kota2 together with the following patch:
794d78f drivers: sh: late disabling of clocks V2
Signed-off-by: Magnus Damm <damm@opensource.se>
---
arch/arm/mach-shmobile/clock-sh73a0.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- 0001/arch/arm/mach-shmobile/clock-sh73a0.c
+++ work/arch/arm/mach-shmobile/clock-sh73a0.c 2011-08-22 14:31:42.000000000 +0900
@@ -243,7 +243,7 @@ static struct clk div6_clks[DIV6_NR] = {
[DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0),
[DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0),
[DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0),
- [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, 0),
+ [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, CLK_ENABLE_ON_INIT),
[DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0),
[DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0),
[DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0),
^ 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