Commit | Line | Data |
---|---|---|
30be4c96 TT |
1 | /* |
2 | * P1022DS board specific routines | |
3 | * | |
4 | * Authors: Travis Wheatley <travis.wheatley@freescale.com> | |
5 | * Dave Liu <daveliu@freescale.com> | |
6 | * Timur Tabi <timur@freescale.com> | |
7 | * | |
8 | * Copyright 2010 Freescale Semiconductor, Inc. | |
9 | * | |
10 | * This file is taken from the Freescale P1022DS BSP, with modifications: | |
30be4c96 TT |
11 | * 2) No AMP support |
12 | * 3) No PCI endpoint support | |
13 | * | |
14 | * This file is licensed under the terms of the GNU General Public License | |
15 | * version 2. This program is licensed "as is" without any warranty of any | |
16 | * kind, whether express or implied. | |
17 | */ | |
18 | ||
19 | #include <linux/pci.h> | |
20 | #include <linux/of_platform.h> | |
2c184cd3 | 21 | #include <asm/div64.h> |
30be4c96 TT |
22 | #include <asm/mpic.h> |
23 | #include <asm/swiotlb.h> | |
24 | ||
25 | #include <sysdev/fsl_soc.h> | |
26 | #include <sysdev/fsl_pci.h> | |
ba8438fb | 27 | #include <asm/udbg.h> |
2c184cd3 | 28 | #include <asm/fsl_guts.h> |
6bd825f0 | 29 | #include <asm/fsl_lbc.h> |
582d3e09 | 30 | #include "smp.h" |
2c184cd3 | 31 | |
543a07b1 DES |
32 | #include "mpc85xx.h" |
33 | ||
2c184cd3 TT |
34 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) |
35 | ||
6597c713 TT |
36 | #define PMUXCR_ELBCDIU_MASK 0xc0000000 |
37 | #define PMUXCR_ELBCDIU_NOR16 0x80000000 | |
38 | #define PMUXCR_ELBCDIU_DIU 0x40000000 | |
39 | ||
2c184cd3 TT |
40 | /* |
41 | * Board-specific initialization of the DIU. This code should probably be | |
42 | * executed when the DIU is opened, rather than in arch code, but the DIU | |
43 | * driver does not have a mechanism for this (yet). | |
44 | * | |
45 | * This is especially problematic on the P1022DS because the local bus (eLBC) | |
46 | * and the DIU video signals share the same pins, which means that enabling the | |
47 | * DIU will disable access to NOR flash. | |
48 | */ | |
49 | ||
50 | /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ | |
51 | #define CLKDVDR_PXCKEN 0x80000000 | |
52 | #define CLKDVDR_PXCKINV 0x10000000 | |
53 | #define CLKDVDR_PXCKDLY 0x06000000 | |
54 | #define CLKDVDR_PXCLK_MASK 0x00FF0000 | |
55 | ||
56 | /* Some ngPIXIS register definitions */ | |
6597c713 TT |
57 | #define PX_CTL 3 |
58 | #define PX_BRDCFG0 8 | |
59 | #define PX_BRDCFG1 9 | |
60 | ||
61 | #define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 | |
62 | #define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 | |
63 | #define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 | |
64 | #define PX_BRDCFG0_ELBC_DIU 0x02 | |
65 | ||
2c184cd3 TT |
66 | #define PX_BRDCFG1_DVIEN 0x80 |
67 | #define PX_BRDCFG1_DFPEN 0x40 | |
68 | #define PX_BRDCFG1_BACKLIGHT 0x20 | |
69 | #define PX_BRDCFG1_DDCEN 0x10 | |
70 | ||
6597c713 TT |
71 | #define PX_CTL_ALTACC 0x80 |
72 | ||
2c184cd3 TT |
73 | /* |
74 | * DIU Area Descriptor | |
75 | * | |
76 | * Note that we need to byte-swap the value before it's written to the AD | |
77 | * register. So even though the registers don't look like they're in the same | |
78 | * bit positions as they are on the MPC8610, the same value is written to the | |
79 | * AD register on the MPC8610 and on the P1022. | |
80 | */ | |
81 | #define AD_BYTE_F 0x10000000 | |
82 | #define AD_ALPHA_C_MASK 0x0E000000 | |
83 | #define AD_ALPHA_C_SHIFT 25 | |
84 | #define AD_BLUE_C_MASK 0x01800000 | |
85 | #define AD_BLUE_C_SHIFT 23 | |
86 | #define AD_GREEN_C_MASK 0x00600000 | |
87 | #define AD_GREEN_C_SHIFT 21 | |
88 | #define AD_RED_C_MASK 0x00180000 | |
89 | #define AD_RED_C_SHIFT 19 | |
90 | #define AD_PALETTE 0x00040000 | |
91 | #define AD_PIXEL_S_MASK 0x00030000 | |
92 | #define AD_PIXEL_S_SHIFT 16 | |
93 | #define AD_COMP_3_MASK 0x0000F000 | |
94 | #define AD_COMP_3_SHIFT 12 | |
95 | #define AD_COMP_2_MASK 0x00000F00 | |
96 | #define AD_COMP_2_SHIFT 8 | |
97 | #define AD_COMP_1_MASK 0x000000F0 | |
98 | #define AD_COMP_1_SHIFT 4 | |
99 | #define AD_COMP_0_MASK 0x0000000F | |
100 | #define AD_COMP_0_SHIFT 0 | |
101 | ||
102 | #define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ | |
103 | cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ | |
104 | (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ | |
105 | (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ | |
106 | (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ | |
107 | (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) | |
108 | ||
109 | /** | |
110 | * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth | |
111 | * | |
112 | * The Area Descriptor is a 32-bit value that determine which bits in each | |
113 | * pixel are to be used for each color. | |
114 | */ | |
7653aaab TT |
115 | static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port, |
116 | unsigned int bits_per_pixel) | |
2c184cd3 TT |
117 | { |
118 | switch (bits_per_pixel) { | |
119 | case 32: | |
120 | /* 0x88883316 */ | |
121 | return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8); | |
122 | case 24: | |
123 | /* 0x88082219 */ | |
124 | return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8); | |
125 | case 16: | |
126 | /* 0x65053118 */ | |
127 | return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0); | |
128 | default: | |
129 | pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); | |
130 | return 0; | |
131 | } | |
132 | } | |
133 | ||
134 | /** | |
135 | * p1022ds_set_gamma_table: update the gamma table, if necessary | |
136 | * | |
137 | * On some boards, the gamma table for some ports may need to be modified. | |
138 | * This is not the case on the P1022DS, so we do nothing. | |
139 | */ | |
7653aaab TT |
140 | static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, |
141 | char *gamma_table_base) | |
2c184cd3 TT |
142 | { |
143 | } | |
144 | ||
6bd825f0 TT |
145 | struct fsl_law { |
146 | u32 lawbar; | |
147 | u32 reserved1; | |
148 | u32 lawar; | |
149 | u32 reserved[5]; | |
150 | }; | |
151 | ||
152 | #define LAWBAR_MASK 0x00F00000 | |
153 | #define LAWBAR_SHIFT 12 | |
154 | ||
155 | #define LAWAR_EN 0x80000000 | |
156 | #define LAWAR_TGT_MASK 0x01F00000 | |
157 | #define LAW_TRGT_IF_LBC (0x04 << 20) | |
158 | ||
159 | #define LAWAR_MASK (LAWAR_EN | LAWAR_TGT_MASK) | |
160 | #define LAWAR_MATCH (LAWAR_EN | LAW_TRGT_IF_LBC) | |
161 | ||
162 | #define BR_BA 0xFFFF8000 | |
163 | ||
164 | /* | |
165 | * Map a BRx value to a physical address | |
166 | * | |
167 | * The localbus BRx registers only store the lower 32 bits of the address. To | |
168 | * obtain the upper four bits, we need to scan the LAW table. The entry which | |
169 | * maps to the localbus will contain the upper four bits. | |
170 | */ | |
171 | static phys_addr_t lbc_br_to_phys(const void *ecm, unsigned int count, u32 br) | |
172 | { | |
173 | #ifndef CONFIG_PHYS_64BIT | |
174 | /* | |
175 | * If we only have 32-bit addressing, then the BRx address *is* the | |
176 | * physical address. | |
177 | */ | |
178 | return br & BR_BA; | |
179 | #else | |
180 | const struct fsl_law *law = ecm + 0xc08; | |
181 | unsigned int i; | |
182 | ||
183 | for (i = 0; i < count; i++) { | |
184 | u64 lawbar = in_be32(&law[i].lawbar); | |
185 | u32 lawar = in_be32(&law[i].lawar); | |
186 | ||
187 | if ((lawar & LAWAR_MASK) == LAWAR_MATCH) | |
188 | /* Extract the upper four bits */ | |
189 | return (br & BR_BA) | ((lawbar & LAWBAR_MASK) << 12); | |
190 | } | |
191 | ||
192 | return 0; | |
193 | #endif | |
194 | } | |
195 | ||
2c184cd3 TT |
196 | /** |
197 | * p1022ds_set_monitor_port: switch the output to a different monitor port | |
2c184cd3 | 198 | */ |
7653aaab | 199 | static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) |
2c184cd3 | 200 | { |
6597c713 | 201 | struct device_node *guts_node; |
6bd825f0 TT |
202 | struct device_node *lbc_node = NULL; |
203 | struct device_node *law_node = NULL; | |
9cb6abcb | 204 | struct ccsr_guts __iomem *guts; |
6bd825f0 TT |
205 | struct fsl_lbc_regs *lbc = NULL; |
206 | void *ecm = NULL; | |
6597c713 TT |
207 | u8 __iomem *lbc_lcs0_ba = NULL; |
208 | u8 __iomem *lbc_lcs1_ba = NULL; | |
6bd825f0 | 209 | phys_addr_t cs0_addr, cs1_addr; |
896c01cb | 210 | u32 br0, or0, br1, or1; |
6bd825f0 TT |
211 | const __be32 *iprop; |
212 | unsigned int num_laws; | |
6597c713 TT |
213 | u8 b; |
214 | ||
215 | /* Map the global utilities registers. */ | |
216 | guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); | |
217 | if (!guts_node) { | |
218 | pr_err("p1022ds: missing global utilties device node\n"); | |
2c184cd3 TT |
219 | return; |
220 | } | |
221 | ||
6597c713 TT |
222 | guts = of_iomap(guts_node, 0); |
223 | if (!guts) { | |
224 | pr_err("p1022ds: could not map global utilties device\n"); | |
225 | goto exit; | |
226 | } | |
227 | ||
6bd825f0 TT |
228 | lbc_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); |
229 | if (!lbc_node) { | |
230 | pr_err("p1022ds: missing localbus node\n"); | |
231 | goto exit; | |
232 | } | |
233 | ||
234 | lbc = of_iomap(lbc_node, 0); | |
235 | if (!lbc) { | |
236 | pr_err("p1022ds: could not map localbus node\n"); | |
6597c713 | 237 | goto exit; |
2c184cd3 | 238 | } |
6597c713 | 239 | |
6bd825f0 TT |
240 | law_node = of_find_compatible_node(NULL, NULL, "fsl,ecm-law"); |
241 | if (!law_node) { | |
242 | pr_err("p1022ds: missing local access window node\n"); | |
6597c713 TT |
243 | goto exit; |
244 | } | |
245 | ||
6bd825f0 TT |
246 | ecm = of_iomap(law_node, 0); |
247 | if (!ecm) { | |
248 | pr_err("p1022ds: could not map local access window node\n"); | |
6597c713 TT |
249 | goto exit; |
250 | } | |
251 | ||
6bd825f0 TT |
252 | iprop = of_get_property(law_node, "fsl,num-laws", 0); |
253 | if (!iprop) { | |
254 | pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); | |
255 | goto exit; | |
256 | } | |
257 | num_laws = be32_to_cpup(iprop); | |
258 | ||
896c01cb TT |
259 | /* |
260 | * Indirect mode requires both BR0 and BR1 to be set to "GPCM", | |
261 | * otherwise writes to these addresses won't actually appear on the | |
262 | * local bus, and so the PIXIS won't see them. | |
263 | * | |
264 | * In FCM mode, writes go to the NAND controller, which does not pass | |
265 | * them to the localbus directly. So we force BR0 and BR1 into GPCM | |
266 | * mode, since we don't care about what's behind the localbus any | |
267 | * more. | |
268 | */ | |
269 | br0 = in_be32(&lbc->bank[0].br); | |
270 | br1 = in_be32(&lbc->bank[1].br); | |
271 | or0 = in_be32(&lbc->bank[0].or); | |
272 | or1 = in_be32(&lbc->bank[1].or); | |
273 | ||
274 | /* Make sure CS0 and CS1 are programmed */ | |
275 | if (!(br0 & BR_V) || !(br1 & BR_V)) { | |
276 | pr_err("p1022ds: CS0 and/or CS1 is not programmed\n"); | |
277 | goto exit; | |
278 | } | |
279 | ||
280 | /* | |
281 | * Use the existing BRx/ORx values if it's already GPCM. Otherwise, | |
282 | * force the values to simple 32KB GPCM windows with the most | |
283 | * conservative timing. | |
284 | */ | |
285 | if ((br0 & BR_MSEL) != BR_MS_GPCM) { | |
286 | br0 = (br0 & BR_BA) | BR_V; | |
287 | or0 = 0xFFFF8000 | 0xFF7; | |
288 | out_be32(&lbc->bank[0].br, br0); | |
289 | out_be32(&lbc->bank[0].or, or0); | |
290 | } | |
291 | if ((br1 & BR_MSEL) != BR_MS_GPCM) { | |
292 | br1 = (br1 & BR_BA) | BR_V; | |
293 | or1 = 0xFFFF8000 | 0xFF7; | |
294 | out_be32(&lbc->bank[1].br, br1); | |
295 | out_be32(&lbc->bank[1].or, or1); | |
296 | } | |
297 | ||
298 | cs0_addr = lbc_br_to_phys(ecm, num_laws, br0); | |
299 | if (!cs0_addr) { | |
300 | pr_err("p1022ds: could not determine physical address for CS0" | |
301 | " (BR0=%08x)\n", br0); | |
302 | goto exit; | |
303 | } | |
304 | cs1_addr = lbc_br_to_phys(ecm, num_laws, br1); | |
305 | if (!cs0_addr) { | |
306 | pr_err("p1022ds: could not determine physical address for CS1" | |
307 | " (BR1=%08x)\n", br1); | |
308 | goto exit; | |
309 | } | |
6bd825f0 TT |
310 | |
311 | lbc_lcs0_ba = ioremap(cs0_addr, 1); | |
896c01cb TT |
312 | if (!lbc_lcs0_ba) { |
313 | pr_err("p1022ds: could not ioremap CS0 address %llx\n", | |
314 | (unsigned long long)cs0_addr); | |
315 | goto exit; | |
316 | } | |
6bd825f0 | 317 | lbc_lcs1_ba = ioremap(cs1_addr, 1); |
896c01cb TT |
318 | if (!lbc_lcs1_ba) { |
319 | pr_err("p1022ds: could not ioremap CS1 address %llx\n", | |
320 | (unsigned long long)cs1_addr); | |
321 | goto exit; | |
322 | } | |
6bd825f0 | 323 | |
6597c713 TT |
324 | /* Make sure we're in indirect mode first. */ |
325 | if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != | |
326 | PMUXCR_ELBCDIU_DIU) { | |
327 | struct device_node *pixis_node; | |
328 | void __iomem *pixis; | |
329 | ||
330 | pixis_node = | |
331 | of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); | |
332 | if (!pixis_node) { | |
333 | pr_err("p1022ds: missing pixis node\n"); | |
334 | goto exit; | |
335 | } | |
336 | ||
337 | pixis = of_iomap(pixis_node, 0); | |
338 | of_node_put(pixis_node); | |
339 | if (!pixis) { | |
340 | pr_err("p1022ds: could not map pixis registers\n"); | |
341 | goto exit; | |
342 | } | |
343 | ||
344 | /* Enable indirect PIXIS mode. */ | |
345 | setbits8(pixis + PX_CTL, PX_CTL_ALTACC); | |
346 | iounmap(pixis); | |
347 | ||
348 | /* Switch the board mux to the DIU */ | |
349 | out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ | |
350 | b = in_8(lbc_lcs1_ba); | |
351 | b |= PX_BRDCFG0_ELBC_DIU; | |
352 | out_8(lbc_lcs1_ba, b); | |
353 | ||
354 | /* Set the chip mux to DIU mode. */ | |
355 | clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, | |
356 | PMUXCR_ELBCDIU_DIU); | |
357 | in_be32(&guts->pmuxcr); | |
358 | } | |
359 | ||
2c184cd3 | 360 | |
7653aaab TT |
361 | switch (port) { |
362 | case FSL_DIU_PORT_DVI: | |
2c184cd3 | 363 | /* Enable the DVI port, disable the DFP and the backlight */ |
6597c713 TT |
364 | out_8(lbc_lcs0_ba, PX_BRDCFG1); |
365 | b = in_8(lbc_lcs1_ba); | |
366 | b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); | |
367 | b |= PX_BRDCFG1_DVIEN; | |
368 | out_8(lbc_lcs1_ba, b); | |
2c184cd3 | 369 | break; |
7653aaab | 370 | case FSL_DIU_PORT_LVDS: |
6597c713 TT |
371 | /* |
372 | * LVDS also needs backlight enabled, otherwise the display | |
373 | * will be blank. | |
374 | */ | |
2c184cd3 | 375 | /* Enable the DFP port, disable the DVI and the backlight */ |
6597c713 TT |
376 | out_8(lbc_lcs0_ba, PX_BRDCFG1); |
377 | b = in_8(lbc_lcs1_ba); | |
378 | b &= ~PX_BRDCFG1_DVIEN; | |
379 | b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; | |
380 | out_8(lbc_lcs1_ba, b); | |
2c184cd3 TT |
381 | break; |
382 | default: | |
7653aaab | 383 | pr_err("p1022ds: unsupported monitor port %i\n", port); |
2c184cd3 | 384 | } |
31655958 | 385 | |
6597c713 TT |
386 | exit: |
387 | if (lbc_lcs1_ba) | |
388 | iounmap(lbc_lcs1_ba); | |
389 | if (lbc_lcs0_ba) | |
390 | iounmap(lbc_lcs0_ba); | |
6bd825f0 TT |
391 | if (lbc) |
392 | iounmap(lbc); | |
393 | if (ecm) | |
394 | iounmap(ecm); | |
6597c713 TT |
395 | if (guts) |
396 | iounmap(guts); | |
397 | ||
6bd825f0 TT |
398 | of_node_put(law_node); |
399 | of_node_put(lbc_node); | |
6597c713 | 400 | of_node_put(guts_node); |
2c184cd3 TT |
401 | } |
402 | ||
403 | /** | |
404 | * p1022ds_set_pixel_clock: program the DIU's clock | |
405 | * | |
406 | * @pixclock: the wavelength, in picoseconds, of the clock | |
407 | */ | |
408 | void p1022ds_set_pixel_clock(unsigned int pixclock) | |
409 | { | |
410 | struct device_node *guts_np = NULL; | |
9cb6abcb | 411 | struct ccsr_guts __iomem *guts; |
2c184cd3 TT |
412 | unsigned long freq; |
413 | u64 temp; | |
414 | u32 pxclk; | |
415 | ||
416 | /* Map the global utilities registers. */ | |
417 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); | |
418 | if (!guts_np) { | |
419 | pr_err("p1022ds: missing global utilties device node\n"); | |
420 | return; | |
421 | } | |
422 | ||
423 | guts = of_iomap(guts_np, 0); | |
424 | of_node_put(guts_np); | |
425 | if (!guts) { | |
426 | pr_err("p1022ds: could not map global utilties device\n"); | |
427 | return; | |
428 | } | |
429 | ||
430 | /* Convert pixclock from a wavelength to a frequency */ | |
431 | temp = 1000000000000ULL; | |
432 | do_div(temp, pixclock); | |
433 | freq = temp; | |
434 | ||
7b93eccf TT |
435 | /* |
436 | * 'pxclk' is the ratio of the platform clock to the pixel clock. | |
437 | * This number is programmed into the CLKDVDR register, and the valid | |
438 | * range of values is 2-255. | |
439 | */ | |
2c184cd3 | 440 | pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); |
7b93eccf | 441 | pxclk = clamp_t(u32, pxclk, 2, 255); |
2c184cd3 TT |
442 | |
443 | /* Disable the pixel clock, and set it to non-inverted and no delay */ | |
444 | clrbits32(&guts->clkdvdr, | |
445 | CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); | |
446 | ||
447 | /* Enable the clock and set the pxclk */ | |
448 | setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); | |
31655958 TT |
449 | |
450 | iounmap(guts); | |
2c184cd3 TT |
451 | } |
452 | ||
453 | /** | |
7653aaab | 454 | * p1022ds_valid_monitor_port: set the monitor port for sysfs |
2c184cd3 | 455 | */ |
7653aaab TT |
456 | enum fsl_diu_monitor_port |
457 | p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) | |
2c184cd3 | 458 | { |
7653aaab TT |
459 | switch (port) { |
460 | case FSL_DIU_PORT_DVI: | |
461 | case FSL_DIU_PORT_LVDS: | |
462 | return port; | |
463 | default: | |
464 | return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ | |
465 | } | |
2c184cd3 TT |
466 | } |
467 | ||
468 | #endif | |
30be4c96 TT |
469 | |
470 | void __init p1022_ds_pic_init(void) | |
471 | { | |
e55d7f73 | 472 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
30be4c96 TT |
473 | MPIC_SINGLE_DEST_CPU, |
474 | 0, 256, " OpenPIC "); | |
30be4c96 | 475 | BUG_ON(mpic == NULL); |
30be4c96 TT |
476 | mpic_init(mpic); |
477 | } | |
478 | ||
4951896a TT |
479 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) |
480 | ||
4951896a TT |
481 | /* TRUE if there is a "video=fslfb" command-line parameter. */ |
482 | static bool fslfb; | |
483 | ||
484 | /* | |
485 | * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to | |
486 | * true if we find it. | |
487 | * | |
488 | * We need to use early_param() instead of __setup() because the normal | |
489 | * __setup() gets called to late. However, early_param() gets called very | |
490 | * early, before the device tree is unflattened, so all we can do now is set a | |
491 | * global variable. Later on, p1022_ds_setup_arch() will use that variable | |
492 | * to determine if we need to update the device tree. | |
493 | */ | |
494 | static int __init early_video_setup(char *options) | |
495 | { | |
496 | fslfb = (strncmp(options, "fslfb:", 6) == 0); | |
497 | ||
498 | return 0; | |
499 | } | |
500 | early_param("video", early_video_setup); | |
501 | ||
502 | #endif | |
503 | ||
30be4c96 TT |
504 | /* |
505 | * Setup the architecture | |
506 | */ | |
507 | static void __init p1022_ds_setup_arch(void) | |
508 | { | |
30be4c96 TT |
509 | if (ppc_md.progress) |
510 | ppc_md.progress("p1022_ds_setup_arch()", 0); | |
511 | ||
2c184cd3 TT |
512 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) |
513 | diu_ops.get_pixel_format = p1022ds_get_pixel_format; | |
514 | diu_ops.set_gamma_table = p1022ds_set_gamma_table; | |
515 | diu_ops.set_monitor_port = p1022ds_set_monitor_port; | |
516 | diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; | |
7653aaab | 517 | diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; |
4951896a TT |
518 | |
519 | /* | |
6269f258 TT |
520 | * Disable the NOR and NAND flash nodes if there is video=fslfb... |
521 | * command-line parameter. When the DIU is active, the localbus is | |
522 | * unavailable, so we have to disable these nodes before the MTD | |
523 | * driver loads. | |
4951896a TT |
524 | */ |
525 | if (fslfb) { | |
526 | struct device_node *np = | |
527 | of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); | |
528 | ||
529 | if (np) { | |
6269f258 TT |
530 | struct device_node *np2; |
531 | ||
532 | of_node_get(np); | |
533 | np2 = of_find_compatible_node(np, NULL, "cfi-flash"); | |
534 | if (np2) { | |
4951896a TT |
535 | static struct property nor_status = { |
536 | .name = "status", | |
537 | .value = "disabled", | |
538 | .length = sizeof("disabled"), | |
539 | }; | |
540 | ||
6269f258 | 541 | /* |
79d1c712 | 542 | * of_update_property() is called before |
6269f258 TT |
543 | * kmalloc() is available, so the 'new' object |
544 | * should be allocated in the global area. | |
545 | * The easiest way is to do that is to | |
546 | * allocate one static local variable for each | |
547 | * call to this function. | |
548 | */ | |
549 | pr_info("p1022ds: disabling %s node", | |
550 | np2->full_name); | |
79d1c712 | 551 | of_update_property(np2, &nor_status); |
6269f258 TT |
552 | of_node_put(np2); |
553 | } | |
554 | ||
555 | of_node_get(np); | |
556 | np2 = of_find_compatible_node(np, NULL, | |
557 | "fsl,elbc-fcm-nand"); | |
558 | if (np2) { | |
559 | static struct property nand_status = { | |
560 | .name = "status", | |
561 | .value = "disabled", | |
562 | .length = sizeof("disabled"), | |
563 | }; | |
564 | ||
4951896a | 565 | pr_info("p1022ds: disabling %s node", |
6269f258 | 566 | np2->full_name); |
79d1c712 | 567 | of_update_property(np2, &nand_status); |
6269f258 | 568 | of_node_put(np2); |
4951896a | 569 | } |
6269f258 TT |
570 | |
571 | of_node_put(np); | |
4951896a TT |
572 | } |
573 | ||
574 | } | |
575 | ||
2c184cd3 TT |
576 | #endif |
577 | ||
30be4c96 | 578 | mpc85xx_smp_init(); |
30be4c96 | 579 | |
905e75c4 JH |
580 | fsl_pci_assign_primary(); |
581 | ||
582 | swiotlb_detect_4g(); | |
30be4c96 TT |
583 | |
584 | pr_info("Freescale P1022 DS reference board\n"); | |
585 | } | |
586 | ||
905e75c4 | 587 | machine_arch_initcall(p1022_ds, mpc85xx_common_publish_devices); |
30be4c96 TT |
588 | |
589 | machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier); | |
590 | ||
591 | /* | |
592 | * Called very early, device-tree isn't unflattened | |
593 | */ | |
594 | static int __init p1022_ds_probe(void) | |
595 | { | |
596 | unsigned long root = of_get_flat_dt_root(); | |
597 | ||
598 | return of_flat_dt_is_compatible(root, "fsl,p1022ds"); | |
599 | } | |
600 | ||
601 | define_machine(p1022_ds) { | |
602 | .name = "P1022 DS", | |
603 | .probe = p1022_ds_probe, | |
604 | .setup_arch = p1022_ds_setup_arch, | |
605 | .init_IRQ = p1022_ds_pic_init, | |
606 | #ifdef CONFIG_PCI | |
607 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | |
608 | #endif | |
609 | .get_irq = mpic_get_irq, | |
610 | .restart = fsl_rstcr_restart, | |
611 | .calibrate_decr = generic_calibrate_decr, | |
612 | .progress = udbg_progress, | |
613 | }; |