Vladimir Serbinenko | 45988da | 2013-03-30 02:02:13 +0100 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2013 Vladimir Serbinenko |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation, either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
Vladimir Serbinenko | 45988da | 2013-03-30 02:02:13 +0100 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | #include <console/console.h> |
| 18 | #include <arch/io.h> |
| 19 | #include <console/spkmodem.h> |
| 20 | #include <cpu/x86/tsc.h> |
| 21 | |
| 22 | #define SPEAKER_PIT_FREQUENCY 0x1234dd |
| 23 | |
| 24 | |
| 25 | enum { |
| 26 | PIT_COUNTER_0 = 0x40, |
| 27 | PIT_COUNTER_1 = 0x41, |
| 28 | PIT_COUNTER_2 = 0x42, |
| 29 | PIT_CTRL = 0x43, |
| 30 | PIT_SPEAKER_PORT = 0x61, |
| 31 | }; |
| 32 | |
| 33 | |
| 34 | enum { |
| 35 | PIT_SPK_TMR2 = 0x01, |
| 36 | PIT_SPK_DATA = 0x02, |
| 37 | PIT_SPK_TMR2_LATCH = 0x20 |
| 38 | }; |
| 39 | |
| 40 | enum { |
| 41 | PIT_CTRL_SELECT_MASK = 0xc0, |
| 42 | PIT_CTRL_SELECT_0 = 0x00, |
| 43 | PIT_CTRL_SELECT_1 = 0x40, |
| 44 | PIT_CTRL_SELECT_2 = 0x80, |
| 45 | |
| 46 | PIT_CTRL_READLOAD_MASK= 0x30, |
| 47 | PIT_CTRL_COUNTER_LATCH = 0x00, |
| 48 | PIT_CTRL_READLOAD_LSB = 0x10, |
| 49 | PIT_CTRL_READLOAD_MSB = 0x20, |
| 50 | PIT_CTRL_READLOAD_WORD = 0x30, |
| 51 | |
| 52 | PIT_CTRL_MODE_MASK = 0x0e, |
| 53 | PIT_CTRL_INTR_ON_TERM = 0x00, |
| 54 | PIT_CTRL_PROGR_ONE_SHOT = 0x02, |
| 55 | |
| 56 | PIT_CTRL_RATE_GEN = 0x04, |
| 57 | |
| 58 | PIT_CTRL_SQUAREWAVE_GEN = 0x06, |
| 59 | PIT_CTRL_SOFTSTROBE = 0x08, |
| 60 | |
| 61 | PIT_CTRL_HARDSTROBE = 0x0a, |
| 62 | |
| 63 | |
| 64 | PIT_CTRL_COUNT_MASK = 0x01, |
| 65 | PIT_CTRL_COUNT_BINARY = 0x00, |
| 66 | PIT_CTRL_COUNT_BCD = 0x01 |
| 67 | }; |
| 68 | |
| 69 | |
| 70 | static void |
| 71 | make_tone (uint16_t freq_count, unsigned int duration) |
| 72 | { |
| 73 | outb (PIT_CTRL_SELECT_2 |
| 74 | | PIT_CTRL_READLOAD_WORD |
| 75 | | PIT_CTRL_SQUAREWAVE_GEN |
| 76 | | PIT_CTRL_COUNT_BINARY, PIT_CTRL); |
| 77 | |
| 78 | outb (freq_count & 0xff, PIT_COUNTER_2); |
| 79 | |
| 80 | outb ((freq_count >> 8) & 0xff, PIT_COUNTER_2); |
| 81 | |
| 82 | outb (inb (PIT_SPEAKER_PORT) |
| 83 | | PIT_SPK_TMR2 | PIT_SPK_DATA, |
| 84 | PIT_SPEAKER_PORT); |
| 85 | |
| 86 | for (; duration; duration--) { |
| 87 | unsigned short counter, previous_counter = 0xffff; |
| 88 | while (1) { |
| 89 | counter = inb (PIT_COUNTER_2); |
| 90 | counter |= ((uint16_t) inb (PIT_COUNTER_2)) << 8; |
| 91 | if (counter > previous_counter) |
| 92 | { |
| 93 | previous_counter = counter; |
| 94 | break; |
| 95 | } |
| 96 | previous_counter = counter; |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | void spkmodem_tx_byte(unsigned char c) |
| 102 | { |
| 103 | int i; |
| 104 | |
| 105 | make_tone (SPEAKER_PIT_FREQUENCY / 200, 4); |
| 106 | for (i = 7; i >= 0; i--) { |
| 107 | if ((c >> i) & 1) |
| 108 | make_tone (SPEAKER_PIT_FREQUENCY / 2000, 20); |
| 109 | else |
| 110 | make_tone (SPEAKER_PIT_FREQUENCY / 4000, 40); |
| 111 | make_tone (SPEAKER_PIT_FREQUENCY / 1000, 10); |
| 112 | } |
| 113 | make_tone (SPEAKER_PIT_FREQUENCY / 200, 0); |
| 114 | } |
| 115 | |
| 116 | void spkmodem_init(void) |
| 117 | { |
| 118 | /* Some cards need time to come online. Output some message to get it started. */ |
| 119 | spkmodem_tx_byte('S'); |
| 120 | spkmodem_tx_byte('P'); |
| 121 | spkmodem_tx_byte('K'); |
| 122 | spkmodem_tx_byte('\r'); |
| 123 | spkmodem_tx_byte('\n'); |
| 124 | } |