* Re: [PATCH] radeonfb: Let hwmon driver probe the "monid" I2C bus
From: Benjamin Herrenschmidt @ 2011-02-02 9:51 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <20110111162352.5a634e9e@endymion.delvare>
On Wed, 2011-02-02 at 09:12 +0100, Jean Delvare wrote:
> > If this is a concern to you, I'd be fine excluding CONFIG_PPC from
> the
> > change. Or are you worried about Intel Mac machines too? If there's
> an
> > easy way to spot all powermac machines, we can use that too, just
> let
> > me know how.
> >
> > > Haven't had a chance to look much yet.
>
> Ben, any progress on this?
Sorry, too swamped. Go on with CONFIG_PPC excluded for now.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH] radeonfb: Let hwmon driver probe the "monid" I2C bus
From: Michel Dänzer @ 2011-02-02 10:00 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <20110111162352.5a634e9e@endymion.delvare>
On Mit, 2011-02-02 at 07:50 +0200, Alexander Goomenyuk wrote:
>
> P.S. There is also strange side effect after reloading radeon driver
> from X console: the screen switch off. So I have to switch between
> virtual console and X. Is it an bug?
I think there's a bug where unloading the radeon kernel module without
KMS will interfere with the hardware state for the X driver. However,
you can only unload the radeon kernel module if the X driver uses
neither KMS nor DRI in general, which is undesirable in the first place.
So fixing this is low priority even as far as UMS bugs are concerned.
--
Earthling Michel Dänzer | http://www.vmware.com
Libre software enthusiast | Debian, X and DRI developer
^ permalink raw reply
* Re: [PATCH 0/2][concept RFC] x86: BIOS-save kernel log to disk
From: Ahmed S. Darwish @ 2011-02-02 11:13 UTC (permalink / raw)
To: Ingo Molnar, Eric W. Biederman
Cc: H. Peter Anvin, Vivek Goyal, Linus Torvalds, Thomas Gleixner,
Ingo Molnar, X86-ML, Tony Luck, Dave Jones, Andrew Morton,
Randy Dunlap, Willy Tarreau, Willy Tarreau, Dirk Hohndel,
Dirk.Hohndel, IDE-ML, LKML, Peter Zijlstra,
Frédéric Weisbecker, Borislav Petkov, Arjan van de Ven,
Tejun Heo, James Bottomley, Mark Lord, Jeff Garzik
In-Reply-To: <m1sjweyeax.fsf@fess.ebiederm.org>
Hi,
Quick note: the Internet has just returned back here after a full
5-day shutdown by the “authorities”. I will hopefully return back
home on Saturday to continue working on this.
thanks,
^ permalink raw reply
* [PATCH] ARM: PXA: Make PXA27x/PXA3xx overlay actually work
From: Vasily Khoruzhick @ 2011-02-02 20:46 UTC (permalink / raw)
To: linux-arm-kernel
From: "Russell King - ARM Linux" <linux@arm.linux.org.uk>
Release callback tries to free memory even if it was not allocated in
map_video_memory. Fix PXA27x/3xx overlay memory management and make overlay
actually work.
Added by Vasily Khoruzhick:
- Move overlay Z-ordering selection into main fb initialization,
otherwise plane ordering is wrong.
- Clear x_res/y_res fields of fb.var on release, to make sure
our callback will be called on next FBIOPUT_VSCREENINFO ioctl.
- Disable overlay only if it was enabled.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
drivers/video/pxafb.c | 86 ++++++++++++++++++++++++++++++------------------
drivers/video/pxafb.h | 2 +-
2 files changed, 55 insertions(+), 33 deletions(-)
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 825b665..33f607a 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -629,16 +629,19 @@ static void overlay1fb_disable(struct pxafb_layer *ofb)
{
uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
- lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN);
+ if (lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN) {
+ lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN);
- lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(1));
- lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(1));
- lcd_writel(ofb->fbi, FBR1, ofb->fbi->fdadr[DMA_OV1] | 0x3);
+ lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(1));
+ lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(1));
+ lcd_writel(ofb->fbi, FBR1, ofb->fbi->fdadr[DMA_OV1] | 0x3);
- if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) = 0)
- pr_warning("%s: timeout disabling overlay1\n", __func__);
+ if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) = 0)
+ pr_warning("%s: timeout disabling overlay1\n",
+ __func__);
- lcd_writel(ofb->fbi, LCCR5, lccr5);
+ lcd_writel(ofb->fbi, LCCR5, lccr5);
+ }
}
static void overlay2fb_setup(struct pxafb_layer *ofb)
@@ -687,16 +690,19 @@ static void overlay2fb_disable(struct pxafb_layer *ofb)
{
uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
- lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN);
+ if (lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN) {
+ lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN);
- lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(2));
- lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(2));
- lcd_writel(ofb->fbi, FBR2, ofb->fbi->fdadr[DMA_OV2_Y] | 0x3);
- lcd_writel(ofb->fbi, FBR3, ofb->fbi->fdadr[DMA_OV2_Cb] | 0x3);
- lcd_writel(ofb->fbi, FBR4, ofb->fbi->fdadr[DMA_OV2_Cr] | 0x3);
+ lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(2));
+ lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(2));
+ lcd_writel(ofb->fbi, FBR2, ofb->fbi->fdadr[DMA_OV2_Y] | 0x3);
+ lcd_writel(ofb->fbi, FBR3, ofb->fbi->fdadr[DMA_OV2_Cb] | 0x3);
+ lcd_writel(ofb->fbi, FBR4, ofb->fbi->fdadr[DMA_OV2_Cr] | 0x3);
- if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) = 0)
- pr_warning("%s: timeout disabling overlay2\n", __func__);
+ if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) = 0)
+ pr_warning("%s: timeout disabling overlay2\n",
+ __func__);
+ }
}
static struct pxafb_layer_ops ofb_ops[] = {
@@ -720,12 +726,10 @@ static int overlayfb_open(struct fb_info *info, int user)
if (user = 0)
return -ENODEV;
- /* allow only one user at a time */
- if (atomic_inc_and_test(&ofb->usage))
- return -EBUSY;
+ if (ofb->usage++ = 0)
+ /* unblank the base framebuffer */
+ fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
- /* unblank the base framebuffer */
- fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
return 0;
}
@@ -733,12 +737,24 @@ static int overlayfb_release(struct fb_info *info, int user)
{
struct pxafb_layer *ofb = (struct pxafb_layer*) info;
- atomic_dec(&ofb->usage);
- ofb->ops->disable(ofb);
-
- free_pages_exact(ofb->video_mem, ofb->video_mem_size);
- ofb->video_mem = NULL;
- ofb->video_mem_size = 0;
+ if (--ofb->usage = 0) {
+ ofb->ops->disable(ofb);
+ ofb->fb.var.height = -1;
+ ofb->fb.var.width = -1;
+ ofb->fb.var.xres = ofb->fb.var.xres_virtual = 0;
+ ofb->fb.var.yres = ofb->fb.var.yres_virtual = 0;
+
+ mutex_lock(&ofb->fb.mm_lock);
+ ofb->fb.fix.smem_start = 0;
+ ofb->fb.fix.smem_len = 0;
+ mutex_unlock(&ofb->fb.mm_lock);
+
+ if (ofb->video_mem) {
+ free_pages_exact(ofb->video_mem, ofb->video_mem_size);
+ ofb->video_mem = NULL;
+ ofb->video_mem_size = 0;
+ }
+ }
return 0;
}
@@ -817,7 +833,8 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
if (ofb->video_mem_size >= size)
return 0;
- free_pages_exact(ofb->video_mem, ofb->video_mem_size);
+ /* don't re-allocate: userspace may have the buffer mapped */
+ return -EINVAL;
}
ofb->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
@@ -891,7 +908,7 @@ static void __devinit init_pxafb_overlay(struct pxafb_info *fbi,
ofb->id = id;
ofb->ops = &ofb_ops[id];
- atomic_set(&ofb->usage, 0);
+ ofb->usage = 0;
ofb->fbi = fbi;
init_completion(&ofb->branch_done);
}
@@ -923,8 +940,6 @@ static int __devinit pxafb_overlay_init(struct pxafb_info *fbi)
/* mask all IU/BS/EOF/SOF interrupts */
lcd_writel(fbi, LCCR5, ~0);
- /* place overlay(s) on top of base */
- fbi->lccr0 |= LCCR0_OUC;
pr_info("PXA Overlay driver loaded successfully!\n");
return 0;
}
@@ -1368,7 +1383,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
(lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
(lcd_readl(fbi, LCCR4) != fbi->reg_lccr4) ||
(lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
- (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
+ ((fbi->lccr0 & LCCR0_SDS) &&
+ (lcd_readl(fbi, FDADR1) != fbi->fdadr[1])))
pxafb_schedule_work(fbi, C_REENABLE);
return 0;
@@ -1420,7 +1436,8 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
- lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
+ if (fbi->lccr0 & LCCR0_SDS)
+ lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
}
@@ -1806,6 +1823,11 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
pxafb_decode_mach_info(fbi, inf);
+#ifdef CONFIG_FB_PXA_OVERLAY
+ if (cpu_is_pxa27x())
+ fbi->lccr0 |= LCCR0_OUC;
+#endif
+
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, pxafb_task);
mutex_init(&fbi->ctrlr_lock);
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 2353521..84e3ae1 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -92,7 +92,7 @@ struct pxafb_layer_ops {
struct pxafb_layer {
struct fb_info fb;
int id;
- atomic_t usage;
+ uint32_t usage;
uint32_t control[2];
struct pxafb_layer_ops *ops;
--
1.7.4.rc1
^ permalink raw reply related
* Re: [PATCH] radeonfb: Let hwmon driver probe the "monid" I2C bus
From: Alexander Goomenyuk @ 2011-02-03 5:41 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <20110111162352.5a634e9e@endymion.delvare>
Thanks for fast reply.
> I'm sorry but I don't understand what you mean. For one thing, I can't
> see how the above change (?) is related to your problem, as it only
> affects the DDC channels and not the MONID channel. For another, I
> can't see how the bus being software or hardware driven would have any
> effect.
>
Sorry, that was my mistake (artifact left after experiments).
> But this isn't the way the drm radeon driver is designed. It reads
from
> the BIOS whether there are sensors available, what is their type and
> their address, etc. It does not rely on physical probing as the
> radeonfb driver does. So the above is NOT correct.
>
> I can imagine that sensor support has only been implemented for
> atom-BIOS based boards and not older com-BIOS based ones. At least
> searching for "lm63" in the source code has matches in only
> radeon_atombios.c and not radeon_combios.c. I have no idea if it would
> be possible to extend this mechanism to older boards or not - I don't
> know if the com-BIOS included the information already.
>
I would like to make some clarifications:
The intention was to check how new radeon is working, or not working :),
with thermal sensors. I am not competent enough to introduce any fixes
to radeon driver.
The question is: Should I file the bug for radeon driver to implement
thermal sensor support for com-BIOS based cards or not?
On Wed, 2011-02-02 at 09:11 +0100, Jean Delvare wrote:
> Alexander,
>
> On Wed, 02 Feb 2011 07:50:16 +0200, Alexander Goomenyuk wrote:
> > On Thu, 2011-01-13 at 14:44 +1000, Dave Airlie wrote:
> > > On Thu, Jan 13, 2011 at 2:11 PM, Paul Mundt <lethal@linux-sh.org> wrote:
> > > > On Tue, Jan 11, 2011 at 04:23:52PM +0100, Jean Delvare wrote:
> > > >> Some Radeon cards have an I2C-based thermal sensor chip connected to
> > > >> the "monid" I2C bus. Set the I2C probing class of this bus properly so
> > > >> that hwmon drivers can detect devices on it and bind to them.
> > > >>
> > > >> This closes kernel.org bug #26172.
> > > >>
> > >
> > > The radeon BIOS actually contains a table to tell us what chip is on the bus,
> > > in the KMS driver we read this table and load the appropriate hwmon device,
> > >
> > > There could possibly be other things on this bus than hw monitor devices.
> > >
> > > Though radeonfb should be considered mostly dead.
> > >
> > > Dave.
> >
> > I have tried radeon KMS driver.
> > modinfo output:
> > filename: /lib/modules/2.6.36-tuxonice-r3/kernel/drivers/gpu/drm/radeon/radeon.ko
> > depends:
> > drm,drm_kms_helper,ttm,fb,i2c-core,cfbfillrect,cfbimgblt,cfbcopyarea,i2c-algo-bit
> > vermagic: 2.6.36-tuxonice-r3 SMP mod_unload 686
> > parm: no_wb:Disable AGP writeback for scratch
> > registers (int)
> > parm: modeset:Disable/Enable modesetting (int)
> > parm: dynclks:Disable/Enable dynamic clocks (int)
> > parm: r4xx_atom:Enable ATOMBIOS modesetting for R4xx
> > (int)
> > parm: vramlimit:Restrict VRAM for testing (int)
> > parm: agpmode:AGP Mode (-1 = PCI) (int)
> > parm: gartsize:Size of PCIE/IGP gart to setup in
> > megabytes (32,64, etc)
> > (int)
> > parm: benchmark:Run benchmark (int)
> > parm: test:Run tests (int)
> > parm: connector_table:Force connector table (int)
> > parm: tv:TV enable (0 = disable) (int)
> > parm: new_pll:Select new PLL code (int)
> > parm: audio:Audio enable (0 = disable) (int)
> > parm: disp_priority:Display Priority (0 = auto, 1 > > normal, 2 = high) (int)
> > parm: hw_i2c:hw i2c engine enable (0 = disable) (int)
> >
> > But it also need modifications in order to be used by lm63 hwmon driver.
> > 1. MONID line is disable by combios_setup_i2c_bus() for RV380 because
> > of:
> > case CHIP_RV350:
> > case CHIP_RV380:
> > case CHIP_RS400:
> > case CHIP_RS480:
> > switch (ddc_line) {
> > case RADEON_GPIO_VGA_DDC:
> > case RADEON_GPIO_DVI_DDC:
> > + i2c.hw_capable = true;
> > - i2c.hw_capable = false;
> > break;
> > case RADEON_GPIO_MONID:
> > /* hw i2c on RADEON_GPIO_MONID doesn't seem to work
> > * reliably on some pre-r4xx hardware; not sure why
> > */
> > i2c.hw_capable = true;
> > break;
> >
> > extracted from the sources.
> > It would be nice if there will be some driver parameter to control this
> > behavior. Or/and control it in kernel configuration menu.
>
> I'm sorry but I don't understand what you mean. For one thing, I can't
> see how the above change (?) is related to your problem, as it only
> affects the DDC channels and not the MONID channel. For another, I
> can't see how the bus being software or hardware driven would have any
> effect.
>
> >
> > 2. MONID adapter is not registered as HWMON capable.
> > So I have added the following line into radeon_combios_i2c_init():
> >
> > } else if (rdev->family >= CHIP_R300) {
> > i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
> > rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
> > + rdev->i2c_bus[3]->adapter.class = I2C_CLASS_HWMON;
> >
> > Now I see GPU temperature using lm_sensors.
>
> But this isn't the way the drm radeon driver is designed. It reads from
> the BIOS whether there are sensors available, what is their type and
> their address, etc. It does not rely on physical probing as the
> radeonfb driver does. So the above is NOT correct.
>
> I can imagine that sensor support has only been implemented for
> atom-BIOS based boards and not older com-BIOS based ones. At least
> searching for "lm63" in the source code has matches in only
> radeon_atombios.c and not radeon_combios.c. I have no idea if it would
> be possible to extend this mechanism to older boards or not - I don't
> know if the com-BIOS included the information already.
>
^ permalink raw reply
* Re: [PATCH] radeonfb: Let hwmon driver probe the "monid" I2C bus
From: Jean Delvare @ 2011-02-03 8:04 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <20110111162352.5a634e9e@endymion.delvare>
On Thu, 03 Feb 2011 07:41:01 +0200, Alexander Goomenyuk wrote:
> > I can imagine that sensor support has only been implemented for
> > atom-BIOS based boards and not older com-BIOS based ones. At least
> > searching for "lm63" in the source code has matches in only
> > radeon_atombios.c and not radeon_combios.c. I have no idea if it would
> > be possible to extend this mechanism to older boards or not - I don't
> > know if the com-BIOS included the information already.
>
> I would like to make some clarifications:
> The intention was to check how new radeon is working, or not working :),
> with thermal sensors. I am not competent enough to introduce any fixes
> to radeon driver.
And neither am I.
> The question is: Should I file the bug for radeon driver to implement
> thermal sensor support for com-BIOS based cards or not?
This would obviously be a feature request rather than a bug report.
I don't know if the com-BIOS based cards have the thermal sensor
information in the first place, so I don't know if the feature can be
implemented. If they don't, then auto-detection is the way to go, and
we can do it ourselves. If they do, the radeon driver maintainers would
have to work on it, if they are able and willing to do so.
So the next step is the radeon driver maintainers telling us whether
com-BIOS based cards have thermal sensor information as atom-BIOS based
ones do. You should ask this question to the right people and list.
--
Jean Delvare
^ permalink raw reply
* [PATCH v2] radeonfb: Let hwmon driver probe the "monid" I2C bus
From: Jean Delvare @ 2011-02-03 8:23 UTC (permalink / raw)
To: linux-fbdev
Some Radeon cards have an I2C-based thermal sensor chip connected to
the "monid" I2C bus. Set the I2C probing class of this bus properly so
that hwmon drivers can detect devices on it and bind to them.
This closes kernel.org bug #26172.
We exclude PPC for the time being, as Benjamin doesn't want us to
mess up with them without explicit testing, and there is no evidence
that this change is needed for them either.
Reported-by: Alexander Goomenyuk <emerg.reanimator@gmail.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Changes since v1:
* Excluded CONFIG_PPC as requested by Benjamin H.
drivers/video/aty/radeon_i2c.c | 3 +++
1 file changed, 3 insertions(+)
--- linux-2.6.38-rc3.orig/drivers/video/aty/radeon_i2c.c 2011-02-03 08:42:36.000000000 +0100
+++ linux-2.6.38-rc3/drivers/video/aty/radeon_i2c.c 2011-02-03 09:13:41.000000000 +0100
@@ -100,6 +100,9 @@ void radeon_create_i2c_busses(struct rad
{
rinfo->i2c[0].rinfo = rinfo;
rinfo->i2c[0].ddc_reg = GPIO_MONID;
+#ifndef CONFIG_PPC
+ rinfo->i2c[0].adapter.class = I2C_CLASS_HWMON;
+#endif
radeon_setup_i2c_bus(&rinfo->i2c[0], "monid");
rinfo->i2c[1].rinfo = rinfo;
--
Jean Delvare
^ permalink raw reply
* Re: [PATCH] uvesafb,vesafb: create write-combining or write-back PAT entries
From: Thomas Schlichter @ 2011-02-06 11:02 UTC (permalink / raw)
To: Paul Mundt; +Cc: Michal Januszewski, linux-fbdev, linux-kernel
In-Reply-To: <20101130061051.GD17114@linux-sh.org>
[-- Attachment #1: Type: Text/Plain, Size: 1705 bytes --]
Sorry for answering this late, unfortunately I was quite busy with my daily
work...
Am Dienstag 30 November 2010, um 07:10:51 schrieb Paul Mundt:
> uvesafb presently has no special architecture dependencies, but
> ioremap_wc() is not as of yet a wholly generic interface. Some
> architectures that don't set ARCH_HAS_IOREMAP_WC get it by virtue of the
> asm-generic/iomap.h include, and most of the nommu architectures will
> stub it in via asm-generic/io.h, but this still leaves quite a long list
> of platforms that don't handle it at all.
>
> Your options at this point are either to establish ioremap_wc() as a
> generic API, and layer this patch on top of that, or rework
> uvesafb_init_mtrr() to do the actual broken-out remapping and rework it
> in to something like a uvesafb_remap(), where you bury the MTRR details
> under CONFIG_MTRR.
>
> While there's probably value in exposing ioremap_wc() as a generic
> interface, you're never going to hit any of the non-default ioremap()
> calls on platforms lacking MTRRs anyways, so special-casing it is ok.
Thank you for finding that problem and showing possibilities for fixing it. I
prepared 3 patches, where the first essentially is my old patch with special-
casing via ifdef CONFIG_X86. The second patch establishes ioremap_cache() and
ioremap_wc() for all architectures, and the third patch removed the special-
casing from uvesafb.
So the first patch can stand on its own and hopefully can be merged upstream.
The third patch needs the second one, which may be merged for unifying
purposes. But as these are mor cleanup-patches, they are not that important
for me.
Best regards,
Thomas Schlichter
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [PATCH 1/3] uvesafb,vesafb: create WC or WB PAT entries
From: Thomas Schlichter @ 2011-02-06 11:11 UTC (permalink / raw)
To: Paul Mundt; +Cc: Michal Januszewski, linux-fbdev, linux-kernel
In-Reply-To: <201102061202.09503.thomas.schlichter@web.de>
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: 0001-uvesafb-vesafb-create-WC-or-WB-PAT-entries.patch --]
[-- Type: text/x-patch, Size: 9661 bytes --]
From 7172689eb500a7ab7090e8539f88d382fc686336 Mon Sep 17 00:00:00 2001
From: Thomas Schlichter <thomas.schlichter@web.de>
Date: Sat, 27 Nov 2010 14:17:55 +0100
Subject: [PATCH 1/3] uvesafb,vesafb: create WC or WB PAT-entries
with an PAT-enabled kernel, when using uvesafb or vesafb, these drivers will
create uncached-minus PAT entries for the framebuffer memory because they use
ioremap() (not the *_cache or *_wc variants). When the framebuffer memory
intersects with the video RAM used by Xorg, the complete video RAM will be
mapped uncached-minus what results in a serve performance penalty.
Here are the correct MTRR entries created by uvesafb:
schlicht@netbook:~$ cat /proc/mtrr
reg00: base=0x000000000 ( 0MB), size= 2048MB, count=1: write-back
reg01: base=0x06ff00000 ( 1791MB), size= 1MB, count=1: uncachable
reg02: base=0x070000000 ( 1792MB), size= 256MB, count=1: uncachable
reg03: base=0x0d0000000 ( 3328MB), size= 16MB, count=1: write-combining
And here are the problematic PAT entries:
schlicht@netbook:~$ sudo cat /sys/kernel/debug/x86/pat_memtype_list
PAT memtype list:
write-back @ 0x0-0x1000
uncached-minus @ 0x6fedd000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee3000-0x6fee4000
uncached-minus @ 0x6fee3000-0x6fee4000
uncached-minus @ 0x6fee3000-0x6fee4000
uncached-minus @ 0xd0000000-0xe0000000 <-- created by xserver-xorg
uncached-minus @ 0xd0000000-0xd1194000 <-- created by uvesafb
uncached-minus @ 0xf4000000-0xf4009000
uncached-minus @ 0xf4200000-0xf4400000
uncached-minus @ 0xf5000000-0xf5010000
uncached-minus @ 0xf5100000-0xf5104000
uncached-minus @ 0xf5400000-0xf5404000
uncached-minus @ 0xf5404000-0xf5405000
uncached-minus @ 0xf5404000-0xf5405000
uncached-minus @ 0xfed00000-0xfed01000
Therefore I created the attached patch for uvesafb which uses ioremap_wc() to
create the correct PAT entries, as shown below:
schlicht@netbook:~$ sudo cat /sys/kernel/debug/x86/pat_memtype_list
PAT memtype list:
write-back @ 0x0-0x1000
uncached-minus @ 0x6fedd000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee2000-0x6fee3000
uncached-minus @ 0x6fee3000-0x6fee4000
uncached-minus @ 0x6fee3000-0x6fee4000
uncached-minus @ 0x6fee3000-0x6fee4000
write-combining @ 0xd0000000-0xe0000000
write-combining @ 0xd0000000-0xd1194000
uncached-minus @ 0xf4000000-0xf4009000
uncached-minus @ 0xf4200000-0xf4400000
uncached-minus @ 0xf5000000-0xf5010000
uncached-minus @ 0xf5100000-0xf5104000
uncached-minus @ 0xf5400000-0xf5404000
uncached-minus @ 0xf5404000-0xf5405000
uncached-minus @ 0xf5404000-0xf5405000
uncached-minus @ 0xfed00000-0xfed01000
This results in a performance gain, objectively measurable with e.g.
x11perf -comppixwin10 -comppixwin100 -comppixwin500:
1: x11perf_xaa.log
2: x11perf_xaa_patched.log
1 2 Operation
-------- ---------------- -----------------
124000.0 202000.0 ( 1.63) Composite 10x10 from pixmap to window
3340.0 24400.0 ( 7.31) Composite 100x100 from pixmap to window
131.0 1150.0 ( 8.78) Composite 500x500 from pixmap to window
You can see the serve performance gain when composing larger pixmaps to window.
The patches replace the ioremap() function with the variant matching the mtrr-
parameter. To create "write-back" PAT entries, the ioremap_cache() function
must be called after creating the MTRR entries, and the ioremap_cache() region
must completely fit into the MTRR region, this is why the MTRR region size is
now rounded up to the next power-of-two.
Signed-off-by: Thomas Schlichter <thomas.schlichter@web.de>
---
drivers/video/uvesafb.c | 49 +++++++++++++++++++++++++++++++++-------------
drivers/video/vesafb.c | 44 +++++++++++++++++++++++++++--------------
2 files changed, 64 insertions(+), 29 deletions(-)
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 52ec095..2d6f799 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -1552,8 +1552,7 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
int rc;
/* Find the largest power-of-two */
- while (temp_size & (temp_size - 1))
- temp_size &= (temp_size - 1);
+ temp_size = roundup_pow_of_two(temp_size);
/* Try and find a power of two to add */
do {
@@ -1566,6 +1565,28 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
#endif /* CONFIG_MTRR */
}
+static void __devinit uvesafb_ioremap(struct fb_info *info)
+{
+#ifdef CONFIG_X86
+ switch (mtrr) {
+ case 1: /* uncachable */
+ info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
+ break;
+ case 2: /* write-back */
+ info->screen_base = ioremap_cache(info->fix.smem_start, info->fix.smem_len);
+ break;
+ case 3: /* write-combining */
+ info->screen_base = ioremap_wc(info->fix.smem_start, info->fix.smem_len);
+ break;
+ case 4: /* write-through */
+ default:
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+ break;
+ }
+#else
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+#endif /* CONFIG_X86 */
+}
static ssize_t uvesafb_show_vbe_ver(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1736,15 +1757,22 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
uvesafb_init_info(info, mode);
+ if (!request_region(0x3c0, 32, "uvesafb")) {
+ printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
+ err = -EIO;
+ goto out_mode;
+ }
+
if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
"uvesafb")) {
printk(KERN_ERR "uvesafb: cannot reserve video memory at "
"0x%lx\n", info->fix.smem_start);
err = -EIO;
- goto out_mode;
+ goto out_reg;
}
- info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+ uvesafb_init_mtrr(info);
+ uvesafb_ioremap(info);
if (!info->screen_base) {
printk(KERN_ERR
@@ -1755,20 +1783,13 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
goto out_mem;
}
- if (!request_region(0x3c0, 32, "uvesafb")) {
- printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
- err = -EIO;
- goto out_unmap;
- }
-
- uvesafb_init_mtrr(info);
platform_set_drvdata(dev, info);
if (register_framebuffer(info) < 0) {
printk(KERN_ERR
"uvesafb: failed to register framebuffer device\n");
err = -EINVAL;
- goto out_reg;
+ goto out_unmap;
}
printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
@@ -1785,12 +1806,12 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
return 0;
-out_reg:
- release_region(0x3c0, 32);
out_unmap:
iounmap(info->screen_base);
out_mem:
release_mem_region(info->fix.smem_start, info->fix.smem_len);
+out_reg:
+ release_region(0x3c0, 32);
out_mode:
if (!list_empty(&info->modelist))
fb_destroy_modelist(&info->modelist);
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 6a069d0..a99bbe8 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -303,19 +303,6 @@ static int __init vesafb_probe(struct platform_device *dev)
info->apertures->ranges[0].base = screen_info.lfb_base;
info->apertures->ranges[0].size = size_total;
- info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
- if (!info->screen_base) {
- printk(KERN_ERR
- "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
- vesafb_fix.smem_len, vesafb_fix.smem_start);
- err = -EIO;
- goto err;
- }
-
- printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, "
- "using %dk, total %dk\n",
- vesafb_fix.smem_start, info->screen_base,
- size_remap/1024, size_total/1024);
printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
@@ -438,8 +425,7 @@ static int __init vesafb_probe(struct platform_device *dev)
int rc;
/* Find the largest power-of-two */
- while (temp_size & (temp_size - 1))
- temp_size &= (temp_size - 1);
+ temp_size = roundup_pow_of_two(temp_size);
/* Try and find a power of two to add */
do {
@@ -451,6 +437,34 @@ static int __init vesafb_probe(struct platform_device *dev)
}
#endif
+ switch (mtrr) {
+ case 1: /* uncachable */
+ info->screen_base = ioremap_nocache(vesafb_fix.smem_start, vesafb_fix.smem_len);
+ break;
+ case 2: /* write-back */
+ info->screen_base = ioremap_cache(vesafb_fix.smem_start, vesafb_fix.smem_len);
+ break;
+ case 3: /* write-combining */
+ info->screen_base = ioremap_wc(vesafb_fix.smem_start, vesafb_fix.smem_len);
+ break;
+ case 4: /* write-through */
+ default:
+ info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
+ break;
+ }
+ if (!info->screen_base) {
+ printk(KERN_ERR
+ "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+ vesafb_fix.smem_len, vesafb_fix.smem_start);
+ err = -EIO;
+ goto err;
+ }
+
+ printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, "
+ "using %dk, total %dk\n",
+ vesafb_fix.smem_start, info->screen_base,
+ size_remap/1024, size_total/1024);
+
info->fbops = &vesafb_ops;
info->var = vesafb_defined;
info->fix = vesafb_fix;
--
1.7.1
^ permalink raw reply related
* [PATCH 2/3] Add ioremap_cache and ioremap_wc to all architectures
From: Thomas Schlichter @ 2011-02-06 11:12 UTC (permalink / raw)
To: Paul Mundt; +Cc: Michal Januszewski, linux-fbdev, linux-kernel
In-Reply-To: <201102061202.09503.thomas.schlichter@web.de>
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: 0002-Add-ioremap_cache-and-ioremap_wc-to-all-architecture.patch --]
[-- Type: text/x-patch, Size: 15246 bytes --]
From 194ea8d7dc39c1587d0e38d2571775e73949953b Mon Sep 17 00:00:00 2001
From: Thomas Schlichter <thomas.schlichter@web.de>
Date: Sat, 5 Feb 2011 15:07:41 +0100
Subject: [PATCH 2/3] Add ioremap_cache and ioremap_wc to all architectures
Establish ioremap_cache() and ioremap_wc() to be available besides
ioremap() and ioremap_nocache() on all architectures. This allows
generic drivers to use them without any ifdef-cludge.
Signed-off-by: Thomas Schlichter <thomas.schlichter@web.de>
---
arch/alpha/include/asm/io.h | 3 +++
arch/arm/include/asm/io.h | 2 +-
arch/arm/mm/mmu.c | 2 +-
arch/avr32/include/asm/io.h | 6 ++++++
arch/cris/include/asm/io.h | 3 +++
arch/frv/include/asm/io.h | 1 +
arch/h8300/include/asm/io.h | 3 +++
arch/ia64/include/asm/io.h | 1 +
arch/m32r/include/asm/io.h | 2 ++
arch/m68k/include/asm/io_mm.h | 3 +++
arch/m68k/include/asm/io_no.h | 3 +++
arch/microblaze/include/asm/io.h | 4 ++++
arch/mips/include/asm/io.h | 6 ++++--
arch/mn10300/include/asm/io.h | 1 +
arch/parisc/include/asm/io.h | 2 ++
arch/powerpc/include/asm/io.h | 2 ++
arch/sh/include/asm/io.h | 1 +
arch/sparc/include/asm/io_32.h | 1 +
arch/sparc/include/asm/io_64.h | 1 +
arch/tile/include/asm/io.h | 2 ++
arch/x86/include/asm/io.h | 2 --
arch/xtensa/include/asm/io.h | 3 +++
drivers/mtd/maps/pxa2xx-flash.c | 2 +-
include/asm-generic/io.h | 4 ++++
include/asm-generic/iomap.h | 4 ----
25 files changed, 53 insertions(+), 11 deletions(-)
diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h
index 56ff965..beb17bc 100644
--- a/arch/alpha/include/asm/io.h
+++ b/arch/alpha/include/asm/io.h
@@ -300,6 +300,9 @@ static inline void __iomem * ioremap_nocache(unsigned long offset,
return ioremap(offset, size);
}
+#define ioremap_cache ioremap
+#define ioremap_wc ioremap_nocache
+
static inline void iounmap(volatile void __iomem *addr)
{
IO_CONCAT(__IO_PREFIX,iounmap)(addr);
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index d66605d..adb0e46 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -248,7 +248,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
-#define ioremap_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
+#define ioremap_cache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap __arch_iounmap
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 3c67e92..d4bf66b 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -208,7 +208,7 @@ static struct mem_type mem_types[] = {
.prot_sect = PROT_SECT_DEVICE,
.domain = DOMAIN_IO,
},
- [MT_DEVICE_CACHED] = { /* ioremap_cached */
+ [MT_DEVICE_CACHED] = { /* ioremap_cache */
.prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED,
.prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB,
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index 22c97ef..35095c4 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -287,6 +287,12 @@ extern void __iounmap(void __iomem *addr);
#define ioremap_nocache(offset, size) \
__ioremap((offset), (size), 0)
+#define ioremap_cache(offset, size) \
+ __ioremap((offset), (size), 0)
+
+#define ioremap_wc(offset, size) \
+ __ioremap((offset), (size), 0)
+
#define iounmap(addr) \
__iounmap(addr)
diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h
index 32567bc..9dad86e 100644
--- a/arch/cris/include/asm/io.h
+++ b/arch/cris/include/asm/io.h
@@ -45,6 +45,9 @@ extern void iounmap(volatile void * __iomem addr);
extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
+#define ioremap_cache ioremap
+#define ioremap_wc ioremap_nocache
+
/*
* IO bus memory addresses are also 1:1 with the physical address
*/
diff --git a/arch/frv/include/asm/io.h b/arch/frv/include/asm/io.h
index ca7475e..44d0adf 100644
--- a/arch/frv/include/asm/io.h
+++ b/arch/frv/include/asm/io.h
@@ -271,6 +271,7 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr, unsigned l
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
+#define ioremap_cache ioremap_fullcache
#define ioremap_wc ioremap_nocache
extern void iounmap(void volatile __iomem *addr);
diff --git a/arch/h8300/include/asm/io.h b/arch/h8300/include/asm/io.h
index c1a8df2..f5e6aec 100644
--- a/arch/h8300/include/asm/io.h
+++ b/arch/h8300/include/asm/io.h
@@ -262,6 +262,9 @@ static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
+#define ioremap_cache ioremap_fullcache
+#define ioremap_wc ioremap_nocache
+
extern void iounmap(void *addr);
/* H8/300 internal I/O functions */
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h
index e5a6c35..9f9e156 100644
--- a/arch/ia64/include/asm/io.h
+++ b/arch/ia64/include/asm/io.h
@@ -431,6 +431,7 @@ static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned lo
return ioremap(phys_addr, size);
}
+#define ioremap_wc ioremap_nocache
/*
* String version of IO memory access ops:
diff --git a/arch/m32r/include/asm/io.h b/arch/m32r/include/asm/io.h
index 4010f1f..0a4a2a9 100644
--- a/arch/m32r/include/asm/io.h
+++ b/arch/m32r/include/asm/io.h
@@ -67,6 +67,8 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
extern void iounmap(volatile void __iomem *addr);
#define ioremap_nocache(off,size) ioremap(off,size)
+#define ioremap_cache(off,size) ioremap(off,size)
+#define ioremap_wc(off,size) ioremap(off,size)
/*
* IO bus memory addresses are also 1:1 with the physical address
diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h
index 0fb3468..603b973 100644
--- a/arch/m68k/include/asm/io_mm.h
+++ b/arch/m68k/include/asm/io_mm.h
@@ -299,6 +299,9 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr,
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
+#define ioremap_cache ioremap_fullcache
+#define ioremap_wc ioremap_nocache
+
static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
{
__builtin_memset((void __force *) addr, val, count);
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index cf20f30..ecfead4 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -163,6 +163,9 @@ static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
+#define ioremap_cache ioremap_fullcache
+#define ioremap_wc ioremap_nocache
+
extern void iounmap(void *addr);
/*
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index eae3222..9af2203 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -153,6 +153,8 @@ extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
#define ioremap_writethrough(addr, size) ioremap((addr), (size))
#define ioremap_nocache(addr, size) ioremap((addr), (size))
#define ioremap_fullcache(addr, size) ioremap((addr), (size))
+#define ioremap_cache(addr, size) ioremap((addr), (size))
+#define ioremap_wc(addr, size) ioremap((addr), (size))
#else /* CONFIG_MMU */
@@ -203,6 +205,8 @@ static inline void __iomem *__ioremap(phys_addr_t address, unsigned long size,
#define ioremap(physaddr, size) ((void __iomem *)(unsigned long)(physaddr))
#define iounmap(addr) ((void)0)
#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_cache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_wc(physaddr, size) ioremap(physaddr, size)
#endif /* CONFIG_MMU */
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 5b017f2..51dad4a 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -251,7 +251,7 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
__ioremap_mode((offset), (size), _CACHE_UNCACHED)
/*
- * ioremap_cachable - map bus memory into CPU space
+ * ioremap_cache - map bus memory into CPU space
* @offset: bus address of the memory
* @size: size of the resource to map
*
@@ -265,9 +265,11 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
* the CPU. Also enables full write-combining. Useful for some
* memory-like regions on I/O busses.
*/
-#define ioremap_cachable(offset, size) \
+#define ioremap_cache(offset, size) \
__ioremap_mode((offset), (size), _page_cachable_default)
+#define ioremap_wc ioremap_nocache
+
/*
* These two are MIPS specific ioremap variant. ioremap_cacheable_cow
* requests a cachable mapping, ioremap_uncached_accelerated requests a
diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h
index 787255d..1ed75a0 100644
--- a/arch/mn10300/include/asm/io.h
+++ b/arch/mn10300/include/asm/io.h
@@ -272,6 +272,7 @@ static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
return (void *) (offset | 0x20000000);
}
+#define ioremap_cache ioremap
#define ioremap_wc ioremap_nocache
static inline void iounmap(void *addr)
diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h
index 1f6d2ae..01edb85 100644
--- a/arch/parisc/include/asm/io.h
+++ b/arch/parisc/include/asm/io.h
@@ -137,6 +137,8 @@ static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
return __ioremap(offset, size, _PAGE_NO_CACHE);
}
#define ioremap_nocache(off, sz) ioremap((off), (sz))
+#define ioremap_cache(off, sz) ioremap((off), (sz))
+#define ioremap_wc(off, sz) ioremap((off), (sz))
extern void iounmap(const volatile void __iomem *addr);
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 001f2f1..ee41d61 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -643,6 +643,8 @@ extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size,
unsigned long flags);
#define ioremap_nocache(addr, size) ioremap((addr), (size))
+#define ioremap_cache(addr, size) ioremap((addr), (size))
+#define ioremap_wc(addr, size) ioremap((addr), (size))
#define ioremap_prot(addr, size, prot) ioremap_flags((addr), (size), (prot))
extern void iounmap(volatile void __iomem *addr);
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 28c5aa5..7dfbb47 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -369,6 +369,7 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; }
#endif
#define ioremap_nocache ioremap
+#define ioremap_wc ioremap
#define iounmap __iounmap
/*
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index c2ced21..f0a8173 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -275,6 +275,7 @@ _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
*/
extern void __iomem *ioremap(unsigned long offset, unsigned long size);
#define ioremap_nocache(X,Y) ioremap((X),(Y))
+#define ioremap_cache(X,Y) ioremap((X),(Y))
#define ioremap_wc(X,Y) ioremap((X),(Y))
extern void iounmap(volatile void __iomem *addr);
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 9c89654..08fcfdb 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -491,6 +491,7 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
}
#define ioremap_nocache(X,Y) ioremap((X),(Y))
+#define ioremap_cache(X,Y) ioremap((X),(Y))
#define ioremap_wc(X,Y) ioremap((X),(Y))
static inline void iounmap(volatile void __iomem *addr)
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index d3cbb9b..a9c5320 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -54,6 +54,8 @@ extern void iounmap(volatile void __iomem *addr);
#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_cache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_wc(physaddr, size) ioremap(physaddr, size)
#define mmiowb()
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 0722730..4977ddc 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -34,8 +34,6 @@
* - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*/
-#define ARCH_HAS_IOREMAP_WC
-
#include <linux/string.h>
#include <linux/compiler.h>
#include <asm-generic/int-ll64.h>
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index d04cd3a..c392cd8 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -93,6 +93,9 @@ static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
#endif
}
+#define ioremap_cache ioremap
+#define ioremap_wc ioremap_nocache
+
static inline void iounmap(void *addr)
{
}
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index d8ae634..2170634 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -81,7 +81,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
return -ENOMEM;
}
info->map.cached =
- ioremap_cached(info->map.phys, info->map.size);
+ ioremap_cache(info->map.phys, info->map.size);
if (!info->map.cached)
printk(KERN_WARNING "Failed to ioremap cached %s\n",
info->map.name);
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 4644c9a..598d26c 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -318,6 +318,10 @@ static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
#define ioremap_wc ioremap_nocache
#endif
+#ifndef ioremap_cache
+#define ioremap_cache ioremap
+#endif
+
static inline void iounmap(void *addr)
{
}
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
index 76b0cc5..67dc84c 100644
--- a/include/asm-generic/iomap.h
+++ b/include/asm-generic/iomap.h
@@ -60,10 +60,6 @@ extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long cou
extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
extern void ioport_unmap(void __iomem *);
-#ifndef ARCH_HAS_IOREMAP_WC
-#define ioremap_wc ioremap_nocache
-#endif
-
/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
struct pci_dev;
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
--
1.7.1
^ permalink raw reply related
* [PATCH 3/3] uvesafb: remove-ifdef-CONFIG_X86-around-ioremap
From: Thomas Schlichter @ 2011-02-06 11:14 UTC (permalink / raw)
To: Paul Mundt; +Cc: Michal Januszewski, linux-fbdev, linux-kernel
In-Reply-To: <201102061202.09503.thomas.schlichter@web.de>
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: 0003-uvesafb-remove-ifdef-CONFIG_X86-around-ioremap.patch --]
[-- Type: text/x-patch, Size: 1308 bytes --]
From d1e432f878746b699856160456f811affc3c42fe Mon Sep 17 00:00:00 2001
From: Thomas Schlichter <thomas.schlichter@web.de>
Date: Sun, 6 Feb 2011 11:45:08 +0100
Subject: [PATCH 3/3] uvesafb: remove ifdef CONFIG_X86 around ioremap in
Now that ioremap_cache() and ioremap_wc() are available on each architecture
we can remove the unneccessary ifdef in uvesafb.
Signed-off-by: Thomas Schlichter <thomas.schlichter@web.de>
---
drivers/video/uvesafb.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 2d6f799..ca15166 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -1567,7 +1567,6 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
static void __devinit uvesafb_ioremap(struct fb_info *info)
{
-#ifdef CONFIG_X86
switch (mtrr) {
case 1: /* uncachable */
info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
@@ -1583,9 +1582,6 @@ static void __devinit uvesafb_ioremap(struct fb_info *info)
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
break;
}
-#else
- info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
-#endif /* CONFIG_X86 */
}
static ssize_t uvesafb_show_vbe_ver(struct device *dev,
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 2/3] Add ioremap_cache and ioremap_wc to all architectures
From: Geert Uytterhoeven @ 2011-02-06 12:34 UTC (permalink / raw)
To: Thomas Schlichter
Cc: Paul Mundt, Michal Januszewski, linux-fbdev, linux-kernel,
Linux-Arch
In-Reply-To: <201102061212.32528.thomas.schlichter@web.de>
This really should go to linux-arch...
On Sun, Feb 6, 2011 at 12:12, Thomas Schlichter
<thomas.schlichter@web.de> wrote:
>
>
Oops, no inline patch. Well, people know they can find the attachment
on lkml ;-)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH] fb: fix potential deadlock between lock_fb_info and console_lock
From: Andrea Righi @ 2011-02-06 15:50 UTC (permalink / raw)
To: Andrew Morton
Cc: Greg KH, Peter Nordström (Palm GBU), linux-fbdev,
linux-kernel, stable
The function fb_set_suspend() must be called with the console semaphore
held, which means the code path coming in here will first take the
console_lock() and then call lock_fb_info().
However several framebuffer ioctl commands acquire these locks in
reverse order (lock_fb_info() and then console_lock()). This gives rise
to potential AB-BA deadlock.
Fix this by changing the order of acquisition in the ioctl commands that
make use of console_lock().
Reported-by: Peter Nordström (Palm GBU) <peter.nordstrom@palm.com>
Signed-off-by: Andrea Righi <arighi@develer.com>
---
drivers/video/fbmem.c | 24 +++++++++++++++---------
1 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index e2bf953..def59f0 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1034,14 +1034,16 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
case FBIOPUT_VSCREENINFO:
if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT;
- if (!lock_fb_info(info))
- return -ENODEV;
console_lock();
+ if (!lock_fb_info(info)) {
+ console_unlock();
+ return -ENODEV;
+ }
info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT;
- console_unlock();
unlock_fb_info(info);
+ console_unlock();
if (!ret && copy_to_user(argp, &var, sizeof(var)))
ret = -EFAULT;
break;
@@ -1070,12 +1072,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
case FBIOPAN_DISPLAY:
if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT;
- if (!lock_fb_info(info))
- return -ENODEV;
console_lock();
+ if (!lock_fb_info(info)) {
+ console_unlock();
+ return -ENODEV;
+ }
ret = fb_pan_display(info, &var);
- console_unlock();
unlock_fb_info(info);
+ console_unlock();
if (ret = 0 && copy_to_user(argp, &var, sizeof(var)))
return -EFAULT;
break;
@@ -1117,14 +1121,16 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
unlock_fb_info(info);
break;
case FBIOBLANK:
- if (!lock_fb_info(info))
- return -ENODEV;
console_lock();
+ if (!lock_fb_info(info)) {
+ console_unlock();
+ return -ENODEV;
+ }
info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_blank(info, arg);
info->flags &= ~FBINFO_MISC_USEREVENT;
- console_unlock();
unlock_fb_info(info);
+ console_unlock();
break;
default:
if (!lock_fb_info(info))
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 1/2] video, sm501: add OF binding to support SM501
From: Benjamin Herrenschmidt @ 2011-02-06 23:45 UTC (permalink / raw)
To: Heiko Schocher; +Cc: linux-fbdev, devicetree-discuss, linuxppc-dev
In-Reply-To: <1291451028-22532-1-git-send-email-hs@denx.de>
On Sat, 2010-12-04 at 09:23 +0100, Heiko Schocher wrote:
> - add binding to OF, compatible name "smi,sm501"
>
> - add read/write functions for using this driver
> also on powerpc plattforms
.../...
Who plans to merge that patch series ? I'm happy for whoever is doing
that to take the powerpc patch at the end (that adds the entry to
the .dts file) with my
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cheers,
Ben.
^ permalink raw reply
* [PATCH] video: ffb: fix ffb_probe error path
From: Axel Lin @ 2011-02-08 14:58 UTC (permalink / raw)
To: linux-kernel; +Cc: David S. Miller, Paul Mundt, linux-fbdev
Current implementation calls of_iounmap for par->fbc twice in error path.
In the case of goto out_unmap_dac, we should call of_iounmap for par->dac.
Signed-off-by: Axel Lin <axel.lin@gmail.com>
---
drivers/video/ffb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 6739b2a..b5d6a46 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -1011,7 +1011,7 @@ out_dealloc_cmap:
fb_dealloc_cmap(&info->cmap);
out_unmap_dac:
- of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+ of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
out_unmap_fbc:
of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] video: ffb: fix ffb_probe error path
From: David Miller @ 2011-02-08 19:41 UTC (permalink / raw)
To: axel.lin; +Cc: linux-kernel, lethal, linux-fbdev
In-Reply-To: <1297177125.2343.3.camel@phoenix>
From: Axel Lin <axel.lin@gmail.com>
Date: Tue, 08 Feb 2011 22:58:45 +0800
> Current implementation calls of_iounmap for par->fbc twice in error path.
> In the case of goto out_unmap_dac, we should call of_iounmap for par->dac.
>
> Signed-off-by: Axel Lin <axel.lin@gmail.com>
Good spotting:
Acked-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Sascha Hauer @ 2011-02-09 13:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297257651-8002-1-git-send-email-s.hauer@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: linux-fbdev@vger.kernel.org
Cc: Shawn Guo <shawn.guo@freescale.com>
---
arch/arm/mach-mxs/include/mach/fb.h | 48 ++
drivers/video/Kconfig | 9 +
drivers/video/Makefile | 1 +
drivers/video/mxsfb.c | 914 +++++++++++++++++++++++++++++++++++
4 files changed, 972 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-mxs/include/mach/fb.h
create mode 100644 drivers/video/mxsfb.c
diff --git a/arch/arm/mach-mxs/include/mach/fb.h b/arch/arm/mach-mxs/include/mach/fb.h
new file mode 100644
index 0000000..923f397
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/fb.h
@@ -0,0 +1,48 @@
+/*
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ * 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 __MACH_FB_H
+#define __MACH_FB_H
+
+#include <linux/fb.h>
+
+#define STMLCDIF_8BIT 1 /** pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /** pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
+
+#define FB_SYNC_DATA_ENABLE_HIGH_ACT 64
+
+struct mxsfb_platform_data {
+ struct fb_videomode *mode_list;
+ unsigned mode_count;
+
+ unsigned default_bpp;
+
+ unsigned dotclk_delay; /* refer manual HW_LCDIF_VDCTRL4 register */
+ unsigned ld_intf_width; /* refer STMLCDIF_* macros */
+
+ unsigned fb_size; /* Size of the video memory. If zero a
+ * default will be used
+ */
+ unsigned long fb_phys; /* physical address for the video memory. If
+ * zero the framebuffer memory will be dynamically
+ * allocated. If specified,fb_size must also be specified.
+ * fb_phys must be unused by Linux.
+ */
+};
+
+#endif /* __MACH_FB_H */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6bafb51b..e0ea23f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2365,6 +2365,15 @@ config FB_JZ4740
help
Framebuffer support for the JZ4740 SoC.
+config FB_MXS
+ tristate "MXS LCD framebuffer support"
+ depends on FB && ARCH_MXS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Framebuffer support for the MXS SoC.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8c8fabd..9a096ae 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o
obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
+obj-$(CONFIG_FB_MXS) += mxsfb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
new file mode 100644
index 0000000..92a5804
--- /dev/null
+++ b/drivers/video/mxsfb.c
@@ -0,0 +1,914 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ *
+ * This code is based on:
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ * 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.
+ */
+
+#define DRIVER_NAME "mxsfb"
+
+/**
+ * @file
+ * @brief LCDIF driver for i.MX23 and i.MX28
+ *
+ * The LCDIF support four modes of operation
+ * - MPU interface (to drive smart displays) -> not supported yet
+ * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet
+ * - Dotclock interface (to drive LC displays with RGB data and sync signals)
+ * - DVI (to drive ITU-R BT656) -> not supported yet
+ *
+ * This driver depends on a correct setup of the pins used for this purpose
+ * (platform specific).
+ *
+ * For the developer: Don't forget to set the data bus width to the display
+ * in the imx_fb_videomode structure. You will else end up with ugly colours.
+ * If you fight against jitter you can vary the clock delay. This is a feature
+ * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give
+ * the required value in the imx_fb_videomode structure.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <mach/fb.h>
+#include <mach/hardware.h>
+#include <mach/mxs.h>
+
+#define CTRL 0x00
+#define CTRL1 0x10
+#define MX28_CTRL2 0x20
+#define MX23_TRANSFER_COUNT 0x20
+#define MX28_TRANSFER_COUNT 0x30
+#define MX28_CUR_BUF 0x40
+#define MX28_NEXT_BUF 0x50
+#define MX23_CUR_BUF 0x30
+#define MX23_NEXT_BUF 0x40
+#define TIMING 0x60
+#define VDCTRL0 0x70
+#define VDCTRL1 0x80
+#define VDCTRL2 0x90
+#define VDCTRL3 0xa0
+#define VDCTRL4 0xb0
+#define DVICTRL0 0xc0
+#define DVICTRL1 0xd0
+#define DVICTRL2 0xe0
+#define DVICTRL3 0xf0
+#define DVICTRL4 0x100
+#define MX28_DATA 0x180
+#define MX23_DATA 0x1b0
+#define MX28_DEBUG0 0x1d0
+#define MX23_DEBUG0 0x1f0
+
+#define CTRL_SFTRST (1 << 31)
+#define CTRL_CLKGATE (1 << 30)
+#define CTRL_BYPASS_COUNT (1 << 19)
+#define CTRL_VSYNC_MODE (1 << 18)
+#define CTRL_DOTCLK_MODE (1 << 17)
+#define CTRL_DATA_SELECT (1 << 16)
+#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10)
+#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3)
+#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8)
+#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3)
+#define CTRL_MASTER (1 << 5)
+#define CTRL_DF16 (1 << 3)
+#define CTRL_DF18 (1 << 2)
+#define CTRL_DF24 (1 << 1)
+#define CTRL_RUN (1 << 0)
+
+#define CTRL1_FIFO_CLEAR (1 << 21)
+#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
+#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
+#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
+#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
+
+
+#define VDCTRL0_ENABLE_PRESENT (1 << 28)
+#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
+#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26)
+#define VDCTRL0_DOTCLK_ACTIVE_HIGH (1 << 25)
+#define VDCTRL0_POL_ACTIVE_HIGH (1 << 24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
+#define VDCTRL0_HALF_LINE (1 << 19)
+#define VDCTRL0_HALF_LINE_MODE (1 << 18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
+#define VDCTRL3_VSYNC_ONLY (1 << 28)
+#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
+#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
+#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* i.MX28 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* i.MX28 only */
+#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
+
+#define DEBUG0_HSYNC (1 < 26)
+#define DEBUG0_VSYNC (1 < 25)
+
+#define MIN_XRES 120
+#define MIN_YRES 120
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+enum mxsfb_devtype {
+ MXSFB_MX23,
+ MXSFB_MX28,
+};
+
+/* CPU dependent register offsets */
+struct mxsfb_devdata {
+ unsigned transfer_count;
+ unsigned cur_buf;
+ unsigned next_buf;
+ unsigned debug0;
+ unsigned hs_wdth_mask;
+ unsigned hs_wdth_shift;
+};
+
+struct mxsfb_info {
+ struct fb_info fb_info;
+ struct platform_device *pdev;
+ struct clk *clk;
+ void __iomem *base; /* registers */
+ unsigned allocated_size;
+ int enabled;
+ unsigned ld_intf_width;
+ unsigned dotclk_delay;
+ const struct mxsfb_devdata *devdata;
+ int mapped;
+};
+
+static const struct mxsfb_devdata mxsfb_devdata[] = {
+ [MXSFB_MX23] = {
+ .transfer_count = MX23_TRANSFER_COUNT,
+ .cur_buf = MX23_CUR_BUF,
+ .next_buf = MX23_NEXT_BUF,
+ .debug0 = MX23_DEBUG0,
+ .hs_wdth_mask = 0xff,
+ .hs_wdth_shift = 24,
+ },
+ [MXSFB_MX28] = {
+ .transfer_count = MX28_TRANSFER_COUNT,
+ .cur_buf = MX28_CUR_BUF,
+ .next_buf = MX28_NEXT_BUF,
+ .debug0 = MX28_DEBUG0,
+ .hs_wdth_mask = 0x3fff,
+ .hs_wdth_shift = 18,
+ },
+};
+
+#define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info))
+
+/* mask and shift depends on architecture */
+static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
+{
+ return (val & host->devdata->hs_wdth_mask) <<
+ host->devdata->hs_wdth_shift;
+}
+
+static inline u32 get_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
+{
+ return (val >> host->devdata->hs_wdth_shift) &
+ host->devdata->hs_wdth_mask;
+}
+
+static const struct fb_bitfield def_rgb565[] = {
+ [RED] = {
+ .offset = 11,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+static const struct fb_bitfield def_rgb666[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 6,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 6,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+static const struct fb_bitfield def_rgb888[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int mxsfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ const struct fb_bitfield *rgb = NULL;
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+
+ var->xres_virtual = var->xres;
+
+ var->yres_virtual = var->yres;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ /* always expect RGB 565 */
+ rgb = def_rgb565;
+ break;
+ case 32:
+ switch (host->ld_intf_width) {
+ case STMLCDIF_8BIT:
+ pr_debug("Unsupported LCD bus width mapping\n");
+ break;
+ case STMLCDIF_16BIT:
+ case STMLCDIF_18BIT:
+ /* 24 bit to 18 bit mapping */
+ rgb = def_rgb666;
+ break;
+ case STMLCDIF_24BIT:
+ /* real 24 bit */
+ rgb = def_rgb888;
+ break;
+ }
+ break;
+ default:
+ pr_debug("Unsupported colour depth: %u\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /*
+ * Copy the RGB parameters for this display
+ * from the machine specific parameters.
+ */
+ var->red = rgb[RED];
+ var->green = rgb[GREEN];
+ var->blue = rgb[BLUE];
+ var->transp = rgb[TRANSP];
+
+ return 0;
+}
+
+static void mxsfb_enable_controller(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ u32 reg;
+
+ dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+ clk_enable(host->clk);
+ clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
+
+ /* if it was disabled, re-enable the mode again */
+ reg = readl(host->base + CTRL);
+ reg |= CTRL_DOTCLK_MODE;
+ writel(reg, host->base + CTRL);
+
+ /* enable the SYNC signals first, then the DMA engine */
+ reg = readl(host->base + VDCTRL4);
+ reg |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, host->base + VDCTRL4);
+
+ reg = readl(host->base + CTRL);
+ reg |= CTRL_RUN;
+ writel(reg, host->base + CTRL);
+
+ host->enabled = 1;
+}
+
+static void mxsfb_disable_controller(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ unsigned loop;
+ u32 reg;
+
+ dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+ /*
+ * Even if we disable the controller here, it will still continue
+ * until its FIFOs are running out of data
+ */
+ reg = readl(host->base + CTRL);
+ reg &= ~CTRL_DOTCLK_MODE;
+ writel(reg, host->base + CTRL);
+
+ loop = 1000;
+ while (loop) {
+ reg = readl(host->base + CTRL);
+ if (!(reg & CTRL_RUN))
+ break;
+ loop--;
+ }
+
+ reg = readl(host->base + VDCTRL4);
+ reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, host->base + VDCTRL4);
+
+ clk_disable(host->clk);
+
+ host->enabled = 0;
+}
+
+static int mxsfb_set_par(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ u32 ctrl, vdctrl0, vdctrl4;
+ int line_size, fb_size;
+ int reenable = 0;
+
+ line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
+ fb_size = fb_info->var.yres_virtual * line_size;
+
+ if (fb_size > fb_info->fix.smem_len)
+ return -ENOMEM;
+
+ fb_info->fix.line_length = line_size;
+
+ /*
+ * It seems, you can't re-program the controller if it is still running.
+ * This may lead into shifted pictures (FIFO issue?).
+ * So, first stop the controller and drain its FIFOs
+ */
+ if (host->enabled) {
+ reenable = 1;
+ mxsfb_disable_controller(fb_info);
+ }
+
+ /* clear the FIFOs */
+ writel(CTRL1_FIFO_CLEAR, host->base + CTRL1 + 4);
+
+ ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER |
+ CTRL_SET_BUS_WIDTH(host->ld_intf_width);;
+
+ switch (fb_info->var.bits_per_pixel) {
+ case 16:
+ dev_dbg(&host->pdev->dev, "Setting up RGB565 mode\n");
+ ctrl |= CTRL_SET_WORD_LENGTH(0);
+ writel(CTRL1_SET_BYTE_PACKAGING(0xf), host->base + CTRL1);
+ break;
+ case 32:
+ dev_dbg(&host->pdev->dev, "Setting up RGB888/666 mode\n");
+ ctrl |= CTRL_SET_WORD_LENGTH(3);
+ switch (host->ld_intf_width) {
+ case STMLCDIF_8BIT:
+ dev_dbg(&host->pdev->dev,
+ "Unsupported LCD bus width mapping\n");
+ return -EINVAL;
+ case STMLCDIF_16BIT:
+ case STMLCDIF_18BIT:
+ /* 24 bit to 18 bit mapping */
+ ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
+ * each colour component
+ */
+ break;
+ case STMLCDIF_24BIT:
+ /* real 24 bit */
+ break;
+ }
+ /* do not use packed pixels = one pixel per word instead */
+ writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + CTRL1);
+ break;
+ default:
+ dev_dbg(&host->pdev->dev, "Unhandled color depth of %u\n",
+ fb_info->var.bits_per_pixel);
+ return -EINVAL;
+ }
+
+ writel(ctrl, host->base + CTRL);
+
+ writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) |
+ TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres),
+ host->base + host->devdata->transfer_count);
+
+ vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+ VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len);
+ if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+ if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+ if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT)
+ vdctrl0 |= VDCTRL0_POL_ACTIVE_HIGH;
+
+ writel(vdctrl0, host->base + VDCTRL0);
+
+ /* frame length in lines */
+ writel(fb_info->var.upper_margin + fb_info->var.vsync_len +
+ fb_info->var.lower_margin + fb_info->var.yres,
+ host->base + VDCTRL1);
+
+ /* line length in units of clocks or pixels */
+ writel(set_hsync_pulse_width(host, fb_info->var.hsync_len) |
+ VDCTRL2_SET_HSYNC_PERIOD(fb_info->var.left_margin +
+ fb_info->var.hsync_len + fb_info->var.right_margin +
+ fb_info->var.xres),
+ host->base + VDCTRL2);
+
+ writel(SET_HOR_WAIT_CNT(fb_info->var.left_margin +
+ fb_info->var.hsync_len) |
+ SET_VERT_WAIT_CNT(fb_info->var.upper_margin +
+ fb_info->var.vsync_len),
+ host->base + VDCTRL3);
+
+ vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(fb_info->var.xres);
+ if (cpu_is_mx28())
+ vdctrl4 |= VDCTRL4_SET_DOTCLK_DLY(host->dotclk_delay);
+ writel(vdctrl4, host->base + VDCTRL4);
+
+ writel(fb_info->fix.smem_start +
+ fb_info->fix.line_length * fb_info->var.yoffset,
+ host->base + host->devdata->next_buf);
+
+ if (reenable)
+ mxsfb_enable_controller(fb_info);
+
+ return 0;
+}
+
+static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb_info)
+{
+ unsigned int val;
+ int ret = -EINVAL;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (fb_info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+
+ switch (fb_info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 12 or 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = fb_info->pseudo_palette;
+
+ val = chan_to_field(red, &fb_info->var.red);
+ val |= chan_to_field(green, &fb_info->var.green);
+ val |= chan_to_field(blue, &fb_info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+static int mxsfb_blank(int blank, struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ if (host->enabled)
+ mxsfb_disable_controller(fb_info);
+ break;
+
+ case FB_BLANK_UNBLANK:
+ if (!host->enabled)
+ mxsfb_enable_controller(fb_info);
+ break;
+ }
+ return 0;
+}
+
+static int mxsfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ unsigned offset;
+
+ if (var->xoffset != 0)
+ return -EINVAL;
+
+ offset = fb_info->fix.line_length * var->yoffset;
+
+ /* update on next VSYNC */
+ writel(fb_info->fix.smem_start + offset,
+ host->base + host->devdata->next_buf);
+
+ return 0;
+}
+
+static struct fb_ops mxsfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mxsfb_check_var,
+ .fb_set_par = mxsfb_set_par,
+ .fb_setcolreg = mxsfb_setcolreg,
+ .fb_blank = mxsfb_blank,
+ .fb_pan_display = mxsfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __devinit mxsfb_restore_mode(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+ unsigned line_count;
+ unsigned period;
+ unsigned long pa, fbsize;
+ int bits_per_pixel, ofs;
+ u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
+ struct fb_videomode vmode;
+
+ /* Only restore the mode when the controller is running */
+ ctrl = readl(host->base + CTRL);
+ if (!(ctrl & CTRL_RUN))
+ return -EINVAL;
+
+ vdctrl0 = readl(host->base + VDCTRL0);
+ vdctrl2 = readl(host->base + VDCTRL2);
+ vdctrl3 = readl(host->base + VDCTRL3);
+ vdctrl4 = readl(host->base + VDCTRL4);
+
+ transfer_count = readl(host->base + host->devdata->transfer_count);
+
+ vmode.xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
+ vmode.yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count);
+
+ switch (CTRL_GET_WORD_LENGTH(ctrl)) {
+ case 0:
+ bits_per_pixel = 16;
+ break;
+ case 3:
+ bits_per_pixel = 32;
+ case 1:
+ default:
+ return -EINVAL;
+ }
+
+ fb_info->var.bits_per_pixel = bits_per_pixel;
+
+ vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U);
+ vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2);
+ vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len;
+ vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len -
+ vmode.left_margin - vmode.xres;
+ vmode.vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0);
+ period = readl(host->base + VDCTRL1);
+ vmode.upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode.vsync_len;
+ vmode.lower_margin = period - vmode.vsync_len - vmode.upper_margin - vmode.yres;
+
+ vmode.vmode = FB_VMODE_NONINTERLACED;
+
+ vmode.sync = 0;
+ if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH)
+ vmode.sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH)
+ vmode.sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ pr_debug("Reconstructed video mode:\n");
+ pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n",
+ vmode.xres, vmode.yres,
+ vmode.hsync_len, vmode.left_margin, vmode.right_margin,
+ vmode.vsync_len, vmode.upper_margin, vmode.lower_margin);
+ pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode.pixclock));
+
+ fb_add_videomode(&vmode, &fb_info->modelist);
+
+ host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl);
+ host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4);
+
+ fb_info->fix.line_length = vmode.xres * (bits_per_pixel >> 3);
+
+ pa = readl(host->base + host->devdata->cur_buf);
+ fbsize = fb_info->fix.line_length * vmode.yres;
+ if (pa < fb_info->fix.smem_start)
+ return -EINVAL;
+ if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len)
+ return -EINVAL;
+ ofs = pa - fb_info->fix.smem_start;
+ if (ofs) {
+ memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize);
+ writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf);
+ }
+
+ line_count = fb_info->fix.smem_len / fb_info->fix.line_length;
+ fb_info->fix.ypanstep = 1;
+
+ clk_enable(host->clk);
+ host->enabled = 1;
+
+ return 0;
+}
+
+static int __devinit mxsfb_init_fbinfo(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+ struct fb_var_screeninfo *var = &fb_info->var;
+ struct mxsfb_platform_data *pdata = host->pdev->dev.platform_data;
+ dma_addr_t fb_phys;
+ void *fb_virt;
+ unsigned fb_size = pdata->fb_size;
+
+ fb_info->fbops = &mxsfb_ops;
+ fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
+ strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id));
+ fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
+ fb_info->fix.ypanstep = 1;
+ fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
+ fb_info->fix.accel = FB_ACCEL_NONE;
+
+ var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
+ var->nonstd = 0;
+ var->activate = FB_ACTIVATE_NOW;
+ var->accel_flags = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ host->dotclk_delay = pdata->dotclk_delay;
+ host->ld_intf_width = pdata->ld_intf_width;
+
+ /* Memory allocation for framebuffer */
+ if (pdata->fb_phys) {
+ if (!fb_size)
+ return -EINVAL;
+
+ fb_phys = pdata->fb_phys;
+
+ if (!request_mem_region(fb_phys, fb_size, host->pdev->name))
+ return -ENOMEM;
+
+ fb_virt = ioremap(fb_phys, fb_size);
+ if (!fb_virt) {
+ release_mem_region(fb_phys, fb_size);
+ return -ENOMEM;
+ }
+ host->mapped = 1;
+ } else {
+ if (!fb_size)
+ fb_size = SZ_2M; /* default */
+ fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
+ if (!fb_info->screen_base)
+ return -ENOMEM;
+
+ fb_phys = virt_to_phys(fb_virt);
+ }
+
+ fb_info->fix.smem_start = fb_phys;
+ fb_info->screen_base = fb_virt;
+ fb_info->screen_size = fb_info->fix.smem_len = fb_size;
+
+ if (mxsfb_restore_mode(host))
+ memset(fb_virt, 0, fb_size);
+
+ return 0;
+}
+
+static void __devexit mxsfb_free_videomem(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+
+ if (host->mapped) {
+ iounmap(fb_info->screen_base);
+ release_mem_region(fb_info->fix.smem_start,
+ fb_info->screen_size);
+ } else {
+ free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len);
+ }
+}
+
+static int __devinit mxsfb_probe(struct platform_device *pdev)
+{
+ struct mxsfb_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct mxsfb_info *host;
+ struct fb_info *fb_info;
+ struct fb_modelist *modelist;
+ int i, ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platformdata. Giving up\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Cannot get memory IO resource\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name))
+ return -EBUSY;
+
+ fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev);
+ if (!fb_info) {
+ dev_err(&pdev->dev, "Failed to allocate fbdev\n");
+ ret = -ENOMEM;
+ goto error_alloc_info;
+ }
+
+ host = to_imxfb_host(fb_info);
+
+ host->base = ioremap(res->start, resource_size(res));
+ if (!host->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto error_ioremap;
+ }
+
+ host->pdev = pdev;
+ platform_set_drvdata(pdev, host);
+
+ host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+
+ host->clk = clk_get(&host->pdev->dev, NULL);
+ if (IS_ERR(host->clk)) {
+ ret = PTR_ERR(host->clk);
+ goto error_getclock;
+ }
+
+ fb_info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ if (!fb_info->pseudo_palette) {
+ ret = -ENOMEM;
+ goto error_pseudo_pallette;
+ }
+
+ INIT_LIST_HEAD(&fb_info->modelist);
+
+ ret = mxsfb_init_fbinfo(host);
+ if (ret != 0)
+ goto error_init_fb;
+
+ for (i = 0; i < pdata->mode_count; i++)
+ fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist);
+
+ modelist = list_first_entry(&fb_info->modelist,
+ struct fb_modelist, list);
+ fb_videomode_to_var(&fb_info->var, &modelist->mode);
+
+ /* init the color fields */
+ mxsfb_check_var(&fb_info->var, fb_info);
+
+ platform_set_drvdata(pdev, fb_info);
+
+ ret = register_framebuffer(fb_info);
+ if (ret != 0) {
+ dev_err(&pdev->dev,"Failed to register framebuffer\n");
+ goto error_register;
+ }
+
+ if (!host->enabled) {
+ writel(0, host->base + CTRL);
+ mxsfb_set_par(fb_info);
+ mxsfb_enable_controller(fb_info);
+ }
+
+ return 0;
+
+error_register:
+ if (host->enabled)
+ clk_disable(host->clk);
+ fb_destroy_modelist(&fb_info->modelist);
+error_init_fb:
+ kfree(fb_info->pseudo_palette);
+error_pseudo_pallette:
+ clk_put(host->clk);
+error_getclock:
+ iounmap(host->base);
+error_ioremap:
+ framebuffer_release(fb_info);
+error_alloc_info:
+ release_mem_region(res->start, resource_size(res));
+
+ return ret;
+}
+
+static int __devexit mxsfb_remove(struct platform_device *pdev)
+{
+ struct fb_info *fb_info = platform_get_drvdata(pdev);
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mxsfb_disable_controller(fb_info);
+
+ unregister_framebuffer(fb_info);
+ kfree(fb_info->pseudo_palette);
+ mxsfb_free_videomem(host);
+ iounmap(host->base);
+ clk_put(host->clk);
+
+ framebuffer_release(fb_info);
+ release_mem_region(res->start, resource_size(res));
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_device_id mxsfb_devtype[] = {
+ {
+ .name = "imx23-fb",
+ .driver_data = MXSFB_MX23,
+ }, {
+ .name = "imx28-fb",
+ .driver_data = MXSFB_MX28,
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
+
+static struct platform_driver mxsfb_driver = {
+ .probe = mxsfb_probe,
+ .remove = __devexit_p(mxsfb_remove),
+ .id_table = mxsfb_devtype,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init mxsfb_init(void)
+{
+ return platform_driver_register(&mxsfb_driver);
+}
+
+static void __exit mxsfb_exit(void)
+{
+ platform_driver_unregister(&mxsfb_driver);
+}
+
+module_init(mxsfb_init);
+module_exit(mxsfb_exit);
+
+MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
--
1.7.2.3
^ permalink raw reply related
* Re: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Lothar Waßmann @ 2011-02-09 13:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297257651-8002-2-git-send-email-s.hauer@pengutronix.de>
Hi Sascha,
Sascha Hauer writes:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Paul Mundt <lethal@linux-sh.org>
> Cc: linux-fbdev@vger.kernel.org
> Cc: Shawn Guo <shawn.guo@freescale.com>
> ---
> arch/arm/mach-mxs/include/mach/fb.h | 48 ++
> drivers/video/Kconfig | 9 +
> drivers/video/Makefile | 1 +
> drivers/video/mxsfb.c | 914 +++++++++++++++++++++++++++++++++++
> 4 files changed, 972 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-mxs/include/mach/fb.h
> create mode 100644 drivers/video/mxsfb.c
>
[...]
> diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
> new file mode 100644
> index 0000000..92a5804
> --- /dev/null
> +++ b/drivers/video/mxsfb.c
[...]
> +static int __devexit mxsfb_remove(struct platform_device *pdev)
> +{
> + struct fb_info *fb_info = platform_get_drvdata(pdev);
> + struct mxsfb_info *host = to_imxfb_host(fb_info);
> + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + mxsfb_disable_controller(fb_info);
>
IMO this should also be guarded by an:
| if (host->enabled)
otherwise it may lead to an unbalanced clk_disable() call.
Lothar Waßmann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________
^ permalink raw reply
* Re: [PATCH] i.MX23/28 framebuffer driver
From: Arnd Bergmann @ 2011-02-09 16:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110209153716.GN9041@pengutronix.de>
On Wednesday 09 February 2011, Sascha Hauer wrote:
> The driver patch itself is Cced to linux-fbdev, only the introductory
> mail is not.
Ok, I see.
> > Did you consider making the driver a KMS driver instead of
> > a frame buffer? I think the recommendation these days is
> > to start out with KMS for new drivers, which will be somewhat
> > simpler and give you a frame buffer device as well. I don't
> > think that there is a need to change over any drivers from
> > fb to kms though, since you've already done the work.
>
> I tried doing so for the i.MX51 which supports multiple displays on dvi
> and vga outputs and thus could make good use of KMS and friends. Anyway,
> I got stuck quite fast. The KMS stuff is tightly coupled with DRM/DRI
> and needs many many callbacks to implement. Additionally the userspace
> tools expect a nvidia/amd/intel driver and do not have a generic
> fallback. I think this stuff is good for implementing a full blown
> graphics driver, but is lacking support for simple framebuffer grapics.
> I'd love to go this way but it still requires a lot of work.
Ok. This sounds like a lot of upfront work indeed, to make KMS more
generic, though I think a number of driver would benefit from it
eventually. It could be something for the Linaro graphics working
group to look at in the following 11.11 release, depending on how
many other people are interested in getting there.
Arnd
^ permalink raw reply
* RE: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Li Frank-B20596 @ 2011-02-10 3:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297257651-8002-2-git-send-email-s.hauer@pengutronix.de>
> +#define CTRL 0x00
> +#define CTRL1 0x10
> +#define MX28_CTRL2 0x20
> +#define MX23_TRANSFER_COUNT 0x20
> +#define MX28_TRANSFER_COUNT 0x30
> +#define MX28_CUR_BUF 0x40
> +#define MX28_NEXT_BUF 0x50
> +#define MX23_CUR_BUF 0x30
> +#define MX23_NEXT_BUF 0x40
> +#define TIMING 0x60
> +#define VDCTRL0 0x70
> +#define VDCTRL1 0x80
> +#define VDCTRL2 0x90
> +#define VDCTRL3 0xa0
> +#define VDCTRL4 0xb0
Why you give up mx23/mx28 register define role, which generate from SOC xml.
There is a set header files for each mx23/mx28 module, which generate from xml.
I know original header files affect run time one Image.
But I think we can copy common part of such register definition because
That keep consistent with mx23/mx28 data sheet. Data sheet and header file generate
from one source xml.
HW_<Module name>_<Register name>.
BM_<Module name>_<Register name>_Bit name.
^ permalink raw reply
* Re: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Juergen Beisert @ 2011-02-10 8:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <09EC74FE2C9E8444BF2FF67BD36E1D6916776E@039-SN1MPN1-003.039d.mgd.msft.net>
Li Frank-B20596 wrote:
> > +#define CTRL 0x00
> > +#define CTRL1 0x10
> > +#define MX28_CTRL2 0x20
> > +#define MX23_TRANSFER_COUNT 0x20
> > +#define MX28_TRANSFER_COUNT 0x30
> > +#define MX28_CUR_BUF 0x40
> > +#define MX28_NEXT_BUF 0x50
> > +#define MX23_CUR_BUF 0x30
> > +#define MX23_NEXT_BUF 0x40
> > +#define TIMING 0x60
> > +#define VDCTRL0 0x70
> > +#define VDCTRL1 0x80
> > +#define VDCTRL2 0x90
> > +#define VDCTRL3 0xa0
> > +#define VDCTRL4 0xb0
>
> Why you give up mx23/mx28 register define role, which generate from SOC
> xml.
Your macros prevent me from writing short and compact code. If you need more
than one of these macros you always have to split each line to follow the 80
columns rule. Unreadable.
> There is a set header files for each mx23/mx28 module, which generate
> from xml. I know original header files affect run time one Image.
> But I think we can copy common part of such register definition because
> That keep consistent with mx23/mx28 data sheet. Data sheet and header file
> generate from one source xml.
>
> HW_<Module name>_<Register name>.
> BM_<Module name>_<Register name>_Bit name.
IMHO when I define the macros where they belong to, there is not need for this
redundant HW_<Module name> or BW__<Module name> prefixes. They are just
needless.
Regards,
Juergen
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | Phone: +49-8766-939 228 |
Vertretung Sued/Muenchen, Germany | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de/ |
^ permalink raw reply
* RE: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Li Frank-B20596 @ 2011-02-10 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201102100951.10977.jbe@pengutronix.de>
> > > +#define VDCTRL1 0x80
> > > +#define VDCTRL2 0x90
> > > +#define VDCTRL3 0xa0
> > > +#define VDCTRL4 0xb0
> >
> > Why you give up mx23/mx28 register define role, which generate from SOC
> > xml.
>
> Your macros prevent me from writing short and compact code. If you need
> more
> than one of these macros you always have to split each line to follow the
> 80
> columns rule. Unreadable.
>
> > There is a set header files for each mx23/mx28 module, which generate
> > from xml. I know original header files affect run time one Image.
> > But I think we can copy common part of such register definition because
> > That keep consistent with mx23/mx28 data sheet. Data sheet and header
> file
> > generate from one source xml.
> >
> > HW_<Module name>_<Register name>.
> > BM_<Module name>_<Register name>_Bit name.
>
> IMHO when I define the macros where they belong to, there is not need for
> this
> redundant HW_<Module name> or BW__<Module name> prefixes. They are just
> needless.
At first, someone complain name is longer. But during mx23/mx28 developing,
Everyone start enjoy such definition because there are not error happen about
register and bit position definition and identical map to silicon spec.
Developer needn't look up register header file when coding, just write down
Register name or bit name according to mx23/mx28 spec.
If you still think it is too long, I suggest keep HW_ and BM_ prefix to distinguish
Which one is register name, which one is bit mask.
Imx23/imx28 register have consistent convention.
HW_ is register name
BM_ is bit mask
BP_ is bit position.
BF_(x) is ((x<<BP)&BM_)
>
> Regards,
> Juergen
>
^ permalink raw reply
* RE: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Li Frank-B20596 @ 2011-02-10 9:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1297257651-8002-2-git-send-email-s.hauer@pengutronix.de>
> +
> + /* if it was disabled, re-enable the mode again */
> + reg = readl(host->base + CTRL);
> + reg |= CTRL_DOTCLK_MODE;
> + writel(reg, host->base + CTRL);
writel(CTRL_DOTCLK_MODE, host->base + CTRL_SET)
CTRL_SET is CTRL+0x4
SET and CLR register is easier than Read and write back.
^ permalink raw reply
* Re: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Juergen Beisert @ 2011-02-10 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <09EC74FE2C9E8444BF2FF67BD36E1D69167919@039-SN1MPN1-003.039d.mgd.msft.net>
Li Frank-B20596 wrote:
> > +
> > + /* if it was disabled, re-enable the mode again */
> > + reg = readl(host->base + CTRL);
> > + reg |= CTRL_DOTCLK_MODE;
> > + writel(reg, host->base + CTRL);
>
> writel(CTRL_DOTCLK_MODE, host->base + CTRL_SET)
> CTRL_SET is CTRL+0x4
> SET and CLR register is easier than Read and write back.
But you must always check, if the register really has such a SET and CLEAR
feature. Not all registers have this feature...
But in this case you are right.
But I would prefer:
#define SET 4
#define CLEAR 8
[...]
writel(CTRL_DOTCLK_MODE, host->base + CTRL + SET)
:-)
Regards,
Juergen
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | Phone: +49-8766-939 228 |
Vertretung Sued/Muenchen, Germany | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH 1/2] video: Add i.MX23/28 framebuffer driver
From: Juergen Beisert @ 2011-02-10 9:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <09EC74FE2C9E8444BF2FF67BD36E1D691678C9@039-SN1MPN1-003.039d.mgd.msft.net>
Li Frank-B20596 wrote:
> > > > +#define VDCTRL1 0x80
> > > > +#define VDCTRL2 0x90
> > > > +#define VDCTRL3 0xa0
> > > > +#define VDCTRL4 0xb0
> > >
> > > Why you give up mx23/mx28 register define role, which generate from SOC
> > > xml.
> >
> > Your macros prevent me from writing short and compact code. If you need
> > more than one of these macros you always have to split each line to follow
> > the 80 columns rule. Unreadable.
> >
> > > There is a set header files for each mx23/mx28 module, which generate
> > > from xml. I know original header files affect run time one Image.
> > > But I think we can copy common part of such register definition because
> > > That keep consistent with mx23/mx28 data sheet. Data sheet and header
> > > file
> >
> > > generate from one source xml.
> > >
> > > HW_<Module name>_<Register name>.
> > > BM_<Module name>_<Register name>_Bit name.
> >
> > IMHO when I define the macros where they belong to, there is not need for
> > this redundant HW_<Module name> or BW__<Module name> prefixes. They are
> > just needless.
>
> At first, someone complain name is longer. But during mx23/mx28 developing,
> Everyone start enjoy such definition because there are not error happen
> about register and bit position definition and identical map to silicon
> spec.
This kind of macro encryption _may_ help when you are coding the driver the
first time. But after reading and reading it again (while testing and
debugging) all these prefixes and suffixes do not add any valuable
information. They only fill up your lines, enlarges your source code and make
you blind for the real bug...
Everyone who wants to see how source code looks that uses these longs macros I
can recommend reading the so called 'bootlets' source code. :-))
> Developer needn't look up register header file when coding, just
That's why I add these macros into the source file instead into a header file.
> write down Register name or bit name according to mx23/mx28 spec.
And sometimes the spec is incomplete or just wrong and so on. Independent of
any macro naming policy.
> If you still think it is too long, I suggest keep HW_ and BM_ prefix to
> distinguish Which one is register name, which one is bit mask.
The used macro in the address part of the writel() must be an offset, while
the macro used in the value part must be a bit definition. Anything else is
redundant.
Regards,
Juergen
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | Phone: +49-8766-939 228 |
Vertretung Sued/Muenchen, Germany | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de/ |
^ 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