提交 c8bfa77b 编写于 作者: T Timur Tabi 提交者: Kumar Gala

powerpc/86xx: improve calculation of DIU pixel clock on the MPC8610 HPCD

mpc8610hpcd_set_pixel_clock() calculates the correct value of the PXCLK
bits in the CLKDVDR register for a given pixel clock rate.  The code which
performs this calculation is overly complicated and includes an error
estimation routine that doesn't work most of the time anyway.  Replace the
code with the simpler routine that's currently used on the P1022DS.
Signed-off-by: NTimur Tabi <timur@freescale.com>
Signed-off-by: NKumar Gala <galak@kernel.crashing.org>
上级 3846e332
...@@ -39,12 +39,19 @@ ...@@ -39,12 +39,19 @@
#include <sysdev/fsl_pci.h> #include <sysdev/fsl_pci.h>
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
#include <sysdev/simple_gpio.h> #include <sysdev/simple_gpio.h>
#include <asm/fsl_guts.h>
#include "mpc86xx.h" #include "mpc86xx.h"
static struct device_node *pixis_node; static struct device_node *pixis_node;
static unsigned char *pixis_bdcfg0, *pixis_arch; static unsigned char *pixis_bdcfg0, *pixis_arch;
/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
#define CLKDVDR_PXCKEN 0x80000000
#define CLKDVDR_PXCKINV 0x10000000
#define CLKDVDR_PXCKDLY 0x06000000
#define CLKDVDR_PXCLK_MASK 0x001F0000
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
static irqreturn_t mpc8610_sw9_irq(int irq, void *data) static irqreturn_t mpc8610_sw9_irq(int irq, void *data)
{ {
...@@ -205,72 +212,54 @@ void mpc8610hpcd_set_monitor_port(int monitor_port) ...@@ -205,72 +212,54 @@ void mpc8610hpcd_set_monitor_port(int monitor_port)
bdcfg[monitor_port]); bdcfg[monitor_port]);
} }
/**
* mpc8610hpcd_set_pixel_clock: program the DIU's clock
*
* @pixclock: the wavelength, in picoseconds, of the clock
*/
void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
{ {
u32 __iomem *clkdvdr; struct device_node *guts_np = NULL;
u32 temp; struct ccsr_guts_86xx __iomem *guts;
/* variables for pixel clock calcs */ unsigned long freq;
ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock; u64 temp;
ulong pixval; u32 pxclk;
long err;
int i; /* Map the global utilities registers. */
guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32)); if (!guts_np) {
if (!clkdvdr) { pr_err("mpc8610hpcd: missing global utilties device node\n");
printk(KERN_ERR "Err: can't map clock divider register!\n");
return; return;
} }
/* Pixel Clock configuration */ guts = of_iomap(guts_np, 0);
speed_ccb = fsl_get_sys_freq(); of_node_put(guts_np);
if (!guts) {
/* Calculate the pixel clock with the smallest error */ pr_err("mpc8610hpcd: could not map global utilties device\n");
/* calculate the following in steps to avoid overflow */ return;
pr_debug("DIU pixclock in ps - %d\n", pixclock);
temp = 1000000000/pixclock;
temp *= 1000;
pixclock = temp;
pr_debug("DIU pixclock freq - %u\n", pixclock);
temp = pixclock * 5 / 100;
pr_debug("deviation = %d\n", temp);
minpixclock = pixclock - temp;
maxpixclock = pixclock + temp;
pr_debug("DIU minpixclock - %lu\n", minpixclock);
pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
pixval = speed_ccb/pixclock;
pr_debug("DIU pixval = %lu\n", pixval);
err = 100000000;
bestval = pixval;
pr_debug("DIU bestval = %lu\n", bestval);
bestfreq = 0;
for (i = -1; i <= 1; i++) {
temp = speed_ccb / ((pixval+i) + 1);
pr_debug("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n",
i, pixval, temp);
if ((temp < minpixclock) || (temp > maxpixclock))
pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
minpixclock, maxpixclock);
else if (abs(temp - pixclock) < err) {
pr_debug("Entered the else if block %d\n", i);
err = abs(temp - pixclock);
bestval = pixval+i;
bestfreq = temp;
}
} }
pr_debug("DIU chose = %lx\n", bestval); /* Convert pixclock from a wavelength to a frequency */
pr_debug("DIU error = %ld\n NomPixClk ", err); temp = 1000000000000ULL;
pr_debug("DIU: Best Freq = %lx\n", bestfreq); do_div(temp, pixclock);
/* Modify PXCLK in GUTS CLKDVDR */ freq = temp;
pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr));
temp = (*clkdvdr) & 0x2000FFFF; /*
*clkdvdr = temp; /* turn off clock */ * 'pxclk' is the ratio of the platform clock to the pixel clock.
*clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16); * On the MPC8610, the value programmed into CLKDVDR is the ratio
pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr)); * minus one. The valid range of values is 2-31.
iounmap(clkdvdr); */
pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq) - 1;
pxclk = clamp_t(u32, pxclk, 2, 31);
/* Disable the pixel clock, and set it to non-inverted and no delay */
clrbits32(&guts->clkdvdr,
CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
/* Enable the clock and set the pxclk */
setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
iounmap(guts);
} }
ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册