1e8c7c482SRalf Baechle /* 278814465SManuel Lauss * Copyright (C) 2008-2009 Manuel Lauss <manuel.lauss@gmail.com> 3e8c7c482SRalf Baechle * 40c694de1SManuel Lauss * Previous incarnations were: 5e8c7c482SRalf Baechle * Copyright (C) 2001, 2006, 2008 MontaVista Software, <source@mvista.com> 6e8c7c482SRalf Baechle * Copied and modified Carsten Langgaard's time.c 7e8c7c482SRalf Baechle * 8e8c7c482SRalf Baechle * Carsten Langgaard, carstenl@mips.com 9e8c7c482SRalf Baechle * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. 10e8c7c482SRalf Baechle * 11e8c7c482SRalf Baechle * ######################################################################## 12e8c7c482SRalf Baechle * 13e8c7c482SRalf Baechle * This program is free software; you can distribute it and/or modify it 14e8c7c482SRalf Baechle * under the terms of the GNU General Public License (Version 2) as 15e8c7c482SRalf Baechle * published by the Free Software Foundation. 16e8c7c482SRalf Baechle * 17e8c7c482SRalf Baechle * This program is distributed in the hope it will be useful, but WITHOUT 18e8c7c482SRalf Baechle * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19e8c7c482SRalf Baechle * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20e8c7c482SRalf Baechle * for more details. 21e8c7c482SRalf Baechle * 22e8c7c482SRalf Baechle * You should have received a copy of the GNU General Public License along 23e8c7c482SRalf Baechle * with this program; if not, write to the Free Software Foundation, Inc., 24e8c7c482SRalf Baechle * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 25e8c7c482SRalf Baechle * 26e8c7c482SRalf Baechle * ######################################################################## 27e8c7c482SRalf Baechle * 280c694de1SManuel Lauss * Clocksource/event using the 32.768kHz-clocked Counter1 ('RTC' in the 290c694de1SManuel Lauss * databooks). Firmware/Board init code must enable the counters in the 300c694de1SManuel Lauss * counter control register, otherwise the CP0 counter clocksource/event 310c694de1SManuel Lauss * will be installed instead (and use of 'wait' instruction is prohibited). 32e8c7c482SRalf Baechle */ 33e8c7c482SRalf Baechle 340c694de1SManuel Lauss #include <linux/clockchips.h> 350c694de1SManuel Lauss #include <linux/clocksource.h> 360c694de1SManuel Lauss #include <linux/interrupt.h> 37e8c7c482SRalf Baechle #include <linux/spinlock.h> 38e8c7c482SRalf Baechle 39bdc92d74SRalf Baechle #include <asm/idle.h> 402882b0c6SManuel Lauss #include <asm/processor.h> 41e8c7c482SRalf Baechle #include <asm/time.h> 42e8c7c482SRalf Baechle #include <asm/mach-au1x00/au1000.h> 43e8c7c482SRalf Baechle 440c694de1SManuel Lauss /* 32kHz clock enabled and detected */ 450c694de1SManuel Lauss #define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S) 460c694de1SManuel Lauss 47ad058e95SManuel Lauss static cycle_t au1x_counter1_read(struct clocksource *cs) 480c694de1SManuel Lauss { 491d09de7dSManuel Lauss return alchemy_rdsys(AU1000_SYS_RTCREAD); 500c694de1SManuel Lauss } 510c694de1SManuel Lauss 520c694de1SManuel Lauss static struct clocksource au1x_counter1_clocksource = { 530c694de1SManuel Lauss .name = "alchemy-counter1", 540c694de1SManuel Lauss .read = au1x_counter1_read, 550c694de1SManuel Lauss .mask = CLOCKSOURCE_MASK(32), 560c694de1SManuel Lauss .flags = CLOCK_SOURCE_IS_CONTINUOUS, 578e0d7372SManuel Lauss .rating = 1500, 580c694de1SManuel Lauss }; 590c694de1SManuel Lauss 600c694de1SManuel Lauss static int au1x_rtcmatch2_set_next_event(unsigned long delta, 610c694de1SManuel Lauss struct clock_event_device *cd) 620c694de1SManuel Lauss { 631d09de7dSManuel Lauss delta += alchemy_rdsys(AU1000_SYS_RTCREAD); 640c694de1SManuel Lauss /* wait for register access */ 651d09de7dSManuel Lauss while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M21) 660c694de1SManuel Lauss ; 671d09de7dSManuel Lauss alchemy_wrsys(delta, AU1000_SYS_RTCMATCH2); 680c694de1SManuel Lauss 690c694de1SManuel Lauss return 0; 700c694de1SManuel Lauss } 710c694de1SManuel Lauss 720c694de1SManuel Lauss static void au1x_rtcmatch2_set_mode(enum clock_event_mode mode, 730c694de1SManuel Lauss struct clock_event_device *cd) 740c694de1SManuel Lauss { 750c694de1SManuel Lauss } 760c694de1SManuel Lauss 770c694de1SManuel Lauss static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id) 780c694de1SManuel Lauss { 790c694de1SManuel Lauss struct clock_event_device *cd = dev_id; 800c694de1SManuel Lauss cd->event_handler(cd); 810c694de1SManuel Lauss return IRQ_HANDLED; 820c694de1SManuel Lauss } 830c694de1SManuel Lauss 840c694de1SManuel Lauss static struct clock_event_device au1x_rtcmatch2_clockdev = { 850c694de1SManuel Lauss .name = "rtcmatch2", 860c694de1SManuel Lauss .features = CLOCK_EVT_FEAT_ONESHOT, 878e0d7372SManuel Lauss .rating = 1500, 880c694de1SManuel Lauss .set_next_event = au1x_rtcmatch2_set_next_event, 890c694de1SManuel Lauss .set_mode = au1x_rtcmatch2_set_mode, 9051c870a2SRusty Russell .cpumask = cpu_all_mask, 910c694de1SManuel Lauss }; 920c694de1SManuel Lauss 930c694de1SManuel Lauss static struct irqaction au1x_rtcmatch2_irqaction = { 940c694de1SManuel Lauss .handler = au1x_rtcmatch2_irq, 958b5690f8SYong Zhang .flags = IRQF_TIMER, 960c694de1SManuel Lauss .name = "timer", 970c694de1SManuel Lauss .dev_id = &au1x_rtcmatch2_clockdev, 980c694de1SManuel Lauss }; 990c694de1SManuel Lauss 10078814465SManuel Lauss static int __init alchemy_time_init(unsigned int m2int) 101e8c7c482SRalf Baechle { 1020c694de1SManuel Lauss struct clock_event_device *cd = &au1x_rtcmatch2_clockdev; 1030c694de1SManuel Lauss unsigned long t; 104e8c7c482SRalf Baechle 10578814465SManuel Lauss au1x_rtcmatch2_clockdev.irq = m2int; 10678814465SManuel Lauss 1070c694de1SManuel Lauss /* Check if firmware (YAMON, ...) has enabled 32kHz and clock 1080c694de1SManuel Lauss * has been detected. If so install the rtcmatch2 clocksource, 1090c694de1SManuel Lauss * otherwise don't bother. Note that both bits being set is by 1100c694de1SManuel Lauss * no means a definite guarantee that the counters actually work 1110c694de1SManuel Lauss * (the 32S bit seems to be stuck set to 1 once a single clock- 1120c694de1SManuel Lauss * edge is detected, hence the timeouts). 113e8c7c482SRalf Baechle */ 1141d09de7dSManuel Lauss if (CNTR_OK != (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & CNTR_OK)) 1150c694de1SManuel Lauss goto cntr_err; 116e8c7c482SRalf Baechle 1170c694de1SManuel Lauss /* 1180c694de1SManuel Lauss * setup counter 1 (RTC) to tick at full speed 1190c694de1SManuel Lauss */ 1200c694de1SManuel Lauss t = 0xffffff; 1211d09de7dSManuel Lauss while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_T1S) && --t) 1220c694de1SManuel Lauss asm volatile ("nop"); 1230c694de1SManuel Lauss if (!t) 1240c694de1SManuel Lauss goto cntr_err; 1250c694de1SManuel Lauss 1261d09de7dSManuel Lauss alchemy_wrsys(0, AU1000_SYS_RTCTRIM); /* 32.768 kHz */ 127e8c7c482SRalf Baechle 1280c694de1SManuel Lauss t = 0xffffff; 1291d09de7dSManuel Lauss while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C1S) && --t) 1300c694de1SManuel Lauss asm volatile ("nop"); 1310c694de1SManuel Lauss if (!t) 1320c694de1SManuel Lauss goto cntr_err; 1331d09de7dSManuel Lauss alchemy_wrsys(0, AU1000_SYS_RTCWRITE); 134e8c7c482SRalf Baechle 1350c694de1SManuel Lauss t = 0xffffff; 1361d09de7dSManuel Lauss while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C1S) && --t) 1370c694de1SManuel Lauss asm volatile ("nop"); 1380c694de1SManuel Lauss if (!t) 1390c694de1SManuel Lauss goto cntr_err; 1400c694de1SManuel Lauss 1410c694de1SManuel Lauss /* register counter1 clocksource and event device */ 14275c4fd8cSJohn Stultz clocksource_register_hz(&au1x_counter1_clocksource, 32768); 1430c694de1SManuel Lauss 1440c694de1SManuel Lauss cd->shift = 32; 1450c694de1SManuel Lauss cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift); 1460c694de1SManuel Lauss cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd); 1478e365790SManuel Lauss cd->min_delta_ns = clockevent_delta2ns(9, cd); /* ~0.28ms */ 1480c694de1SManuel Lauss clockevents_register_device(cd); 14978814465SManuel Lauss setup_irq(m2int, &au1x_rtcmatch2_irqaction); 1500c694de1SManuel Lauss 1510c694de1SManuel Lauss printk(KERN_INFO "Alchemy clocksource installed\n"); 1520c694de1SManuel Lauss 15378814465SManuel Lauss return 0; 154e8c7c482SRalf Baechle 1550c694de1SManuel Lauss cntr_err: 15678814465SManuel Lauss return -1; 15778814465SManuel Lauss } 15878814465SManuel Lauss 15978814465SManuel Lauss static int alchemy_m2inttab[] __initdata = { 16078814465SManuel Lauss AU1000_RTC_MATCH2_INT, 16178814465SManuel Lauss AU1500_RTC_MATCH2_INT, 16278814465SManuel Lauss AU1100_RTC_MATCH2_INT, 16378814465SManuel Lauss AU1550_RTC_MATCH2_INT, 16478814465SManuel Lauss AU1200_RTC_MATCH2_INT, 165809f36c6SManuel Lauss AU1300_RTC_MATCH2_INT, 16678814465SManuel Lauss }; 16778814465SManuel Lauss 16878814465SManuel Lauss void __init plat_time_init(void) 16978814465SManuel Lauss { 17078814465SManuel Lauss int t; 17178814465SManuel Lauss 17278814465SManuel Lauss t = alchemy_get_cputype(); 1738e0d7372SManuel Lauss if (t == ALCHEMY_CPU_UNKNOWN || 1748e0d7372SManuel Lauss alchemy_time_init(alchemy_m2inttab[t])) 1758e0d7372SManuel Lauss cpu_wait = NULL; /* wait doesn't work with r4k timer */ 17678814465SManuel Lauss } 177