Commit 6f90a8bdd17e63fb27b4f6d50e8a2919704ea254

Authored by York Sun
Committed by Linus Torvalds
1 parent 9b53a9e28a

powerpc: 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.

Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Timur Tabi <timur@freescale.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 245 additions and 9 deletions Side-by-side Diff

arch/powerpc/platforms/86xx/mpc8610_hpcd.c
... ... @@ -3,11 +3,12 @@
3 3 *
4 4 * Initial author: Xianghua Xiao <x.xiao@freescale.com>
5 5 * Recode: Jason Jin <jason.jin@freescale.com>
  6 + * York Sun <yorksun@freescale.com>
6 7 *
7 8 * Rewrite the interrupt routing. remove the 8259PIC support,
8 9 * All the integrated device in ULI use sideband interrupt.
9 10 *
10   - * Copyright 2007 Freescale Semiconductor Inc.
  11 + * Copyright 2008 Freescale Semiconductor Inc.
11 12 *
12 13 * This program is free software; you can redistribute it and/or modify it
13 14 * under the terms of the GNU General Public License as published by the
... ... @@ -38,6 +39,8 @@
38 39 #include <sysdev/fsl_pci.h>
39 40 #include <sysdev/fsl_soc.h>
40 41  
  42 +static unsigned char *pixis_bdcfg0, *pixis_arch;
  43 +
41 44 static struct of_device_id __initdata mpc8610_ids[] = {
42 45 { .compatible = "fsl,mpc8610-immr", },
43 46 {}
... ... @@ -52,8 +55,7 @@
52 55 }
53 56 machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
54 57  
55   -static void __init
56   -mpc86xx_hpcd_init_irq(void)
  58 +static void __init mpc86xx_hpcd_init_irq(void)
57 59 {
58 60 struct mpic *mpic1;
59 61 struct device_node *np;
60 62  
61 63  
... ... @@ -161,12 +163,159 @@
161 163 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288);
162 164 #endif /* CONFIG_PCI */
163 165  
164   -static void __init
165   -mpc86xx_hpcd_setup_arch(void)
  166 +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
  167 +
  168 +static u32 get_busfreq(void)
166 169 {
167   -#ifdef CONFIG_PCI
168   - struct device_node *np;
  170 + struct device_node *node;
  171 +
  172 + u32 fs_busfreq = 0;
  173 + node = of_find_node_by_type(NULL, "cpu");
  174 + if (node) {
  175 + unsigned int size;
  176 + const unsigned int *prop =
  177 + of_get_property(node, "bus-frequency", &size);
  178 + if (prop)
  179 + fs_busfreq = *prop;
  180 + of_node_put(node);
  181 + };
  182 + return fs_busfreq;
  183 +}
  184 +
  185 +unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
  186 + int monitor_port)
  187 +{
  188 + static const unsigned long pixelformat[][3] = {
  189 + {0x88882317, 0x88083218, 0x65052119},
  190 + {0x88883316, 0x88082219, 0x65053118},
  191 + };
  192 + unsigned int pix_fmt, arch_monitor;
  193 +
  194 + arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1;
  195 + /* DVI port for board version 0x01 */
  196 +
  197 + if (bits_per_pixel == 32)
  198 + pix_fmt = pixelformat[arch_monitor][0];
  199 + else if (bits_per_pixel == 24)
  200 + pix_fmt = pixelformat[arch_monitor][1];
  201 + else if (bits_per_pixel == 16)
  202 + pix_fmt = pixelformat[arch_monitor][2];
  203 + else
  204 + pix_fmt = pixelformat[1][0];
  205 +
  206 + return pix_fmt;
  207 +}
  208 +
  209 +void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
  210 +{
  211 + int i;
  212 + if (monitor_port == 2) { /* dual link LVDS */
  213 + for (i = 0; i < 256*3; i++)
  214 + gamma_table_base[i] = (gamma_table_base[i] << 2) |
  215 + ((gamma_table_base[i] >> 6) & 0x03);
  216 + }
  217 +}
  218 +
  219 +void mpc8610hpcd_set_monitor_port(int monitor_port)
  220 +{
  221 + static const u8 bdcfg[] = {0xBD, 0xB5, 0xA5};
  222 + if (monitor_port < 3)
  223 + *pixis_bdcfg0 = bdcfg[monitor_port];
  224 +}
  225 +
  226 +void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
  227 +{
  228 + u32 __iomem *clkdvdr;
  229 + u32 temp;
  230 + /* variables for pixel clock calcs */
  231 + ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock;
  232 + ulong pixval;
  233 + long err;
  234 + int i;
  235 +
  236 + clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32));
  237 + if (!clkdvdr) {
  238 + printk(KERN_ERR "Err: can't map clock divider register!\n");
  239 + return;
  240 + }
  241 +
  242 + /* Pixel Clock configuration */
  243 + pr_debug("DIU: Bus Frequency = %d\n", get_busfreq());
  244 + speed_ccb = get_busfreq();
  245 +
  246 + /* Calculate the pixel clock with the smallest error */
  247 + /* calculate the following in steps to avoid overflow */
  248 + pr_debug("DIU pixclock in ps - %d\n", pixclock);
  249 + temp = 1000000000/pixclock;
  250 + temp *= 1000;
  251 + pixclock = temp;
  252 + pr_debug("DIU pixclock freq - %u\n", pixclock);
  253 +
  254 + temp = pixclock * 5 / 100;
  255 + pr_debug("deviation = %d\n", temp);
  256 + minpixclock = pixclock - temp;
  257 + maxpixclock = pixclock + temp;
  258 + pr_debug("DIU minpixclock - %lu\n", minpixclock);
  259 + pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
  260 + pixval = speed_ccb/pixclock;
  261 + pr_debug("DIU pixval = %lu\n", pixval);
  262 +
  263 + err = 100000000;
  264 + bestval = pixval;
  265 + pr_debug("DIU bestval = %lu\n", bestval);
  266 +
  267 + bestfreq = 0;
  268 + for (i = -1; i <= 1; i++) {
  269 + temp = speed_ccb / ((pixval+i) + 1);
  270 + pr_debug("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n",
  271 + i, pixval, temp);
  272 + if ((temp < minpixclock) || (temp > maxpixclock))
  273 + pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
  274 + minpixclock, maxpixclock);
  275 + else if (abs(temp - pixclock) < err) {
  276 + pr_debug("Entered the else if block %d\n", i);
  277 + err = abs(temp - pixclock);
  278 + bestval = pixval+i;
  279 + bestfreq = temp;
  280 + }
  281 + }
  282 +
  283 + pr_debug("DIU chose = %lx\n", bestval);
  284 + pr_debug("DIU error = %ld\n NomPixClk ", err);
  285 + pr_debug("DIU: Best Freq = %lx\n", bestfreq);
  286 + /* Modify PXCLK in GUTS CLKDVDR */
  287 + pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr));
  288 + temp = (*clkdvdr) & 0x2000FFFF;
  289 + *clkdvdr = temp; /* turn off clock */
  290 + *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16);
  291 + pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr));
  292 + iounmap(clkdvdr);
  293 +}
  294 +
  295 +ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf)
  296 +{
  297 + return snprintf(buf, PAGE_SIZE,
  298 + "%c0 - DVI\n"
  299 + "%c1 - Single link LVDS\n"
  300 + "%c2 - Dual link LVDS\n",
  301 + monitor_port == 0 ? '*' : ' ',
  302 + monitor_port == 1 ? '*' : ' ',
  303 + monitor_port == 2 ? '*' : ' ');
  304 +}
  305 +
  306 +int mpc8610hpcd_set_sysfs_monitor_port(int val)
  307 +{
  308 + return val < 3 ? val : 0;
  309 +}
  310 +
169 311 #endif
  312 +
  313 +static void __init mpc86xx_hpcd_setup_arch(void)
  314 +{
  315 + struct resource r;
  316 + struct device_node *np;
  317 + unsigned char *pixis;
  318 +
170 319 if (ppc_md.progress)
171 320 ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0);
172 321  
173 322  
... ... @@ -183,7 +332,31 @@
183 332 }
184 333 }
185 334 #endif
  335 +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
  336 + preallocate_diu_videomemory();
  337 + diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format;
  338 + diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table;
  339 + diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port;
  340 + diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock;
  341 + diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port;
  342 + diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port;
  343 +#endif
186 344  
  345 + np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
  346 + if (np) {
  347 + of_address_to_resource(np, 0, &r);
  348 + of_node_put(np);
  349 + pixis = ioremap(r.start, 32);
  350 + if (!pixis) {
  351 + printk(KERN_ERR "Err: can't map FPGA cfg register!\n");
  352 + return;
  353 + }
  354 + pixis_bdcfg0 = pixis + 8;
  355 + pixis_arch = pixis + 1;
  356 + } else
  357 + printk(KERN_ERR "Err: "
  358 + "can't find device node 'fsl,fpga-pixis'\n");
  359 +
187 360 printk("MPC86xx HPCD board from Freescale Semiconductor\n");
188 361 }
189 362  
... ... @@ -200,8 +373,7 @@
200 373 return 0;
201 374 }
202 375  
203   -static long __init
204   -mpc86xx_time_init(void)
  376 +static long __init mpc86xx_time_init(void)
205 377 {
206 378 unsigned int temp;
207 379  
arch/powerpc/sysdev/fsl_soc.c
... ... @@ -892,4 +892,45 @@
892 892 while (1) ;
893 893 }
894 894 #endif
  895 +
  896 +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
  897 +struct platform_diu_data_ops diu_ops = {
  898 + .diu_size = 1280 * 1024 * 4, /* default one 1280x1024 buffer */
  899 +};
  900 +EXPORT_SYMBOL(diu_ops);
  901 +
  902 +int __init preallocate_diu_videomemory(void)
  903 +{
  904 + pr_debug("diu_size=%lu\n", diu_ops.diu_size);
  905 +
  906 + diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0);
  907 + if (!diu_ops.diu_mem) {
  908 + printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n",
  909 + diu_ops.diu_size);
  910 + return -ENOMEM;
  911 + }
  912 +
  913 + pr_debug("diu_mem=%p\n", diu_ops.diu_mem);
  914 +
  915 + rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block),
  916 + diu_ops.diu_rh_block);
  917 + return rh_attach_region(&diu_ops.diu_rh_info,
  918 + (unsigned long) diu_ops.diu_mem,
  919 + diu_ops.diu_size);
  920 +}
  921 +
  922 +static int __init early_parse_diufb(char *p)
  923 +{
  924 + if (!p)
  925 + return 1;
  926 +
  927 + diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8);
  928 +
  929 + pr_debug("diu_size=%lu\n", diu_ops.diu_size);
  930 +
  931 + return 0;
  932 +}
  933 +early_param("diufb", early_parse_diufb);
  934 +
  935 +#endif
arch/powerpc/sysdev/fsl_soc.h
... ... @@ -17,6 +17,29 @@
17 17 void (*deactivate_cs)(u8 cs, u8 polarity));
18 18  
19 19 extern void fsl_rstcr_restart(char *cmd);
  20 +
  21 +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
  22 +#include <linux/bootmem.h>
  23 +#include <asm/rheap.h>
  24 +struct platform_diu_data_ops {
  25 + rh_block_t diu_rh_block[16];
  26 + rh_info_t diu_rh_info;
  27 + unsigned long diu_size;
  28 + void *diu_mem;
  29 +
  30 + unsigned int (*get_pixel_format) (unsigned int bits_per_pixel,
  31 + int monitor_port);
  32 + void (*set_gamma_table) (int monitor_port, char *gamma_table_base);
  33 + void (*set_monitor_port) (int monitor_port);
  34 + void (*set_pixel_clock) (unsigned int pixclock);
  35 + ssize_t (*show_monitor_port) (int monitor_port, char *buf);
  36 + int (*set_sysfs_monitor_port) (int val);
  37 +};
  38 +
  39 +extern struct platform_diu_data_ops diu_ops;
  40 +int __init preallocate_diu_videomemory(void);
  41 +#endif
  42 +
20 43 #endif
21 44 #endif