diff options
Diffstat (limited to 'arch/powerpc/platforms/86xx/mpc8610_hpcd.c')
-rw-r--r-- | arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 107 |
1 files changed, 48 insertions, 59 deletions
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index a896511690c..74e018ef724 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c | |||
@@ -39,12 +39,19 @@ | |||
39 | #include <sysdev/fsl_pci.h> | 39 | #include <sysdev/fsl_pci.h> |
40 | #include <sysdev/fsl_soc.h> | 40 | #include <sysdev/fsl_soc.h> |
41 | #include <sysdev/simple_gpio.h> | 41 | #include <sysdev/simple_gpio.h> |
42 | #include <asm/fsl_guts.h> | ||
42 | 43 | ||
43 | #include "mpc86xx.h" | 44 | #include "mpc86xx.h" |
44 | 45 | ||
45 | static struct device_node *pixis_node; | 46 | static struct device_node *pixis_node; |
46 | static unsigned char *pixis_bdcfg0, *pixis_arch; | 47 | static unsigned char *pixis_bdcfg0, *pixis_arch; |
47 | 48 | ||
49 | /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ | ||
50 | #define CLKDVDR_PXCKEN 0x80000000 | ||
51 | #define CLKDVDR_PXCKINV 0x10000000 | ||
52 | #define CLKDVDR_PXCKDLY 0x06000000 | ||
53 | #define CLKDVDR_PXCLK_MASK 0x001F0000 | ||
54 | |||
48 | #ifdef CONFIG_SUSPEND | 55 | #ifdef CONFIG_SUSPEND |
49 | static irqreturn_t mpc8610_sw9_irq(int irq, void *data) | 56 | static irqreturn_t mpc8610_sw9_irq(int irq, void *data) |
50 | { | 57 | { |
@@ -205,72 +212,54 @@ void mpc8610hpcd_set_monitor_port(int monitor_port) | |||
205 | bdcfg[monitor_port]); | 212 | bdcfg[monitor_port]); |
206 | } | 213 | } |
207 | 214 | ||
215 | /** | ||
216 | * mpc8610hpcd_set_pixel_clock: program the DIU's clock | ||
217 | * | ||
218 | * @pixclock: the wavelength, in picoseconds, of the clock | ||
219 | */ | ||
208 | void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) | 220 | void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) |
209 | { | 221 | { |
210 | u32 __iomem *clkdvdr; | 222 | struct device_node *guts_np = NULL; |
211 | u32 temp; | 223 | struct ccsr_guts_86xx __iomem *guts; |
212 | /* variables for pixel clock calcs */ | 224 | unsigned long freq; |
213 | ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock; | 225 | u64 temp; |
214 | ulong pixval; | 226 | u32 pxclk; |
215 | long err; | 227 | |
216 | int i; | 228 | /* Map the global utilities registers. */ |
217 | 229 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); | |
218 | clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32)); | 230 | if (!guts_np) { |
219 | if (!clkdvdr) { | 231 | pr_err("mpc8610hpcd: missing global utilties device node\n"); |
220 | printk(KERN_ERR "Err: can't map clock divider register!\n"); | ||
221 | return; | 232 | return; |
222 | } | 233 | } |
223 | 234 | ||
224 | /* Pixel Clock configuration */ | 235 | guts = of_iomap(guts_np, 0); |
225 | speed_ccb = fsl_get_sys_freq(); | 236 | of_node_put(guts_np); |
226 | 237 | if (!guts) { | |
227 | /* Calculate the pixel clock with the smallest error */ | 238 | pr_err("mpc8610hpcd: could not map global utilties device\n"); |
228 | /* calculate the following in steps to avoid overflow */ | 239 | return; |
229 | pr_debug("DIU pixclock in ps - %d\n", pixclock); | ||
230 | temp = 1000000000/pixclock; | ||
231 | temp *= 1000; | ||
232 | pixclock = temp; | ||
233 | pr_debug("DIU pixclock freq - %u\n", pixclock); | ||
234 | |||
235 | temp = pixclock * 5 / 100; | ||
236 | pr_debug("deviation = %d\n", temp); | ||
237 | minpixclock = pixclock - temp; | ||
238 | maxpixclock = pixclock + temp; | ||
239 | pr_debug("DIU minpixclock - %lu\n", minpixclock); | ||
240 | pr_debug("DIU maxpixclock - %lu\n", maxpixclock); | ||
241 | pixval = speed_ccb/pixclock; | ||
242 | pr_debug("DIU pixval = %lu\n", pixval); | ||
243 | |||
244 | err = 100000000; | ||
245 | bestval = pixval; | ||
246 | pr_debug("DIU bestval = %lu\n", bestval); | ||
247 | |||
248 | bestfreq = 0; | ||
249 | for (i = -1; i <= 1; i++) { | ||
250 | temp = speed_ccb / ((pixval+i) + 1); | ||
251 | pr_debug("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n", | ||
252 | i, pixval, temp); | ||
253 | if ((temp < minpixclock) || (temp > maxpixclock)) | ||
254 | pr_debug("DIU exceeds monitor range (%lu to %lu)\n", | ||
255 | minpixclock, maxpixclock); | ||
256 | else if (abs(temp - pixclock) < err) { | ||
257 | pr_debug("Entered the else if block %d\n", i); | ||
258 | err = abs(temp - pixclock); | ||
259 | bestval = pixval+i; | ||
260 | bestfreq = temp; | ||
261 | } | ||
262 | } | 240 | } |
263 | 241 | ||
264 | pr_debug("DIU chose = %lx\n", bestval); | 242 | /* Convert pixclock from a wavelength to a frequency */ |
265 | pr_debug("DIU error = %ld\n NomPixClk ", err); | 243 | temp = 1000000000000ULL; |
266 | pr_debug("DIU: Best Freq = %lx\n", bestfreq); | 244 | do_div(temp, pixclock); |
267 | /* Modify PXCLK in GUTS CLKDVDR */ | 245 | freq = temp; |
268 | pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr)); | 246 | |
269 | temp = (*clkdvdr) & 0x2000FFFF; | 247 | /* |
270 | *clkdvdr = temp; /* turn off clock */ | 248 | * 'pxclk' is the ratio of the platform clock to the pixel clock. |
271 | *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16); | 249 | * On the MPC8610, the value programmed into CLKDVDR is the ratio |
272 | pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr)); | 250 | * minus one. The valid range of values is 2-31. |
273 | iounmap(clkdvdr); | 251 | */ |
252 | pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq) - 1; | ||
253 | pxclk = clamp_t(u32, pxclk, 2, 31); | ||
254 | |||
255 | /* Disable the pixel clock, and set it to non-inverted and no delay */ | ||
256 | clrbits32(&guts->clkdvdr, | ||
257 | CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); | ||
258 | |||
259 | /* Enable the clock and set the pxclk */ | ||
260 | setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); | ||
261 | |||
262 | iounmap(guts); | ||
274 | } | 263 | } |
275 | 264 | ||
276 | ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) | 265 | ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) |