Commit fdb9482b42c28d314317ea0118181b1f32a7c689

Authored by Timur Tabi
Committed by Kumar Gala
1 parent 2c1764efc2

p1022ds: fix switching of DIU/LBC signals

On the P1022, the pins which drive the video display (DIU) are muxed with the
local bus controller (LBC), so if the DIU is active, the pins need to be
temporarily muxed to LBC whenever accessing NOR flash.

The code which handled this transition is checking and changing the wrong
bits in PMUXCR.

Also add a follow-up read after a write to NOR flash if we're going to
mux back to DIU after the write, as described in the P1022 RM.

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

Showing 1 changed file with 57 additions and 10 deletions Side-by-side Diff

board/freescale/p1022ds/diu.c
... ... @@ -32,6 +32,7 @@
32 32  
33 33 #define PMUXCR_ELBCDIU_MASK 0xc0000000
34 34 #define PMUXCR_ELBCDIU_NOR16 0x80000000
  35 +#define PMUXCR_ELBCDIU_DIU 0x40000000
35 36  
36 37 /*
37 38 * DIU Area Descriptor
... ... @@ -131,9 +132,8 @@
131 132 px_brdcfg0 = in_8(lbc_lcs1_ba);
132 133 out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU);
133 134  
134   - /* Setting PMUXCR to switch to DVI from ELBC */
135   - clrsetbits_be32(&gur->pmuxcr,
136   - PMUXCR_ELBCDIU_MASK, PMUXCR_ELBCDIU_NOR16);
  135 + /* Set PMUXCR to switch the muxed pins from the LBC to the DIU */
  136 + clrsetbits_be32(&gur->pmuxcr, PMUXCR_ELBCDIU_MASK, PMUXCR_ELBCDIU_DIU);
137 137 pmuxcr = in_be32(&gur->pmuxcr);
138 138  
139 139 return fsl_diu_init(*xres, pixel_format, 0);
... ... @@ -161,7 +161,7 @@
161 161 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
162 162  
163 163 /* Switch the muxes only if they're currently set to DIU mode */
164   - if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) ==
  164 + if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
165 165 PMUXCR_ELBCDIU_NOR16) {
166 166 /*
167 167 * In DIU mode, the PIXIS can only be accessed indirectly
168 168  
... ... @@ -216,8 +216,17 @@
216 216 int sw = set_mux_to_lbc();
217 217  
218 218 __raw_writeb(value, addr);
219   - if (sw)
  219 + if (sw) {
  220 + /*
  221 + * To ensure the post-write is completed to eLBC, software must
  222 + * perform a dummy read from one valid address from eLBC space
  223 + * before changing the eLBC_DIU from NOR mode to DIU mode.
  224 + * set_mux_to_diu() includes a sync that will ensure the
  225 + * __raw_readb() completes before it switches the mux.
  226 + */
  227 + __raw_readb(addr);
220 228 set_mux_to_diu();
  229 + }
221 230 }
222 231  
223 232 void flash_write16(u16 value, void *addr)
224 233  
... ... @@ -225,8 +234,17 @@
225 234 int sw = set_mux_to_lbc();
226 235  
227 236 __raw_writew(value, addr);
228   - if (sw)
  237 + if (sw) {
  238 + /*
  239 + * To ensure the post-write is completed to eLBC, software must
  240 + * perform a dummy read from one valid address from eLBC space
  241 + * before changing the eLBC_DIU from NOR mode to DIU mode.
  242 + * set_mux_to_diu() includes a sync that will ensure the
  243 + * __raw_readb() completes before it switches the mux.
  244 + */
  245 + __raw_readb(addr);
229 246 set_mux_to_diu();
  247 + }
230 248 }
231 249  
232 250 void flash_write32(u32 value, void *addr)
233 251  
234 252  
235 253  
236 254  
... ... @@ -234,18 +252,47 @@
234 252 int sw = set_mux_to_lbc();
235 253  
236 254 __raw_writel(value, addr);
237   - if (sw)
  255 + if (sw) {
  256 + /*
  257 + * To ensure the post-write is completed to eLBC, software must
  258 + * perform a dummy read from one valid address from eLBC space
  259 + * before changing the eLBC_DIU from NOR mode to DIU mode.
  260 + * set_mux_to_diu() includes a sync that will ensure the
  261 + * __raw_readb() completes before it switches the mux.
  262 + */
  263 + __raw_readb(addr);
238 264 set_mux_to_diu();
  265 + }
239 266 }
240 267  
241 268 void flash_write64(u64 value, void *addr)
242 269 {
243 270 int sw = set_mux_to_lbc();
  271 + uint32_t *p = addr;
244 272  
245   - /* There is no __raw_writeq(), so do the write manually */
246   - *(volatile u64 *)addr = value;
247   - if (sw)
  273 + /*
  274 + * There is no __raw_writeq(), so do the write manually. We don't trust
  275 + * the compiler, so we use inline assembly.
  276 + */
  277 + __asm__ __volatile__(
  278 + "stw%U0%X0 %2,%0;\n"
  279 + "stw%U1%X1 %3,%1;\n"
  280 + : "=m" (*p), "=m" (*(p + 1))
  281 + : "r" ((uint32_t) (value >> 32)), "r" ((uint32_t) (value)));
  282 +
  283 + if (sw) {
  284 + /*
  285 + * To ensure the post-write is completed to eLBC, software must
  286 + * perform a dummy read from one valid address from eLBC space
  287 + * before changing the eLBC_DIU from NOR mode to DIU mode. We
  288 + * read addr+4 because we just wrote to addr+4, so that's how we
  289 + * maintain execution order. set_mux_to_diu() includes a sync
  290 + * that will ensure the __raw_readb() completes before it
  291 + * switches the mux.
  292 + */
  293 + __raw_readb(addr + 4);
248 294 set_mux_to_diu();
  295 + }
249 296 }
250 297  
251 298 u8 flash_read8(void *addr)