blob: 898f4c7b194d040bc1434ab7e48bf1c032f83bb3 [file] [log] [blame]
Timur Tabid5e01e42010-09-24 01:25:53 +02001/*
Timur Tabiaa8d3fb2011-01-21 16:03:57 -06002 * Copyright 2010-2011 Freescale Semiconductor, Inc.
Timur Tabid5e01e42010-09-24 01:25:53 +02003 * Authors: Timur Tabi <timur@freescale.com>
4 *
5 * FSL DIU Framebuffer driver
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12
13#include <common.h>
14#include <command.h>
Timur Tabiba8e76b2011-04-11 14:18:22 -050015#include <linux/ctype.h>
Timur Tabid5e01e42010-09-24 01:25:53 +020016#include <asm/io.h>
17#include <stdio_dev.h>
18#include <video_fb.h>
19#include "../common/ngpixis.h"
20#include <fsl_diu_fb.h>
21
Timur Tabi55b05232010-09-16 16:35:44 -050022/* The CTL register is called 'csr' in the ngpixis_t structure */
23#define PX_CTL_ALTACC 0x80
24
25#define PX_BRDCFG0_ELBC_SPI_MASK 0xc0
26#define PX_BRDCFG0_ELBC_SPI_ELBC 0x00
27#define PX_BRDCFG0_ELBC_SPI_NULL 0xc0
28#define PX_BRDCFG0_ELBC_DIU 0x02
Timur Tabid5e01e42010-09-24 01:25:53 +020029
30#define PX_BRDCFG1_DVIEN 0x80
31#define PX_BRDCFG1_DFPEN 0x40
32#define PX_BRDCFG1_BACKLIGHT 0x20
33
Timur Tabi55b05232010-09-16 16:35:44 -050034#define PMUXCR_ELBCDIU_MASK 0xc0000000
35#define PMUXCR_ELBCDIU_NOR16 0x80000000
Timur Tabifdb94822010-12-03 13:03:45 -060036#define PMUXCR_ELBCDIU_DIU 0x40000000
Timur Tabi55b05232010-09-16 16:35:44 -050037
Timur Tabid5e01e42010-09-24 01:25:53 +020038/*
39 * DIU Area Descriptor
40 *
41 * Note that we need to byte-swap the value before it's written to the AD
42 * register. So even though the registers don't look like they're in the same
43 * bit positions as they are on the MPC8610, the same value is written to the
44 * AD register on the MPC8610 and on the P1022.
45 */
46#define AD_BYTE_F 0x10000000
47#define AD_ALPHA_C_SHIFT 25
48#define AD_BLUE_C_SHIFT 23
49#define AD_GREEN_C_SHIFT 21
50#define AD_RED_C_SHIFT 19
51#define AD_PIXEL_S_SHIFT 16
52#define AD_COMP_3_SHIFT 12
53#define AD_COMP_2_SHIFT 8
54#define AD_COMP_1_SHIFT 4
55#define AD_COMP_0_SHIFT 0
56
Timur Tabi55b05232010-09-16 16:35:44 -050057/*
58 * Variables used by the DIU/LBC switching code. It's safe to makes these
59 * global, because the DIU requires DDR, so we'll only run this code after
60 * relocation.
61 */
62static u8 px_brdcfg0;
63static u32 pmuxcr;
64static void *lbc_lcs0_ba;
65static void *lbc_lcs1_ba;
Timur Tabi7a946962012-05-18 09:09:09 +000066static u32 old_br0, old_or0, old_br1, old_or1;
67static u32 new_br0, new_or0, new_br1, new_or1;
Timur Tabi55b05232010-09-16 16:35:44 -050068
Timur Tabid5e01e42010-09-24 01:25:53 +020069void diu_set_pixel_clock(unsigned int pixclock)
70{
71 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
72 unsigned long speed_ccb, temp;
73 u32 pixval;
74
75 speed_ccb = get_bus_freq(0);
76 temp = 1000000000 / pixclock;
77 temp *= 1000;
78 pixval = speed_ccb / temp;
Marek Vasut1f09b442011-10-21 14:17:08 +000079 debug("DIU pixval = %u\n", pixval);
Timur Tabid5e01e42010-09-24 01:25:53 +020080
81 /* Modify PXCLK in GUTS CLKDVDR */
82 temp = in_be32(&gur->clkdvdr) & 0x2000FFFF;
83 out_be32(&gur->clkdvdr, temp); /* turn off clock */
84 out_be32(&gur->clkdvdr, temp | 0x80000000 | ((pixval & 0x1F) << 16));
85}
86
Timur Tabiba8e76b2011-04-11 14:18:22 -050087int platform_diu_init(unsigned int xres, unsigned int yres, const char *port)
Timur Tabid5e01e42010-09-24 01:25:53 +020088{
89 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
Timur Tabiba8e76b2011-04-11 14:18:22 -050090 const char *name;
Timur Tabid5e01e42010-09-24 01:25:53 +020091 u32 pixel_format;
92 u8 temp;
Timur Tabi7a946962012-05-18 09:09:09 +000093 phys_addr_t phys0, phys1; /* BR0/BR1 physical addresses */
Timur Tabid5e01e42010-09-24 01:25:53 +020094
Timur Tabi7a946962012-05-18 09:09:09 +000095 /*
96 * Indirect mode requires both BR0 and BR1 to be set to "GPCM",
97 * otherwise writes to these addresses won't actually appear on the
98 * local bus, and so the PIXIS won't see them.
99 *
100 * In FCM mode, writes go to the NAND controller, which does not pass
101 * them to the localbus directly. So we force BR0 and BR1 into GPCM
102 * mode, since we don't care about what's behind the localbus any
103 * more. However, we save those registers first, so that we can
104 * restore them when necessary.
105 */
106 new_br0 = old_br0 = get_lbc_br(0);
107 new_br1 = old_br1 = get_lbc_br(1);
108 new_or0 = old_or0 = get_lbc_or(0);
109 new_or1 = old_or1 = get_lbc_or(1);
110
111 /*
112 * Use the existing BRx/ORx values if it's already GPCM. Otherwise,
113 * force the values to simple 32KB GPCM windows with the most
114 * conservative timing.
115 */
116 if ((old_br0 & BR_MSEL) != BR_MS_GPCM) {
117 new_br0 = (get_lbc_br(0) & BR_BA) | BR_V;
118 new_or0 = OR_AM_32KB | 0xFF7;
119 set_lbc_br(0, new_br0);
120 set_lbc_or(0, new_or0);
121 }
122 if ((old_br1 & BR_MSEL) != BR_MS_GPCM) {
123 new_br1 = (get_lbc_br(1) & BR_BA) | BR_V;
124 new_or1 = OR_AM_32KB | 0xFF7;
125 set_lbc_br(1, new_br1);
126 set_lbc_or(1, new_or1);
127 }
128
129 /*
130 * Determine the physical addresses for Chip Selects 0 and 1. The
131 * BR0/BR1 registers contain the truncated physical addresses for the
132 * chip selects, mapped via the localbus LAW. Since the BRx registers
133 * only contain the lower 32 bits of the address, we have to determine
134 * the upper 4 bits some other way. The proper way is to scan the LAW
135 * table looking for a matching localbus address. Instead, we cheat.
136 * We know that the upper bits are 0 for 32-bit addressing, or 0xF for
137 * 36-bit addressing.
138 */
139#ifdef CONFIG_PHYS_64BIT
140 phys0 = 0xf00000000ULL | (old_br0 & old_or0 & BR_BA);
141 phys1 = 0xf00000000ULL | (old_br1 & old_or1 & BR_BA);
142#else
143 phys0 = old_br0 & old_or0 & BR_BA;
144 phys1 = old_br1 & old_or1 & BR_BA;
145#endif
146
147 /* Save the LBC LCS0 and LCS1 addresses for the DIU mux functions */
148 lbc_lcs0_ba = map_physmem(phys0, 1, 0);
149 lbc_lcs1_ba = map_physmem(phys1, 1, 0);
Timur Tabi55b05232010-09-16 16:35:44 -0500150
Timur Tabid5e01e42010-09-24 01:25:53 +0200151 pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) |
152 (0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) |
153 (2 << AD_RED_C_SHIFT) | (8 << AD_COMP_3_SHIFT) |
154 (8 << AD_COMP_2_SHIFT) | (8 << AD_COMP_1_SHIFT) |
155 (8 << AD_COMP_0_SHIFT) | (3 << AD_PIXEL_S_SHIFT));
156
157 temp = in_8(&pixis->brdcfg1);
158
Timur Tabiba8e76b2011-04-11 14:18:22 -0500159 if (strncmp(port, "lvds", 4) == 0) {
160 /* Single link LVDS */
161 temp &= ~PX_BRDCFG1_DVIEN;
162 /*
163 * LVDS also needs backlight enabled, otherwise the display
164 * will be blank.
165 */
166 temp |= (PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
167 name = "Single-Link LVDS";
Timur Tabid5e01e42010-09-24 01:25:53 +0200168 } else { /* DVI */
Timur Tabid5e01e42010-09-24 01:25:53 +0200169 /* Enable the DVI port, disable the DFP and the backlight */
170 temp &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
171 temp |= PX_BRDCFG1_DVIEN;
Timur Tabiba8e76b2011-04-11 14:18:22 -0500172 name = "DVI";
Timur Tabid5e01e42010-09-24 01:25:53 +0200173 }
174
Timur Tabiba8e76b2011-04-11 14:18:22 -0500175 printf("DIU: Switching to %s monitor @ %ux%u\n", name, xres, yres);
Timur Tabid5e01e42010-09-24 01:25:53 +0200176 out_8(&pixis->brdcfg1, temp);
177
178 /*
Timur Tabi55b05232010-09-16 16:35:44 -0500179 * Enable PIXIS indirect access mode. This is a hack that allows us to
180 * access PIXIS registers even when the LBC pins have been muxed to the
181 * DIU.
182 */
183 setbits_8(&pixis->csr, PX_CTL_ALTACC);
184
185 /*
Timur Tabid5e01e42010-09-24 01:25:53 +0200186 * Route the LAD pins to the DIU. This will disable access to the eLBC,
187 * which means we won't be able to read/write any NOR flash addresses!
188 */
Timur Tabi55b05232010-09-16 16:35:44 -0500189 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0));
190 px_brdcfg0 = in_8(lbc_lcs1_ba);
191 out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU);
Timur Tabi7a946962012-05-18 09:09:09 +0000192 in_8(lbc_lcs1_ba);
Timur Tabid5e01e42010-09-24 01:25:53 +0200193
Timur Tabifdb94822010-12-03 13:03:45 -0600194 /* Set PMUXCR to switch the muxed pins from the LBC to the DIU */
195 clrsetbits_be32(&gur->pmuxcr, PMUXCR_ELBCDIU_MASK, PMUXCR_ELBCDIU_DIU);
Timur Tabi55b05232010-09-16 16:35:44 -0500196 pmuxcr = in_be32(&gur->pmuxcr);
Timur Tabid5e01e42010-09-24 01:25:53 +0200197
Timur Tabi3b4a2262011-05-26 09:02:17 -0500198 return fsl_diu_init(xres, yres, pixel_format, 0);
Timur Tabid5e01e42010-09-24 01:25:53 +0200199}
Timur Tabi55b05232010-09-16 16:35:44 -0500200
Timur Tabi55b05232010-09-16 16:35:44 -0500201/*
202 * set_mux_to_lbc - disable the DIU so that we can read/write to elbc
203 *
204 * On the Freescale P1022, the DIU video signal and the LBC address/data lines
205 * share the same pins, which means that when the DIU is active (e.g. the
206 * console is on the DVI display), NOR flash cannot be accessed. So we use the
207 * weak accessor feature of the CFI flash code to temporarily switch the pin
208 * mux from DIU to LBC whenever we want to read or write flash. This has a
209 * significant performance penalty, but it's the only way to make it work.
210 *
211 * There are two muxes: one on the chip, and one on the board. The chip mux
212 * controls whether the pins are used for the DIU or the LBC, and it is
213 * set via PMUXCR. The board mux controls whether those signals go to
214 * the video connector or the NOR flash chips, and it is set via the ngPIXIS.
215 */
216static int set_mux_to_lbc(void)
217{
218 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
219
220 /* Switch the muxes only if they're currently set to DIU mode */
Timur Tabifdb94822010-12-03 13:03:45 -0600221 if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
Timur Tabi55b05232010-09-16 16:35:44 -0500222 PMUXCR_ELBCDIU_NOR16) {
223 /*
224 * In DIU mode, the PIXIS can only be accessed indirectly
225 * since we can't read/write the LBC directly.
226 */
Timur Tabi55b05232010-09-16 16:35:44 -0500227 /* Set the board mux to LBC. This will disable the display. */
228 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0));
Timur Tabi7a946962012-05-18 09:09:09 +0000229 out_8(lbc_lcs1_ba, px_brdcfg0);
230 in_8(lbc_lcs1_ba);
Timur Tabi55b05232010-09-16 16:35:44 -0500231
232 /* Disable indirect PIXIS mode */
233 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, csr));
234 clrbits_8(lbc_lcs1_ba, PX_CTL_ALTACC);
235
236 /* Set the chip mux to LBC mode, so that writes go to flash. */
237 out_be32(&gur->pmuxcr, (pmuxcr & ~PMUXCR_ELBCDIU_MASK) |
238 PMUXCR_ELBCDIU_NOR16);
239 in_be32(&gur->pmuxcr);
240
Timur Tabi7a946962012-05-18 09:09:09 +0000241 /* Restore the BR0 and BR1 settings */
242 set_lbc_br(0, old_br0);
243 set_lbc_or(0, old_or0);
244 set_lbc_br(1, old_br1);
245 set_lbc_or(1, old_or1);
246
Timur Tabi55b05232010-09-16 16:35:44 -0500247 return 1;
248 }
249
250 return 0;
251}
252
253/*
254 * set_mux_to_diu - re-enable the DIU muxing
255 *
256 * This function restores the chip and board muxing to point to the DIU.
257 */
258static void set_mux_to_diu(void)
259{
260 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
261
Timur Tabi7a946962012-05-18 09:09:09 +0000262 /* Set BR0 and BR1 to GPCM mode */
263 set_lbc_br(0, new_br0);
264 set_lbc_or(0, new_or0);
265 set_lbc_br(1, new_br1);
266 set_lbc_or(1, new_or1);
267
Timur Tabi55b05232010-09-16 16:35:44 -0500268 /* Enable indirect PIXIS mode */
269 setbits_8(&pixis->csr, PX_CTL_ALTACC);
270
271 /* Set the board mux to DIU. This will enable the display. */
272 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0));
Timur Tabi7a946962012-05-18 09:09:09 +0000273 out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU);
Timur Tabi55b05232010-09-16 16:35:44 -0500274 in_8(lbc_lcs1_ba);
275
276 /* Set the chip mux to DIU mode. */
277 out_be32(&gur->pmuxcr, pmuxcr);
278 in_be32(&gur->pmuxcr);
279}
280
Timur Tabiaa8d3fb2011-01-21 16:03:57 -0600281/*
282 * pixis_read - board-specific function to read from the PIXIS
283 *
284 * This function overrides the generic pixis_read() function, so that it can
285 * use PIXIS indirect mode if necessary.
286 */
287u8 pixis_read(unsigned int reg)
288{
289 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
290
291 /* Use indirect mode if the mux is currently set to DIU mode */
292 if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
293 PMUXCR_ELBCDIU_NOR16) {
294 out_8(lbc_lcs0_ba, reg);
295 return in_8(lbc_lcs1_ba);
296 } else {
297 void *p = (void *)PIXIS_BASE;
298
299 return in_8(p + reg);
300 }
301}
302
303/*
304 * pixis_write - board-specific function to write to the PIXIS
305 *
306 * This function overrides the generic pixis_write() function, so that it can
307 * use PIXIS indirect mode if necessary.
308 */
309void pixis_write(unsigned int reg, u8 value)
310{
311 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
312
313 /* Use indirect mode if the mux is currently set to DIU mode */
314 if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
315 PMUXCR_ELBCDIU_NOR16) {
316 out_8(lbc_lcs0_ba, reg);
317 out_8(lbc_lcs1_ba, value);
318 /* Do a read-back to ensure the write completed */
319 in_8(lbc_lcs1_ba);
320 } else {
321 void *p = (void *)PIXIS_BASE;
322
323 out_8(p + reg, value);
324 }
325}
326
327void pixis_bank_reset(void)
328{
329 /*
330 * For some reason, a PIXIS bank reset does not work if the PIXIS is
331 * in indirect mode, so switch to direct mode first.
332 */
333 set_mux_to_lbc();
334
335 out_8(&pixis->vctl, 0);
336 out_8(&pixis->vctl, 1);
337
338 while (1);
339}
340
341#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
342
Timur Tabi55b05232010-09-16 16:35:44 -0500343void flash_write8(u8 value, void *addr)
344{
345 int sw = set_mux_to_lbc();
346
347 __raw_writeb(value, addr);
Timur Tabifdb94822010-12-03 13:03:45 -0600348 if (sw) {
349 /*
350 * To ensure the post-write is completed to eLBC, software must
351 * perform a dummy read from one valid address from eLBC space
352 * before changing the eLBC_DIU from NOR mode to DIU mode.
353 * set_mux_to_diu() includes a sync that will ensure the
354 * __raw_readb() completes before it switches the mux.
355 */
356 __raw_readb(addr);
Timur Tabi55b05232010-09-16 16:35:44 -0500357 set_mux_to_diu();
Timur Tabifdb94822010-12-03 13:03:45 -0600358 }
Timur Tabi55b05232010-09-16 16:35:44 -0500359}
360
361void flash_write16(u16 value, void *addr)
362{
363 int sw = set_mux_to_lbc();
364
365 __raw_writew(value, addr);
Timur Tabifdb94822010-12-03 13:03:45 -0600366 if (sw) {
367 /*
368 * To ensure the post-write is completed to eLBC, software must
369 * perform a dummy read from one valid address from eLBC space
370 * before changing the eLBC_DIU from NOR mode to DIU mode.
371 * set_mux_to_diu() includes a sync that will ensure the
372 * __raw_readb() completes before it switches the mux.
373 */
374 __raw_readb(addr);
Timur Tabi55b05232010-09-16 16:35:44 -0500375 set_mux_to_diu();
Timur Tabifdb94822010-12-03 13:03:45 -0600376 }
Timur Tabi55b05232010-09-16 16:35:44 -0500377}
378
379void flash_write32(u32 value, void *addr)
380{
381 int sw = set_mux_to_lbc();
382
383 __raw_writel(value, addr);
Timur Tabifdb94822010-12-03 13:03:45 -0600384 if (sw) {
385 /*
386 * To ensure the post-write is completed to eLBC, software must
387 * perform a dummy read from one valid address from eLBC space
388 * before changing the eLBC_DIU from NOR mode to DIU mode.
389 * set_mux_to_diu() includes a sync that will ensure the
390 * __raw_readb() completes before it switches the mux.
391 */
392 __raw_readb(addr);
Timur Tabi55b05232010-09-16 16:35:44 -0500393 set_mux_to_diu();
Timur Tabifdb94822010-12-03 13:03:45 -0600394 }
Timur Tabi55b05232010-09-16 16:35:44 -0500395}
396
397void flash_write64(u64 value, void *addr)
398{
399 int sw = set_mux_to_lbc();
Timur Tabifdb94822010-12-03 13:03:45 -0600400 uint32_t *p = addr;
Timur Tabi55b05232010-09-16 16:35:44 -0500401
Timur Tabifdb94822010-12-03 13:03:45 -0600402 /*
403 * There is no __raw_writeq(), so do the write manually. We don't trust
404 * the compiler, so we use inline assembly.
405 */
406 __asm__ __volatile__(
407 "stw%U0%X0 %2,%0;\n"
408 "stw%U1%X1 %3,%1;\n"
409 : "=m" (*p), "=m" (*(p + 1))
410 : "r" ((uint32_t) (value >> 32)), "r" ((uint32_t) (value)));
411
412 if (sw) {
413 /*
414 * To ensure the post-write is completed to eLBC, software must
415 * perform a dummy read from one valid address from eLBC space
416 * before changing the eLBC_DIU from NOR mode to DIU mode. We
417 * read addr+4 because we just wrote to addr+4, so that's how we
418 * maintain execution order. set_mux_to_diu() includes a sync
419 * that will ensure the __raw_readb() completes before it
420 * switches the mux.
421 */
422 __raw_readb(addr + 4);
Timur Tabi55b05232010-09-16 16:35:44 -0500423 set_mux_to_diu();
Timur Tabifdb94822010-12-03 13:03:45 -0600424 }
Timur Tabi55b05232010-09-16 16:35:44 -0500425}
426
427u8 flash_read8(void *addr)
428{
429 u8 ret;
430
431 int sw = set_mux_to_lbc();
432
433 ret = __raw_readb(addr);
434 if (sw)
435 set_mux_to_diu();
436
437 return ret;
438}
439
440u16 flash_read16(void *addr)
441{
442 u16 ret;
443
444 int sw = set_mux_to_lbc();
445
446 ret = __raw_readw(addr);
447 if (sw)
448 set_mux_to_diu();
449
450 return ret;
451}
452
453u32 flash_read32(void *addr)
454{
455 u32 ret;
456
457 int sw = set_mux_to_lbc();
458
459 ret = __raw_readl(addr);
460 if (sw)
461 set_mux_to_diu();
462
463 return ret;
464}
465
466u64 flash_read64(void *addr)
467{
468 u64 ret;
469
470 int sw = set_mux_to_lbc();
471
472 /* There is no __raw_readq(), so do the read manually */
473 ret = *(volatile u64 *)addr;
474 if (sw)
475 set_mux_to_diu();
476
477 return ret;
478}
479
480#endif