/* * Calculate the Au1x00's LCD clock based on the current * cpu clock and the system bus clock, and try to keep it * below 40 MHz (the Pb1000 board can lock-up if the LCD * clock is over 40 MHz). */ void set_au1x00_lcd_clock(void) { unsigned int static_cfg0; unsigned int sys_busclk = (get_au1x00_speed()/1000) / ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2); static_cfg0 = au_readl(MEM_STCFG0); if (static_cfg0 & (1<<11)) lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */ else lcd_clock = sys_busclk / 4; if (lcd_clock > 50000) /* Epson MAX */ printk(__FUNCTION__ ": warning: LCD clock too high (%d KHz)\n", lcd_clock); }
static int pm_do_freq(ctl_table * ctl, int write, struct file *file, void *buffer, size_t * len) { int retval = 0, i; unsigned long val, pll; #define TMPBUFLEN 64 #define MAX_CPU_FREQ 396 char buf[TMPBUFLEN], *p; unsigned long flags, intc0_mask, intc1_mask; unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk, old_refresh; unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; spin_lock_irqsave(&pm_lock, flags); if (!write) { *len = 0; } else { /* Parse the new frequency */ if (*len > TMPBUFLEN - 1) { spin_unlock_irqrestore(&pm_lock, flags); return -EFAULT; } if (copy_from_user(buf, buffer, *len)) { spin_unlock_irqrestore(&pm_lock, flags); return -EFAULT; } buf[*len] = 0; p = buf; val = simple_strtoul(p, &p, 0); if (val > MAX_CPU_FREQ) { spin_unlock_irqrestore(&pm_lock, flags); return -EFAULT; } pll = val / 12; if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ /* revisit this for higher speed cpus */ spin_unlock_irqrestore(&pm_lock, flags); return -EFAULT; } old_baud_base = get_au1x00_uart_baud_base(); old_cpu_freq = get_au1x00_speed(); new_cpu_freq = pll * 12 * 1000000; new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); set_au1x00_speed(new_cpu_freq); set_au1x00_uart_baud_base(new_baud_base); old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff; new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff); au_writel(pll, SYS_CPUPLL); au_sync_delay(1); au_writel(new_refresh, MEM_SDREFCFG); au_sync_delay(1); for (i = 0; i < 4; i++) { if (au_readl (UART_BASE + UART_MOD_CNTRL + i * 0x00100000) == 3) { old_clk = au_readl(UART_BASE + UART_CLK + i * 0x00100000); // baud_rate = baud_base/clk baud_rate = old_baud_base / old_clk; /* we won't get an exact baud rate and the error * could be significant enough that our new * calculation will result in a clock that will * give us a baud rate that's too far off from * what we really want. */ if (baud_rate > 100000) baud_rate = 115200; else if (baud_rate > 50000) baud_rate = 57600; else if (baud_rate > 30000) baud_rate = 38400; else if (baud_rate > 17000) baud_rate = 19200; else (baud_rate = 9600); // new_clk = new_baud_base/baud_rate new_clk = new_baud_base / baud_rate; au_writel(new_clk, UART_BASE + UART_CLK + i * 0x00100000); au_sync_delay(10); } } } /* We don't want _any_ interrupts other than * match20. Otherwise our calibrate_delay() * calculation will be off, potentially a lot. */ intc0_mask = save_local_and_disable(0); intc1_mask = save_local_and_disable(1); local_enable_irq(AU1000_TOY_MATCH2_INT); spin_unlock_irqrestore(&pm_lock, flags); calibrate_delay(); restore_local_and_enable(0, intc0_mask); restore_local_and_enable(1, intc1_mask); return retval; }