Thomas Hebb | f128090 | 2020-03-30 12:09:37 -0400 | [diff] [blame] | 1 | =============================== |
| 2 | Realtek PC Beep Hidden Register |
| 3 | =============================== |
| 4 | |
| 5 | This file documents the "PC Beep Hidden Register", which is present in certain |
| 6 | Realtek HDA codecs and controls a muxer and pair of passthrough mixers that can |
| 7 | route audio between pins but aren't themselves exposed as HDA widgets. As far |
| 8 | as I can tell, these hidden routes are designed to allow flexible PC Beep output |
| 9 | for codecs that don't have mixer widgets in their output paths. Why it's easier |
| 10 | to hide a mixer behind an undocumented vendor register than to just expose it |
| 11 | as a widget, I have no idea. |
| 12 | |
| 13 | Register Description |
| 14 | ==================== |
| 15 | |
| 16 | The register is accessed via processing coefficient 0x36 on NID 20h. Bits not |
| 17 | identified below have no discernible effect on my machine, a Dell XPS 13 9350:: |
| 18 | |
| 19 | MSB LSB |
| 20 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 21 | | |h|S|L| | B |R| | Known bits |
| 22 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| 23 | |0|0|1|1| 0x7 |0|0x0|1| 0x7 | Reset value |
| 24 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 25 | |
| 26 | 1Ah input select (B): 2 bits |
| 27 | When zero, expose the PC Beep line (from the internal beep generator, when |
| 28 | enabled with the Set Beep Generation verb on NID 01h, or else from the |
| 29 | external PCBEEP pin) on the 1Ah pin node. When nonzero, expose the headphone |
| 30 | jack (or possibly Line In on some machines) input instead. If PC Beep is |
| 31 | selected, the 1Ah boost control has no effect. |
| 32 | |
| 33 | Amplify 1Ah loopback, left (L): 1 bit |
| 34 | Amplify the left channel of 1Ah before mixing it into outputs as specified |
| 35 | by h and S bits. Does not affect the level of 1Ah exposed to other widgets. |
| 36 | |
| 37 | Amplify 1Ah loopback, right (R): 1 bit |
| 38 | Amplify the right channel of 1Ah before mixing it into outputs as specified |
| 39 | by h and S bits. Does not affect the level of 1Ah exposed to other widgets. |
| 40 | |
| 41 | Loopback 1Ah to 21h [active low] (h): 1 bit |
| 42 | When zero, mix 1Ah (possibly with amplification, depending on L and R bits) |
| 43 | into 21h (headphone jack on my machine). Mixed signal respects the mute |
| 44 | setting on 21h. |
| 45 | |
| 46 | Loopback 1Ah to 14h (S): 1 bit |
| 47 | When one, mix 1Ah (possibly with amplification, depending on L and R bits) |
| 48 | into 14h (internal speaker on my machine). Mixed signal **ignores** the mute |
| 49 | setting on 14h and is present whenever 14h is configured as an output. |
| 50 | |
| 51 | Path diagrams |
| 52 | ============= |
| 53 | |
| 54 | 1Ah input selection (DIV is the PC Beep divider set on NID 01h):: |
| 55 | |
| 56 | <Beep generator> <PCBEEP pin> <Headphone jack> |
| 57 | | | | |
| 58 | +--DIV--+--!DIV--+ {1Ah boost control} |
| 59 | | | |
| 60 | +--(b == 0)--+--(b != 0)--+ |
| 61 | | |
| 62 | >1Ah (Beep/Headphone Mic/Line In)< |
| 63 | |
| 64 | Loopback of 1Ah to 21h/14h:: |
| 65 | |
| 66 | <1Ah (Beep/Headphone Mic/Line In)> |
| 67 | | |
| 68 | {amplify if L/R} |
| 69 | | |
| 70 | +-----!h-----+-----S-----+ |
| 71 | | | |
| 72 | {21h mute control} | |
| 73 | | | |
| 74 | >21h (Headphone)< >14h (Internal Speaker)< |
| 75 | |
| 76 | Background |
| 77 | ========== |
| 78 | |
| 79 | All Realtek HDA codecs have a vendor-defined widget with node ID 20h which |
| 80 | provides access to a bank of registers that control various codec functions. |
| 81 | Registers are read and written via the standard HDA processing coefficient |
| 82 | verbs (Set/Get Coefficient Index, Set/Get Processing Coefficient). The node is |
| 83 | named "Realtek Vendor Registers" in public datasheets' verb listings and, |
| 84 | apart from that, is entirely undocumented. |
| 85 | |
| 86 | This particular register, exposed at coefficient 0x36 and named in commits from |
| 87 | Realtek, is of note: unlike most registers, which seem to control detailed |
| 88 | amplifier parameters not in scope of the HDA specification, it controls audio |
| 89 | routing which could just as easily have been defined using standard HDA mixer |
| 90 | and selector widgets. |
| 91 | |
| 92 | Specifically, it selects between two sources for the input pin widget with Node |
| 93 | ID (NID) 1Ah: the widget's signal can come either from an audio jack (on my |
| 94 | laptop, a Dell XPS 13 9350, it's the headphone jack, but comments in Realtek |
| 95 | commits indicate that it might be a Line In on some machines) or from the PC |
| 96 | Beep line (which is itself multiplexed between the codec's internal beep |
| 97 | generator and external PCBEEP pin, depending on if the beep generator is |
| 98 | enabled via verbs on NID 01h). Additionally, it can mix (with optional |
| 99 | amplification) that signal onto the 21h and/or 14h output pins. |
| 100 | |
| 101 | The register's reset value is 0x3717, corresponding to PC Beep on 1Ah that is |
| 102 | then amplified and mixed into both the headphones and the speakers. Not only |
| 103 | does this violate the HDA specification, which says that "[a vendor defined |
| 104 | beep input pin] connection may be maintained *only* while the Link reset |
| 105 | (**RST#**) is asserted", it means that we cannot ignore the register if we care |
| 106 | about the input that 1Ah would otherwise expose or if the PCBEEP trace is |
| 107 | poorly shielded and picks up chassis noise (both of which are the case on my |
| 108 | machine). |
| 109 | |
| 110 | Unfortunately, there are lots of ways to get this register configuration wrong. |
| 111 | Linux, it seems, has gone through most of them. For one, the register resets |
| 112 | after S3 suspend: judging by existing code, this isn't the case for all vendor |
| 113 | registers, and it's led to some fixes that improve behavior on cold boot but |
| 114 | don't last after suspend. Other fixes have successfully switched the 1Ah input |
| 115 | away from PC Beep but have failed to disable both loopback paths. On my |
| 116 | machine, this means that the headphone input is amplified and looped back to |
| 117 | the headphone output, which uses the exact same pins! As you might expect, this |
| 118 | causes terrible headphone noise, the character of which is controlled by the |
| 119 | 1Ah boost control. (If you've seen instructions online to fix XPS 13 headphone |
| 120 | noise by changing "Headphone Mic Boost" in ALSA, now you know why.) |
| 121 | |
| 122 | The information here has been obtained through black-box reverse engineering of |
| 123 | the ALC256 codec's behavior and is not guaranteed to be correct. It likely |
| 124 | also applies for the ALC255, ALC257, ALC235, and ALC236, since those codecs |
| 125 | seem to be close relatives of the ALC256. (They all share one initialization |
| 126 | function.) Additionally, other codecs like the ALC225 and ALC285 also have this |
| 127 | register, judging by existing fixups in ``patch_realtek.c``, but specific |
| 128 | data (e.g. node IDs, bit positions, pin mappings) for those codecs may differ |
| 129 | from what I've described here. |