?? time.patch
字號:
- update_process_times(user_mode(regs));-#endif- time_elapsed -= MATCH20_INC;- last_match20 += MATCH20_INC;- jiffie_drift++;- }-- last_pc0 = pc0;- au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);- au_sync();-- /* our counter ticks at 10.009765625 ms/tick, we we're running- * almost 10uS too slow per tick.- */-- if (jiffie_drift >= 999) {- jiffie_drift -= 999;- do_timer(regs); /* increment jiffies by one */-#ifndef CONFIG_SMP- update_process_times(user_mode(regs));-#endif- }+ /* translate the offset to microseconds by multiplying with 30.5175...+ which is identical to 15625/512 */+ offset = (unsigned long)(((u64)offset * (u64)15625) >> 9);+ return offset; }+#endif /* CONFIG_SOC_AU1X00_32KHZ_TIMER */ -/* When we wakeup from sleep, we have to "catch up" on all of the- * timer ticks we have missed.- */-void-wakeup_counter0_adjust(void)+#ifdef CONFIG_SOC_AU1X00_32KHZ+static unsigned long rtc_au1xxx_get_time(void) {- unsigned long pc0;- int time_elapsed;+ /* The TOY counter simply contains the number of seconds elapsed.+ This is interpreted from the kernel viewpoint as the number of+ seconds elapsed starting in 1970. */+ return au_readl(SYS_TOYREAD);+ } - pc0 = au_readl(SYS_TOYREAD);- if (pc0 < last_match20) {- /* counter overflowed */- time_elapsed = (0xffffffff - last_match20) + pc0;+static int rtc_au1xxx_set_time(unsigned long t)+{+ /* Take the kernel's value and record it in the counter. There is+ no need to spin on TS since this register is written infrequently. */+ au_writel(t, SYS_TOYWRITE);+ return 0; }- else {- time_elapsed = pc0 - last_match20;++static unsigned long rtc_au1xxx_get_toym2(void)+{+ return au_readl(SYS_TOYMATCH2); } - while (time_elapsed > 0) {- time_elapsed -= MATCH20_INC;- last_match20 += MATCH20_INC;+static int rtc_au1xxx_set_toym2(unsigned long t)+{+ au_writel(t, SYS_TOYMATCH2);+ return 0; } - last_pc0 = pc0;- au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);- au_sync();+/********************************************************************+The following is the /dev/rtc driver that utilizes the TOY.+This code a blatant pilfer of ds1742.c */++#define AU1XXX_RTC_VERSION "1.0"+#define RTC_IS_OPEN 0x1++static unsigned long rtc_status = 0;+static spinlock_t rtc_lock; +extern void to_tm(unsigned long tim, struct rtc_time * tm);++static int rtc_au1xxx_ioctl(struct inode *inode, struct file *file,+ unsigned int cmd, unsigned long arg)+{+ struct rtc_time rtc_tm;+ ulong curr_time;++ switch (cmd) {+ case RTC_RD_TIME: /* Read the time/date from TOY */+ curr_time = rtc_au1xxx_get_time();+ memset(&rtc_tm, 0, sizeof(struct rtc_time));+ to_tm(curr_time, &rtc_tm);+ rtc_tm.tm_year -= 1900;+ return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ?+ -EFAULT : 0;+ break;++ case RTC_SET_TIME:+ if (!capable(CAP_SYS_TIME))+ return -EACCES;++ if (copy_from_user(&rtc_tm,+ (struct rtc_time *) arg,+ sizeof(struct rtc_time)))+ return -EFAULT;++ curr_time = mktime(rtc_tm.tm_year + 1900,+ rtc_tm.tm_mon + 1, /* tm_mon starts from 0 */+ rtc_tm.tm_mday,+ rtc_tm.tm_hour,+ rtc_tm.tm_min,+ rtc_tm.tm_sec);+ return rtc_au1xxx_set_time(curr_time);+ break;++ case RTC_WKALM_RD: /* Read the wakeup alarm time/date from TOY M2 */+ curr_time = rtc_au1xxx_get_toym2();+ memset(&rtc_tm, 0, sizeof(struct rtc_time));+ to_tm(curr_time, &rtc_tm);+ rtc_tm.tm_year -= 1900;+ return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ?+ -EFAULT : 0;+ break;++ case RTC_WKALM_SET:+ if (!capable(CAP_SYS_TIME))+ return -EACCES;++ if (copy_from_user(&rtc_tm,+ (struct rtc_time *) arg,+ sizeof(struct rtc_time)))+ return -EFAULT;++ curr_time = mktime(rtc_tm.tm_year + 1900,+ rtc_tm.tm_mon + 1, /* tm_mon starts from 0 */+ rtc_tm.tm_mday,+ rtc_tm.tm_hour,+ rtc_tm.tm_min,+ rtc_tm.tm_sec);+ return rtc_au1xxx_set_toym2(curr_time);+ break;++ default:+ return -EINVAL;+ } } -/* This is just for debugging to set the timer for a sleep delay.-*/-void-wakeup_counter0_set(int ticks)+static int rtc_au1xxx_open(struct inode *inode, struct file *file) {- unsigned long pc0;+ int err = 0;++ spin_lock_irq(&rtc_lock); - pc0 = au_readl(SYS_TOYREAD);- last_pc0 = pc0;- au_writel(last_match20 + (MATCH20_INC * ticks), SYS_TOYMATCH2);- au_sync();+ if (rtc_status & RTC_IS_OPEN)+ err = -EBUSY;+ else {+ /* If oscillator isn't running, then don't open() */+ if (!(au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_32S))+ err = -EIO;+ else+ rtc_status |= RTC_IS_OPEN; }-#endif -/* I haven't found anyone that doesn't use a 12 MHz source clock,- * but just in case.....- */-#ifdef CONFIG_AU1000_SRC_CLK-#define AU1000_SRC_CLK CONFIG_AU1000_SRC_CLK-#else-#define AU1000_SRC_CLK 12000000-#endif+ spin_unlock_irq(&rtc_lock); -/*- * 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)+ return err;+}++static int rtc_au1xxx_release(struct inode *inode, struct file *file) {- unsigned long count;- unsigned long cpu_speed;- unsigned long flags;- unsigned long counter;+ spin_lock_irq(&rtc_lock);+ rtc_status &= ~RTC_IS_OPEN;+ spin_unlock_irq(&rtc_lock);+ return 0;+} - spin_lock_irqsave(&time_lock, flags);+static struct file_operations rtc_au1xxx_fops = {+ owner:THIS_MODULE,+ llseek:no_llseek,+ ioctl:rtc_au1xxx_ioctl,+ open:rtc_au1xxx_open,+ release:rtc_au1xxx_release,+};++static struct miscdevice rtc_au1xxx_dev = {+ RTC_MINOR,+ "rtc",+ &rtc_au1xxx_fops+};+++static int __init rtc_au1xxx_init(void)+{+ printk(KERN_INFO "Au1XXX Real Time Clock Driver v%s\n", AU1XXX_RTC_VERSION);+ misc_register(&rtc_au1xxx_dev);+ return 0;+}++static void __exit rtc_au1xxx_exit(void)+{+ misc_deregister(&rtc_au1xxx_dev);+} - /* 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);+module_init(rtc_au1xxx_init);+module_exit(rtc_au1xxx_exit); -#if defined(CONFIG_AU1000_USE32K)+/*******************************************************************/++static int au1xxx_32khz_startup(void) {- unsigned long start, end;+ /* Setup the 32kHz oscillator for operation per scheme described above */ - 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;+ if (!(au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_32S)) {+ int timeout = 500000;+ /* Start the 32khz oscillator - NOTE: usually best to do this+ in the board boot up code to give the oscillator plenty of+ time to startup prior to this code */+ au_writel(SYS_CNTRCTRL_E0, SYS_COUNTER_CNTRL);+ /* Wait for it to start...can hang here if there is+ a problem with the 32khz oscillator!!! */+ while (--timeout > 0)+ if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_32S)+ break; /* oscillator started */+ }++ /* 32khz oscillator present and running */+ if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_32S) {+ /* Configure RTC counter */+ /* Set trim to 0 for max clock resolution */+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RTS);+ au_writel(0, SYS_RTCTRIM);+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RTS);++ /* start RTC counter at zero */+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RS);+ au_writel(0, SYS_RTCWRITE);+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RS);++ /* Configure the TOY counter */+ /* Set trim for 1 second clock resolution */+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_TTS);+ au_writel(CONFIG_AU1000_32KHZ_CLK - 1, SYS_TOYTRIM);+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_TTS); - while (end > au_readl(SYS_RTCREAD));+ /* the TOY counter is not written since it contains date/time */ - count = read_c0_count();- cpu_speed = count * 2;+ return 1; }+ return 0;+ }++#else++static void setup_cp0_interrupt(void)+{+ /* Setup CP0 Count/Compare interrupt */+ r4k_cur = (read_c0_count() + r4k_offset);+ write_c0_compare(r4k_cur);+}++#endif /* CONFIG_SOC_AU1X00_32KHZ */++void wakeup_kernel_timer(void)+{+#ifdef CONFIG_SOC_AU1X00_32KHZ_TIMER+ au1xxx_32khz_startup();+ setup_rtcm1_interrupt(); #else- cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * - AU1000_SRC_CLK;- count = cpu_speed / 2;+ setup_cp0_interrupt(); #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;- count = cpu_speed / 2;- no_au1xxx_32khz = 1;- }- mips_hpt_frequency = count;- // 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); } -/* This is for machines which generate the exact clock. */-#define USECS_PER_JIFFY (1000000/HZ)-#define USECS_PER_JIFFY_FRAC (0x100000000LL*1000000/HZ&0xffffffff)+/* This is to set the timer upon resuming from sleep */+void wakeup_toym2_set(int ticks)+{+#ifdef CONFIG_SOC_AU1X00_32KHZ+ /* sets timeout from sleep mode */+ u32 pc0 = au_readl(SYS_TOYREAD);+ au_writel(pc0 + ticks, SYS_TOYMATCH2);+#endif+} -static unsigned long-div64_32(unsigned long v1, unsigned long v2, unsigned long v3)+static inline void ack_r4ktimer(unsigned long newval) {- unsigned long r0;- do_div64_32(r0, v1, v2, v3);- return r0;+ write_c0_compare(newval); } -static unsigned long do_fast_cp0_gettimeoffset(void)+unsigned long wtimer;+void mips_timer_interrupt(struct pt_regs *regs) {- u32 count;- unsigned long res, tmp;- unsigned long r0;+ int irq = 63;+ unsigned long count; - /* Last jiffy when do_fast_gettimeoffset() was called. */- static unsigned long last_jiffies=0;- unsigned long quotient;+ extern void do_softirq(void); - /*- * Cached "1/(clocks per usec)*2^32" value.- * It has to be recalculated once each jiffy.- */- static unsigned long cached_quotient=0;+ irq_enter(); - tmp = jiffies;+ kstat_this_cpu.irqs[irq]++;+#ifndef CONFIG_SMP+ update_process_times(user_mode(regs));+#endif - quotient = cached_quotient;+ if (r4k_offset == 0)+ goto null; - if (tmp && last_jiffies != tmp) {- last_jiffies = tmp;- if (last_jiffies != 0) {- r0 = div64_32(timerhi, timerlo, tmp);- quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0);- cached_quotient = quotient;- }- }+ do {+ count = read_c0_count();+ timerhi += (count < timerlo); /* Wrap around */+ timerlo = count; - /* Get last timer tick in absolute kernel time */- count = read_c0_count();+ do_timer(regs);+ r4k_cur += r4k_offset;+ ack_r4ktimer(r4k_cur); - /* .. relative to previous jiffy (32 bits is enough) */- count -= timerlo;+ } while (((unsigned long)read_c0_count()+ - r4k_cur) < 0x7fffffff); - __asm__("multu\t%1,%2\n\t"- "mfhi\t%0"- : "=r" (res)- : "r" (count), "r" (quotient)- : "hi", "lo", GCC_REG_ACCUM);-- /*- * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic.- */- if (res >= USECS_PER_JIFFY)- res = USECS_PER_JIFFY-1;-- return res;-}--#ifdef CONFIG_PM-static unsigned long do_fast_pm_gettimeoffset(void)-{- unsigned long pc0;- unsigned long offset;-- pc0 = au_readl(SYS_TOYREAD);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -