|
| 1 | +/** |
| 2 | + * @file modules/hda/hda.h |
| 3 | + * @author Craig Edwards (craigedwards@brainbox.cc) |
| 4 | + * @copyright Copyright (c) 2012-2025 |
| 5 | + * |
| 6 | + * Intel High Definition Audio (Azalia) output driver |
| 7 | + */ |
1 | 8 | #pragma once |
2 | 9 | #include <stdint.h> |
3 | 10 | #include <stdbool.h> |
4 | 11 |
|
| 12 | +/** PCI class code for Intel High Definition Audio controllers. */ |
5 | 13 | #define HDA_PCI_CLASSC 0x0403 |
6 | 14 |
|
7 | 15 | /* Controller MMIO registers (offsets from BAR0) */ |
8 | | -#define HDA_REG_GCAP 0x00 /* Global Capabilities */ |
9 | | -#define HDA_REG_VMIN 0x02 |
10 | | -#define HDA_REG_VMAJ 0x03 |
11 | | -#define HDA_REG_GCTL 0x08 /* bit0=CRST */ |
12 | | -#define HDA_REG_WAKEEN 0x0C |
13 | | -#define HDA_REG_STATESTS 0x0E /* codec presence bits 0..2 */ |
14 | | -#define HDA_REG_INTCTL 0x20 |
15 | | -#define HDA_REG_INTSTS 0x24 |
16 | | -#define HDA_REG_WALCLK 0x30 |
17 | | -#define HDA_REG_SSYNC 0x34 |
18 | | - |
19 | | -/* CORB / RIRB */ |
20 | | -#define HDA_REG_CORBLBASE 0x40 |
21 | | -#define HDA_REG_CORBUBASE 0x44 |
22 | | -#define HDA_REG_CORBWP 0x48 |
23 | | -#define HDA_REG_CORBRP 0x4A |
24 | | -#define HDA_CORBRP_RST 0x8000 |
25 | | -#define HDA_REG_CORBCTL 0x4C |
26 | | -#define HDA_CORBCTL_MEIE 0x01 |
27 | | -#define HDA_CORBCTL_DMAE 0x02 |
28 | | -#define HDA_REG_CORBSTS 0x4D |
29 | | -#define HDA_REG_CORBSIZE 0x4E /* bits[1:0]=00:2,01:16,10:256 entries; feature bits [6:4] */ |
30 | | -#define HDA_REG_RIRBLBASE 0x50 |
31 | | -#define HDA_REG_RIRBUBASE 0x54 |
32 | | -#define HDA_REG_RIRBWP 0x58 |
33 | | -#define HDA_RIRBWP_RST 0x8000 |
34 | | -#define HDA_REG_RINTCNT 0x5A |
35 | | -#define HDA_REG_RIRBCTL 0x5C |
36 | | -#define HDA_RIRBCTL_INT_ON_OVERRUN 0x01 |
37 | | -#define HDA_RIRBCTL_DMAE 0x02 |
38 | | -#define HDA_RIRBCTL_IRQE 0x04 |
39 | | -#define HDA_REG_RIRBSTS 0x5D |
40 | | -#define HDA_REG_RIRBSIZE 0x5E |
41 | | - |
42 | | -/* DMA position buffer (unused here, but handy for debugging latency) */ |
43 | | -#define HDA_REG_DPLBASE 0x70 |
44 | | -#define HDA_REG_DPUBASE 0x74 |
45 | | - |
46 | | -/* Stream descriptor block: layout is 0x80 + n*0x20; order: input, output, bidi */ |
47 | | -#define HDA_SD_BASE 0x80 |
48 | | -#define HDA_SD_STRIDE 0x20 |
| 16 | +#define HDA_REG_GCAP 0x00 /**< Global Capabilities register. */ |
| 17 | +#define HDA_REG_VMIN 0x02 /**< Minor version. */ |
| 18 | +#define HDA_REG_VMAJ 0x03 /**< Major version. */ |
| 19 | +#define HDA_REG_GCTL 0x08 /**< Global Control; bit0 = CRST (controller reset). */ |
| 20 | +#define HDA_REG_WAKEEN 0x0C /**< Wake enable. */ |
| 21 | +#define HDA_REG_STATESTS 0x0E /**< Codec presence status bits (0..2). */ |
| 22 | +#define HDA_REG_INTCTL 0x20 /**< Global interrupt control. */ |
| 23 | +#define HDA_REG_INTSTS 0x24 /**< Global interrupt status (R/WC). */ |
| 24 | +#define HDA_REG_WALCLK 0x30 /**< Free-running wall clock (~24.576 MHz). */ |
| 25 | +#define HDA_REG_SSYNC 0x34 /**< Stream synchronisation. */ |
| 26 | + |
| 27 | +/* CORB / RIRB registers */ |
| 28 | +#define HDA_REG_CORBLBASE 0x40 /**< CORB lower base address. */ |
| 29 | +#define HDA_REG_CORBUBASE 0x44 /**< CORB upper base address. */ |
| 30 | +#define HDA_REG_CORBWP 0x48 /**< CORB write pointer. */ |
| 31 | +#define HDA_REG_CORBRP 0x4A /**< CORB read pointer. */ |
| 32 | +#define HDA_CORBRP_RST 0x8000 /**< Reset CORB read pointer. */ |
| 33 | +#define HDA_REG_CORBCTL 0x4C /**< CORB control. */ |
| 34 | +#define HDA_CORBCTL_MEIE 0x01 /**< CORB memory error interrupt enable. */ |
| 35 | +#define HDA_CORBCTL_DMAE 0x02 /**< CORB DMA enable. */ |
| 36 | +#define HDA_REG_CORBSTS 0x4D /**< CORB status. */ |
| 37 | +#define HDA_REG_CORBSIZE 0x4E /**< CORB size; bits[1:0]=00:2,01:16,10:256 entries. */ |
| 38 | + |
| 39 | +#define HDA_REG_RIRBLBASE 0x50 /**< RIRB lower base address. */ |
| 40 | +#define HDA_REG_RIRBUBASE 0x54 /**< RIRB upper base address. */ |
| 41 | +#define HDA_REG_RIRBWP 0x58 /**< RIRB write pointer. */ |
| 42 | +#define HDA_RIRBWP_RST 0x8000 /**< Reset RIRB write pointer. */ |
| 43 | +#define HDA_REG_RINTCNT 0x5A /**< RIRB response interrupt count. */ |
| 44 | +#define HDA_REG_RIRBCTL 0x5C /**< RIRB control. */ |
| 45 | +#define HDA_RIRBCTL_INT_ON_OVERRUN 0x01 /**< Interrupt on overrun. */ |
| 46 | +#define HDA_RIRBCTL_DMAE 0x02 /**< RIRB DMA enable. */ |
| 47 | +#define HDA_RIRBCTL_IRQE 0x04 /**< RIRB interrupt enable. */ |
| 48 | +#define HDA_REG_RIRBSTS 0x5D /**< RIRB status. */ |
| 49 | +#define HDA_REG_RIRBSIZE 0x5E /**< RIRB size; encoding matches CORBSIZE. */ |
| 50 | + |
| 51 | +/* DMA position buffer registers (not used here, but useful for debugging latency) */ |
| 52 | +#define HDA_REG_DPLBASE 0x70 /**< DMA position buffer lower base. */ |
| 53 | +#define HDA_REG_DPUBASE 0x74 /**< DMA position buffer upper base. */ |
| 54 | + |
| 55 | +/* Stream descriptor block layout (SDn) */ |
| 56 | +#define HDA_SD_BASE 0x80 /**< Base offset of first stream descriptor. */ |
| 57 | +#define HDA_SD_STRIDE 0x20 /**< Stride between SDn blocks. */ |
49 | 58 |
|
50 | 59 | /* Offsets inside SDn */ |
51 | | -#define SD_CTL0 0x00 /* byte0: RUN(1), SRST(0); byte2: stream tag (7:4) + traf prio */ |
52 | | -#define SD_CTL2 0x02 |
53 | | -#define SD_STS 0x03 |
54 | | -#define SD_LPIB 0x04 |
55 | | -#define SD_CBL 0x08 |
56 | | -#define SD_LVI 0x0C |
57 | | -#define SD_FMT 0x12 |
58 | | -#define SD_BDPL 0x18 |
59 | | -#define SD_BDPU 0x1C |
| 60 | +#define SD_CTL0 0x00 /**< Control0: RUN, SRST, tag/prio. */ |
| 61 | +#define SD_CTL2 0x02 /**< Control2: stream tag in [7:4]. */ |
| 62 | +#define SD_STS 0x03 /**< Status (R/WC). */ |
| 63 | +#define SD_LPIB 0x04 /**< Link position in bytes. */ |
| 64 | +#define SD_CBL 0x08 /**< Cyclic buffer length in bytes. */ |
| 65 | +#define SD_LVI 0x0C /**< Last valid index. */ |
| 66 | +#define SD_FMT 0x12 /**< Stream format. */ |
| 67 | +#define SD_BDPL 0x18 /**< BDL pointer low. */ |
| 68 | +#define SD_BDPU 0x1C /**< BDL pointer upper. */ |
60 | 69 |
|
61 | 70 | /* SD_CTL0 bits */ |
62 | | -#define SD_CTL_RUN (1u << 1) |
63 | | -#define SD_CTL_SRST (1u << 0) |
| 71 | +#define SD_CTL_RUN (1 << 1) /**< Start/stop stream DMA. */ |
| 72 | +#define SD_CTL_SRST (1 << 0) /**< Stream reset. */ |
64 | 73 |
|
65 | | -/* BDL entry (HDA): 16 bytes */ |
| 74 | +/** |
| 75 | + * Buffer Descriptor List entry (HDA). |
| 76 | + * Each entry is 16 bytes, aligned to 16. |
| 77 | + */ |
66 | 78 | typedef struct { |
67 | | - uint64_t addr; |
68 | | - uint32_t len; |
69 | | - uint32_t flags; /* bit0 = IOC */ |
| 79 | + uint64_t addr; /**< Physical address of buffer. */ |
| 80 | + uint32_t len; /**< Length in bytes. */ |
| 81 | + uint32_t flags; /**< Flags; bit0 = IOC (interrupt on completion). */ |
70 | 82 | } __attribute__((packed)) hda_bdl_entry_t; |
71 | 83 |
|
72 | | -/* Verb construction: [31:28] cad, [27:20] nid, [19:8] verb, [7:0] payload */ |
| 84 | +/** |
| 85 | + * Construct a verb value for the CORB or Immediate Command registers. |
| 86 | + * Fields: [31:28] cad, [27:20] nid, [19:8] verb, [7:0] payload. |
| 87 | + */ |
73 | 88 | #define HDA_MAKE_VERB(cad, nid, verb, payload) \ |
74 | 89 | ( ((uint32_t)(cad) & 0xF) << 28 | ((uint32_t)(nid) & 0x7F) << 20 | ((uint32_t)(verb) & 0xFFF) << 8 | ((uint32_t)(payload) & 0xFF) ) |
75 | 90 |
|
76 | | -/* Useful verbs (see spec / OSDev table) */ |
77 | | -#define V_GET_PARAM 0xF00 |
78 | | -#define V_GET_CONN_LIST 0xF02 |
79 | | -#define V_SET_POWER_STATE 0x705 /* data: 0=D0 */ |
80 | | -#define V_SET_CONV_STREAMCH 0x706 /* data: stream tag (7:4), channel (3:0) */ |
81 | | -#define V_SET_PIN_WCTRL 0x707 /* data bits: OUT_EN=bit6, HP_EN=bit7, IN_EN=bit5 */ |
82 | | -#define V_GET_PIN_SENSE 0xF09 |
83 | | -#define V_SET_EAPD_BTL 0x70C /* data bit1=EAPD */ |
84 | | -#define V_GET_DEF_CFG 0xF1C |
85 | | -#define V_SET_CHANNEL_COUNT 0x72D /* data: channels-1 */ |
86 | | -#define V_SET_AMP_GAIN_MUTE 0x003 /* 16-bit payload via immediate data */ |
| 91 | +/* Common verbs */ |
| 92 | +#define V_GET_PARAM 0xF00 /**< Get parameter. */ |
| 93 | +#define V_GET_CONN_LIST 0xF02 /**< Get connection list. */ |
| 94 | +#define V_SET_POWER_STATE 0x705 /**< Set power state; 0 = D0. */ |
| 95 | +#define V_SET_CONV_STREAMCH 0x706 /**< Assign stream/channel. */ |
| 96 | +#define V_SET_PIN_WCTRL 0x707 /**< Set pin widget control. */ |
| 97 | +#define V_GET_PIN_SENSE 0xF09 /**< Get pin sense. */ |
| 98 | +#define V_SET_EAPD_BTL 0x70C /**< Set EAPD/BTL enable. */ |
| 99 | +#define V_GET_DEF_CFG 0xF1C /**< Get default configuration. */ |
| 100 | +#define V_SET_CHANNEL_COUNT 0x72D /**< Set channel count. */ |
| 101 | +#define V_SET_AMP_GAIN_MUTE 0x003 /**< Set amplifier gain/mute. */ |
87 | 102 |
|
88 | 103 | /* GET_PARAM indices */ |
89 | | -#define P_NODE_COUNT 0x04 /* high byte: start node; low byte: count (AFG or func grp) */ |
90 | | -#define P_FUNC_GRP_TYPE 0x05 /* expect 1 = AFG */ |
91 | | -#define P_AW_CAPS 0x09 /* Audio Widget Capabilities (type in bits 23:20) */ |
92 | | -#define P_PIN_CAPS 0x0C |
93 | | - |
94 | | -/* Widget types (P_AW_CAPS bits 23:20) — per HDA spec */ |
95 | | -#define WTYPE_AUDIO_OUT 0x00 |
96 | | -#define WTYPE_AUDIO_IN 0x01 |
97 | | -#define WTYPE_MIXER 0x02 |
98 | | -#define WTYPE_SELECTOR 0x03 |
99 | | -#define WTYPE_PIN_COMPLEX 0x04 |
100 | | -/* (others exist but aren’t needed here: POWER=0x05, VOL_KNOB=0x06, BEEP=0x07, VENDOR=0x0F) */ |
| 104 | +#define P_NODE_COUNT 0x04 /**< Node count (high=start, low=count). */ |
| 105 | +#define P_FUNC_GRP_TYPE 0x05 /**< Function group type; 1=AFG. */ |
| 106 | +#define P_AW_CAPS 0x09 /**< Audio widget capabilities. */ |
| 107 | +#define P_PIN_CAPS 0x0C /**< Pin widget capabilities. */ |
| 108 | + |
| 109 | +/* Widget types (from P_AW_CAPS bits 23:20) */ |
| 110 | +#define WTYPE_AUDIO_OUT 0x00 /**< Audio output converter. */ |
| 111 | +#define WTYPE_AUDIO_IN 0x01 /**< Audio input converter. */ |
| 112 | +#define WTYPE_MIXER 0x02 /**< Mixer. */ |
| 113 | +#define WTYPE_SELECTOR 0x03 /**< Selector. */ |
| 114 | +#define WTYPE_PIN_COMPLEX 0x04 /**< Pin complex. */ |
101 | 115 |
|
102 | 116 | /* Pin caps bits */ |
103 | | -#define PINCAP_OUT (1u << 4) |
104 | | - |
105 | | -/* Default config decode (spec): 31:30 connectivity, 29:24 location, 23:20 default device, 19:16 conn type */ |
106 | | -#define DEFDEV_SPEAKER 0x01 |
107 | | -#define DEFDEV_LINEOUT 0x02 |
108 | | -#define DEFDEV_HP_OUT 0x0F |
109 | | - |
110 | | -/* SDnFMT fields (spec 3.3.41) */ |
111 | | -#define SD_FMT_BASE_48K (0u << 14) |
112 | | -#define SD_FMT_BASE_44K1 (1u << 14) |
113 | | -#define SD_FMT_MULT_X1 (0u << 11) |
114 | | -#define SD_FMT_MULT_X2 (1u << 11) |
115 | | -#define SD_FMT_DIV_1 (0u << 8) |
116 | | -#define SD_FMT_DIV_2 (1u << 8) |
117 | | -/* Bits per sample */ |
118 | | -#define SD_FMT_BITS_16 (1u << 4) |
119 | | -/* Channels: value = (channels-1) */ |
120 | | -#define SD_FMT_CHANS(n) ((uint16_t)(((n) - 1u) & 0x0F)) |
121 | | - |
122 | | -/* Driver state */ |
| 117 | +#define PINCAP_OUT (1 << 4) /**< Pin supports output. */ |
| 118 | + |
| 119 | +/* Default configuration decode values (bits 23:20 default device) */ |
| 120 | +#define DEFDEV_SPEAKER 0x01 /**< Default device: speaker. */ |
| 121 | +#define DEFDEV_LINEOUT 0x02 /**< Default device: line-out. */ |
| 122 | +#define DEFDEV_HP_OUT 0x0F /**< Default device: headphone. */ |
| 123 | + |
| 124 | +/* SDnFMT field helpers */ |
| 125 | +#define SD_FMT_BASE_48K (0 << 14) /**< Base rate 48 kHz. */ |
| 126 | +#define SD_FMT_BASE_44K1 (1 << 14) /**< Base rate 44.1 kHz. */ |
| 127 | +#define SD_FMT_MULT_X1 (0 << 11) /**< Multiplier ×1. */ |
| 128 | +#define SD_FMT_MULT_X2 (1 << 11) /**< Multiplier ×2. */ |
| 129 | +#define SD_FMT_DIV_1 (0 << 8) /**< Divider ÷1. */ |
| 130 | +#define SD_FMT_DIV_2 (1 << 8) /**< Divider ÷2. */ |
| 131 | +#define SD_FMT_BITS_16 (1 << 4) /**< 16-bit samples. */ |
| 132 | +#define SD_FMT_CHANS(n) ((uint16_t)(((n) - 1u) & 0x0F)) /**< Channels = n. */ |
| 133 | + |
| 134 | +/** |
| 135 | + * Driver state for HDA controller and single output stream. |
| 136 | + */ |
123 | 137 | typedef struct { |
124 | | - uint32_t mmio; /* BAR0 MMIO base (mapped) */ |
125 | | - /* CORB/RIRB rings (phys + virt) */ |
126 | | - uint64_t *corb; |
127 | | - uint64_t *rirb; |
128 | | - uint32_t corb_phys; |
129 | | - uint32_t rirb_phys; |
130 | | - uint16_t corb_entries; /* 256 */ |
131 | | - uint16_t rirb_entries; /* 256 */ |
132 | | - |
133 | | - /* Chosen codec/function/wid path */ |
134 | | - uint8_t cad; /* codec address (0..15) */ |
135 | | - uint8_t afg_nid; /* audio function group node id */ |
136 | | - uint8_t dac_nid; /* output converter (DAC) NID */ |
137 | | - uint8_t pin_nid; /* output pin NID */ |
138 | | - |
139 | | - /* Single output stream descriptor we use (first HW output stream) */ |
140 | | - uint8_t out_sd_index; /* 0-based among output SDs */ |
141 | | - uint8_t out_stream_tag; /* 1..15; we use 1 */ |
142 | | - |
143 | | - /* BDL / audio ring */ |
144 | | - hda_bdl_entry_t *bdl; |
145 | | - uint32_t bdl_phys; |
146 | | - uint8_t *buf; |
147 | | - uint32_t buf_phys; |
148 | | - uint32_t bdl_n; /* 32 */ |
149 | | - uint32_t frag_bytes; /* fragment size in bytes */ |
150 | | - uint32_t frag_frames; /* frames per fragment (S16LE stereo => 4 bytes/frame) */ |
151 | | - int tail; /* last valid index in the ring (−1 if empty) */ |
152 | | - bool started; |
153 | | - uint32_t rate_hz; /* 44100 */ |
154 | | - |
| 138 | + uint32_t mmio; /**< BAR0 MMIO base (mapped). */ |
| 139 | + |
| 140 | + /* CORB / RIRB rings */ |
| 141 | + uint64_t *corb; /**< CORB virtual base. */ |
| 142 | + uint64_t *rirb; /**< RIRB virtual base. */ |
| 143 | + uint32_t corb_phys; /**< CORB physical base. */ |
| 144 | + uint32_t rirb_phys; /**< RIRB physical base. */ |
| 145 | + uint16_t corb_entries; /**< CORB entries (typically 256). */ |
| 146 | + uint16_t rirb_entries; /**< RIRB entries (typically 256). */ |
| 147 | + |
| 148 | + /* Chosen codec/function/path */ |
| 149 | + uint8_t cad; /**< Codec address (0..15). */ |
| 150 | + uint8_t afg_nid; /**< Audio function group node id. */ |
| 151 | + uint8_t dac_nid; /**< DAC node id. */ |
| 152 | + uint8_t pin_nid; /**< Pin node id. */ |
| 153 | + |
| 154 | + /* Output stream descriptor */ |
| 155 | + uint8_t out_sd_index; /**< Index of output stream descriptor. */ |
| 156 | + uint8_t out_stream_tag; /**< Stream tag (1..15). */ |
| 157 | + |
| 158 | + /* Buffer descriptor list (BDL) and audio ring buffer */ |
| 159 | + hda_bdl_entry_t *bdl; /**< BDL virtual base. */ |
| 160 | + uint32_t bdl_phys; /**< BDL physical base. */ |
| 161 | + uint8_t *buf; /**< Audio buffer virtual base. */ |
| 162 | + uint32_t buf_phys; /**< Audio buffer physical base. */ |
| 163 | + uint32_t bdl_n; /**< Number of BDL entries. */ |
| 164 | + uint32_t frag_bytes; /**< Fragment size in bytes. */ |
| 165 | + uint32_t frag_frames; /**< Frames per fragment (4 bytes per stereo S16 frame). */ |
| 166 | + int tail; /**< Last valid BDL index; −1 if empty. */ |
| 167 | + bool started; /**< Stream running state. */ |
| 168 | + uint32_t rate_hz; /**< Current sample rate. */ |
155 | 169 | } hda_dev_t; |
156 | 170 |
|
157 | | -/* Codec topology discovery (pick DAC + output Pin) */ |
| 171 | +/** |
| 172 | + * Simple node range (start NID, count). |
| 173 | + * Used during codec topology discovery. |
| 174 | + */ |
158 | 175 | typedef struct { |
159 | | - uint8_t start_nid; |
160 | | - uint8_t count; |
| 176 | + uint8_t start_nid; /**< Starting node id. */ |
| 177 | + uint8_t count; /**< Number of nodes. */ |
161 | 178 | } nid_range_t; |
162 | | - |
|
0 commit comments