diff options
| -rw-r--r-- | arch/powerpc/include/asm/mpc5121.h | 32 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_generic.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc512x.h | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc512x_shared.c | 284 | ||||
| -rw-r--r-- | arch/powerpc/sysdev/fsl_soc.h | 1 | ||||
| -rw-r--r-- | drivers/video/fsl-diu-fb.c | 17 |
7 files changed, 338 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h index e6a30bb1d16a..8c0ab2ca689c 100644 --- a/arch/powerpc/include/asm/mpc5121.h +++ b/arch/powerpc/include/asm/mpc5121.h | |||
| @@ -21,4 +21,36 @@ struct mpc512x_reset_module { | |||
| 21 | u32 rcer; /* Reset Control Enable Register */ | 21 | u32 rcer; /* Reset Control Enable Register */ |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | /* | ||
| 25 | * Clock Control Module | ||
| 26 | */ | ||
| 27 | struct mpc512x_ccm { | ||
| 28 | u32 spmr; /* System PLL Mode Register */ | ||
| 29 | u32 sccr1; /* System Clock Control Register 1 */ | ||
| 30 | u32 sccr2; /* System Clock Control Register 2 */ | ||
| 31 | u32 scfr1; /* System Clock Frequency Register 1 */ | ||
| 32 | u32 scfr2; /* System Clock Frequency Register 2 */ | ||
| 33 | u32 scfr2s; /* System Clock Frequency Shadow Register 2 */ | ||
| 34 | u32 bcr; /* Bread Crumb Register */ | ||
| 35 | u32 p0ccr; /* PSC0 Clock Control Register */ | ||
| 36 | u32 p1ccr; /* PSC1 CCR */ | ||
| 37 | u32 p2ccr; /* PSC2 CCR */ | ||
| 38 | u32 p3ccr; /* PSC3 CCR */ | ||
| 39 | u32 p4ccr; /* PSC4 CCR */ | ||
| 40 | u32 p5ccr; /* PSC5 CCR */ | ||
| 41 | u32 p6ccr; /* PSC6 CCR */ | ||
| 42 | u32 p7ccr; /* PSC7 CCR */ | ||
| 43 | u32 p8ccr; /* PSC8 CCR */ | ||
| 44 | u32 p9ccr; /* PSC9 CCR */ | ||
| 45 | u32 p10ccr; /* PSC10 CCR */ | ||
| 46 | u32 p11ccr; /* PSC11 CCR */ | ||
| 47 | u32 spccr; /* SPDIF Clock Control Register */ | ||
| 48 | u32 cccr; /* CFM Clock Control Register */ | ||
| 49 | u32 dccr; /* DIU Clock Control Register */ | ||
| 50 | u32 m1ccr; /* MSCAN1 CCR */ | ||
| 51 | u32 m2ccr; /* MSCAN2 CCR */ | ||
| 52 | u32 m3ccr; /* MSCAN3 CCR */ | ||
| 53 | u32 m4ccr; /* MSCAN4 CCR */ | ||
| 54 | u8 res[0x98]; /* Reserved */ | ||
| 55 | }; | ||
| 24 | #endif /* __ASM_POWERPC_MPC5121_H__ */ | 56 | #endif /* __ASM_POWERPC_MPC5121_H__ */ |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index ee6ae129c25c..dcef6ade48e1 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c | |||
| @@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void) | |||
| 42 | for_each_compatible_node(np, "pci", "fsl,mpc5121-pci") | 42 | for_each_compatible_node(np, "pci", "fsl,mpc5121-pci") |
| 43 | mpc83xx_add_bridge(np); | 43 | mpc83xx_add_bridge(np); |
| 44 | #endif | 44 | #endif |
| 45 | mpc512x_setup_diu(); | ||
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | static void __init mpc5121_ads_init_IRQ(void) | 48 | static void __init mpc5121_ads_init_IRQ(void) |
| @@ -65,6 +66,7 @@ define_machine(mpc5121_ads) { | |||
| 65 | .probe = mpc5121_ads_probe, | 66 | .probe = mpc5121_ads_probe, |
| 66 | .setup_arch = mpc5121_ads_setup_arch, | 67 | .setup_arch = mpc5121_ads_setup_arch, |
| 67 | .init = mpc512x_init, | 68 | .init = mpc512x_init, |
| 69 | .init_early = mpc512x_init_diu, | ||
| 68 | .init_IRQ = mpc5121_ads_init_IRQ, | 70 | .init_IRQ = mpc5121_ads_init_IRQ, |
| 69 | .get_irq = ipic_get_irq, | 71 | .get_irq = ipic_get_irq, |
| 70 | .calibrate_decr = generic_calibrate_decr, | 72 | .calibrate_decr = generic_calibrate_decr, |
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c index a6c0e3a2615d..e487eb06ec6b 100644 --- a/arch/powerpc/platforms/512x/mpc5121_generic.c +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c | |||
| @@ -52,6 +52,8 @@ define_machine(mpc5121_generic) { | |||
| 52 | .name = "MPC5121 generic", | 52 | .name = "MPC5121 generic", |
| 53 | .probe = mpc5121_generic_probe, | 53 | .probe = mpc5121_generic_probe, |
| 54 | .init = mpc512x_init, | 54 | .init = mpc512x_init, |
| 55 | .init_early = mpc512x_init_diu, | ||
| 56 | .setup_arch = mpc512x_setup_diu, | ||
| 55 | .init_IRQ = mpc512x_init_IRQ, | 57 | .init_IRQ = mpc512x_init_IRQ, |
| 56 | .get_irq = ipic_get_irq, | 58 | .get_irq = ipic_get_irq, |
| 57 | .calibrate_decr = generic_calibrate_decr, | 59 | .calibrate_decr = generic_calibrate_decr, |
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h index b2daca0d1488..1ab6d11d0b19 100644 --- a/arch/powerpc/platforms/512x/mpc512x.h +++ b/arch/powerpc/platforms/512x/mpc512x.h | |||
| @@ -16,4 +16,6 @@ extern void __init mpc512x_init(void); | |||
| 16 | extern int __init mpc5121_clk_init(void); | 16 | extern int __init mpc5121_clk_init(void); |
| 17 | void __init mpc512x_declare_of_platform_devices(void); | 17 | void __init mpc512x_declare_of_platform_devices(void); |
| 18 | extern void mpc512x_restart(char *cmd); | 18 | extern void mpc512x_restart(char *cmd); |
| 19 | extern void mpc512x_init_diu(void); | ||
| 20 | extern void mpc512x_setup_diu(void); | ||
| 19 | #endif /* __MPC512X_H__ */ | 21 | #endif /* __MPC512X_H__ */ |
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index 707e572b7c40..e41ebbdb3e12 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c | |||
| @@ -16,7 +16,11 @@ | |||
| 16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
| 17 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
| 18 | #include <linux/of_platform.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> | ||
| 19 | 22 | ||
| 23 | #include <asm/cacheflush.h> | ||
| 20 | #include <asm/machdep.h> | 24 | #include <asm/machdep.h> |
| 21 | #include <asm/ipic.h> | 25 | #include <asm/ipic.h> |
| 22 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
| @@ -54,6 +58,286 @@ void mpc512x_restart(char *cmd) | |||
| 54 | ; | 58 | ; |
| 55 | } | 59 | } |
| 56 | 60 | ||
| 61 | struct 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 | |||
| 69 | unsigned 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 | |||
| 83 | void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base) | ||
| 84 | { | ||
| 85 | } | ||
| 86 | |||
| 87 | void mpc512x_set_monitor_port(int monitor_port) | ||
| 88 | { | ||
| 89 | } | ||
| 90 | |||
| 91 | #define DIU_DIV_MASK 0x000000ff | ||
| 92 | void 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 | |||
| 185 | ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf) | ||
| 186 | { | ||
| 187 | return sprintf(buf, "0 - 5121 LCD\n"); | ||
| 188 | } | ||
| 189 | |||
| 190 | int mpc512x_set_sysfs_monitor_port(int val) | ||
| 191 | { | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; | ||
| 196 | |||
| 197 | #if defined(CONFIG_FB_FSL_DIU) || \ | ||
| 198 | defined(CONFIG_FB_FSL_DIU_MODULE) | ||
| 199 | static inline void mpc512x_free_bootmem(struct page *page) | ||
| 200 | { | ||
| 201 | __ClearPageReserved(page); | ||
| 202 | BUG_ON(PageTail(page)); | ||
| 203 | BUG_ON(atomic_read(&page->_count) > 1); | ||
| 204 | atomic_set(&page->_count, 1); | ||
| 205 | __free_page(page); | ||
| 206 | totalram_pages++; | ||
| 207 | } | ||
| 208 | |||
| 209 | void mpc512x_release_bootmem(void) | ||
| 210 | { | ||
| 211 | unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK; | ||
| 212 | unsigned long size = diu_shared_fb.fb_len; | ||
| 213 | unsigned long start, end; | ||
| 214 | |||
| 215 | if (diu_shared_fb.in_use) { | ||
| 216 | start = PFN_UP(addr); | ||
| 217 | end = PFN_DOWN(addr + size); | ||
| 218 | |||
| 219 | for (; start < end; start++) | ||
| 220 | mpc512x_free_bootmem(pfn_to_page(start)); | ||
| 221 | |||
| 222 | diu_shared_fb.in_use = false; | ||
| 223 | } | ||
| 224 | diu_ops.release_bootmem = NULL; | ||
| 225 | } | ||
| 226 | #endif | ||
| 227 | |||
| 228 | /* | ||
| 229 | * Check if DIU was pre-initialized. If so, perform steps | ||
| 230 | * needed to continue displaying through the whole boot process. | ||
| 231 | * Move area descriptor and gamma table elsewhere, they are | ||
| 232 | * destroyed by bootmem allocator otherwise. The frame buffer | ||
| 233 | * address range will be reserved in setup_arch() after bootmem | ||
| 234 | * allocator is up. | ||
| 235 | */ | ||
| 236 | void __init mpc512x_init_diu(void) | ||
| 237 | { | ||
| 238 | struct device_node *np; | ||
| 239 | struct diu __iomem *diu_reg; | ||
| 240 | phys_addr_t desc; | ||
| 241 | void __iomem *vaddr; | ||
| 242 | unsigned long mode, pix_fmt, res, bpp; | ||
| 243 | unsigned long dst; | ||
| 244 | |||
| 245 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu"); | ||
| 246 | if (!np) { | ||
| 247 | pr_err("No DIU node\n"); | ||
| 248 | return; | ||
| 249 | } | ||
| 250 | |||
| 251 | diu_reg = of_iomap(np, 0); | ||
| 252 | of_node_put(np); | ||
| 253 | if (!diu_reg) { | ||
| 254 | pr_err("Can't map DIU\n"); | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | |||
| 258 | mode = in_be32(&diu_reg->diu_mode); | ||
| 259 | if (mode != MFB_MODE1) { | ||
| 260 | pr_info("%s: DIU OFF\n", __func__); | ||
| 261 | goto out; | ||
| 262 | } | ||
| 263 | |||
| 264 | desc = in_be32(&diu_reg->desc[0]); | ||
| 265 | vaddr = ioremap(desc, sizeof(struct diu_ad)); | ||
| 266 | if (!vaddr) { | ||
| 267 | pr_err("Can't map DIU area desc.\n"); | ||
| 268 | goto out; | ||
| 269 | } | ||
| 270 | memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad)); | ||
| 271 | /* flush fb area descriptor */ | ||
| 272 | dst = (unsigned long)&diu_shared_fb.ad0; | ||
| 273 | flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1); | ||
| 274 | |||
| 275 | res = in_be32(&diu_reg->disp_size); | ||
| 276 | pix_fmt = in_le32(vaddr); | ||
| 277 | bpp = ((pix_fmt >> 16) & 0x3) + 1; | ||
| 278 | diu_shared_fb.fb_phys = in_le32(vaddr + 4); | ||
| 279 | diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp; | ||
| 280 | diu_shared_fb.in_use = true; | ||
| 281 | iounmap(vaddr); | ||
| 282 | |||
| 283 | desc = in_be32(&diu_reg->gamma); | ||
| 284 | vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma)); | ||
| 285 | if (!vaddr) { | ||
| 286 | pr_err("Can't map DIU area desc.\n"); | ||
| 287 | diu_shared_fb.in_use = false; | ||
| 288 | goto out; | ||
| 289 | } | ||
| 290 | memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma)); | ||
| 291 | /* flush gamma table */ | ||
| 292 | dst = (unsigned long)&diu_shared_fb.gamma; | ||
| 293 | flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1); | ||
| 294 | |||
| 295 | iounmap(vaddr); | ||
| 296 | out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma)); | ||
| 297 | out_be32(&diu_reg->desc[1], 0); | ||
| 298 | out_be32(&diu_reg->desc[2], 0); | ||
| 299 | out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0)); | ||
| 300 | |||
| 301 | out: | ||
| 302 | iounmap(diu_reg); | ||
| 303 | } | ||
| 304 | |||
| 305 | void __init mpc512x_setup_diu(void) | ||
| 306 | { | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | /* | ||
| 310 | * We do not allocate and configure new area for bitmap buffer | ||
| 311 | * because it would requere copying bitmap data (splash image) | ||
| 312 | * and so negatively affect boot time. Instead we reserve the | ||
| 313 | * already configured frame buffer area so that it won't be | ||
| 314 | * destroyed. The starting address of the area to reserve and | ||
| 315 | * also it's length is passed to reserve_bootmem(). It will be | ||
| 316 | * freed later on first open of fbdev, when splash image is not | ||
| 317 | * needed any more. | ||
| 318 | */ | ||
| 319 | if (diu_shared_fb.in_use) { | ||
| 320 | ret = reserve_bootmem(diu_shared_fb.fb_phys, | ||
| 321 | diu_shared_fb.fb_len, | ||
| 322 | BOOTMEM_EXCLUSIVE); | ||
| 323 | if (ret) { | ||
| 324 | pr_err("%s: reserve bootmem failed\n", __func__); | ||
| 325 | diu_shared_fb.in_use = false; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | #if defined(CONFIG_FB_FSL_DIU) || \ | ||
| 330 | defined(CONFIG_FB_FSL_DIU_MODULE) | ||
| 331 | diu_ops.get_pixel_format = mpc512x_get_pixel_format; | ||
| 332 | diu_ops.set_gamma_table = mpc512x_set_gamma_table; | ||
| 333 | diu_ops.set_monitor_port = mpc512x_set_monitor_port; | ||
| 334 | diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; | ||
| 335 | diu_ops.show_monitor_port = mpc512x_show_monitor_port; | ||
| 336 | diu_ops.set_sysfs_monitor_port = mpc512x_set_sysfs_monitor_port; | ||
| 337 | diu_ops.release_bootmem = mpc512x_release_bootmem; | ||
| 338 | #endif | ||
| 339 | } | ||
| 340 | |||
| 57 | void __init mpc512x_init_IRQ(void) | 341 | void __init mpc512x_init_IRQ(void) |
| 58 | { | 342 | { |
| 59 | struct device_node *np; | 343 | struct device_node *np; |
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 42381bb6cd51..53609489a62b 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h | |||
| @@ -30,6 +30,7 @@ struct platform_diu_data_ops { | |||
| 30 | void (*set_pixel_clock) (unsigned int pixclock); | 30 | void (*set_pixel_clock) (unsigned int pixclock); |
| 31 | ssize_t (*show_monitor_port) (int monitor_port, char *buf); | 31 | ssize_t (*show_monitor_port) (int monitor_port, char *buf); |
| 32 | int (*set_sysfs_monitor_port) (int val); | 32 | int (*set_sysfs_monitor_port) (int val); |
| 33 | void (*release_bootmem) (void); | ||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | extern struct platform_diu_data_ops diu_ops; | 36 | extern struct platform_diu_data_ops diu_ops; |
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 48905d5f4e8d..db3e360e6aad 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c | |||
| @@ -1108,6 +1108,10 @@ static int fsl_diu_open(struct fb_info *info, int user) | |||
| 1108 | struct mfb_info *mfbi = info->par; | 1108 | struct mfb_info *mfbi = info->par; |
| 1109 | int res = 0; | 1109 | int res = 0; |
| 1110 | 1110 | ||
| 1111 | /* free boot splash memory on first /dev/fb0 open */ | ||
| 1112 | if (!mfbi->index && diu_ops.release_bootmem) | ||
| 1113 | diu_ops.release_bootmem(); | ||
| 1114 | |||
| 1111 | spin_lock(&diu_lock); | 1115 | spin_lock(&diu_lock); |
| 1112 | mfbi->count++; | 1116 | mfbi->count++; |
| 1113 | if (mfbi->count == 1) { | 1117 | if (mfbi->count == 1) { |
| @@ -1435,6 +1439,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, | |||
| 1435 | int ret, i, error = 0; | 1439 | int ret, i, error = 0; |
| 1436 | struct resource res; | 1440 | struct resource res; |
| 1437 | struct fsl_diu_data *machine_data; | 1441 | struct fsl_diu_data *machine_data; |
| 1442 | int diu_mode; | ||
| 1438 | 1443 | ||
| 1439 | machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); | 1444 | machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); |
| 1440 | if (!machine_data) | 1445 | if (!machine_data) |
| @@ -1471,7 +1476,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, | |||
| 1471 | goto error2; | 1476 | goto error2; |
| 1472 | } | 1477 | } |
| 1473 | 1478 | ||
| 1474 | out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ | 1479 | diu_mode = in_be32(&dr.diu_reg->diu_mode); |
| 1480 | if (diu_mode != MFB_MODE1) | ||
| 1481 | out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */ | ||
| 1475 | 1482 | ||
| 1476 | /* Get the IRQ of the DIU */ | 1483 | /* Get the IRQ of the DIU */ |
| 1477 | machine_data->irq = irq_of_parse_and_map(np, 0); | 1484 | machine_data->irq = irq_of_parse_and_map(np, 0); |
| @@ -1519,7 +1526,13 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, | |||
| 1519 | machine_data->dummy_ad->offset_xyd = 0; | 1526 | machine_data->dummy_ad->offset_xyd = 0; |
| 1520 | machine_data->dummy_ad->next_ad = 0; | 1527 | machine_data->dummy_ad->next_ad = 0; |
| 1521 | 1528 | ||
| 1522 | out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); | 1529 | /* |
| 1530 | * Let DIU display splash screen if it was pre-initialized | ||
| 1531 | * by the bootloader, set dummy area descriptor otherwise. | ||
| 1532 | */ | ||
| 1533 | if (diu_mode != MFB_MODE1) | ||
| 1534 | out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); | ||
| 1535 | |||
| 1523 | out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); | 1536 | out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); |
| 1524 | out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); | 1537 | out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); |
| 1525 | 1538 | ||
