xref: /openbmc/u-boot/arch/x86/lib/i8254.c (revision 821aa191)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2da3fe247SBin Meng /*
3da3fe247SBin Meng  * (C) Copyright 2002
4da3fe247SBin Meng  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
5da3fe247SBin Meng  */
6da3fe247SBin Meng 
7da3fe247SBin Meng #include <common.h>
8da3fe247SBin Meng #include <asm/io.h>
9da3fe247SBin Meng #include <asm/i8254.h>
10da3fe247SBin Meng 
11da3fe247SBin Meng #define TIMER1_VALUE		18	/* 15.6us */
1279a5be82SSimon Glass #define BEEP_FREQUENCY_HZ	440
1379a5be82SSimon Glass #define SYSCTL_PORTB		0x61
1479a5be82SSimon Glass #define PORTB_BEEP_ENABLE	0x3
1579a5be82SSimon Glass 
i8254_set_beep_freq(uint frequency_hz)1679a5be82SSimon Glass static void i8254_set_beep_freq(uint frequency_hz)
1779a5be82SSimon Glass {
1879a5be82SSimon Glass 	uint countdown;
1979a5be82SSimon Glass 
2079a5be82SSimon Glass 	countdown = PIT_TICK_RATE / frequency_hz;
2179a5be82SSimon Glass 
2279a5be82SSimon Glass 	outb(countdown & 0xff, PIT_BASE + PIT_T2);
2379a5be82SSimon Glass 	outb((countdown >> 8) & 0xff, PIT_BASE + PIT_T2);
2479a5be82SSimon Glass }
25da3fe247SBin Meng 
i8254_init(void)26da3fe247SBin Meng int i8254_init(void)
27da3fe247SBin Meng {
28da3fe247SBin Meng 	/*
29da3fe247SBin Meng 	 * Initialize counter 1, used to refresh request signal.
30da3fe247SBin Meng 	 * This is required for legacy purpose as some codes like
31da3fe247SBin Meng 	 * vgabios utilizes counter 1 to provide delay functionality.
32da3fe247SBin Meng 	 */
33da3fe247SBin Meng 	outb(PIT_CMD_CTR1 | PIT_CMD_LOW | PIT_CMD_MODE2,
34da3fe247SBin Meng 	     PIT_BASE + PIT_COMMAND);
35da3fe247SBin Meng 	outb(TIMER1_VALUE, PIT_BASE + PIT_T1);
36da3fe247SBin Meng 
37da3fe247SBin Meng 	/*
38da3fe247SBin Meng 	 * Initialize counter 2, used to drive the speaker.
39da3fe247SBin Meng 	 * To start a beep, set both bit0 and bit1 of port 0x61.
40da3fe247SBin Meng 	 * To stop it, clear both bit0 and bit1 of port 0x61.
41da3fe247SBin Meng 	 */
42da3fe247SBin Meng 	outb(PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
43da3fe247SBin Meng 	     PIT_BASE + PIT_COMMAND);
4479a5be82SSimon Glass 	i8254_set_beep_freq(BEEP_FREQUENCY_HZ);
45da3fe247SBin Meng 
46da3fe247SBin Meng 	return 0;
47da3fe247SBin Meng }
4879a5be82SSimon Glass 
i8254_enable_beep(uint frequency_hz)4979a5be82SSimon Glass int i8254_enable_beep(uint frequency_hz)
5079a5be82SSimon Glass {
5179a5be82SSimon Glass 	if (!frequency_hz)
5279a5be82SSimon Glass 		return -EINVAL;
5379a5be82SSimon Glass 
54*7d0a53a4SBin Meng 	/* make sure i8254 is setup correctly before generating beeps */
55*7d0a53a4SBin Meng 	outb(PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
56*7d0a53a4SBin Meng 	     PIT_BASE + PIT_COMMAND);
57*7d0a53a4SBin Meng 
5879a5be82SSimon Glass 	i8254_set_beep_freq(frequency_hz);
5979a5be82SSimon Glass 	setio_8(SYSCTL_PORTB, PORTB_BEEP_ENABLE);
6079a5be82SSimon Glass 
6179a5be82SSimon Glass 	return 0;
6279a5be82SSimon Glass }
6379a5be82SSimon Glass 
i8254_disable_beep(void)6479a5be82SSimon Glass void i8254_disable_beep(void)
6579a5be82SSimon Glass {
6679a5be82SSimon Glass 	clrio_8(SYSCTL_PORTB, PORTB_BEEP_ENABLE);
6779a5be82SSimon Glass }
68