15b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* A couple of routines to implement a low-overhead timer for drivers */ 25b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 35b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 45b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * This program is free software; you can redistribute it and/or 55b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * modify it under the terms of the GNU General Public License as 65b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * published by the Free Software Foundation; either version 2, or (at 75b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * your option) any later version. 85b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 95b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "etherboot.h" 115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "timer.h" 125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectvoid load_timer2(unsigned int ticks) 145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Set up the timer gate, turn off the speaker */ 165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); 175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); 185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(ticks & 0xFF, TIMER2_PORT); 195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(ticks >> 8, TIMER2_PORT); 205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#if defined(CONFIG_TSC_CURRTICKS) 235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define rdtsc(low,high) \ 245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) 255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define rdtscll(val) \ 275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project __asm__ __volatile__ ("rdtsc" : "=A" (val)) 285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define HZ TICKS_PER_SEC 315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */ 325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* LATCH is used in the interval timer and ftape setup. */ 335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ 345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* ------ Calibrate the TSC ------- 375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). 385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Too much 64-bit arithmetic here to do this cleanly in C, and for 395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) 405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * output busy loop as low as possible. We avoid reading the CTC registers 415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * directly because of the awkward 8-bit access mechanism of the 82C54 425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * device. 435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define CALIBRATE_LATCH (5 * LATCH) 465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic unsigned long long calibrate_tsc(void) 485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Set the Gate high, disable speaker */ 505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb((inb(0x61) & ~0x02) | 0x01, 0x61); 515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Now let's take care of CTC channel 2 545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Set the Gate high, program CTC channel 2 for mode 0, 565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * (interrupt on terminal count mode), binary count, 575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * load 5 * LATCH count, (LSB and MSB) to begin countdown. 585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ 605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ 615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ 625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project { 645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long startlow, starthigh; 655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long endlow, endhigh; 665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long count; 675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rdtsc(startlow,starthigh); 695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project count = 0; 705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project do { 715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project count++; 725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } while ((inb(0x61) & 0x20) == 0); 735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rdtsc(endlow,endhigh); 745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Error: ECTCNEVERSET */ 765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (count <= 1) 775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project goto bad_ctc; 785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 64-bit subtract - gcc just messes up with long longs */ 805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project __asm__("subl %2,%0\n\t" 815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project "sbbl %3,%1" 825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project :"=a" (endlow), "=d" (endhigh) 835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project :"g" (startlow), "g" (starthigh), 845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project "0" (endlow), "1" (endhigh)); 855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Error: ECPUTOOFAST */ 875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (endhigh) 885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project goto bad_ctc; 895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project endlow /= 5; 915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return endlow; 925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * The CTC wasn't reliable: we got a hit on the very first read, 965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * or the CPU was so fast/slow that the quotient wouldn't fit in 975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 32 bits.. 985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectbad_ctc: 1005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("bad_ctc\n"); 1015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 1025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 1035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectunsigned long currticks(void) 1065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 1075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project static unsigned long clocks_per_tick; 1085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long clocks_high, clocks_low; 1095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long currticks; 1105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (!clocks_per_tick) { 1115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project clocks_per_tick = calibrate_tsc(); 1125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("clocks_per_tick = %d\n", clocks_per_tick); 1135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 1145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Read the Time Stamp Counter */ 1165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project rdtsc(clocks_low, clocks_high); 1175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* currticks = clocks / clocks_per_tick; */ 1195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project __asm__("divl %1" 1205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project :"=a" (currticks) 1215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project :"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high)); 1225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return currticks; 1255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 1265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif /* RTC_CURRTICKS */ 128