diff options
Diffstat (limited to 'arch/powerpc')
-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 |
6 files changed, 323 insertions, 0 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; |