Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[MIPS] time: Add GT641xx timer0 clockevent driver

And make use of it for Cobalt. A few others such as the Malta could make
use of it as well.

Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Yoichi Yuasa and committed by
Ralf Baechle
1097c6ac d0453365

+193 -22
+4
arch/mips/Kconfig
··· 66 66 config MIPS_COBALT 67 67 bool "Cobalt Server" 68 68 select CEVT_R4K 69 + select CEVT_GT641XX 69 70 select DMA_NONCOHERENT 70 71 select HW_HAS_PCI 71 72 select I8253 ··· 728 727 bool 729 728 730 729 config BOOT_RAW 730 + bool 731 + 732 + config CEVT_GT641XX 731 733 bool 732 734 733 735 config CEVT_R4K
+1 -1
arch/mips/cobalt/Makefile
··· 2 2 # Makefile for the Cobalt micro systems family specific parts of the kernel 3 3 # 4 4 5 - obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o 5 + obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o time.o 6 6 7 7 obj-$(CONFIG_PCI) += pci.o 8 8 obj-$(CONFIG_EARLY_PRINTK) += console.o
+3 -21
arch/mips/cobalt/setup.c
··· 9 9 * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) 10 10 * 11 11 */ 12 - #include <linux/interrupt.h> 13 12 #include <linux/init.h> 13 + #include <linux/interrupt.h> 14 + #include <linux/io.h> 15 + #include <linux/ioport.h> 14 16 #include <linux/pm.h> 15 17 16 18 #include <asm/bootinfo.h> 17 - #include <asm/time.h> 18 - #include <asm/i8253.h> 19 - #include <asm/io.h> 20 19 #include <asm/reboot.h> 21 20 #include <asm/gt64120.h> 22 21 23 22 #include <cobalt.h> 24 - #include <irq.h> 25 23 26 24 extern void cobalt_machine_restart(char *command); 27 25 extern void cobalt_machine_halt(void); ··· 37 39 return "Cobalt RaQ2"; 38 40 } 39 41 return "MIPS Cobalt"; 40 - } 41 - 42 - void __init plat_timer_setup(struct irqaction *irq) 43 - { 44 - /* Load timer value for HZ (TCLK is 50MHz) */ 45 - GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ); 46 - 47 - /* Enable timer0 */ 48 - GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); 49 - 50 - setup_irq(GT641XX_TIMER0_IRQ, irq); 51 42 } 52 43 53 44 /* ··· 70 83 .flags = IORESOURCE_BUSY | IORESOURCE_IO, 71 84 }, 72 85 }; 73 - 74 - void __init plat_time_init(void) 75 - { 76 - setup_pit_timer(); 77 - } 78 86 79 87 void __init plat_mem_setup(void) 80 88 {
+35
arch/mips/cobalt/time.c
··· 1 + /* 2 + * Cobalt time initialization. 3 + * 4 + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 + */ 20 + #include <linux/init.h> 21 + 22 + #include <asm/gt64120.h> 23 + #include <asm/i8253.h> 24 + #include <asm/time.h> 25 + 26 + #define GT641XX_BASE_CLOCK 50000000 /* 50MHz */ 27 + 28 + void __init plat_time_init(void) 29 + { 30 + setup_pit_timer(); 31 + 32 + gt641xx_set_base_clock(GT641XX_BASE_CLOCK); 33 + 34 + mips_timer_state = gt641xx_timer0_state; 35 + }
+1
arch/mips/kernel/Makefile
··· 9 9 time.o topology.o traps.o unaligned.o 10 10 11 11 obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o 12 + obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o 12 13 13 14 binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ 14 15 irix5sys.o sysirix.o
+144
arch/mips/kernel/cevt-gt641xx.c
··· 1 + /* 2 + * GT641xx clockevent routines. 3 + * 4 + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 + */ 20 + #include <linux/clockchips.h> 21 + #include <linux/init.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/spinlock.h> 24 + 25 + #include <asm/gt64120.h> 26 + #include <asm/time.h> 27 + 28 + #include <irq.h> 29 + 30 + static DEFINE_SPINLOCK(gt641xx_timer_lock); 31 + static unsigned int gt641xx_base_clock; 32 + 33 + void gt641xx_set_base_clock(unsigned int clock) 34 + { 35 + gt641xx_base_clock = clock; 36 + } 37 + 38 + int gt641xx_timer0_state(void) 39 + { 40 + if (GT_READ(GT_TC0_OFS)) 41 + return 0; 42 + 43 + GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ); 44 + GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK); 45 + 46 + return 1; 47 + } 48 + 49 + static int gt641xx_timer0_set_next_event(unsigned long delta, 50 + struct clock_event_device *evt) 51 + { 52 + unsigned long flags; 53 + u32 ctrl; 54 + 55 + spin_lock_irqsave(&gt641xx_timer_lock, flags); 56 + 57 + ctrl = GT_READ(GT_TC_CONTROL_OFS); 58 + ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); 59 + ctrl |= GT_TC_CONTROL_ENTC0_MSK; 60 + 61 + GT_WRITE(GT_TC0_OFS, delta); 62 + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); 63 + 64 + spin_unlock_irqrestore(&gt641xx_timer_lock, flags); 65 + 66 + return 0; 67 + } 68 + 69 + static void gt641xx_timer0_set_mode(enum clock_event_mode mode, 70 + struct clock_event_device *evt) 71 + { 72 + unsigned long flags; 73 + u32 ctrl; 74 + 75 + spin_lock_irqsave(&gt641xx_timer_lock, flags); 76 + 77 + ctrl = GT_READ(GT_TC_CONTROL_OFS); 78 + ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); 79 + 80 + switch (mode) { 81 + case CLOCK_EVT_MODE_PERIODIC: 82 + ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; 83 + break; 84 + case CLOCK_EVT_MODE_ONESHOT: 85 + ctrl |= GT_TC_CONTROL_ENTC0_MSK; 86 + break; 87 + default: 88 + break; 89 + } 90 + 91 + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); 92 + 93 + spin_unlock_irqrestore(&gt641xx_timer_lock, flags); 94 + } 95 + 96 + static void gt641xx_timer0_event_handler(struct clock_event_device *dev) 97 + { 98 + } 99 + 100 + static struct clock_event_device gt641xx_timer0_clockevent = { 101 + .name = "gt641xx-timer0", 102 + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 103 + .cpumask = CPU_MASK_CPU0, 104 + .irq = GT641XX_TIMER0_IRQ, 105 + .set_next_event = gt641xx_timer0_set_next_event, 106 + .set_mode = gt641xx_timer0_set_mode, 107 + .event_handler = gt641xx_timer0_event_handler, 108 + }; 109 + 110 + static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) 111 + { 112 + struct clock_event_device *cd = &gt641xx_timer0_clockevent; 113 + 114 + cd->event_handler(cd); 115 + 116 + return IRQ_HANDLED; 117 + } 118 + 119 + static struct irqaction gt641xx_timer0_irqaction = { 120 + .handler = gt641xx_timer0_interrupt, 121 + .flags = IRQF_DISABLED | IRQF_PERCPU, 122 + .name = "gt641xx_timer0", 123 + }; 124 + 125 + static int __init gt641xx_timer0_clockevent_init(void) 126 + { 127 + struct clock_event_device *cd; 128 + 129 + if (!gt641xx_base_clock) 130 + return 0; 131 + 132 + GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ); 133 + 134 + cd = &gt641xx_timer0_clockevent; 135 + cd->rating = 200 + gt641xx_base_clock / 10000000; 136 + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); 137 + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); 138 + clockevent_set_clock(cd, gt641xx_base_clock); 139 + 140 + clockevents_register_device(&gt641xx_timer0_clockevent); 141 + 142 + return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction); 143 + } 144 + arch_initcall(gt641xx_timer0_clockevent_init);
+5
include/asm-mips/gt64120.h
··· 21 21 #ifndef _ASM_GT64120_H 22 22 #define _ASM_GT64120_H 23 23 24 + #include <linux/clocksource.h> 25 + 24 26 #include <asm/addrspace.h> 25 27 #include <asm/byteorder.h> 26 28 ··· 573 571 do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) 574 572 #define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs)) 575 573 #define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data)) 574 + 575 + extern void gt641xx_set_base_clock(unsigned int clock); 576 + extern int gt641xx_timer0_state(void); 576 577 577 578 #endif /* _ASM_GT64120_H */