Skip to content

Commit be4d7e9

Browse files
working hda
1 parent 7442689 commit be4d7e9

2 files changed

Lines changed: 162 additions & 148 deletions

File tree

modules/hda/hda.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,16 @@
44
* @copyright Copyright (c) 2012-2025
55
*
66
* Intel High Definition Audio (Azalia) output driver
7-
* Contract matches AC'97 module: async SW FIFO push, idle drain into HW ring.
87
*
98
* References:
109
* - Intel High Definition Audio Specification Rev. 1.0a
1110
* (section 3.3.* stream regs, section 3.4 ICOI/ICII/ICIS,
12-
* CORB/RIRB, SDnFMT encoding, BDL alignment) and widget verbs. (intel.com PDF)
11+
* CORB/RIRB, SDnFMT encoding, BDL alignment) and widget verbs
1312
* - OSDev HDA overview for register map & verb list
1413
*/
1514
#include <kernel.h>
1615
#include "hda.h"
1716

18-
static int hda_dbg = 1; /* set to 0 to silence */
19-
#define HDA_D(fmt, ...) do { if (hda_dbg) dprintf("hda: " fmt "\n", ##__VA_ARGS__); } while (0)
20-
2117
static hda_dev_t hda;
2218
static int16_t *s_q_pcm = NULL;
2319
static size_t s_q_cap_fr = 0, s_q_len_fr = 0, s_q_head_fr = 0;
@@ -51,8 +47,6 @@ static inline void hda_mmio_fence(void) {
5147
mmio_r32(HDA_REG_GCTL);
5248
}
5349

54-
55-
5650
static inline void tiny_delay(void) {
5751
for (int i = 0; i < 64; i++) {
5852
io_wait();
@@ -452,7 +446,7 @@ static bool hda_pick_output_path(uint8_t cad, nid_range_t wr, uint8_t *out_dac,
452446
}
453447

454448
static void hda_dump_topology(uint8_t cad, uint8_t afg, nid_range_t wr) {
455-
HDA_D("HDA topology: cad=%u afg=0x%02x nodes [%u..%u]", cad, afg, wr.start_nid, (uint8_t) (wr.start_nid + wr.count - 1));
449+
dprintf("HDA topology: cad=%u afg=0x%02x nodes [%u..%u]", cad, afg, wr.start_nid, (uint8_t) (wr.start_nid + wr.count - 1));
456450
for (uint8_t n = 0; n < wr.count; n++) {
457451
uint8_t nid = wr.start_nid + n;
458452
uint8_t t;
@@ -466,7 +460,7 @@ static void hda_dump_topology(uint8_t cad, uint8_t afg, nid_range_t wr) {
466460
uint32_t cfg = 0;
467461
hda_cmd(cad, nid, V_GET_DEF_CFG, 0, &cfg);
468462
uint8_t dev = (uint8_t) ((cfg >> 20) & 0x0F);
469-
HDA_D("NID 0x%02x: PIN caps=0x%08lx defdev=%u", nid, (unsigned long) pc, dev);
463+
dprintf("NID 0x%02x: PIN caps=0x%08lx defdev=%u", nid, (unsigned long) pc, dev);
470464

471465
uint8_t peers[64];
472466
uint32_t n_peers = hda_get_conn_list(cad, nid, peers, (uint32_t) sizeof(peers));
@@ -475,11 +469,11 @@ static void hda_dump_topology(uint8_t cad, uint8_t afg, nid_range_t wr) {
475469
uint8_t pt;
476470
uint32_t pc2;
477471
if (hda_widget_type(cad, p, &pt, &pc2)) {
478-
HDA_D(" -> 0x%02x type=%u", p, pt);
472+
dprintf(" -> 0x%02x type=%u", p, pt);
479473
}
480474
}
481475
} else {
482-
HDA_D("NID 0x%02x: type=%u caps=0x%08lx", nid, t, (unsigned long) c);
476+
dprintf("NID 0x%02x: type=%u caps=0x%08lx", nid, t, (unsigned long) c);
483477
}
484478
}
485479
}
@@ -611,10 +605,14 @@ static void hda_sd_reset(uint32_t sdbase) {
611605
/* reset */
612606
ctl0 |= SD_CTL_SRST;
613607
mmio_w8(sdbase + SD_CTL0, ctl0);
614-
for (int i = 0; i < 1000 && !(mmio_r8(sdbase + SD_CTL0) & SD_CTL_SRST); i++) { tiny_delay(); }
608+
for (int i = 0; i < 1000 && !(mmio_r8(sdbase + SD_CTL0) & SD_CTL_SRST); i++) {
609+
tiny_delay();
610+
}
615611
ctl0 &= ~SD_CTL_SRST;
616612
mmio_w8(sdbase + SD_CTL0, ctl0);
617-
for (int i = 0; i < 1000 && (mmio_r8(sdbase + SD_CTL0) & SD_CTL_SRST); i++) { tiny_delay(); }
613+
for (int i = 0; i < 1000 && (mmio_r8(sdbase + SD_CTL0) & SD_CTL_SRST); i++) {
614+
tiny_delay();
615+
}
618616
/* clear status */
619617
mmio_w8(sdbase + SD_STS, mmio_r8(sdbase + SD_STS));
620618
}

modules/hda/hda.h

Lines changed: 151 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,178 @@
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+
*/
18
#pragma once
29
#include <stdint.h>
310
#include <stdbool.h>
411

12+
/** PCI class code for Intel High Definition Audio controllers. */
513
#define HDA_PCI_CLASSC 0x0403
614

715
/* 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. */
4958

5059
/* 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. */
6069

6170
/* 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. */
6473

65-
/* BDL entry (HDA): 16 bytes */
74+
/**
75+
* Buffer Descriptor List entry (HDA).
76+
* Each entry is 16 bytes, aligned to 16.
77+
*/
6678
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). */
7082
} __attribute__((packed)) hda_bdl_entry_t;
7183

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+
*/
7388
#define HDA_MAKE_VERB(cad, nid, verb, payload) \
7489
( ((uint32_t)(cad) & 0xF) << 28 | ((uint32_t)(nid) & 0x7F) << 20 | ((uint32_t)(verb) & 0xFFF) << 8 | ((uint32_t)(payload) & 0xFF) )
7590

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. */
87102

88103
/* 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. */
101115

102116
/* 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+
*/
123137
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. */
155169
} hda_dev_t;
156170

157-
/* Codec topology discovery (pick DAC + output Pin) */
171+
/**
172+
* Simple node range (start NID, count).
173+
* Used during codec topology discovery.
174+
*/
158175
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. */
161178
} nid_range_t;
162-

0 commit comments

Comments
 (0)