• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * arch/i386/core/i386_timer.c
3  *
4  * Use the "System Timer 2" to implement the udelay callback in
5  * the BIOS timer driver. Also used to calibrate the clock rate
6  * in the RTDSC timer driver.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2, or (at
11  * your option) any later version.
12  */
13 
14 FILE_LICENCE ( GPL2_OR_LATER );
15 
16 #include <stddef.h>
17 #include <gpxe/timer2.h>
18 #include <gpxe/io.h>
19 
20 /* Timers tick over at this rate */
21 #define TIMER2_TICKS_PER_SEC	1193180U
22 
23 /* Parallel Peripheral Controller Port B */
24 #define	PPC_PORTB	0x61
25 
26 /* Meaning of the port bits */
27 #define	PPCB_T2OUT	0x20	/* Bit 5 */
28 #define	PPCB_SPKR	0x02	/* Bit 1 */
29 #define	PPCB_T2GATE	0x01	/* Bit 0 */
30 
31 /* Ports for the 8254 timer chip */
32 #define	TIMER2_PORT	0x42
33 #define	TIMER_MODE_PORT	0x43
34 
35 /* Meaning of the mode bits */
36 #define	TIMER0_SEL	0x00
37 #define	TIMER1_SEL	0x40
38 #define	TIMER2_SEL	0x80
39 #define	READBACK_SEL	0xC0
40 
41 #define	LATCH_COUNT	0x00
42 #define	LOBYTE_ACCESS	0x10
43 #define	HIBYTE_ACCESS	0x20
44 #define	WORD_ACCESS	0x30
45 
46 #define	MODE0		0x00
47 #define	MODE1		0x02
48 #define	MODE2		0x04
49 #define	MODE3		0x06
50 #define	MODE4		0x08
51 #define	MODE5		0x0A
52 
53 #define	BINARY_COUNT	0x00
54 #define	BCD_COUNT	0x01
55 
load_timer2(unsigned int ticks)56 static void load_timer2 ( unsigned int ticks ) {
57 	/*
58 	 * Now let's take care of PPC channel 2
59 	 *
60 	 * Set the Gate high, program PPC channel 2 for mode 0,
61 	 * (interrupt on terminal count mode), binary count,
62 	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
63 	 *
64 	 * Note some implementations have a bug where the high bits byte
65 	 * of channel 2 is ignored.
66 	 */
67 	/* Set up the timer gate, turn off the speaker */
68 	/* Set the Gate high, disable speaker */
69 	outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
70 	/* binary, mode 0, LSB/MSB, Ch 2 */
71 	outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
72 	/* LSB of ticks */
73 	outb(ticks & 0xFF, TIMER2_PORT);
74 	/* MSB of ticks */
75 	outb(ticks >> 8, TIMER2_PORT);
76 }
77 
timer2_running(void)78 static int timer2_running ( void ) {
79 	return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
80 }
81 
timer2_udelay(unsigned long usecs)82 void timer2_udelay ( unsigned long usecs ) {
83 	load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
84 	while (timer2_running()) {
85 		/* Do nothing */
86 	}
87 }
88