1/* 2 * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. 3 * 4 * Author: John Rigby <jrigby@freescale.com> 5 * 6 * Description: 7 * MPC512x Shared code 8 * 9 * This is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 */ 14 15#include <linux/kernel.h> 16#include <linux/io.h> 17#include <linux/irq.h> 18#include <linux/of_platform.h> 19#include <linux/fsl-diu-fb.h> 20#include <linux/bootmem.h> 21#include <sysdev/fsl_soc.h> 22 23#include <asm/cacheflush.h> 24#include <asm/machdep.h> 25#include <asm/ipic.h> 26#include <asm/prom.h> 27#include <asm/time.h> 28#include <asm/mpc5121.h> 29#include <asm/mpc52xx_psc.h> 30 31#include "mpc512x.h" 32 33static struct mpc512x_reset_module __iomem *reset_module_base; 34 35static void __init mpc512x_restart_init(void) 36{ 37 struct device_node *np; 38 39 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); 40 if (!np) 41 return; 42 43 reset_module_base = of_iomap(np, 0); 44 of_node_put(np); 45} 46 47void mpc512x_restart(char *cmd) 48{ 49 if (reset_module_base) { 50 /* Enable software reset "RSTE" */ 51 out_be32(&reset_module_base->rpr, 0x52535445); 52 /* Set software hard reset */ 53 out_be32(&reset_module_base->rcr, 0x2); 54 } else { 55 pr_err("Restart module not mapped.\n"); 56 } 57 for (;;) 58 ; 59} 60 61struct fsl_diu_shared_fb { 62 u8 gamma[0x300]; /* 32-bit aligned! */ 63 struct diu_ad ad0; /* 32-bit aligned! */ 64 phys_addr_t fb_phys; 65 size_t fb_len; 66 bool in_use; 67}; 68 69unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel, 70 int monitor_port) 71{ 72 switch (bits_per_pixel) { 73 case 32: 74 return 0x88883316; 75 case 24: 76 return 0x88082219; 77 case 16: 78 return 0x65053118; 79 } 80 return 0x00000400; 81} 82 83void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base) 84{ 85} 86 87void mpc512x_set_monitor_port(int monitor_port) 88{ 89} 90 91#define DIU_DIV_MASK 0x000000ff 92void mpc512x_set_pixel_clock(unsigned int pixclock) 93{ 94 unsigned long bestval, bestfreq, speed, busfreq; 95 unsigned long minpixclock, maxpixclock, pixval; 96 struct mpc512x_ccm __iomem *ccm; 97 struct device_node *np; 98 u32 temp; 99 long err; 100 int i; 101 102 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); 103 if (!np) { 104 pr_err("Can't find clock control module.\n"); 105 return; 106 } 107 108 ccm = of_iomap(np, 0); 109 of_node_put(np); 110 if (!ccm) { 111 pr_err("Can't map clock control module reg.\n"); 112 return; 113 } 114 115 np = of_find_node_by_type(NULL, "cpu"); 116 if (np) { 117 const unsigned int *prop = 118 of_get_property(np, "bus-frequency", NULL); 119 120 of_node_put(np); 121 if (prop) { 122 busfreq = *prop; 123 } else { 124 pr_err("Can't get bus-frequency property\n"); 125 return; 126 } 127 } else { 128 pr_err("Can't find 'cpu' node.\n"); 129 return; 130 } 131 132 /* Pixel Clock configuration */ 133 pr_debug("DIU: Bus Frequency = %lu\n", busfreq); 134 speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */ 135 136 /* Calculate the pixel clock with the smallest error */ 137 /* calculate the following in steps to avoid overflow */ 138 pr_debug("DIU pixclock in ps - %d\n", pixclock); 139 temp = (1000000000 / pixclock) * 1000; 140 pixclock = temp; 141 pr_debug("DIU pixclock freq - %u\n", pixclock); 142 143 temp = temp / 20; /* pixclock * 0.05 */ 144 pr_debug("deviation = %d\n", temp); 145 minpixclock = pixclock - temp; 146 maxpixclock = pixclock + temp; 147 pr_debug("DIU minpixclock - %lu\n", minpixclock); 148 pr_debug("DIU maxpixclock - %lu\n", maxpixclock); 149 pixval = speed/pixclock; 150 pr_debug("DIU pixval = %lu\n", pixval); 151 152 err = LONG_MAX; 153 bestval = pixval; 154 pr_debug("DIU bestval = %lu\n", bestval); 155 156 bestfreq = 0; 157 for (i = -1; i <= 1; i++) { 158 temp = speed / (pixval+i); 159 pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n", 160 i, pixval, temp); 161 if ((temp < minpixclock) || (temp > maxpixclock)) 162 pr_debug("DIU exceeds monitor range (%lu to %lu)\n", 163 minpixclock, maxpixclock); 164 else if (abs(temp - pixclock) < err) { 165 pr_debug("Entered the else if block %d\n", i); 166 err = abs(temp - pixclock); 167 bestval = pixval + i; 168 bestfreq = temp; 169 } 170 } 171 172 pr_debug("DIU chose = %lx\n", bestval); 173 pr_debug("DIU error = %ld\n NomPixClk ", err); 174 pr_debug("DIU: Best Freq = %lx\n", bestfreq); 175 /* Modify DIU_DIV in CCM SCFR1 */ 176 temp = in_be32(&ccm->scfr1); 177 pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp); 178 temp &= ~DIU_DIV_MASK; 179 temp |= (bestval & DIU_DIV_MASK); 180 out_be32(&ccm->scfr1, temp); 181 pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp); 182 iounmap(ccm); 183} 184 185ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf) 186{ 187 return sprintf(buf, "0 - 5121 LCD\n"); 188} 189 190int mpc512x_set_sysfs_monitor_port(int val) 191{ 192 return 0; 193} 194 195static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; 196 197#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 198static inline void mpc512x_free_bootmem(struct page *page) 199{ 200 __ClearPageReserved(page); 201 BUG_ON(PageTail(page)); 202 BUG_ON(atomic_read(&page->_count) > 1); 203 atomic_set(&page->_count, 1); 204 __free_page(page); 205 totalram_pages++; 206} 207 208void mpc512x_release_bootmem(void) 209{ 210 unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK; 211 unsigned long size = diu_shared_fb.fb_len; 212 unsigned long start, end; 213 214 if (diu_shared_fb.in_use) { 215 start = PFN_UP(addr); 216 end = PFN_DOWN(addr + size); 217 218 for (; start < end; start++) 219 mpc512x_free_bootmem(pfn_to_page(start)); 220 221 diu_shared_fb.in_use = false; 222 } 223 diu_ops.release_bootmem = NULL; 224} 225#endif 226 227/* 228 * Check if DIU was pre-initialized. If so, perform steps 229 * needed to continue displaying through the whole boot process. 230 * Move area descriptor and gamma table elsewhere, they are 231 * destroyed by bootmem allocator otherwise. The frame buffer 232 * address range will be reserved in setup_arch() after bootmem 233 * allocator is up. 234 */ 235void __init mpc512x_init_diu(void) 236{ 237 struct device_node *np; 238 struct diu __iomem *diu_reg; 239 phys_addr_t desc; 240 void __iomem *vaddr; 241 unsigned long mode, pix_fmt, res, bpp; 242 unsigned long dst; 243 244 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu"); 245 if (!np) { 246 pr_err("No DIU node\n"); 247 return; 248 } 249 250 diu_reg = of_iomap(np, 0); 251 of_node_put(np); 252 if (!diu_reg) { 253 pr_err("Can't map DIU\n"); 254 return; 255 } 256 257 mode = in_be32(&diu_reg->diu_mode); 258 if (mode != MFB_MODE1) { 259 pr_info("%s: DIU OFF\n", __func__); 260 goto out; 261 } 262 263 desc = in_be32(&diu_reg->desc[0]); 264 vaddr = ioremap(desc, sizeof(struct diu_ad)); 265 if (!vaddr) { 266 pr_err("Can't map DIU area desc.\n"); 267 goto out; 268 } 269 memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad)); 270 /* flush fb area descriptor */ 271 dst = (unsigned long)&diu_shared_fb.ad0; 272 flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1); 273 274 res = in_be32(&diu_reg->disp_size); 275 pix_fmt = in_le32(vaddr); 276 bpp = ((pix_fmt >> 16) & 0x3) + 1; 277 diu_shared_fb.fb_phys = in_le32(vaddr + 4); 278 diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp; 279 diu_shared_fb.in_use = true; 280 iounmap(vaddr); 281 282 desc = in_be32(&diu_reg->gamma); 283 vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma)); 284 if (!vaddr) { 285 pr_err("Can't map DIU area desc.\n"); 286 diu_shared_fb.in_use = false; 287 goto out; 288 } 289 memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma)); 290 /* flush gamma table */ 291 dst = (unsigned long)&diu_shared_fb.gamma; 292 flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1); 293 294 iounmap(vaddr); 295 out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma)); 296 out_be32(&diu_reg->desc[1], 0); 297 out_be32(&diu_reg->desc[2], 0); 298 out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0)); 299 300out: 301 iounmap(diu_reg); 302} 303 304void __init mpc512x_setup_diu(void) 305{ 306 int ret; 307 308 /* 309 * We do not allocate and configure new area for bitmap buffer 310 * because it would requere copying bitmap data (splash image) 311 * and so negatively affect boot time. Instead we reserve the 312 * already configured frame buffer area so that it won't be 313 * destroyed. The starting address of the area to reserve and 314 * also it's length is passed to reserve_bootmem(). It will be 315 * freed later on first open of fbdev, when splash image is not 316 * needed any more. 317 */ 318 if (diu_shared_fb.in_use) { 319 ret = reserve_bootmem(diu_shared_fb.fb_phys, 320 diu_shared_fb.fb_len, 321 BOOTMEM_EXCLUSIVE); 322 if (ret) { 323 pr_err("%s: reserve bootmem failed\n", __func__); 324 diu_shared_fb.in_use = false; 325 } 326 } 327 328#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 329 diu_ops.get_pixel_format = mpc512x_get_pixel_format; 330 diu_ops.set_gamma_table = mpc512x_set_gamma_table; 331 diu_ops.set_monitor_port = mpc512x_set_monitor_port; 332 diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; 333 diu_ops.show_monitor_port = mpc512x_show_monitor_port; 334 diu_ops.set_sysfs_monitor_port = mpc512x_set_sysfs_monitor_port; 335 diu_ops.release_bootmem = mpc512x_release_bootmem; 336#endif 337} 338 339void __init mpc512x_init_IRQ(void) 340{ 341 struct device_node *np; 342 343 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ipic"); 344 if (!np) 345 return; 346 347 ipic_init(np, 0); 348 of_node_put(np); 349 350 /* 351 * Initialize the default interrupt mapping priorities, 352 * in case the boot rom changed something on us. 353 */ 354 ipic_set_default_priority(); 355} 356 357/* 358 * Nodes to do bus probe on, soc and localbus 359 */ 360static struct of_device_id __initdata of_bus_ids[] = { 361 { .compatible = "fsl,mpc5121-immr", }, 362 { .compatible = "fsl,mpc5121-localbus", }, 363 {}, 364}; 365 366void __init mpc512x_declare_of_platform_devices(void) 367{ 368 struct device_node *np; 369 370 if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) 371 printk(KERN_ERR __FILE__ ": " 372 "Error while probing of_platform bus\n"); 373 374 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-nfc"); 375 if (np) { 376 of_platform_device_create(np, NULL, NULL); 377 of_node_put(np); 378 } 379} 380 381#define DEFAULT_FIFO_SIZE 16 382 383static unsigned int __init get_fifo_size(struct device_node *np, 384 char *prop_name) 385{ 386 const unsigned int *fp; 387 388 fp = of_get_property(np, prop_name, NULL); 389 if (fp) 390 return *fp; 391 392 pr_warning("no %s property in %s node, defaulting to %d\n", 393 prop_name, np->full_name, DEFAULT_FIFO_SIZE); 394 395 return DEFAULT_FIFO_SIZE; 396} 397 398#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \ 399 ((u32)(_base) + sizeof(struct mpc52xx_psc))) 400 401/* Init PSC FIFO space for TX and RX slices */ 402void __init mpc512x_psc_fifo_init(void) 403{ 404 struct device_node *np; 405 void __iomem *psc; 406 unsigned int tx_fifo_size; 407 unsigned int rx_fifo_size; 408 int fifobase = 0; /* current fifo address in 32 bit words */ 409 410 for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") { 411 tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size"); 412 rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size"); 413 414 /* size in register is in 4 byte units */ 415 tx_fifo_size /= 4; 416 rx_fifo_size /= 4; 417 if (!tx_fifo_size) 418 tx_fifo_size = 1; 419 if (!rx_fifo_size) 420 rx_fifo_size = 1; 421 422 psc = of_iomap(np, 0); 423 if (!psc) { 424 pr_err("%s: Can't map %s device\n", 425 __func__, np->full_name); 426 continue; 427 } 428 429 /* FIFO space is 4KiB, check if requested size is available */ 430 if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) { 431 pr_err("%s: no fifo space available for %s\n", 432 __func__, np->full_name); 433 iounmap(psc); 434 /* 435 * chances are that another device requests less 436 * fifo space, so we continue. 437 */ 438 continue; 439 } 440 441 /* set tx and rx fifo size registers */ 442 out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size); 443 fifobase += tx_fifo_size; 444 out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size); 445 fifobase += rx_fifo_size; 446 447 /* reset and enable the slices */ 448 out_be32(&FIFOC(psc)->txcmd, 0x80); 449 out_be32(&FIFOC(psc)->txcmd, 0x01); 450 out_be32(&FIFOC(psc)->rxcmd, 0x80); 451 out_be32(&FIFOC(psc)->rxcmd, 0x01); 452 453 iounmap(psc); 454 } 455} 456 457void __init mpc512x_init(void) 458{ 459 mpc512x_declare_of_platform_devices(); 460 mpc5121_clk_init(); 461 mpc512x_restart_init(); 462 mpc512x_psc_fifo_init(); 463} 464