xref: /aosp_15_r20/external/coreboot/src/drivers/pc80/pc/spkmodem.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <arch/io.h>
4 #include <console/spkmodem.h>
5 
6 #define SPEAKER_PIT_FREQUENCY		0x1234dd
7 
8 enum {
9 	PIT_COUNTER_0 = 0x40,
10 	PIT_COUNTER_1 = 0x41,
11 	PIT_COUNTER_2 = 0x42,
12 	PIT_CTRL = 0x43,
13 	PIT_SPEAKER_PORT = 0x61,
14 };
15 
16 enum {
17 	PIT_SPK_TMR2 = 0x01,
18 	PIT_SPK_DATA = 0x02,
19 	PIT_SPK_TMR2_LATCH = 0x20
20 };
21 
22 enum {
23 	PIT_CTRL_SELECT_MASK = 0xc0,
24 	PIT_CTRL_SELECT_0 = 0x00,
25 	PIT_CTRL_SELECT_1 = 0x40,
26 	PIT_CTRL_SELECT_2 = 0x80,
27 
28 	PIT_CTRL_READLOAD_MASK = 0x30,
29 	PIT_CTRL_COUNTER_LATCH = 0x00,
30 	PIT_CTRL_READLOAD_LSB = 0x10,
31 	PIT_CTRL_READLOAD_MSB = 0x20,
32 	PIT_CTRL_READLOAD_WORD = 0x30,
33 
34 	PIT_CTRL_MODE_MASK = 0x0e,
35 	PIT_CTRL_INTR_ON_TERM = 0x00,
36 	PIT_CTRL_PROGR_ONE_SHOT = 0x02,
37 
38 	PIT_CTRL_RATE_GEN = 0x04,
39 
40 	PIT_CTRL_SQUAREWAVE_GEN = 0x06,
41 	PIT_CTRL_SOFTSTROBE = 0x08,
42 
43 	PIT_CTRL_HARDSTROBE = 0x0a,
44 
45 	PIT_CTRL_COUNT_MASK = 0x01,
46 	PIT_CTRL_COUNT_BINARY = 0x00,
47 	PIT_CTRL_COUNT_BCD = 0x01
48 };
49 
50 static void
make_tone(uint16_t freq_count,unsigned int duration)51 make_tone(uint16_t freq_count, unsigned int duration)
52 {
53 	outb(PIT_CTRL_SELECT_2
54 		   | PIT_CTRL_READLOAD_WORD
55 		   | PIT_CTRL_SQUAREWAVE_GEN
56 		   | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
57 
58 	outb(freq_count & 0xff, PIT_COUNTER_2);
59 
60 	outb((freq_count >> 8) & 0xff, PIT_COUNTER_2);
61 
62 	outb(inb(PIT_SPEAKER_PORT)
63 		   | PIT_SPK_TMR2 | PIT_SPK_DATA,
64 		   PIT_SPEAKER_PORT);
65 
66 	for (; duration; duration--) {
67 		unsigned short counter, previous_counter = 0xffff;
68 
69 		while (1) {
70 			counter = inb(PIT_COUNTER_2);
71 			counter |= ((uint16_t)inb(PIT_COUNTER_2)) << 8;
72 			if (counter > previous_counter) {
73 				previous_counter = counter;
74 				break;
75 			}
76 			previous_counter = counter;
77 		}
78 	}
79 }
80 
spkmodem_tx_byte(unsigned char c)81 void spkmodem_tx_byte(unsigned char c)
82 {
83 	int i;
84 
85 	make_tone(SPEAKER_PIT_FREQUENCY / 200, 4);
86 	for (i = 7; i >= 0; i--) {
87 		if ((c >> i) & 1)
88 			make_tone(SPEAKER_PIT_FREQUENCY / 2000, 20);
89 		else
90 			make_tone(SPEAKER_PIT_FREQUENCY / 4000, 40);
91 		make_tone(SPEAKER_PIT_FREQUENCY / 1000, 10);
92 	}
93 	make_tone(SPEAKER_PIT_FREQUENCY / 200, 0);
94 }
95 
spkmodem_init(void)96 void spkmodem_init(void)
97 {
98 	/* Some cards need time to come online.
99 	 * Output some message to get it started.
100 	 */
101 	spkmodem_tx_byte('S');
102 	spkmodem_tx_byte('P');
103 	spkmodem_tx_byte('K');
104 	spkmodem_tx_byte('\r');
105 	spkmodem_tx_byte('\n');
106 }
107