2016-11-25 17:18:40 +01:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 8254 Programmable Interval Timer and compatibles.
|
|
|
|
*/
|
|
|
|
enum { /* I/O ports */
|
|
|
|
Timer1 = 0x40,
|
|
|
|
Timer2 = 0x48, /* Counter0 is watchdog (EISA) */
|
|
|
|
|
|
|
|
Counter0 = 0, /* Counter 0 Access Port */
|
|
|
|
Counter1 = 1, /* Counter 1 Access Port */
|
|
|
|
Counter2 = 2, /* Counter 2 Access Port */
|
|
|
|
Control = 3, /* Timer Control Word */
|
|
|
|
};
|
|
|
|
|
|
|
|
enum { /* Control */
|
|
|
|
Bcd = 0x01, /* Binary/BCD countdown select */
|
|
|
|
|
|
|
|
Mode0 = 0x00, /* [3:1] interrupt on terminal count */
|
|
|
|
Mode1 = 0x02, /* hardware re-triggerable one-shot */
|
|
|
|
Mode2 = 0x04, /* rate generator */
|
|
|
|
Mode3 = 0x06, /* square-wave generator */
|
|
|
|
Mode4 = 0x08, /* sofware triggered strobe */
|
|
|
|
Mode5 = 0x0A, /* hardware triggered strobe */
|
|
|
|
|
|
|
|
Clc = 0x00, /* [5:4] Counter Latch Command */
|
|
|
|
RWlsb = 0x10, /* R/W LSB */
|
|
|
|
RWmsb = 0x20, /* R/W MSB */
|
|
|
|
RW16 = 0x30, /* R/W LSB then MSB */
|
|
|
|
Cs0 = 0x00, /* [7:6] Counter 0 Select */
|
|
|
|
Cs1 = 0x40, /* Counter 1 Select */
|
|
|
|
Cs2 = 0x80, /* Counter 2 Select */
|
|
|
|
|
|
|
|
Rbc = 0xC0, /* Read-Back Command */
|
|
|
|
RbCnt0 = 0x02, /* Select Counter 0 */
|
|
|
|
RbCnt1 = 0x04, /* Select Counter 1 */
|
|
|
|
RbCnt2 = 0x08, /* Select Counter 2 */
|
|
|
|
RbS = 0x20, /* Read-Back Status */
|
|
|
|
RbC = 0x10, /* Read-Back Count */
|
|
|
|
RbCS = 0x00, /* Read-Back Count and Status */
|
|
|
|
|
|
|
|
RbNULL = 0x40, /* NULL-Count Flag */
|
|
|
|
RbOUT = 0x80, /* OUT-pin */
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
Osc = 1193182, /* 14.318180MHz/12 */
|
|
|
|
Hz = 82, /* 2*41*14551 = 1193182 */
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
i8254set(int port, int hz)
|
|
|
|
{
|
|
|
|
int counter, timeo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialise Counter0 to be the system clock if necessary,
|
|
|
|
* it's normally connected to IRQ0 on an interrupt controller.
|
|
|
|
* Use a periodic square wave (Mode3).
|
|
|
|
*/
|
|
|
|
counter = Osc/hz;
|
|
|
|
outb(port+Control, Cs0|RW16|Mode3);
|
|
|
|
outb(port+Counter0, counter);
|
|
|
|
outb(port+Counter0, counter>>8);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait until the counting register has been loaded
|
|
|
|
* into the counting element.
|
|
|
|
*/
|
|
|
|
for(timeo = 0; timeo < 100000; timeo++){
|
|
|
|
outb(port+Control, Rbc|RbS|RbCnt0);
|
|
|
|
if(!(inb(port+Counter0) & RbNULL))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t
|
|
|
|
i8254hz(uint32_t info[2][4])
|
|
|
|
{
|
|
|
|
uint32_t ax;
|
|
|
|
uint64_t a, b;
|
|
|
|
int aamcycles, incr, loops, x, y;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the cpuid family info to get the
|
|
|
|
* cycles for the AAM instruction.
|
|
|
|
*/
|
|
|
|
ax = info[1][0] & 0x00000f00;
|
2017-04-19 23:33:14 +02:00
|
|
|
if(jehanne_memcmp(&info[0][1], "GenuntelineI", 12) == 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
switch(ax){
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
case 0x00000600:
|
|
|
|
case 0x00000f00:
|
|
|
|
aamcycles = 16;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-04-19 23:33:14 +02:00
|
|
|
else if(jehanne_memcmp(&info[0][1], "AuthcAMDenti", 12) == 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
switch(ax){
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
case 0x00000600:
|
|
|
|
case 0x00000f00:
|
|
|
|
aamcycles = 11;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-04-19 23:33:14 +02:00
|
|
|
else if(jehanne_memcmp(&info[0][1], "CentaulsaurH", 12) == 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
switch(ax){
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
case 0x00000600:
|
|
|
|
aamcycles = 23;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
i8254set(Timer1, Hz);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find biggest loop that doesn't wrap.
|
|
|
|
*/
|
|
|
|
SET(a, b);
|
|
|
|
incr = 16000000/(aamcycles*Hz*2);
|
|
|
|
x = 2000;
|
|
|
|
for(loops = incr; loops < 64*1024; loops += incr) {
|
|
|
|
/*
|
|
|
|
* Measure time for the loop
|
|
|
|
*
|
|
|
|
* MOVL loops,CX
|
|
|
|
* aaml1:
|
|
|
|
* AAM
|
|
|
|
* LOOP aaml1
|
|
|
|
*
|
|
|
|
* The time for the loop should be independent of external
|
|
|
|
* cache and memory system since it fits in the execution
|
|
|
|
* prefetch buffer.
|
|
|
|
* The AAM instruction is not available in 64-bit mode.
|
|
|
|
*/
|
|
|
|
outb(Timer1+Control, Cs0|Clc);
|
|
|
|
|
|
|
|
a = rdtsc();
|
|
|
|
x = inb(Timer1+Counter0);
|
|
|
|
x |= inb(Timer1+Counter0)<<8;
|
|
|
|
aamloop(loops);
|
|
|
|
outb(Timer1+Control, Cs0|Clc);
|
|
|
|
b = rdtsc();
|
|
|
|
|
|
|
|
y = inb(Timer1+Counter0);
|
|
|
|
y |= inb(Timer1+Counter0)<<8;
|
|
|
|
x -= y;
|
|
|
|
|
|
|
|
if(x < 0)
|
|
|
|
x += Osc/Hz;
|
|
|
|
|
|
|
|
if(x > Osc/(3*Hz))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out clock frequency.
|
|
|
|
*/
|
|
|
|
b = (b-a)<<1;
|
|
|
|
b *= Osc;
|
|
|
|
|
|
|
|
return b/x;
|
|
|
|
}
|