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