1/**
2 * \file
3 */
4
5/*
6 * Copyright (c) 2009, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#ifndef LPC_H
15#define LPC_H
16
17#include <stdint.h>
18#include <stdbool.h>
19#include <timer/timer.h>
20#include "apic.h"
21
22
23/**
24 * \brief Check whether an IRQ may be asserted on the VM right now.
25 *
26 * #irq and #irq_prio are defined if the fuction returns true. The describe
27 * the current waiting interrupt and its priority.
28 */
29typedef bool (*lpc_virtual_irq_pending) (void *user_data, uint8_t *irq,
30        uint8_t *irq_prio);
31
32/**
33 * \brief Assert an IRQ in the virtual machine.
34 */
35typedef void (*lpc_virtual_irq_handler) (void *user_data, uint8_t irq,
36        uint8_t irq_prio);
37
38// LPC Timer
39union lpc_pit_tcw {
40    struct {
41        uint8_t     countdown_select        : 1;
42        uint8_t     mode_select             : 3;
43        uint8_t     rw_select               : 2;
44        uint8_t     counter_select          : 2;
45    } __attribute__((packed)) u;
46    uint8_t raw;
47} __attribute__((packed));
48
49union lpc_pit_sbyte {
50    struct {
51        uint8_t     countdown_type          : 1;
52        uint8_t     mode_type               : 3;
53        uint8_t     rw_mode                 : 2;
54        uint8_t     count_avail             : 1;
55        uint8_t     out_pin_state           : 1;
56    } __attribute__((packed)) u;
57    uint8_t raw;
58} __attribute__((packed));
59
60
61// NMI
62
63union lpc_nmi_sc {
64    struct {
65        uint8_t     tim_cnt2_en             : 1; ///< Timer Counter 2 Enable
66        uint8_t     spkr_dat_en             : 1; ///< Speaker Data Enable
67        uint8_t     pci_serr_en             : 1; ///< PCI SERR# Enable
68        uint8_t     iochk_nmi_en            : 1; ///< IOCHK# NMI Enable
69        uint8_t     ref_toggle              : 1; ///< Refresh Cycle Toggle
70        uint8_t     tmr2_out_sts            : 1; ///< Timer Counter 2 OUT Status
71        uint8_t     iochk_nmi_sts           : 1; ///< IOCHK# NMI Source Status
72        uint8_t     serr_nmi_sts            : 1; ///< SERR# NMI Source Status
73    } __attribute__((packed)) u;
74    uint8_t raw;
75} __attribute__((packed));
76
77
78// PIC
79
80union lpc_pic_icw1 {
81    struct {
82        uint8_t     icw4_req                : 1; ///< ICW4 Write Required
83        /// Single or Cascade, 0 means Cascade
84        uint8_t     sigl_or_casc            : 1;
85        uint8_t     adi                     : 1;
86        uint8_t     edge_lvl_bank_sel       : 1; ///< Edge/Level Bank Select
87        uint8_t     icw_sel                 : 1; ///< ICW/OCW Select
88        uint8_t     rsvd                    : 3;
89    } __attribute__((packed)) u;
90    uint8_t raw;
91} __attribute__((packed));
92
93union lpc_pic_icw2 {
94    struct {
95        uint8_t     intr_req_lvl            : 3; ///< Interrupt Request Level
96        uint8_t     intr_vec_base_addr      : 5; ///< Interrupt Vector Base Address
97    } __attribute__((packed)) u;
98    uint8_t raw;
99} __attribute__((packed));
100
101union lpc_pic_icw3 {
102    /// Master Controller
103    struct {
104        uint8_t     rsvd1                   : 2;
105        /// Cascaded Interrupt Controller IRQ Connection
106        uint8_t     casc_slave_ctrlr        : 1;
107        uint8_t     rsvd2                   : 5;
108    } __attribute__((packed)) um;
109    /// Slave Controller
110    struct {
111        uint8_t     slave_id_code           : 3; ///< Slave Identification Code
112        uint8_t     rsvd                    : 5;
113    } __attribute__((packed)) us;
114    uint8_t raw;
115} __attribute__((packed));
116
117union lpc_pic_icw4 {
118    struct {
119        uint8_t     microproc_mode      : 1; ///< Microprocessor Mode
120        uint8_t     aeoi                : 1; ///< Automatic End of Interrupt
121        uint8_t     ms_sl_mode          : 1; ///< Master/Slave in Buffered Mode
122        uint8_t     buf_mode            : 1; ///< Buffered Mode
123        uint8_t     sfn_mod             : 1; ///< Special Fully Nested Mode
124        uint8_t     rsvd                : 3;
125    } __attribute__((packed)) u;
126    uint8_t raw;
127} __attribute__((packed));
128
129union lpc_pic_ocw1 {
130    struct {
131        uint8_t     irq_mask            : 8; ///< Interrupt Request Mask
132    } __attribute__((packed)) u;
133    uint8_t raw;
134} __attribute__((packed));
135
136union lpc_pic_ocw2 {
137    struct {
138        uint8_t     irq_lvl_sel         : 3; ///< Interrupt Level Select
139        uint8_t     ocw_sel             : 2; ///< OCW Select
140        uint8_t     rot_eio_codes       : 3; ///< Rotate and EOI Codes
141    } __attribute__((packed)) u;
142    uint8_t raw;
143} __attribute__((packed));
144
145union lpc_pic_ocw3 {
146    struct {
147        uint8_t     reg_read_cmd        : 2; ///< Register Read Command
148        uint8_t     poll_mode           : 1; ///< Poll Mode Command
149        uint8_t     ocw_sel             : 2; ///< OCW Select
150        uint8_t     smm_en              : 1; ///< Enable Special Mask Mode
151        uint8_t     smm                 : 1; ///< Special Mask Mode
152        uint8_t     rsvd                : 1;
153    } __attribute__((packed)) u;
154    uint8_t raw;
155} __attribute__((packed));
156
157
158// RTC
159
160union lpc_rtc_a {
161    struct {
162        uint8_t     rate_sel            : 3; ///< Rate Select
163        uint8_t     div_chain_sel       : 3; ///< Division Chain Select
164        uint8_t     uip                 : 1; ///< Update In Progress
165    } __attribute__((packed)) u;
166    uint8_t raw;
167} __attribute__((packed));
168
169union lpc_rtc_b {
170    struct {
171        uint8_t     dse                 : 1; ///< Daylight Savings Enable
172        uint8_t     hour_format         : 1; ///< Hour Format
173        uint8_t     data_mode           : 1; ///< Data Mode
174        uint8_t     sqwe                : 1; ///< Square Wave Enable
175        uint8_t     uie                 : 1; ///< Update-Ended Interrupt Enable
176        uint8_t     aie                 : 1; ///< Alarm Interrupt Enable
177        uint8_t     pie                 : 1; ///< Periodic Interrupt Enable
178        uint8_t     set                 : 1; ///< Update Cycle Inhibit
179    } __attribute__((packed)) u;
180    uint8_t raw;
181} __attribute__((packed));
182
183union lpc_rtc_c {
184    struct {
185        uint8_t     rsvd                : 4;
186        uint8_t     uf                  : 1; ///< Update-Ended Flag
187        uint8_t     af                  : 1; ///< Alarm Flag
188        uint8_t     pf                  : 1; ///< Periodic Interrupt Flag
189        uint8_t     irqf                : 1; ///< Interrupt Request Flag
190    } __attribute__((packed)) u;
191    uint8_t raw;
192} __attribute__((packed));
193
194union lpc_rtc_d {
195    struct {
196        uint8_t     data_alarm          : 6; ///< Data Alarm
197        uint8_t     rsvd                : 1;
198        uint8_t     vrt                 : 1; ///< Valid RAM and Time Bit
199    } __attribute__((packed)) u;
200    uint8_t raw;
201} __attribute__((packed));
202
203union lpc_rtc_prim_ram {
204    struct {
205        uint8_t     seconds;
206        uint8_t     seconds_alarm;
207        uint8_t     minutes;
208        uint8_t     minutes_alarm;
209        uint8_t     hours;
210        uint8_t     hours_alarm;
211        uint8_t     day_of_week;
212        uint8_t     day_of_month;
213        uint8_t     month;
214        uint8_t     year;
215        union lpc_rtc_a A;
216        union lpc_rtc_b B;
217        union lpc_rtc_c C;
218        union lpc_rtc_d D;
219        uint8_t     ram[114];
220    } __attribute__((packed)) u;
221    uint8_t raw[128];
222} __attribute__((packed));
223
224
225// LPC main data structures
226
227enum lpc_pit_next_byte {
228    LPC_PIT_NONE = 0,
229    LPC_PIT_LSB,
230    LPC_PIT_MSB
231};
232
233enum lpc_pic_current_icw {
234    LPC_PIC_ICW_NONE,
235    LPC_PIC_ICW_2,
236    LPC_PIC_ICW_3,
237    LPC_PIC_ICW_4
238};
239
240enum lpc_pic_irq_state {
241    LPC_PIC_IRQ_AVAIL = 0,
242    LPC_PIC_IRQ_PENDING,
243    LPC_PIC_IRQ_ISR
244};
245
246
247struct lpc {
248    struct apic     *apic;  ///< The APIC to send IRQs to
249    lpc_virtual_irq_handler     virq_handler;
250    lpc_virtual_irq_pending     virq_pending;
251    void *                      virq_user_data;
252    // NMI Controller
253    bool                nmi_masked;
254    union lpc_nmi_sc    nmi_sc_reg; ///< NMI Status and Control Register
255
256    // Timer
257    union lpc_pit_sbyte         sbytes[3];
258    enum lpc_pit_next_byte      counter_current_byte[3];
259    uint16_t                    initial_count[3];
260    bool                        counter_latched[3];
261    uint16_t                    buffer_val[3];
262    struct timer                *timer[3];
263
264    // PIC
265    // inside the array pos 0 represents the master and 1 the slave controller
266    enum lpc_pic_current_icw    current_icw[2];
267    union lpc_pic_icw1          icw1[2];
268    union lpc_pic_icw2          icw2[2];
269    union lpc_pic_icw3          icw3[2];
270    union lpc_pic_icw4          icw4[2];
271    union lpc_pic_ocw1          ocw1[2];
272    union lpc_pic_ocw2          ocw2[2];
273    union lpc_pic_ocw3          ocw3[2];
274    enum lpc_pic_irq_state      irq_state[16];
275    int                         current_irq;
276
277    // RTC
278    uint8_t                     rtc_prim_addr;
279    union lpc_rtc_prim_ram      rtc_prim_ram;
280    uint8_t                     rtc_sec_addr;
281    uint8_t                     rtc_sec_ram[128];
282    struct timer                *rtc_timer;
283    uint64_t                    rtc_timer_elapsed;
284};
285
286int lpc_init(void);
287struct lpc * lpc_new (lpc_virtual_irq_handler virq_handler,
288                      lpc_virtual_irq_pending virq_pending, void *user_data,
289                      struct apic *apic);
290int lpc_handle_pio_read (struct lpc *l, uint16_t port, enum opsize size,
291                         uint32_t *val);
292int lpc_handle_pio_write (struct lpc *l, uint16_t port, enum opsize size,
293                          uint32_t val);
294void lpc_pic_assert_irq (struct lpc *l, uint8_t irq);
295void lpc_pic_process_irqs (struct lpc *l);
296
297void lpc_rtc_get_time_bcd (struct lpc *l, uint8_t *hour, uint8_t *min,
298                           uint8_t *sec);
299
300#endif // LPC_H
301