Thread (15 messages) 15 messages, 2 authors, 2010-05-03

Re: [PATCH 3/5] powerpc/mpc5121: shared DIU framebuffer support

From: Anatolij Gustschin <agust@denx.de>
Date: 2010-04-30 10:19:47
Also in: linux-devicetree, linuxppc-dev

On Thu, 29 Apr 2010 21:05:26 -0500
Timur Tabi [off-list ref] wrote:
On Thu, Apr 29, 2010 at 6:49 PM, Anatolij Gustschin [off-list ref] wrote:

quoted
+void __init mpc5121_ads_init_early(void)
+{
+       mpc512x_init_diu();
+}
+
 define_machine(mpc5121_ads) {
       .name                   = "MPC5121 ADS",
       .probe                  = mpc5121_ads_probe,
       .setup_arch             = mpc5121_ads_setup_arch,
       .init                   = mpc512x_init,
+       .init_early             = mpc5121_ads_init_early,
How about just doing this?

.init_early             = mpc512x_init_diu,
I thought it should be prepared for adding other code here.
mpc5121_ads_init_early() is generic and could contain other
things as well. I would vote for current version.
quoted
+void __init mpc512x_generic_init_early(void)
+{
+       mpc512x_init_diu();
+}
+
+void __init mpc512x_generic_setup_arch(void)
+{
+       mpc512x_setup_diu();
+}
+
 define_machine(mpc5121_generic) {
       .name                   = "MPC5121 generic",
       .probe                  = mpc5121_generic_probe,
       .init                   = mpc512x_init,
+       .init_early             = mpc512x_generic_init_early,
+       .setup_arch             = mpc512x_generic_setup_arch,
And a similar change here.
Same here.

...
quoted
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index b7f518a..8e297fa 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -16,7 +16,11 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of_platform.h>
+#include <linux/fsl-diu-fb.h>
+#include <linux/bootmem.h>
+#include <sysdev/fsl_soc.h>

+#include <asm/cacheflush.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/prom.h>
@@ -53,6 +57,286 @@ void mpc512x_restart(char *cmd)
               ;
 }

+struct fsl_diu_shared_fb {
+       char            gamma[0x300];   /* 32-bit aligned! */
char or u8?
Will use u8.
quoted
+       struct diu_ad   ad0;            /* 32-bit aligned! */
+       phys_addr_t     fb_phys;
+       size_t          fb_len;
+       bool            in_use;
+};
Where did "bool" come from?  Use "int" instead.
It is common practise to use "bool" type, grep in drivers dir.
quoted
+unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
+                                     int monitor_port)
+{
+       unsigned int pix_fmt;
+
+       switch (bits_per_pixel) {
+       case 32:
+               pix_fmt = 0x88883316;
+               break;
+       case 24:
+               pix_fmt = 0x88082219;
+               break;
+       case 16:
+               pix_fmt = 0x65053118;
+               break;
+       default:
+               pix_fmt = 0x00000400;
+       }
+       return pix_fmt;
+}
This is simpler:

       switch (bits_per_pixel) {
       case 32:
               return 0x88883316;
       case 24:
               return 0x88082219;
       case 16:
               return = 0x65053118;
      }

      return 0x00000400;
}
Will simplify as suggested, thanks!
quoted
+       ccm = of_iomap(np, 0);
+       if (!ccm) {
+               pr_err("Can't map clock control module reg.\n");
+               of_node_put(np);
+               return;
+       }
+       of_node_put(np);
This is simpler:

       ccm = of_iomap(np, 0);
       of_node_put(np);
       if (!ccm) {
               pr_err("Can't map clock control module reg.\n");
               return;
       }
OK, will fix, thanks.
quoted
+       np = of_find_node_by_type(NULL, "cpu");
+       if (np) {
+               unsigned int size;
+               const unsigned int *prop > > +                       of_get_property(np, "bus-frequency", &size);
Since you don't use 'size', you can skip it:

              const unsigned int *prop >                       of_get_property(np, "bus-frequency", NULL);
quoted
+       } else {
+               pr_err("Can't find \"cpu\" node.\n");
'cpu' is simpler than \"cpu\"
Will simplify, too.
quoted
+       /* 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) * 1000;
I'm pretty sure the compiler will optimize this to:

    temp = (1000000000000UL / pixclock);

so you may as well do it that way.
??
1000000000000 is _not_ UL, but UUL.
quoted
+       pixclock = temp;
+       pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+       temp = (temp * 5) / 100; /* pixclock * 0.05 */
The compiler will optimize this to:

    temp /= 20;
Can do it, too. Thanks.
quoted
+       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;
Why do you assign err to this arbitrary value?
Dunno. It is Freescale's code and I do not have time to check
and understand each bit of it and to explain it.
quoted
+       bestval = pixval;
+       pr_debug("DIU bestval = %lu\n", bestval);
+
+       bestfreq = 0;
+       for (i = -1; i <= 1; i++) {
+               temp = speed_ccb / (pixval+i);
+               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 DIU_DIV in CCM SCFR1 */
+       temp = in_be32(ccm + CCM_SCFR1);
Don't use offsets like + CCM_SCFR1.  Create a structure and use that instead.
Done in next patch version.
quoted
+       pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
+       temp &= ~DIU_DIV_MASK;
+       temp |= (bestval & DIU_DIV_MASK);
+       out_be32(ccm + CCM_SCFR1, temp);
+       pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
+       iounmap(ccm);
+}
+
+ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0 - 5121 LCD\n");
There's no point in using snprintf since you're printing a string
literal.  You can use sprintf.
Will do, thanks.
quoted
+}
+
+int mpc512x_set_sysfs_monitor_port(int val)
+{
+       return 0;
+}
+
+static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+static inline void mpc512x_free_bootmem(struct page *page)
+{
+       __ClearPageReserved(page);
+       BUG_ON(PageTail(page));
+       BUG_ON(atomic_read(&page->_count) > 1);
+       atomic_set(&page->_count, 1);
+       __free_page(page);
+       totalram_pages++;
+}
+
+void mpc512x_release_bootmem(void)
+{
+       unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
+       unsigned long size = diu_shared_fb.fb_len;
+       unsigned long start, end;
+
+       if (diu_shared_fb.in_use) {
+               start = PFN_UP(addr);
+               end = PFN_DOWN(addr + size);
+
+               for (; start < end; start++)
+                       mpc512x_free_bootmem(pfn_to_page(start));
+
+               diu_shared_fb.in_use = false;
+       }
+       diu_ops.release_bootmem = NULL;
+}
+#endif
Do you really need to use reserve_bootmem?  Have you tried kmalloc or
alloc_pages_exact()?
Yes. No, it is too early to use them here.
quoted
+
+/*
+ * Check if DIU was pre-initialized. If so, perform steps
+ * needed to continue displaying through the whole boot process.
+ * Move area descriptor and gamma table elsewhere, they are
+ * destroyed by bootmem allocator otherwise. The frame buffer
+ * address range will be reserved in setup_arch() after bootmem
+ * allocator is up.
+ */
+void __init mpc512x_init_diu(void)
+{
+       struct device_node *np;
+       void __iomem *diu_reg;
+       phys_addr_t desc;
+       void __iomem *vaddr;
+       unsigned long mode, pix_fmt, res, bpp;
+       unsigned long dst;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
+       if (!np) {
+               pr_err("No DIU node\n");
+               return;
+       }
Shouldn't you be probing as an OF driver instead of manually searching
for the DIU node?
No, not here.
quoted
+
+       diu_reg = of_iomap(np, 0);
+       of_node_put(np);
+       if (!diu_reg) {
+               pr_err("Can't map DIU\n");
+               return;
+       }
+
+       mode = in_be32(diu_reg + 0x1c);
+       if (mode != 1) {
How can in_be32() return a -1?
It is a 1, not -1. I will use appropriate macro here and also
change to use a struct instead of adding offset to register base.

Thanks for your review and comments!
Anatolij
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help