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

Commit 229f773e authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by Ralf Baechle
Browse files

[MIPS] txx9tmr clockevent/clocksource driver



Convert jmr3927_clock_event_device to more generic
txx9tmr_clock_event_device which supports one-shot mode.  The
txx9tmr_clock_event_device can be used for TX49 too if the cp0 timer
interrupt was not available.

Convert jmr3927_hpt_read to txx9_clocksource driver which does not
depends jiffies anymore.  The txx9_clocksource itself can be used for
TX49, but normally TX49 uses higher precision clocksource_mips.

Signed-off-by: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 22df3f53
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -583,6 +583,7 @@ config SNI_RM

config TOSHIBA_JMR3927
	bool "Toshiba JMR-TX3927 board"
	select CEVT_TXX9
	select DMA_NONCOHERENT
	select HW_HAS_PCI
	select MIPS_TX3927
@@ -597,6 +598,7 @@ config TOSHIBA_JMR3927
config TOSHIBA_RBTX4927
	bool "Toshiba RBTX49[23]7 board"
	select CEVT_R4K
	select CEVT_TXX9
	select DMA_NONCOHERENT
	select HAS_TXX9_SERIAL
	select HW_HAS_PCI
@@ -618,6 +620,7 @@ config TOSHIBA_RBTX4927
config TOSHIBA_RBTX4938
	bool "Toshiba RBTX4938 board"
	select CEVT_R4K
	select CEVT_TXX9
	select DMA_NONCOHERENT
	select HAS_TXX9_SERIAL
	select HW_HAS_PCI
@@ -736,6 +739,9 @@ config CEVT_GT641XX
config CEVT_R4K
	bool

config CEVT_TXX9
	bool

config CFE
	bool

+7 −76
Original line number Diff line number Diff line
@@ -27,17 +27,13 @@
 * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
 */

#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/param.h>	/* for HZ */
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
@@ -48,17 +44,13 @@
#endif

#include <asm/addrspace.h>
#include <asm/time.h>
#include <asm/txx9tmr.h>
#include <asm/reboot.h>
#include <asm/jmr3927/jmr3927.h>
#include <asm/mipsregs.h>

extern void puts(const char *cp);

/* Tick Timer divider */
#define JMR3927_TIMER_CCD	0	/* 1/2 */
#define JMR3927_TIMER_CLK	(JMR3927_IMCLK / (2 << JMR3927_TIMER_CCD))

/* don't enable - see errata */
static int jmr3927_ccfg_toeon;

@@ -93,66 +85,12 @@ static void jmr3927_machine_power_off(void)
	while (1);
}

static cycle_t jmr3927_hpt_read(void)
{
	/* We assume this function is called xtime_lock held. */
	return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr;
}

static void jmr3927_set_mode(enum clock_event_mode mode,
	struct clock_event_device *evt)
{
	/* Nothing to do here */
}

struct clock_event_device jmr3927_clock_event_device = {
	.name		= "MIPS",
	.features	= CLOCK_EVT_FEAT_PERIODIC,
	.shift		= 32,
	.rating		= 300,
	.cpumask	= CPU_MASK_CPU0,
	.irq		= JMR3927_IRQ_TICK,
	.set_mode	= jmr3927_set_mode,
};

static irqreturn_t jmr3927_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *cd = &jmr3927_clock_event_device;

	jmr3927_tmrptr->tisr = 0;       /* ack interrupt */

	cd->event_handler(cd);

	return IRQ_HANDLED;
}

static struct irqaction jmr3927_timer_irqaction = {
	.handler	= jmr3927_timer_interrupt,
	.flags		= IRQF_DISABLED | IRQF_PERCPU,
	.name		= "jmr3927-timer",
};

void __init plat_time_init(void)
{
	struct clock_event_device *cd;

	clocksource_mips.read = jmr3927_hpt_read;
	mips_hpt_frequency = JMR3927_TIMER_CLK;

	jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ;
	jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE;
	jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD;
	jmr3927_tmrptr->tcr =
		TXx927_TMTCR_TCE | TXx927_TMTCR_CCDE | TXx927_TMTCR_TMODE_ITVL;

	cd = &jmr3927_clock_event_device;
	/* Calculate the min / max delta */
	cd->mult = div_sc((unsigned long) JMR3927_IMCLK, NSEC_PER_SEC, 32);
	cd->max_delta_ns	= clockevent_delta2ns(0x7fffffff, cd);
	cd->min_delta_ns	= clockevent_delta2ns(0x300, cd);
	clockevents_register_device(cd);

	setup_irq(JMR3927_IRQ_TICK, &jmr3927_timer_irqaction);
	txx9_clockevent_init(TX3927_TMR_REG(0),
			     TXX9_IRQ_BASE + JMR3927_IRQ_IRC_TMR(0),
			     JMR3927_IMCLK);
	txx9_clocksource_init(TX3927_TMR_REG(1), JMR3927_IMCLK);
}

#define DO_WRITE_THROUGH
@@ -317,15 +255,8 @@ static void __init tx3927_setup(void)
	       tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg);

	/* TMR */
	/* disable all timers */
	for (i = 0; i < TX3927_NR_TMR; i++) {
		tx3927_tmrptr(i)->tcr = TXx927_TMTCR_CRE;
		tx3927_tmrptr(i)->tisr = 0;
		tx3927_tmrptr(i)->cpra = 0xffffffff;
		tx3927_tmrptr(i)->itmr = 0;
		tx3927_tmrptr(i)->ccdr = 0;
		tx3927_tmrptr(i)->pgmr = 0;
	}
	for (i = 0; i < TX3927_NR_TMR; i++)
		txx9_tmr_init(TX3927_TMR_REG(i));

	/* DMA */
	tx3927_dmaptr->mcr = 0;
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \

obj-$(CONFIG_CEVT_R4K)		+= cevt-r4k.o
obj-$(CONFIG_CEVT_GT641XX)	+= cevt-gt641xx.o
obj-$(CONFIG_CEVT_TXX9)		+= cevt-txx9.o

binfmt_irix-objs	:= irixelf.o irixinv.o irixioctl.o irixsig.o	\
			   irix5sys.o sysirix.o
+171 −0
Original line number Diff line number Diff line
/*
 * 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.
 *
 * Based on linux/arch/mips/kernel/cevt-r4k.c,
 *          linux/arch/mips/jmr3927/rbhma3100/setup.c
 *
 * Copyright 2001 MontaVista Software Inc.
 * Copyright (C) 2000-2001 Toshiba Corporation
 * Copyright (C) 2007 MIPS Technologies, Inc.
 * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
 */
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/time.h>
#include <asm/txx9tmr.h>

#define TCR_BASE (TXx9_TMTCR_CCDE | TXx9_TMTCR_CRE | TXx9_TMTCR_TMODE_ITVL)
#define TIMER_CCD	0	/* 1/2 */
#define TIMER_CLK(imclk)	((imclk) / (2 << TIMER_CCD))

static struct txx9_tmr_reg __iomem *txx9_cs_tmrptr;

static cycle_t txx9_cs_read(void)
{
	return __raw_readl(&txx9_cs_tmrptr->trr);
}

/* Use 1 bit smaller width to use full bits in that width */
#define TXX9_CLOCKSOURCE_BITS (TXX9_TIMER_BITS - 1)

static struct clocksource txx9_clocksource = {
	.name		= "TXx9",
	.rating		= 200,
	.read		= txx9_cs_read,
	.mask		= CLOCKSOURCE_MASK(TXX9_CLOCKSOURCE_BITS),
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

void __init txx9_clocksource_init(unsigned long baseaddr,
				  unsigned int imbusclk)
{
	struct txx9_tmr_reg __iomem *tmrptr;

	clocksource_set_clock(&txx9_clocksource, TIMER_CLK(imbusclk));
	clocksource_register(&txx9_clocksource);

	tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
	__raw_writel(TCR_BASE, &tmrptr->tcr);
	__raw_writel(0, &tmrptr->tisr);
	__raw_writel(TIMER_CCD, &tmrptr->ccdr);
	__raw_writel(TXx9_TMITMR_TZCE, &tmrptr->itmr);
	__raw_writel(1 << TXX9_CLOCKSOURCE_BITS, &tmrptr->cpra);
	__raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr);
	txx9_cs_tmrptr = tmrptr;
}

static struct txx9_tmr_reg __iomem *txx9_tmrptr;

static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr)
{
	/* stop and reset counter */
	__raw_writel(TCR_BASE, &tmrptr->tcr);
	/* clear pending interrupt */
	__raw_writel(0, &tmrptr->tisr);
}

static void txx9tmr_set_mode(enum clock_event_mode mode,
			     struct clock_event_device *evt)
{
	struct txx9_tmr_reg __iomem *tmrptr = txx9_tmrptr;

	txx9tmr_stop_and_clear(tmrptr);
	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
		__raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE,
			     &tmrptr->itmr);
		/* start timer */
		__raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >>
			     evt->shift,
			     &tmrptr->cpra);
		__raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr);
		break;
	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_UNUSED:
		__raw_writel(0, &tmrptr->itmr);
		break;
	case CLOCK_EVT_MODE_ONESHOT:
		__raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr);
		break;
	case CLOCK_EVT_MODE_RESUME:
		__raw_writel(TIMER_CCD, &tmrptr->ccdr);
		__raw_writel(0, &tmrptr->itmr);
		break;
	}
}

static int txx9tmr_set_next_event(unsigned long delta,
				  struct clock_event_device *evt)
{
	struct txx9_tmr_reg __iomem *tmrptr = txx9_tmrptr;

	txx9tmr_stop_and_clear(tmrptr);
	/* start timer */
	__raw_writel(delta, &tmrptr->cpra);
	__raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr);
	return 0;
}

static struct clock_event_device txx9tmr_clock_event_device = {
	.name		= "TXx9",
	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
	.rating		= 200,
	.cpumask	= CPU_MASK_CPU0,
	.set_mode	= txx9tmr_set_mode,
	.set_next_event	= txx9tmr_set_next_event,
};

static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *cd = &txx9tmr_clock_event_device;
	struct txx9_tmr_reg __iomem *tmrptr = txx9_tmrptr;

	__raw_writel(0, &tmrptr->tisr);	/* ack interrupt */
	cd->event_handler(cd);
	return IRQ_HANDLED;
}

static struct irqaction txx9tmr_irq = {
	.handler	= txx9tmr_interrupt,
	.flags		= IRQF_DISABLED | IRQF_PERCPU,
	.name		= "txx9tmr",
};

void __init txx9_clockevent_init(unsigned long baseaddr, int irq,
				 unsigned int imbusclk)
{
	struct clock_event_device *cd = &txx9tmr_clock_event_device;
	struct txx9_tmr_reg __iomem *tmrptr;

	tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
	txx9tmr_stop_and_clear(tmrptr);
	__raw_writel(TIMER_CCD, &tmrptr->ccdr);
	__raw_writel(0, &tmrptr->itmr);
	txx9_tmrptr = tmrptr;

	clockevent_set_clock(cd, TIMER_CLK(imbusclk));
	cd->max_delta_ns =
		clockevent_delta2ns(0xffffffff >> (32 - TXX9_TIMER_BITS), cd);
	cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
	cd->irq = irq;
	clockevents_register_device(cd);
	setup_irq(irq, &txx9tmr_irq);
	printk(KERN_INFO "TXx9: clockevent device at 0x%lx, irq %d\n",
	       baseaddr, irq);
}

void __init txx9_tmr_init(unsigned long baseaddr)
{
	struct txx9_tmr_reg __iomem *tmrptr;

	tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
	__raw_writel(TXx9_TMTCR_CRE, &tmrptr->tcr);
	__raw_writel(0, &tmrptr->tisr);
	__raw_writel(0xffffffff, &tmrptr->cpra);
	__raw_writel(0, &tmrptr->itmr);
	__raw_writel(0, &tmrptr->ccdr);
	__raw_writel(0, &tmrptr->pgmr);
	iounmap(tmrptr);
}
+9 −8
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <asm/txx9tmr.h>
#include <linux/bootmem.h>
#include <linux/blkdev.h>
#ifdef CONFIG_TOSHIBA_FPCIB0
@@ -93,7 +94,6 @@

#define TOSHIBA_RBTX4927_SETUP_EFWFU       ( 1 <<  3 )
#define TOSHIBA_RBTX4927_SETUP_SETUP       ( 1 <<  4 )
#define TOSHIBA_RBTX4927_SETUP_TIME_INIT   ( 1 <<  5 )
#define TOSHIBA_RBTX4927_SETUP_PCIBIOS     ( 1 <<  7 )
#define TOSHIBA_RBTX4927_SETUP_PCI1        ( 1 <<  8 )
#define TOSHIBA_RBTX4927_SETUP_PCI2        ( 1 <<  9 )
@@ -130,7 +130,6 @@ extern void toshiba_rbtx4927_power_off(void);

int tx4927_using_backplane = 0;

extern void gt64120_time_init(void);
extern void toshiba_rbtx4927_irq_setup(void);

char *prom_getcmdline(void);
@@ -721,6 +720,7 @@ void toshiba_rbtx4927_power_off(void)

void __init toshiba_rbtx4927_setup(void)
{
	int i;
	u32 cp0_config;
	char *argptr;

@@ -764,6 +764,9 @@ void __init toshiba_rbtx4927_setup(void)
	_machine_halt = toshiba_rbtx4927_halt;
	pm_power_off = toshiba_rbtx4927_power_off;

	for (i = 0; i < TX4927_NR_TMR; i++)
		txx9_tmr_init(TX4927_TMR_REG(0) & 0xfffffffffULL);

#ifdef CONFIG_PCI

	/* PCIC */
@@ -892,7 +895,6 @@ void __init toshiba_rbtx4927_setup(void)
#ifdef CONFIG_SERIAL_TXX9
	{
		extern int early_serial_txx9_setup(struct uart_port *port);
		int i;
		struct uart_port req;
		for(i = 0; i < 2; i++) {
			memset(&req, 0, sizeof(req));
@@ -937,12 +939,11 @@ void __init toshiba_rbtx4927_setup(void)
void __init
toshiba_rbtx4927_time_init(void)
{
	TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT, "-\n");

	mips_hpt_frequency = tx4927_cpu_clock / 2;

	TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT, "+\n");

	if (tx4927_ccfgptr->ccfg & TX4927_CCFG_TINTDIS)
		txx9_clockevent_init(TX4927_TMR_REG(0) & 0xfffffffffULL,
				     TXX9_IRQ_BASE + 17,
				     50000000);
}

static int __init toshiba_rbtx4927_rtc_init(void)
Loading