Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d01cdaf authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: SH-5 clk fwk support.



Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 50b72e60
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -5,3 +5,8 @@ obj-y := entry.o probe.o switchto.o

obj-$(CONFIG_SH_FPU)		+= fpu.o
obj-$(CONFIG_KALLSYMS)		+= unwind.o

# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH5)		:= clock-sh5.o

obj-y			+= $(clock-y)
+79 −0
Original line number Diff line number Diff line
/*
 * arch/sh/kernel/cpu/sh5/clock-sh5.c
 *
 * SH-5 support for the clock framework
 *
 *  Copyright (C) 2008  Paul Mundt
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/clock.h>
#include <asm/io.h>

static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };

/* Clock, Power and Reset Controller */
#define	CPRC_BLOCK_OFF	0x01010000
#define CPRC_BASE	(PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF)

static unsigned long cprc_base;

static void master_clk_init(struct clk *clk)
{
	int idx = (ctrl_inl(cprc_base + 0x00) >> 6) & 0x0007;
	clk->rate *= ifc_table[idx];
}

static struct clk_ops sh5_master_clk_ops = {
	.init		= master_clk_init,
};

static void module_clk_recalc(struct clk *clk)
{
	int idx = (ctrl_inw(cprc_base) >> 12) & 0x0007;
	clk->rate = clk->parent->rate / ifc_table[idx];
}

static struct clk_ops sh5_module_clk_ops = {
	.recalc		= module_clk_recalc,
};

static void bus_clk_recalc(struct clk *clk)
{
	int idx = (ctrl_inw(cprc_base) >> 3) & 0x0007;
	clk->rate = clk->parent->rate / ifc_table[idx];
}

static struct clk_ops sh5_bus_clk_ops = {
	.recalc		= bus_clk_recalc,
};

static void cpu_clk_recalc(struct clk *clk)
{
	int idx = (ctrl_inw(cprc_base) & 0x0007);
	clk->rate = clk->parent->rate / ifc_table[idx];
}

static struct clk_ops sh5_cpu_clk_ops = {
	.recalc		= cpu_clk_recalc,
};

static struct clk_ops *sh5_clk_ops[] = {
	&sh5_master_clk_ops,
	&sh5_module_clk_ops,
	&sh5_bus_clk_ops,
	&sh5_cpu_clk_ops,
};

void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
{
	cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
	BUG_ON(!cprc_base);

	if (idx < ARRAY_SIZE(sh5_clk_ops))
		*ops = sh5_clk_ops[idx];
}
+7 −161
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
#include <asm/clock.h>

#define TMU_TOCR_INIT	0x00
#define TMU0_TCR_INIT	0x0020
@@ -51,14 +52,6 @@
#define RTC_RCR1_CIE	0x10	/* Carry Interrupt Enable */
#define RTC_RCR1	(rtc_base + 0x38)

/* Clock, Power and Reset Controller */
#define	CPRC_BLOCK_OFF	0x01010000
#define CPRC_BASE	PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF

#define FRQCR		(cprc_base+0x0)
#define WTCSR		(cprc_base+0x0018)
#define STBCR		(cprc_base+0x0030)

/* Time Management Unit */
#define	TMU_BLOCK_OFF	0x01020000
#define TMU_BASE	PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
@@ -293,103 +286,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
	return IRQ_HANDLED;
}


static __init unsigned int get_cpu_hz(void)
{
	unsigned int count;
	unsigned long __dummy;
	unsigned long ctc_val_init, ctc_val;

	/*
	** Regardless the toolchain, force the compiler to use the
	** arbitrary register r3 as a clock tick counter.
	** NOTE: r3 must be in accordance with sh64_rtc_interrupt()
	*/
	register unsigned long long  __rtc_irq_flag __asm__ ("r3");

	local_irq_enable();
	do {} while (ctrl_inb(rtc_base) != 0);
	ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */

	/*
	 * r3 is arbitrary. CDC does not support "=z".
	 */
	ctc_val_init = 0xffffffff;
	ctc_val = ctc_val_init;

	asm volatile("gettr	tr0, %1\n\t"
		     "putcon	%0, " __CTC "\n\t"
		     "and	%2, r63, %2\n\t"
		     "pta	$+4, tr0\n\t"
		     "beq/l	%2, r63, tr0\n\t"
		     "ptabs	%1, tr0\n\t"
		     "getcon	" __CTC ", %0\n\t"
		: "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
		: "0" (0));
	local_irq_disable();
	/*
	 * SH-3:
	 * CPU clock = 4 stages * loop
	 * tst    rm,rm      if id ex
	 * bt/s   1b            if id ex
	 * add    #1,rd            if id ex
         *                            (if) pipe line stole
	 * tst    rm,rm                  if id ex
         * ....
	 *
	 *
	 * SH-4:
	 * CPU clock = 6 stages * loop
	 * I don't know why.
         * ....
	 *
	 * SH-5:
	 * Use CTC register to count.  This approach returns the right value
	 * even if the I-cache is disabled (e.g. whilst debugging.)
	 *
	 */

	count = ctc_val_init - ctc_val; /* CTC counts down */

	/*
	 * This really is count by the number of clock cycles
         * by the ratio between a complete R64CNT
         * wrap-around (128) and CUI interrupt being raised (64).
	 */
	return count*2;
}

static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
{
	struct pt_regs *regs = get_irq_regs();

	ctrl_outb(0, RTC_RCR1);	/* Disable Carry Interrupts */
	regs->regs[3] = 1;	/* Using r3 */

	return IRQ_HANDLED;
}

static struct irqaction irq0  = {
	.handler = timer_interrupt,
	.flags = IRQF_DISABLED,
	.mask = CPU_MASK_NONE,
	.name = "timer",
};
static struct irqaction irq1  = {
	.handler = sh64_rtc_interrupt,
	.flags = IRQF_DISABLED,
	.mask = CPU_MASK_NONE,
	.name = "rtc",
};

void __init time_init(void)
{
	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
	unsigned long interval;
	unsigned long frqcr, ifc, pfc;
	static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };
#define bfc_table ifc_table	/* Same */
#define pfc_table ifc_table	/* Same */
	struct clk *clk;

	tmu_base = onchip_remap(TMU_BASE, 1024, "TMU");
	if (!tmu_base) {
@@ -401,50 +308,19 @@ void __init time_init(void)
		panic("Unable to remap RTC\n");
	}

	cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
	if (!cprc_base) {
		panic("Unable to remap CPRC\n");
	}
	clk = clk_get(NULL, "cpu_clk");
	scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) /
			(unsigned long long)(clk_get_rate(clk) / HZ));

	rtc_sh_get_time(&xtime);

	setup_irq(TIMER_IRQ, &irq0);
	setup_irq(RTC_IRQ, &irq1);

	/* Check how fast it is.. */
	cpu_clock = get_cpu_hz();

	/* Note careful order of operations to maintain reasonable precision and avoid overflow. */
	scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ));

	free_irq(RTC_IRQ, NULL);

	printk("CPU clock: %d.%02dMHz\n",
	       (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
	{
		unsigned short bfc;
		frqcr = ctrl_inl(FRQCR);
		ifc  = ifc_table[(frqcr>> 6) & 0x0007];
		bfc  = bfc_table[(frqcr>> 3) & 0x0007];
		pfc  = pfc_table[(frqcr>> 12) & 0x0007];
		master_clock = cpu_clock * ifc;
		bus_clock = master_clock/bfc;
	}

	printk("Bus clock: %d.%02dMHz\n",
	       (bus_clock/1000000), (bus_clock % 1000000)/10000);
	module_clock = master_clock/pfc;
	printk("Module clock: %d.%02dMHz\n",
	       (module_clock/1000000), (module_clock % 1000000)/10000);
	interval = (module_clock/(HZ*4));
	clk = clk_get(NULL, "module_clk");
	interval = (clk_get_rate(clk)/(HZ*4));

	printk("Interval = %ld\n", interval);

	current_cpu_data.cpu_clock    = cpu_clock;
	current_cpu_data.master_clock = master_clock;
	current_cpu_data.bus_clock    = bus_clock;
	current_cpu_data.module_clock = module_clock;

	/* Start TMU0 */
	ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
@@ -454,36 +330,6 @@ void __init time_init(void)
	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
}

void enter_deep_standby(void)
{
	/* Disable watchdog timer */
	ctrl_outl(0xa5000000, WTCSR);
	/* Configure deep standby on sleep */
	ctrl_outl(0x03, STBCR);

#ifdef CONFIG_SH_ALPHANUMERIC
	{
		extern void mach_alphanum(int position, unsigned char value);
		extern void mach_alphanum_brightness(int setting);
		char halted[] = "Halted. ";
		int i;
		mach_alphanum_brightness(6); /* dimmest setting above off */
		for (i=0; i<8; i++) {
			mach_alphanum(i, halted[i]);
		}
		asm __volatile__ ("synco");
	}
#endif

	asm __volatile__ ("sleep");
	asm __volatile__ ("synci");
	asm __volatile__ ("nop");
	asm __volatile__ ("nop");
	asm __volatile__ ("nop");
	asm __volatile__ ("nop");
	panic("Unexpected wakeup!\n");
}

static struct resource rtc_resources[] = {
	[0] = {
		/* RTC base, filled in by rtc_init */