i8254.c 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2002
  4. * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
  5. */
  6. #include <common.h>
  7. #include <asm/io.h>
  8. #include <asm/i8254.h>
  9. #include <asm/ibmpc.h>
  10. #define TIMER1_VALUE 18 /* 15.6us */
  11. #define BEEP_FREQUENCY_HZ 440
  12. #define SYSCTL_PORTB 0x61
  13. #define PORTB_BEEP_ENABLE 0x3
  14. static void i8254_set_beep_freq(uint frequency_hz)
  15. {
  16. uint countdown;
  17. countdown = PIT_TICK_RATE / frequency_hz;
  18. outb(countdown & 0xff, PIT_BASE + PIT_T2);
  19. outb((countdown >> 8) & 0xff, PIT_BASE + PIT_T2);
  20. }
  21. int i8254_init(void)
  22. {
  23. /*
  24. * Initialize counter 1, used to refresh request signal.
  25. * This is required for legacy purpose as some codes like
  26. * vgabios utilizes counter 1 to provide delay functionality.
  27. */
  28. outb(PIT_CMD_CTR1 | PIT_CMD_LOW | PIT_CMD_MODE2,
  29. PIT_BASE + PIT_COMMAND);
  30. outb(TIMER1_VALUE, PIT_BASE + PIT_T1);
  31. /*
  32. * Initialize counter 2, used to drive the speaker.
  33. * To start a beep, set both bit0 and bit1 of port 0x61.
  34. * To stop it, clear both bit0 and bit1 of port 0x61.
  35. */
  36. outb(PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
  37. PIT_BASE + PIT_COMMAND);
  38. i8254_set_beep_freq(BEEP_FREQUENCY_HZ);
  39. return 0;
  40. }
  41. int i8254_enable_beep(uint frequency_hz)
  42. {
  43. if (!frequency_hz)
  44. return -EINVAL;
  45. /* make sure i8254 is setup correctly before generating beeps */
  46. outb(PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
  47. PIT_BASE + PIT_COMMAND);
  48. i8254_set_beep_freq(frequency_hz);
  49. setio_8(SYSCTL_PORTB, PORTB_BEEP_ENABLE);
  50. return 0;
  51. }
  52. void i8254_disable_beep(void)
  53. {
  54. clrio_8(SYSCTL_PORTB, PORTB_BEEP_ENABLE);
  55. }