v2 patch for Freescale DIU driver
Subsystems (5)
This is the version 2 patch for Freescale DIU driver. Thanks for all the feedback.
The first patch is the driver. The second patch adds platform support for MPC8610HPCD board. To compile, enable the "Freescale MPC8610/MPC5121 DIU framebuffer support" in the menuconfig.
PATCH v2 1/2 Driver for Freescale 8610 and 5121 DIU
The following features are supported:
plane 0 works as a regular frame buffer, can be accessed by /dev/fb0 plane 1 has two AOIs (area of interest), can be accessed by /dev/fb1 and /dev/fb2 plane 2 has two AOIs, can be accessed by /dev/fb3 and /dev/fb4 Special ioctls support AOIs
All /dev/fb* can be used as regular frame buffer devices, except hardware change can only be made through /dev/fb0. Changing pixel clock has no effect on other fbs.
Limitation of usage of AOIs:
AOIs on the same plane can not be horizonally overlapped
AOIs have horizonal order, i.e. AOI0 should be always on top of AOI1 AOIs can not beyond phisical display area. Application should check AOI geometry before changing physical resolution on /dev/fb0
required command line parameters to preallocate memory for frame buffer diufb=15M
optional command line parameters to set modes and monitor video=fslfb:[resolution][,bpp][,monitor]
Syntax:
Resolution
xres x yres-bpp@refresh_rate, the -bpp and @refresh_rate are optional eg, 1024x768, 1280x1024, 1280x1024-32, 1280x1024@60, 1280x1024-32@60, 1280x480-32@60
Bpp
bpp=32, bpp=24, or bpp=16
Monitor
monitor=0, monitor=1, monitor=2
0 is DVI
1 is Single link LVDS
2 is Double link LVDS
Note: switching monitor is a board feather, not DIU feather. MPC8610HPCD has three monitor ports to swtich to. MPC5121ADS doesn't have additional monitor port. So switching monirot port for MPC5121ADS has no effect.
If compiled as a module, it takes pamameters mode, bpp, monitor with the same syntax above.
---
This patch is targeting 2.6.26 kernel.
Documentation/powerpc/booting-without-of.txt | 34 + arch/powerpc/boot/dts/mpc8610_hpcd.dts | 13 + drivers/video/Kconfig | 10 + drivers/video/Makefile | 1 + drivers/video/fsl-diu-fb.c | 1735 ++++++++++++++++++++++++++ drivers/video/fsl-diu-fb.h | 224 ++++ 6 files changed, 2017 insertions(+), 0 deletions(-) create mode 100644 drivers/video/fsl-diu-fb.c create mode 100644 drivers/video/fsl-diu-fb.h
Documentation/powerpc/booting-without-of.txt +34 -0
@@ -2816,6 +2816,40 @@ platforms are moved over to use the flattened-device-tree model. big-endian; }; + r) Freescale Display Interface Unit + + The Freescale DIU is a LCD controller, with proper hardware, it can also + drive DVI monitors. + + Required properties: + - compatible : should be "fsl-diu". + - reg : should contain at least address and length of the DIU register + set. + - Interrupts : one DIU interrupt should be describe here. + + Example (MPC8610HPCD) + diu@2c000 { + device_type = "lcd"; + compatible = "fsl-diu"; + reg = <0x2c000 100>; + interrupts = <72 2>; + interrupt-parent = <&mpic>; + }; + + s) Freescale on board FPGA + + This is the memory-mapped registers for on board FPGA. + + Required properities: + - compatible : should be "fsl,fpga-pixis". + - reg : should contain the address and the lenght of the FPPGA register + set. + + Example (MPC8610HPCD) + fpga { + compatible = "fsl,fpga-pixis"; + reg = <0xe8000000 20>; + }; More devices will be defined as this spec matures.
arch/powerpc/boot/dts/mpc8610_hpcd.dts +13 -0
@@ -45,6 +45,11 @@ reg = <0x00000000 0x20000000>; // 512M at 0x0 }; + fpga { + compatible = "fsl,fpga-pixis"; + reg = <0xe8000000 20>; // pixis at 0xe8000000 + }; + soc@e0000000 { #address-cells = <1>; #size-cells = <1>;
@@ -104,6 +109,14 @@ interrupt-parent = <&mpic>; }; + diu@2c000 { + device_type = "lcd"; + compatible = "fsl-diu"; + reg = <0x2c000 100>; + interrupts = <72 2>; + interrupt-parent = <&mpic>; + }; + mpic: interrupt-controller@40000 { clock-frequency = <0>; interrupt-controller;
drivers/video/Kconfig +10 -0
@@ -1766,6 +1766,16 @@ config FB_MBX_DEBUG If unsure, say N. +config FB_FSL_DIU + tristate "Freescale MPC8610/MPC5121 DIU framebuffer support" + depends on FB && (MPC8610 || MPC5121) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select PPC_LIB_RHEAP + ---help--- + Framebuffer driver for the MPC8610/MPC5121 chip from Freescale + config FB_W100 tristate "W100 frame buffer support" depends on FB && PXA_SHARPSL
drivers/video/Makefile +1 -0
@@ -113,6 +113,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_OMAP) += omap/ +obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o
drivers/video/fsl-diu-fb.c new file +1735 -0
1,735 lines not on this page · raw message
drivers/video/fsl-diu-fb.h new file +224 -0
224 lines not on this page · raw message
Signature · 1 line
1.5.2.2
PATCH v2 2/2 Add DIU platform code for MPC8610HPCD
Add platform code to support Freescale DIU. The platform code includes framebuffer memory allocation, pixel format, monitor port, etc.
---
This patch is targeting 2.6.26 kernel.
arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 182 +++++++++++++++++++++++++++- arch/powerpc/sysdev/fsl_soc.c | 41 ++++++ arch/powerpc/sysdev/fsl_soc.h | 22 ++++ 3 files changed, 243 insertions(+), 2 deletions(-)
arch/powerpc/platforms/86xx/mpc8610_hpcd.c +180 -2
@@ -3,6 +3,7 @@* * Initial author: Xianghua Xiao <[email protected]> * Recode: Jason Jin <[email protected]> +* York Sun <[email protected]> * * Rewrite the interrupt routing. remove the 8259PIC support, * All the integrated device in ULI use sideband interrupt.
@@ -38,6 +39,8 @@#include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +static unsigned char *pixis_bdcfg0, *pixis_arch; +static struct of_device_id __initdata mpc8610_ids[] = { { .compatible ="fsl,mpc8610-immr" , }, {}
@@ -161,12 +164,160 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AL ,0x5288 , final_uli5288);#endif /* CONFIG_PCI */ +#if defined(CONFIG_FB_FSL_DIU ) || defined(CONFIG_FB_FSL_DIU_MODULE ) + +static u32 get_busfreq (void ) +{ +struct device_node *node; + +u32 fs_busfreq =0 ; + node =of_find_node_by_type (NULL ,"cpu" ); +if (node) { +unsigned int size; +const unsigned int *prop = +of_get_property (node,"bus-frequency" , &size); +if (prop) + fs_busfreq = *prop; +of_node_put (node); + }; +return fs_busfreq; +} + +unsigned int mpc8610hpcd_get_pixel_format + (unsigned int bits_per_pixel,int monitor_port) +{ +static const unsigned long pixelformat[][3 ] = { + {0x88882317 ,0x88083218 ,0x65052119 }, + {0x88883316 ,0x88082219 ,0x65053118 }, + }; +unsigned int pix_fmt, arch_monitor; + + arch_monitor = ((*pixis_arch ==0x01 ) && (monitor_port ==0 ))?0 :1 ; +/* DVI port for board version 0x01 */ + +if (bits_per_pixel ==32 ) + pix_fmt = pixelformat[arch_monitor][0 ]; +else if (bits_per_pixel ==24 ) + pix_fmt = pixelformat[arch_monitor][1 ]; +else if (bits_per_pixel ==16 ) + pix_fmt = pixelformat[arch_monitor][2 ]; +else + pix_fmt = pixelformat[1 ][0 ]; + +return pix_fmt; +} + +void mpc8610hpcd_set_gamma_table (int monitor_port,char *gamma_table_base) +{ +int i; +if (monitor_port ==2 ) {/* dual link LVDS */ +for (i =0 ; i <256 *3 ; i++) + gamma_table_base[i] = (gamma_table_base[i] <<2 ) | + ((gamma_table_base[i] >>6 ) &0x03 ); + } +} + +void mpc8610hpcd_set_monitor_port (int monitor_port) +{ +static const u8 bdcfg[] = {0xBD ,0xB5 ,0xA5 }; +if (monitor_port <3 ) + *pixis_bdcfg0 = bdcfg[monitor_port]; +} + +void mpc8610hpcd_set_pixel_clock (unsigned int pixclock) +{ +u32 __iomem *clkdvdr; +u32 temp; +/* variables for pixel clock calcs */ +ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock; +ulong pixval; +long err; +int i; + + clkdvdr =ioremap (get_immrbase () +0xe0800 ,sizeof (u32)); +if (!clkdvdr) { +printk (KERN_ERR "Err: can't map clock divider register!\n" ); +return ; + } + +/* Pixel Clock configuration */ +pr_debug ("DIU: Bus Frequency = %d\n" ,get_busfreq ()); + speed_ccb =get_busfreq (); + +/* Calculate the pixel clock with the smallest error */ +/* calculate the following in steps to avoid overflow */ +pr_debug ("DIU pixclock in ps - %d\n" , pixclock); + temp =1000000000 /pixclock; + temp *=1000 ; + pixclock = temp; +pr_debug ("DIU pixclock freq - %u\n" , pixclock); + + temp = pixclock *5 /100 ; +pr_debug ("deviation = %d\n" , temp); + minpixclock = pixclock - temp; + maxpixclock = pixclock + temp; +pr_debug ("DIU minpixclock - %lu\n" , minpixclock); +pr_debug ("DIU maxpixclock - %lu\n" , maxpixclock); + pixval = speed_ccb/pixclock; +pr_debug ("DIU pixval = %lu\n" , pixval); + + err =100000000 ; + bestval = pixval; +pr_debug ("DIU bestval = %lu\n" , bestval); + + bestfreq =0 ; +for (i =-1 ; i <=1 ; i++) { + temp = speed_ccb / ((pixval+i) +1 ); +pr_debug ("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n" , + i, pixval, temp); +if ((temp < minpixclock) || (temp > maxpixclock)) +pr_debug ("DIU exceeds monitor range (%lu to %lu)\n" , + minpixclock, maxpixclock); +else if (abs (temp - pixclock) < err) { +pr_debug ("Entered the else if block %d\n" , i); + err =abs (temp - pixclock); + bestval = pixval+i; + bestfreq = temp; + } + } + +pr_debug ("DIU chose = %lx\n" , bestval); +pr_debug ("DIU error = %ld\n NomPixClk " , err); +pr_debug ("DIU: Best Freq = %lx\n" , bestfreq); +/* Modify PXCLK in GUTS CLKDVDR */ +pr_debug ("DIU: Current value of CLKDVDR = 0x%08x\n" , (*clkdvdr)); + temp = (*clkdvdr) &0x2000FFFF ; + *clkdvdr = temp;/* turn off clock */ + *clkdvdr = temp |0x80000000 | (((bestval) &0x1F ) <<16 ); +pr_debug ("DIU: Modified value of CLKDVDR = 0x%08x\n" , (*clkdvdr)); +iounmap (clkdvdr); +} + +ssize_t mpc8610hpcd_show_monitor_port (int monitor_port,char *buf) +{ +return snprintf (buf,PAGE_SIZE , +"%c0 - DVI\n" +"%c1 - Single link LVDS\n" +"%c2 - Dual link LVDS\n" , + monitor_port ==0 ?'*' :' ' , + monitor_port ==1 ?'*' :' ' , + monitor_port ==2 ?'*' :' ' ); +} + +int mpc8610hpcd_set_sysfs_monitor_port (int val) +{ +return val <3 ? val :0 ; +} + +#endif + +int __init preallocate_diu_videomemory (void );static void __init mpc86xx_hpcd_setup_arch (void ) { -#ifdef CONFIG_PCI +struct resource r;struct device_node *np; -#endif +if (ppc_md.progress) ppc_md.progress ("mpc86xx_hpcd_setup_arch()" ,0 );
@@ -183,6 +334,33 @@ mpc86xx_hpcd_setup_arch(void) } }#endif +#if defined(CONFIG_FB_FSL_DIU ) || defined(CONFIG_FB_FSL_DIU_MODULE ) +preallocate_diu_videomemory (); + diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format; + diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; + diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; + diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; + diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port; + diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port; +#endif + + np =of_find_compatible_node (NULL ,NULL ,"fsl,fpga-pixis" ); +if (np) { +of_address_to_resource (np,0 , &r); +of_node_put (np); + pixis_bdcfg0 =ioremap (r.start +0x00000008 ,sizeof (u8)); +if (!pixis_bdcfg0) { +printk (KERN_ERR "Err: can't map FPGA cfg register!\n" ); +return ; + } + pixis_arch =ioremap (r.start +0x00000001 ,sizeof (u8)); +if (!pixis_arch) { +printk (KERN_ERR "Err: can't map FPGA arch register!\n" ); +return ; + } + }else +printk (KERN_ERR "Err: " +"can't find device node 'fsl,fpga-pixis'\n" );printk ("MPC86xx HPCD board from Freescale Semiconductor\n" ); }
arch/powerpc/sysdev/fsl_soc.c +41 -0
44 lines not on this page · raw message
arch/powerpc/sysdev/fsl_soc.h +22 -0
@@ -16,5 +16,27 @@ extern int fsl_spi_init(struct spi_board_info *board_infos, void (*deactivate_cs)(u8 cs, u8 polarity));extern void fsl_rstcr_restart (char *cmd); + +#if defined(CONFIG_FB_FSL_DIU ) || defined(CONFIG_FB_FSL_DIU_MODULE ) +#include <linux/bootmem.h> +#include <asm/rheap.h> +struct platform_diu_data_ops { +rh_block_t diu_rh_block[16 ]; +rh_info_t diu_rh_info; +unsigned long diu_size; +void *diu_mem; + +unsigned int (*get_pixel_format) (unsigned int bits_per_pixel, +int monitor_port); +void (*set_gamma_table) (int monitor_port,char *gamma_table_base); +void (*set_monitor_port) (int monitor_port); +void (*set_pixel_clock) (unsigned int pixclock); +ssize_t (*show_monitor_port) (int monitor_port,char *buf); +int (*set_sysfs_monitor_port) (int val); +}; + +extern struct platform_diu_data_ops diu_ops; +#endif +#endif #endif
Signature · 1 line
1.5.2.2
Re: [PATCH 2/2 v2] Add DIU platform code for MPC8610HPCD
arch/powerpc/platforms/86xx/mpc8610_hpcd.c DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); · line 187
Quoted 7 lines · On Wed, 19 Mar 2008 13:50:27 -0500 York Sun <[email protected]> wrote:
Add platform code to support Freescale DIU. The platform code includes framebuffer memory allocation, pixel format, monitor port, etc.
...
arch/powerpc/platforms/86xx/mpc8610_hpcd.c +2
-0+unsigned int mpc8610hpcd_get_pixel_format + (unsigned int bits_per_pixel,int monitor_port)
Again, please do
unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
int monitor_port)
(and anywhere else where this was done)
Quoted 1 line
+int
__initpreallocate_diu_videomemory(void);
Nope, please don't put extern declarations in .c files. Find a suitable header for it - one which is included by the defining file and by all users of the symbol.
Andy, checkpatch missed this.
Quoted 3 lines
}
#endif
+
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
Re: [PATCH 2/2 v2] Add DIU platform code for MPC8610HPCD
Quoted 10 lines · Andrew Morton
arch/powerpc/platforms/86xx/mpc8610_hpcd.c DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); · line 187
Quoted 7 lines · On Wed, 19 Mar 2008 13:50:27 -0500 York Sun <[email protected]> wrote:
Add platform code to support Freescale DIU. The platform code includes framebuffer memory allocation, pixel format, monitor port, etc.
...
arch/powerpc/platforms/86xx/mpc8610_hpcd.c +2
-0+unsigned int mpc8610hpcd_get_pixel_format + (unsigned int bits_per_pixel,int monitor_port)
This seems like it might be detectable, does this seem like something we should try an report?
WARNING: arguments for function declarations should follow identifier #7: FILE: Z110.c:7:
+int __init preallocate_diu_videomemory
Quoted 7 lines
Again, please do
unsigned int mpc8610hpcd_get_pixel_format(unsigned int
bits_per_pixel,
intmonitor_port)(and anywhere else where this was done)
Quoted 7 lines
Quoted 1 line
+int
__initpreallocate_diu_videomemory(void);Nope, please don't put extern declarations in .c files. Find a suitable header for it - one which is included by the defining file and by all users of the symbol.
Andy, checkpatch missed this.
Yeah, we did only look for explicitly extern'd declarations. But this form seems detectable, will be in v0.17.
WARNING: externs should be avoided in .c files
#2: FILE: Z110.c:2:
+int __init preallocate_diu_videomemory(void);
-apw
Re: [PATCH 2/2 v2] Add DIU platform code for MPC8610HPCD
Quoted 7 lines · On Tue, 25 Mar 2008 12:43:22 +0000 Andy Whitcroft <[email protected]> wrote:
Quoted 4 lines
arch/powerpc/platforms/86xx/mpc8610_hpcd.c DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); · line 187
Quoted 4 lines
...
arch/powerpc/platforms/86xx/mpc8610_hpcd.c +2
-0+unsigned int mpc8610hpcd_get_pixel_format + (unsigned int bits_per_pixel,int monitor_port)This seems like it might be detectable, does this seem like something we should try an report?
I guess so. It's quite unusual.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
Re: [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
In reply to York SunQuoted 43 lines · On Wed, 19 Mar 2008 13:50:26 -0500 York Sun <[email protected]> wrote:
The following features are supported:
plane 0 works as a regular frame buffer, can be accessed by/dev/fb0plane 1 has two AOIs (area of interest), can be accessed by/dev/fb1and/dev/fb2plane 2 has two AOIs, can be accessed by/dev/fb3and/dev/fb4Special ioctls support AOIsAll
/dev/fb*can be used as regular frame buffer devices, except hardware change can only be made through/dev/fb0. Changing pixel clock has no effect on other fbs.Limitation of usage of AOIs:
AOIs on the same plane can not be horizonally overlapped
AOIs have horizonal order, i.e. AOI0 should be always on top of AOI1 AOIs can not beyond phisical display area. Application should check AOI geometry before changing physical resolution on/dev/fb0required command line parameters to preallocate memory for frame buffer diufb=15M
optional command line parameters to set modes and monitor video=fslfb:[resolution][,bpp][,monitor]
Syntax:Resolution
xres x yres-bpp@refresh_rate, the -bpp and @refresh_rate are optional eg, 1024x768, 1280x1024, 1280x1024-32, 1280x1024@60, 1280x1024-32@60, 1280x480-32@60Bpp
bpp=32, bpp=24, or bpp=16Monitor
monitor=0, monitor=1, monitor=2
0 is DVI
1 is Single link LVDS
2 is Double link LVDSNote: switching monitor is a board feather, not DIU feather. MPC8610HPCD has three monitor ports to swtich to. MPC5121ADS doesn't have additional monitor port. So switching monirot port for MPC5121ADS has no effect.
If compiled as a module, it takes pamameters mode, bpp, monitor with the same syntax above.
...
Review
Quoted 4 lines
(quoted diff) +4
-0+static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init), +};
I'm not clear on what's supposed to happen with __SPIN_LOCK_UNLOCKED(). I do know that its documentation is crap.
I guess you should have used SPIN_LOCK_UNLOCKED there rather than open-coding its equivalent. And SPIN_LOCK_UNLOCKED _is_ documented. It says "don't use this".
Now, s/documentation/guesswork-and-grep/ says that you're supposed to pick a tree-wide-unique string here as your lockdep key.
So I did this:
drivers/video/fsl-diu-fb.c renamed from drivers/video/fsl-diu-fb.c~fbdev-driver-for-freescale-8610-and-5121-diu-fix +1 -1
@@ -274,7 +274,7 @@ static struct mfb_info mfb_template[] =static struct diu_hw dr = { .mode =MFB_MODE1 , - .reg_lock =__SPIN_LOCK_UNLOCKED (old_style_spin_init), + .reg_lock =__SPIN_LOCK_UNLOCKED (diu_hw.reg_lock), };static struct diu_pool pool;
Quoted 6 lines
(quoted diff) +6
-0+static struct diu_pool pool; + +/* To allocate memory for framebuffer. First try __get_free_pages(). If it + * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate + * very large memory (more than 4MB). We don't want to allocate all memory + * in rheap since small memory allocation/deallocation will fragment the
Review
Quoted 10 lines
(quoted diff) +10
-0+ * rheap and make the furture large allocation fail. + */ + +void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys) +{ + void *virt; + + pr_debug("size=%lu\n", size); + + virt = (void *)__get_free_pages(GFP_DMA | GFP_ATOMIC, get_order(size));
GFP_DMA implies GFP_ATOMIC, but it's appropriate for documentation purposes.
Review
Quoted 4 lines
(quoted diff) +4
-0+ if (virt) { + *phys = virt_to_phys(virt); + pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); + memset(virt, 0, size);
Could have used __GFP_ZERO, I guess.
Review
Quoted 10 lines
(quoted diff) +10
-0+ return virt; + } + if (!diu_ops.diu_mem) { + printk(KERN_INFO "%s: no diu_mem." + " To reserve more memory, put 'diufb=15M' " + "in the command line\n", __func__); + return NULL; + } + + virt = (void *) rh_alloc(&diu_ops.diu_rh_info, size, "DIU");
hm, I'd have expected checkpatch to whine about the space after the cast there. Whatever.
checkpatch does turn up some significant problems:
WARNING: Use #include <linux/uaccess.h> instead of <asm/uaccess.h> #205: FILE: drivers/video/fsl-diu-fb.c:32:
+#include <asm/uaccess.h>
WARNING: consider using strict_strtoul in preference to simple_strtoul #1599: FILE: drivers/video/fsl-diu-fb.c:1426:
+ val = simple_strtoul(buf, last, 0);
WARNING: consider using strict_strtoul in preference to simple_strtoul #1821: FILE: drivers/video/fsl-diu-fb.c:1648:
+ val = simple_strtoul(opt + 8, NULL, 0);
WARNING: consider using strict_strtoul in preference to simple_strtoul #1825: FILE: drivers/video/fsl-diu-fb.c:1652:
+ default_bpp = simple_strtoul(opt + 4, NULL, 0);
please take a look, and please use checkpatch on all future patches.
Quoted 27 lines
(quoted diff) +27
-0+ if (virt) { + *phys = virt_to_bus(virt); + memset(virt, 0, size); + } + + pr_debug("rh virt=%p phys=%lx\n", virt, *phys); + + return virt; +} + +void fsl_diu_free(void *p, unsigned long size) +{ + pr_debug("p=%p size=%lu\n", p, size); + + if (!p) + return; + + if ((p >= diu_ops.diu_mem) && + (p < (diu_ops.diu_mem + diu_ops.diu_size))) { + pr_debug("rh\n"); + rh_free(&diu_ops.diu_rh_info, (unsigned long) p); + } else { + pr_debug("dma\n"); + free_pages((unsigned long)p, get_order(size)); + } +} +
Review
Quoted 10 lines
(quoted diff) +10
-0+ +/* + * Checks to see if the hardware supports the state requested by var passed + * in. This function does not alter the hardware state! If the var passed in + * is slightly off by what the hardware can support then we alter the var + * PASSED in to what we can do. If the hardware doesn't support mode change + * a -EINVAL will be returned by the upper layers. + */ +static int fsl_diu_check_var + (struct fb_var_screeninfo *var, struct fb_info *info)
Like this:
static int fsl_diu_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
please.
Quoted 11 lines
(quoted diff) +8
-0+{ + unsigned long htotal, vtotal; + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + int index = mfbi->index; + +static void update_lcdc(struct fb_info *info) +{
Review
Quoted 10 lines
(quoted diff) +10
-0+ struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu *hw; + int i, j; + char __iomem *cursor_base, *gamma_table_base; + + u32 temp; + + spin_lock_init(&dr.reg_lock);
we already did that at compile-time?
Quoted 24 lines
(quoted diff) +21
-0+ hw = dr.diu_reg; + + if (mfbi->type == MFB_TYPE_OFF) { + fsl_diu_disable_panel(info); + return; + } +static void request_irq_local(int irq) +{ + unsigned long status, ints; + struct diu *hw; + + hw = dr.diu_reg; + + /* Read to clear the status */ + status = in_be32(&(hw->int_status)); + + if (request_irq(irq, fsl_diu_isr, 0, "diu", 0)) + pr_info("Request diu IRQ failed.\n"); + else { + ints = INT_PARERR | INT_LS_BF_VS; +#if !defined(CONFIG_NOT_COHERENT_CACHE)
Review
Quoted 10 lines
(quoted diff) +10
-0+ ints |= INT_VSYNC; +#endif + if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) + ints |= INT_VSYNC_WB; + + /* Read to clear the status */ + status = in_be32(&(hw->int_status)); + out_be32(&(hw->int_mask), ints); + } +}
The request_irq() return value gets dropped on the floor.
Review
Quoted 9 lines
(quoted diff) +9
-0+static void free_irq_local(int irq) +{ + struct diu *hw = dr.diu_reg; + + /* Disable all LCDC interrupt */ + out_be32(&(hw->int_mask), 0x1f); + + free_irq(irq, 0); +}
and the free_irq() will go splat?
Quoted 14 lines
(quoted diff) +14
-0+#ifdef CONFIG_PM +/* + * Power management hooks. Note that we won't be called from IRQ context, + * unlike the blank functions above, so we may sleep. + */ +static int fsl_diu_suspend(struct of_device *dev, pm_message_t state) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +}
Review
Quoted 10 lines
(quoted diff) +10
-0+ +static int fsl_diu_resume(struct of_device *dev) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + enable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +}
Conventionally we'll do
#else
#define fsl_diu_suspend NULL
#define fsl_diu_resume NULL
here, then remove the ifdefs from fsl_diu_driver.
Quoted 6 lines
(quoted diff) +6
-0+#endif /* CONFIG_PM */ + +/* Align to 64-bit(8-byte), 32-byte, etc. */ +static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + u32 offset, ssize;
Review
Quoted 10 lines
(quoted diff) +10
-0+ u32 mask; + dma_addr_t paddr = 0; + + ssize = size + bytes_align; + buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | GFP_KERNEL); + if (!buf->vaddr) + return -ENOMEM; + + buf->paddr = (__u32) paddr; + memset(buf->vaddr, 0, ssize);
__GFP_ZERO?
Quoted 16 lines
(quoted diff) +16
-0+ mask = bytes_align - 1; + offset = (u32)buf->paddr & mask; + if (offset) { + buf->offset = bytes_align - offset; + buf->paddr = (u32)buf->paddr + offset; + } else + buf->offset = 0; + return 0; +} + +static int fsl_diu_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct mfb_info *mfbi; + phys_addr_t dummy_ad_addr;
Review
Quoted 10 lines
(quoted diff) +10
-0+ int ret, i, error = 0; + struct resource res; + struct fsl_diu_data *machine_data; + + machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); + if (!machine_data) + return -ENOMEM; + + for (i = 0; i < sizeof(machine_data->fsl_diu_info) / + sizeof(struct fb_info *); i++) {
Please use ARRAY_SIZE() here, and in all the other places which open-code it.
Review
Quoted 7 lines
(quoted diff) +7
-0+ machine_data->fsl_diu_info[i] = + framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); + if (!machine_data->fsl_diu_info[i]) { + dev_err(&ofdev->dev, "cannot allocate memory\n"); + ret = -ENOMEM; + goto error2; + }
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
Re: [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
Quoted 21 lines · Andrew Morton
Review
Quoted 5 lines
(quoted diff) +4
-0+static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init), +};I'm not clear on what's supposed to happen with
__SPIN_LOCK_UNLOCKED(). I do know that its documentation is crap.I guess you should have used
SPIN_LOCK_UNLOCKEDthere rather than open-coding its equivalent. AndSPIN_LOCK_UNLOCKED_is_ documented. It says "don't use this".Now, s/documentation/guesswork-and-grep/ says that you're supposed to pick a tree-wide-unique string here as your lockdep key.
So I did this:
drivers/video/fsl-diu-fb.c static struct mfb_info mfb_template[] = · line 278
Quoted 6 lines
drivers/video/fsl-diu-fb.c renamed from drivers/video/fsl-diu-fb.c~fbdev-driver-for-freescale-8610-and-5121-diu-fix +1
-1@@ -274,7 +274,7 @@ static struct mfb_info mfb_template[] =static struct diu_hw dr = { .mode =MFB_MODE1 , - .reg_lock =__SPIN_LOCK_UNLOCKED (old_style_spin_init), + .reg_lock =__SPIN_LOCK_UNLOCKED (diu_hw.reg_lock), };
#define __SPIN_LOCK_UNLOCKED(lockname)
seems pretty suggestive to me, also DEFINE_SPINLOCK(x) shows the proper usage; the right thing would have been:
static struct diu_hw dr = {
.mode = MFB_MODE1,
- .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init),
+ .reg_lock = __SPIN_LOCK_UNLOCKED(dr.reg_lock),
};
Where 'dr.reg_lock' is the expression to locate the actual object.
Does something like this make sense to you:
---
Subject: lockdep: document __SPIN_LOCK_UNLOCKED() usage
Small comment clarifying the intended usage of __SPIN_LOCK_UNLOCKED()
[ for the observant readers; yes this prescribes a usage that is more
than strictly needed, it does however enable interesting future uses ]
---
include/linux/spinlock_types.h +4 -0
@@ -63,6 +63,10 @@ typedef struct {# define RW_DEP_MAP_INIT (lockname)#endif +/* +* __*_LOCK_UNLOCKED(lockname), where 'lockname' is a valid C expression +* that evaluates to the actual object being initialized. +*/ #ifdef CONFIG_DEBUG_SPINLOCK # define __SPIN_LOCK_UNLOCKED (lockname) \ (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \
---
Perhaps I should make the macros do something like:
typecheck(spinlock_t, lockname)
And sweep the tree to make it compile again.
Quoted 12 lines
drivers/video/fsl-diu-fb.c renamed from drivers/video/fsl-diu-fb.c~fbdev-driver-for-freescale-8610-and-5121-diu-fix +0
-0static struct diu_pool pool;Quoted 10 lines
(quoted diff) +10
-0+static struct diu_pool pool; + +/* To allocate memory for framebuffer. First try __get_free_pages(). If it + * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate + * very large memory (more than 4MB). We don't want to allocate all memory + * in rheap since small memory allocation/deallocation will fragment the + * rheap and make the furture large allocation fail. + */ + +void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
Quoted 8 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+{ + void *virt; + + pr_debug("size=%lu\n", size); + + virt = (void *)__get_free_pages(GFP_DMA | GFP_ATOMIC, get_order(size));
GFP_DMAimpliesGFP_ATOMIC, but it's appropriate for documentation purposes.
FWIW, I prefer the form: GFP_type | __GFP_modifiers
For instance: 'GFP_KERNEL | __GFP_DMA | __GFP_ZERO'
Re: [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
In reply to Andrew MortonQuoted 7 lines · Andrew Morton
Review
Quoted 4 lines
(quoted diff) +4
-0+static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init), +};I'm not clear on what's supposed to happen with
__SPIN_LOCK_UNLOCKED(). I do know that its documentation is crap.
Yes, "__SPIN_LOCK_UNLOCKED(old_style_spin_init)" is wrong. We'll fix it.
drivers/video/fsl-diu-fb.c static struct mfb_info mfb_template[] = · line 278
Quoted 5 lines
static struct
diu_hwdr = {drivers/video/fsl-diu-fb.c renamed from drivers/video/fsl-diu-fb.c~fbdev-driver-for-freescale-8610-and-5121-diu-fix +1
-1.mode = MFB_MODE1, - .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init), + .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), };
Yes, this is better. Did you already make this change when you applied it to your -mm repo?
Quoted 1 line
GFP_DMAimpliesGFP_ATOMIC, but it's appropriate for documentation purposes.
So does that mean that "GFP_DMA | GFP_KERNEL" is always wrong? If so, this combination is used a lot in the kernel today.
Quoted 6 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ if (virt) { + *phys = virt_to_phys(virt); + pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); + memset(virt, 0, size);Could have used
__GFP_ZERO, I guess.
I had completely forgotten about __GFP_ZERO. Thanks.
Quoted 4 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ virt = (void *) rh_alloc(&diu_ops.diu_rh_info, size, "DIU");hm, I'd have expected checkpatch to whine about the space after the cast there. Whatever.
I thought a space after a cast is the right thing to do?
Quoted 1 line
please take a look, and please use checkpatch on all future patches.
Sorry, we forgot to run it again after our second version of the patch.
Quoted 11 lines
Review
Quoted 9 lines
(quoted diff) +9
-0+static void free_irq_local(int irq) +{ + struct diu *hw = dr.diu_reg; + + /* Disable all LCDC interrupt */ + out_be32(&(hw->int_mask), 0x1f); + + free_irq(irq, 0); +}and the
free_irq()will go splat?
Sorry, but I don't understand what's wrong with this code.
We'll make the other changes you've suggested and repost.
Signature · 2 lines
Timur Tabi Linux kernel developer at Freescale
Re: [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
Quoted 12 lines · On Fri, 21 Mar 2008 11:12:30 -0500 Timur Tabi <[email protected]> wrote:
Quoted 7 lines · Andrew Morton
Review
Quoted 4 lines
(quoted diff) +4
-0+static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init), +};I'm not clear on what's supposed to happen with
__SPIN_LOCK_UNLOCKED(). I do know that its documentation is crap.Yes, "
__SPIN_LOCK_UNLOCKED(old_style_spin_init)" is wrong. We'll fix it.
Quoted 8 lines
Review
Quoted 5 lines
static struct
diu_hwdr = {(quoted diff) +1
-1.mode = MFB_MODE1, - .reg_lock = __SPIN_LOCK_UNLOCKED(old_style_spin_init), + .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), };Yes, this is better. Did you already make this change when you applied it to your -mm repo?
I did:
drivers/video/fsl-diu-fb.c renamed from drivers/video/fsl-diu-fb.c~fbdev-driver-for-freescale-8610-and-5121-diu-fix +1 -1
@@ -274,7 +274,7 @@ static struct mfb_info mfb_template[] =static struct diu_hw dr = { .mode =MFB_MODE1 , - .reg_lock =__SPIN_LOCK_UNLOCKED (old_style_spin_init), + .reg_lock =__SPIN_LOCK_UNLOCKED (dr.reg_lock), };static struct diu_pool pool;
Quoted 3 lines
Quoted 1 line
GFP_DMAimpliesGFP_ATOMIC, but it's appropriate for documentation purposes.So does that mean that "
GFP_DMA|GFP_KERNEL" is always wrong?
No, that's OK too. It's just that GFP_DMA|GFP_ATOMIC is a bit redundant and misleading. GFP_DMA is already atomic; the only effect of adding GFP_ATOMIC to GFP_DMA is to add __GFP_HIGH.
Don't wory about it ;)
Quoted 10 lines
If so, this
combination is used a lot in the kernel today.Quoted 6 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ if (virt) { + *phys = virt_to_phys(virt); + pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); + memset(virt, 0, size);Could have used
__GFP_ZERO, I guess.
Quoted 8 lines
I had completely forgotten about
__GFP_ZERO. Thanks.Quoted 4 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ virt = (void *) rh_alloc(&diu_ops.diu_rh_info, size, "DIU");hm, I'd have expected checkpatch to whine about the space after the cast there. Whatever.
I thought a space after a cast is the right thing to do?
Last time I grepped, no-space is a lot more common.
Quoted 16 lines
Quoted 1 line
please take a look, and please use checkpatch on all future patches.
Sorry, we forgot to run it again after our second version of the patch.
Quoted 11 lines
Review
Quoted 9 lines
(quoted diff) +9
-0+static void free_irq_local(int irq) +{ + struct diu *hw = dr.diu_reg; + + /* Disable all LCDC interrupt */ + out_be32(&(hw->int_mask), 0x1f); + + free_irq(irq, 0); +}and the
free_irq()will go splat?
Quoted 1 line
Sorry, but I don't understand what's wrong with this code.
You snipped a bit. Earlier, request_irq() failures were ignored. So I think there's a code path where free_irq_local() can free an IRQ which this driver never owned.
Quoted 1 line
We'll make the other changes you've suggested and repost.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
Re: [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
Quoted 8 lines · Andrew Morton
Quoted 2 lines
Quoted 1 line
GFP_DMAimpliesGFP_ATOMIC, but it's appropriate for documentation purposes.So does that mean that "
GFP_DMA|GFP_KERNEL" is always wrong?No, that's OK too. It's just that GFP_DMA|GFP_ATOMIC is a bit redundant and misleading.
GFP_DMAis already atomic; the only effect of addingGFP_ATOMICtoGFP_DMAis to add__GFP_HIGH.Don't wory about it ;)
Well, maybe we don't want GFP_ATOMIC then, because I don't think we want __GFP_HIGH. Looking at the code, it appears the __GFP_HIGH has nothing to do with HIGHMEM (which on PowerPC is the not 1-to-1 mapping memory from 0xF000000 to 0xFFFFFFFF). Further examination of the cools shows the __GFP_HIGH says to try access the "emergency pool", and I see this code snippet:
if (alloc_flags & ALLOC_HIGH) min -= min / 2;
I guess this means that we reduce the amount of memory that can be available in order for the allocate to succeed.
Considering that the amount of memory that we allocate is in the order of megabytes, and it really isn't that important, I would think that we don't want to touch the emergency pool. Does that sound right?
Signature · 7 lines
Timur Tabi Linux kernel developer at Freescale ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
Re: [PATCH 1/2 v2] Driver for Freescale 8610 and 5121 DIU
Quoted 20 lines · On Mon, 24 Mar 2008 09:53:16 -0500 Timur Tabi <[email protected]> wrote:
Quoted 8 lines · Andrew Morton
Quoted 2 lines
Quoted 1 line
GFP_DMAimpliesGFP_ATOMIC, but it's appropriate for documentation purposes.So does that mean that "
GFP_DMA|GFP_KERNEL" is always wrong?No, that's OK too. It's just that GFP_DMA|GFP_ATOMIC is a bit redundant and misleading.
GFP_DMAis already atomic; the only effect of addingGFP_ATOMICtoGFP_DMAis to add__GFP_HIGH.Don't wory about it ;)
Well, maybe we don't want
GFP_ATOMICthen, because I don't think we want__GFP_HIGH. Looking at the code, it appears the__GFP_HIGHhas nothing to do with HIGHMEM (which on PowerPC is the not 1-to-1 mapping memory from0xF000000to0xFFFFFFFF). Further examination of the cools shows the__GFP_HIGHsays to try access the "emergency pool", and I see this code snippet:if (alloc_flags & ALLOC_HIGH) min -= min / 2;
Quoted 6 lines
I guess this means that we reduce the amount of memory that can be available in order for the allocate to succeed.
Considering that the amount of memory that we allocate is in the order of megabytes, and it really isn't that important, I would think that we don't want to touch the emergency pool. Does that sound right?
yup. The absence of __GFP_WAIT already causes the page allocator to try a bit harder. Adding __GFP_HIGH would make it try harder still.
You do need to be sure that the driver will robustly and correctly recover from an allocation failure here.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/