source: mainline/kernel/arch/ia32/src/drivers/i8254.c@ 84afc7b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 84afc7b was 84afc7b, checked in by Martin Decky <martin@…>, 16 years ago

as kernel little brother drivers are not needed anymore, the device numbers do not have to be correlated between kernel and uspace in any way
introduce new syscall sys_device_assign_devno() for generating system-wide unique device numbers for uspace

  • Property mode set to 100644
File size: 4.2 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ia32
30 * @{
31 */
32/**
33 * @file
34 * @brief i8254 chip driver.
35 *
36 * Low level time functions.
37 */
38
39#include <arch/types.h>
40#include <time/clock.h>
41#include <time/delay.h>
42#include <arch/cycle.h>
43#include <arch/interrupt.h>
44#include <arch/drivers/i8259.h>
45#include <arch/drivers/i8254.h>
46#include <cpu.h>
47#include <config.h>
48#include <arch/pm.h>
49#include <arch/asm.h>
50#include <arch/cpuid.h>
51#include <arch.h>
52#include <time/delay.h>
53#include <ddi/irq.h>
54#include <ddi/device.h>
55
56#define CLK_PORT1 ((ioport8_t *)0x40)
57#define CLK_PORT4 ((ioport8_t *)0x43)
58
59#define CLK_CONST 1193180
60#define MAGIC_NUMBER 1194
61
62static irq_t i8254_irq;
63
64static irq_ownership_t i8254_claim(irq_t *irq)
65{
66 return IRQ_ACCEPT;
67}
68
69static void i8254_irq_handler(irq_t *irq)
70{
71 /*
72 * This IRQ is responsible for kernel preemption.
73 * Nevertheless, we are now holding a spinlock which prevents
74 * preemption. For this particular IRQ, we don't need the
75 * lock. We just release it, call clock() and then reacquire it again.
76 */
77 spinlock_unlock(&irq->lock);
78 clock();
79 spinlock_lock(&irq->lock);
80}
81
82void i8254_init(void)
83{
84 irq_initialize(&i8254_irq);
85 i8254_irq.preack = true;
86 i8254_irq.devno = device_assign_devno();
87 i8254_irq.inr = IRQ_CLK;
88 i8254_irq.claim = i8254_claim;
89 i8254_irq.handler = i8254_irq_handler;
90 irq_register(&i8254_irq);
91
92 i8254_normal_operation();
93}
94
95void i8254_normal_operation(void)
96{
97 pio_write_8(CLK_PORT4, 0x36);
98 pic_disable_irqs(1 << IRQ_CLK);
99 pio_write_8(CLK_PORT1, (CLK_CONST / HZ) & 0xf);
100 pio_write_8(CLK_PORT1, (CLK_CONST / HZ) >> 8);
101 pic_enable_irqs(1 << IRQ_CLK);
102}
103
104#define LOOPS 150000
105#define SHIFT 11
106void i8254_calibrate_delay_loop(void)
107{
108 uint64_t clk1, clk2;
109 uint32_t t1, t2, o1, o2;
110 uint8_t not_ok;
111
112
113 /*
114 * One-shot timer. Count-down from 0xffff at 1193180Hz
115 * MAGIC_NUMBER is the magic value for 1ms.
116 */
117 pio_write_8(CLK_PORT4, 0x30);
118 pio_write_8(CLK_PORT1, 0xff);
119 pio_write_8(CLK_PORT1, 0xff);
120
121 do {
122 /* will read both status and count */
123 pio_write_8(CLK_PORT4, 0xc2);
124 not_ok = (uint8_t) ((pio_read_8(CLK_PORT1) >> 6) & 1);
125 t1 = pio_read_8(CLK_PORT1);
126 t1 |= pio_read_8(CLK_PORT1) << 8;
127 } while (not_ok);
128
129 asm_delay_loop(LOOPS);
130
131 pio_write_8(CLK_PORT4, 0xd2);
132 t2 = pio_read_8(CLK_PORT1);
133 t2 |= pio_read_8(CLK_PORT1) << 8;
134
135 /*
136 * We want to determine the overhead of the calibrating mechanism.
137 */
138 pio_write_8(CLK_PORT4, 0xd2);
139 o1 = pio_read_8(CLK_PORT1);
140 o1 |= pio_read_8(CLK_PORT1) << 8;
141
142 asm_fake_loop(LOOPS);
143
144 pio_write_8(CLK_PORT4, 0xd2);
145 o2 = pio_read_8(CLK_PORT1);
146 o2 |= pio_read_8(CLK_PORT1) << 8;
147
148 CPU->delay_loop_const =
149 ((MAGIC_NUMBER * LOOPS) / 1000) / ((t1 - t2) - (o1 - o2)) +
150 (((MAGIC_NUMBER * LOOPS) / 1000) % ((t1 - t2) - (o1 - o2)) ? 1 : 0);
151
152 clk1 = get_cycle();
153 delay(1 << SHIFT);
154 clk2 = get_cycle();
155
156 CPU->frequency_mhz = (clk2 - clk1) >> SHIFT;
157
158 return;
159}
160
161/** @}
162 */
Note: See TracBrowser for help on using the repository browser.