Beispiel #1
0
/*
 * We read the real processor speed from the PLL.  This is important
 * because it is more accurate than computing it from the 32KHz
 * counter, if it exists.  If we don't have an accurate processor
 * speed, all of the peripherals that derive their clocks based on
 * this advertised speed will introduce error and sometimes not work
 * properly.  This function is futher convoluted to still allow configurations
 * to do that in case they have really, really old silicon with a
 * write-only PLL register, that we need the 32KHz when power management
 * "wait" is enabled, and we need to detect if the 32KHz isn't present
 * but requested......got it? :-)		-- Dan
 */
unsigned long cal_r4koff(void)
{
	unsigned long cpu_speed;
	unsigned long flags;
	unsigned long counter;

	spin_lock_irqsave(&time_lock, flags);

	/* Power management cares if we don't have a 32KHz counter.
	*/
	no_au1xxx_32khz = 0;
	counter = au_readl(SYS_COUNTER_CNTRL);
	if (counter & SYS_CNTRL_E0) {
		int trim_divide = 16;

		au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);

		while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
		/* RTC now ticks at 32.768/16 kHz */
		au_writel(trim_divide-1, SYS_RTCTRIM);
		while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);

		while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
		au_writel (0, SYS_TOYWRITE);
		while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);

		cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
			AU1000_SRC_CLK;
	}
	else {
		/* The 32KHz oscillator isn't running, so assume there
		 * isn't one and grab the processor speed from the PLL.
		 * NOTE: some old silicon doesn't allow reading the PLL.
		 */
		cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
		no_au1xxx_32khz = 1;
	}
	mips_hpt_frequency = cpu_speed;
	// Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16)
	set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
	spin_unlock_irqrestore(&time_lock, flags);
	return (cpu_speed / HZ);
}
Beispiel #2
0
/*
 * Figure out the r4k offset, the amount to increment the compare
 * register for each time tick.
 * Use the Programmable Counter 1 to do this.
 */
unsigned long cal_r4koff(void)
{
	unsigned long count;
	unsigned long cpu_speed;
	unsigned long start, end;
	unsigned long counter;
	int trim_divide = 16;
	unsigned long flags;

	spin_lock_irqsave(&time_lock, flags);

	counter = au_readl(SYS_COUNTER_CNTRL);
	au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);

	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
	au_writel(trim_divide-1, SYS_RTCTRIM); /* RTC now ticks at 32.768/16 kHz */
	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);

	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
	au_writel (0, SYS_TOYWRITE);
	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);

	start = au_readl(SYS_RTCREAD);
	start += 2;
	/* wait for the beginning of a new tick */
	while (au_readl(SYS_RTCREAD) < start);

	/* Start r4k counter. */
	write_c0_count(0);
	end = start + (32768 / trim_divide)/2; /* wait 0.5 seconds */

	while (end > au_readl(SYS_RTCREAD));

	count = read_c0_count();
	cpu_speed = count * 2;
	mips_counter_frequency = count;
	set_au1x00_uart_baud_base(((cpu_speed) / 4) / 16);
	spin_unlock_irqrestore(&time_lock, flags);
	return (cpu_speed / HZ);
}
Beispiel #3
0
/*
 * We read the real processor speed from the PLL.  This is important
 * because it is more accurate than computing it from the 32KHz
 * counter, if it exists.  If we don't have an accurate processor
 * speed, all of the peripherals that derive their clocks based on
 * this advertised speed will introduce error and sometimes not work
 * properly.  This function is futher convoluted to still allow configurations
 * to do that in case they have really, really old silicon with a
 * write-only PLL register, that we need the 32KHz when power management
 * "wait" is enabled, and we need to detect if the 32KHz isn't present
 * but requested......got it? :-)		-- Dan
 */
unsigned long cal_r4koff(void)
{
    unsigned long cpu_speed;
    unsigned long flags;
    unsigned long counter;

    spin_lock_irqsave(&time_lock, flags);

    /* Power management cares if we don't have a 32KHz counter.
    */
    no_au1xxx_32khz = 0;
    counter = au_readl(SYS_COUNTER_CNTRL);
    if (counter & SYS_CNTRL_E0) {
        int trim_divide = 16;

        au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);

        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
        /* RTC now ticks at 32.768/16 kHz */
        au_writel(trim_divide-1, SYS_RTCTRIM);
        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);

        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
        au_writel (0, SYS_TOYWRITE);
        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);

#if defined(CONFIG_AU1000_USE32K)
        {
            unsigned long start, end, count;

            start = au_readl(SYS_RTCREAD);
            start += 2;
            /* wait for the beginning of a new tick
            */
            while (au_readl(SYS_RTCREAD) < start);

            /* Start r4k counter.
            */
            write_c0_count(0);

            /* Wait 0.5 seconds.
            */
            end = start + (32768 / trim_divide)/2;

            while (end > au_readl(SYS_RTCREAD));

            count = read_c0_count();
            cpu_speed = count * 2;
        }
#else
        cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
                    AU1000_SRC_CLK;
#endif
    }
    else {
        /* The 32KHz oscillator isn't running, so assume there
         * isn't one and grab the processor speed from the PLL.
         * NOTE: some old silicon doesn't allow reading the PLL.
         */
        cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
        no_au1xxx_32khz = 1;
    }
    mips_hpt_frequency = cpu_speed;
    // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16)
    set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
    spin_unlock_irqrestore(&time_lock, flags);
    return (cpu_speed / HZ);
}
Beispiel #4
0
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;
}