1#include "lala/lala.h"
2#include "ichaudio.h"
3#include "io.h"
4
5status_t ichaudio_attach(audio_drv_t *drv, void **cookie);
6status_t ichaudio_powerctl(audio_drv_t *drv, void *cookie, int op);
7status_t ichaudio_detach(audio_drv_t *drv, void *cookie);
8status_t ichaudio_stream_attach(audio_drv_t *drv, void *cookie, int stream_id);
9status_t ichaudio_stream_detach(audio_drv_t *drv, void *cookie, int stream_id);
10status_t ichaudio_stream_control(audio_drv_t *drv, void *cookie, int stream_id, int op);
11status_t ichaudio_stream_set_buffers(audio_drv_t *drv, void *cookie, int stream_id, uint32 *buffer_size, stream_buffer_desc_t *desc);
12status_t ichaudio_stream_set_frame_rate(audio_drv_t *drv, void *cookie, int stream_id, uint32 *frame_rate);
13
14void stream_reset(ichaudio_cookie *cookie, uint32 regbase);
15
16
17pci_id_table_t ichaudio_id_table[] = {
18	{ 0x8086, 0x7195, -1, -1, -1, -1, -1, "Intel 82443MX AC97 audio" },
19	{ 0x8086, 0x2415, -1, -1, -1, -1, -1, "Intel 82801AA (ICH) AC97 audio" },
20	{ 0x8086, 0x2425, -1, -1, -1, -1, -1, "Intel 82801AB (ICH0) AC97 audio" },
21	{ 0x8086, 0x2445, -1, -1, -1, -1, -1, "Intel 82801BA (ICH2) AC97 audio" },
22	{ 0x8086, 0x2485, -1, -1, -1, -1, -1, "Intel 82801CA (ICH3) AC97 audio" },
23	{ 0x8086, 0x24C5, -1, -1, -1, -1, -1, "Intel 82801DB (ICH4) AC97 audio", (void *)TYPE_ICH4 },
24	{ 0x8086, 0x24D5, -1, -1, -1, -1, -1, "Intel 82801EB (ICH5)  AC97 audio", (void *)TYPE_ICH4 },
25	{ 0x1039, 0x7012, -1, -1, -1, -1, -1, "SiS SI7012 AC97 audio", (void *)TYPE_SIS7012 },
26	{ 0x10DE, 0x01B1, -1, -1, -1, -1, -1, "NVIDIA nForce (MCP)  AC97 audio" },
27	{ 0x10DE, 0x006A, -1, -1, -1, -1, -1, "NVIDIA nForce 2 (MCP2)  AC97 audio" },
28	{ 0x10DE, 0x00DA, -1, -1, -1, -1, -1, "NVIDIA nForce 3 (MCP3)  AC97 audio" },
29	{ 0x1022, 0x764D, -1, -1, -1, -1, -1, "AMD AMD8111 AC97 audio" },
30	{ 0x1022, 0x7445, -1, -1, -1, -1, -1, "AMD AMD768 AC97 audio" },
31	{ 0x1103, 0x0004, -1, -1, -1, -1, -1, "Highpoint HPT372 RAID" },
32	{ 0x1095, 0x3112, -1, -1, -1, -1, -1, "Silicon Image SATA Si3112" },
33	{ 0x8086, 0x244b, -1, -1, -1, -1, -1, "Intel IDE controller" },
34	{ 0x8979, 0x6456, -1, -1, -1, -1, -1, "does not exist" },
35	{ /* empty = end */}
36};
37
38
39driver_info_t driver_info = {
40	.basename		= "audio/lala/ichaudio",
41	.pci_id_table	= ichaudio_id_table,
42	.attach			= ichaudio_attach,
43	.detach			= ichaudio_detach,
44	.powerctl		= ichaudio_powerctl,
45};
46
47enum {
48	STREAM_PO = 0,
49	STREAM_PI = 1,
50};
51const uint32 STREAM_REGBASE[2] = { ICH_REG_PO_BASE, ICH_REG_PI_BASE };
52
53
54stream_info_t po_stream = {
55	.flags				= B_PLAYBACK_STREAM | B_BUFFER_SIZE_EXPONETIAL | B_SAMPLE_TYPE_INT16,
56	.cookie_size		= sizeof(ichaudio_cookie),
57	.sample_bits		= 16,
58	.channel_count		= 2,
59	.channel_mask		= B_CHANNEL_LEFT | B_CHANNEL_RIGHT,
60	.frame_rate_min 	= 0, // is setup later after device probing
61	.frame_rate_max		= 0, // is setup later after device probing
62	.frame_rate_mask	= 0, // is setup later after device probing
63	.buffer_size_min	= 256,
64	.buffer_size_max	= 32768,
65	.buffer_count		= 2,
66	.attach				= ichaudio_stream_attach,
67	.detach				= ichaudio_stream_detach,
68	.control			= ichaudio_stream_control,
69	.set_buffers		= ichaudio_stream_set_buffers,
70	.set_frame_rate		= ichaudio_stream_set_frame_rate,
71};
72
73
74stream_info_t pi_stream = {
75	.flags				= B_RECORDING_STREAM | B_BUFFER_SIZE_EXPONETIAL | B_SAMPLE_TYPE_INT16,
76	.sample_bits		= 16,
77	.channel_count		= 2,
78	.channel_mask		= B_CHANNEL_LEFT | B_CHANNEL_RIGHT,
79	.frame_rate_min 	= 0, // is setup later after device probing
80	.frame_rate_max		= 0, // is setup later after device probing
81	.frame_rate_mask	= 0, // is setup later after device probing
82	.buffer_size_min	= 256,
83	.buffer_size_max	= 32768,
84	.buffer_count		= 2,
85	.attach				= ichaudio_stream_attach,
86	.detach				= ichaudio_stream_detach,
87	.control			= ichaudio_stream_control,
88	.set_buffers		= ichaudio_stream_set_buffers,
89	.set_frame_rate		= ichaudio_stream_set_frame_rate,
90};
91
92status_t
93ichaudio_attach(audio_drv_t *drv, void **_cookie)
94{
95	ichaudio_cookie *cookie;
96	uint32 value;
97	int i;
98	bigtime_t start;
99	bool s0cr, s1cr, s2cr;
100
101	dprintf("ichaudio_attach\n");
102
103	*_cookie = cookie = (ichaudio_cookie *) malloc(sizeof(ichaudio_cookie));
104
105	cookie->pci = drv->pci;
106	cookie->flags = (uint32)drv->param;
107
108	// For old ICHs enable programmed IO and busmaster access,
109	// for ICH4 and up enable memory mapped IO and busmaster access
110	value = drv->pci->read_pci_config(drv->bus, drv->device, drv->function, PCI_command, 2);
111	value |= PCI_PCICMD_BME | (cookie->flags & TYPE_ICH4) ? PCI_PCICMD_MSE : PCI_PCICMD_IOS;
112	drv->pci->write_pci_config(drv->bus, drv->device, drv->function, PCI_command, 2, value);
113
114	// get IRQ, we can compensate it later if IRQ is not available (hack!)
115	cookie->irq = drv->pci->read_pci_config(drv->bus, drv->device, drv->function, PCI_interrupt_line, 1);
116	if (cookie->irq == 0xff) cookie->irq = 0;
117	if (cookie->irq == 0) dprintf("ichaudio_attach: no interrupt configured\n");
118
119	if (cookie->flags & TYPE_ICH4) {
120		// memory mapped access
121		uint32 phys_mmbar = PCI_address_memory_32_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x18, 4);
122		uint32 phys_mbbar = PCI_address_memory_32_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x1C, 4);
123		if (!phys_mmbar || !phys_mbbar) {
124			dprintf("ichaudio_attach: memory mapped io unconfigured\n");
125			goto err;
126		}
127		// map into memory
128		cookie->area_mmbar = map_mem(&cookie->mmbar, (void *)phys_mmbar, ICH4_MMBAR_SIZE, 0, "ichaudio mmbar io");
129		cookie->area_mbbar = map_mem(&cookie->mbbar, (void *)phys_mbbar, ICH4_MBBAR_SIZE, 0, "ichaudio mbbar io");
130		if (cookie->area_mmbar < B_OK || cookie->area_mbbar < B_OK) {
131			dprintf("ichaudio_attach: mapping io into memory failed\n");
132			goto err;
133		}
134	} else {
135		// pio access
136		cookie->nambar = PCI_address_io_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x10, 4);
137		cookie->nabmbar = PCI_address_io_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x14, 4);
138		if (!cookie->nambar || !cookie->nabmbar) {
139			dprintf("ichaudio_attach: io unconfigured\n");
140			goto err;
141		}
142	}
143
144	/* We don't do a cold reset here, because this would reset general purpose
145	 * IO pins of the controller. These pins can be used by the machine vendor
146	 * to control external amplifiers, and resetting them prevents audio output
147	 * on some notebooks, like "Compaq Presario 2700".
148	 * If a cold reset is still in progress, we need to finish it by writing
149	 * a 1 to the cold reset bit (CNT_COLD). We do not preserve others bits,
150	 * since this can have strange effects (at least on my system, playback
151	 * speed is 320% in this case).
152	 * Doing a warm reset it required to leave certain power down modes. Warm
153	 * reset does also reset GPIO pins, but the ICH hardware does only execute
154	 * the reset request if BIT_CLOCK is not running and if it's really required.
155	 */
156	LOG(("reset starting, ICH_REG_GLOB_CNT = 0x%08lx\n", ich_reg_read_32(cookie, ICH_REG_GLOB_CNT)));
157	start = system_time();
158	// finish cold reset by writing a 1 and clear all other bits to 0
159	ich_reg_write_32(cookie, ICH_REG_GLOB_CNT, CNT_COLD);
160	ich_reg_read_32(cookie, ICH_REG_GLOB_CNT); // force PCI-to-PCI bridge cache flush
161	snooze(20000);
162	// request warm reset by setting the bit, it will clear when reset is done
163	ich_reg_write_32(cookie, ICH_REG_GLOB_CNT, ich_reg_read_32(cookie, ICH_REG_GLOB_CNT) | CNT_WARM);
164	ich_reg_read_32(cookie, ICH_REG_GLOB_CNT); // force PCI-to-PCI bridge cache flush
165	snooze(20000);
166	// wait up to 1 second for warm reset to be finished
167	for (i = 0; i < 20; i++) {
168		value = ich_reg_read_32(cookie, ICH_REG_GLOB_CNT);
169		if ((value & CNT_WARM) == 0 && (value & CNT_COLD) != 0)
170			break;
171		snooze(50000);
172	}
173	if (i == 20) {
174		LOG(("reset failed, ICH_REG_GLOB_CNT = 0x%08lx\n", value));
175		goto err;
176	}
177	LOG(("reset finished after %Ld, ICH_REG_GLOB_CNT = 0x%08lx\n", system_time() - start, value));
178
179	/* detect which codecs are ready */
180	s0cr = s1cr = s2cr = false;
181	start = system_time();
182	do {
183		value = ich_reg_read_32(cookie, ICH_REG_GLOB_STA);
184		if (!s0cr && (value & STA_S0CR)) {
185			s0cr = true;
186			LOG(("AC_SDIN0 codec ready after %Ld us\n", system_time() - start));
187		}
188		if (!s1cr && (value & STA_S1CR)) {
189			s1cr = true;
190			LOG(("AC_SDIN1 codec ready after %Ld us\n", system_time() - start));
191		}
192		if (!s2cr && (value & STA_S2CR)) {
193			s2cr = true;
194			LOG(("AC_SDIN2 codec ready after %Ld us\n", system_time() - start));
195		}
196		snooze(50000);
197	} while ((system_time() - start) < 1000000);
198
199	if (!s0cr) {
200		LOG(("AC_SDIN0 codec not ready\n"));
201	}
202	if (!s1cr) {
203		LOG(("AC_SDIN1 codec not ready\n"));
204	}
205	if (!s2cr) {
206		LOG(("AC_SDIN2 codec not ready\n"));
207	}
208
209	if (!s0cr && !s1cr && !s2cr) {
210		PRINT(("compatible chipset found, but no codec ready!\n"));
211		goto err;
212	}
213
214	if (cookie->flags & TYPE_ICH4) {
215		/* we are using a ICH4 chipset, and assume that the codec beeing ready
216		 * is the primary one.
217		 */
218		uint8 sdin;
219		uint16 reset;
220		uint8 id;
221		reset = ich_codec_read(cookie, 0x00);	/* access the primary codec */
222		if (reset == 0 || reset == 0xFFFF) {
223			LOG(("primary codec not present\n"));
224		} else {
225			sdin = 0x02 & ich_reg_read_8(cookie, ICH_REG_SDM);
226			id = 0x02 & (ich_codec_read(cookie, 0x00 + 0x28) >> 14);
227			LOG(("primary codec id %d is connected to AC_SDIN%d\n", id, sdin));
228		}
229		reset = ich_codec_read(cookie, 0x80);	/* access the secondary codec */
230		if (reset == 0 || reset == 0xFFFF) {
231			LOG(("secondary codec not present\n"));
232		} else {
233			sdin = 0x02 & ich_reg_read_8(cookie, ICH_REG_SDM);
234			id = 0x02 & (ich_codec_read(cookie, 0x80 + 0x28) >> 14);
235			LOG(("secondary codec id %d is connected to AC_SDIN%d\n", id, sdin));
236		}
237		reset = ich_codec_read(cookie, 0x100);	/* access the tertiary codec */
238		if (reset == 0 || reset == 0xFFFF) {
239			LOG(("tertiary codec not present\n"));
240		} else {
241			sdin = 0x02 & ich_reg_read_8(cookie, ICH_REG_SDM);
242			id = 0x02 & (ich_codec_read(cookie, 0x100 + 0x28) >> 14);
243			LOG(("tertiary codec id %d is connected to AC_SDIN%d\n", id, sdin));
244		}
245
246		/* XXX this may be wrong */
247		ich_reg_write_8(cookie, ICH_REG_SDM, (ich_reg_read_8(cookie, ICH_REG_SDM) & 0x0F) | 0x08 | 0x90);
248	} else {
249		/* we are using a pre-ICH4 chipset, that has a fixed mapping of
250		 * AC_SDIN0 = primary, AC_SDIN1 = secondary codec.
251		 */
252		if (!s0cr && s2cr) {
253			// is is unknown if this really works, perhaps we should better abort here
254			LOG(("primary codec doesn't seem to be available, using secondary!\n"));
255			cookie->codecoffset = 0x80;
256		}
257	}
258
259	create_stream(drv, STREAM_PO, &po_stream);
260	create_stream(drv, STREAM_PI, &pi_stream);
261
262	return B_OK;
263
264err:
265	// delete streams
266	delete_stream(drv, STREAM_PO);
267	delete_stream(drv, STREAM_PI);
268	// unmap io memory
269	if (cookie->area_mmbar > 0) delete_area(cookie->area_mmbar);
270	if (cookie->area_mbbar > 0) delete_area(cookie->area_mbbar);
271	free(cookie);
272	return B_ERROR;
273}
274
275
276status_t
277ichaudio_detach(audio_drv_t *drv, void *_cookie)
278{
279	ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie;
280
281	dprintf("ichaudio_detach\n");
282
283	// delete streams
284	delete_stream(drv, STREAM_PO);
285	delete_stream(drv, STREAM_PI);
286	// unmap io memory
287	if (cookie->area_mmbar > 0) delete_area(cookie->area_mmbar);
288	if (cookie->area_mbbar > 0) delete_area(cookie->area_mbbar);
289	free(cookie);
290	return B_OK;
291}
292
293
294status_t
295ichaudio_powerctl(audio_drv_t *drv, void *_cookie, int op)
296{
297	return B_ERROR;
298}
299
300void
301stream_reset(ichaudio_cookie *cookie, uint32 regbase)
302{
303	int i;
304
305	ich_reg_write_8(cookie, regbase + ICH_REG_X_CR, 0);
306	ich_reg_read_8(cookie, regbase + ICH_REG_X_CR); // force PCI-to-PCI bridge cache flush
307	snooze(10000); // 10 ms
308	ich_reg_write_8(cookie, regbase + ICH_REG_X_CR, CR_RR);
309	for (i = 0; i < 100; i++) {
310		uint8 cr = ich_reg_read_8(cookie, regbase + ICH_REG_X_CR);
311		if (cr == 0) {
312			LOG(("channel reset finished, %d\n",i));
313			return;
314		}
315		snooze(100);
316	}
317	LOG(("channel reset failed after 10ms\n"));
318}
319
320status_t
321ichaudio_stream_attach(audio_drv_t *drv, void *_cookie, int stream_id)
322{
323	ichaudio_cookie *cookie = (ichaudio_cookie *) _cookie;
324	ichaudio_stream *stream = &cookie->stream[stream_id];
325	void *bd_virt_base;
326	void *bd_phys_base;
327	int i;
328
329	stream->regbase = STREAM_REGBASE[stream_id];
330	stream->lastindex = 0;
331	stream->processed_samples = 0;
332
333	stream_reset(cookie, stream->regbase);
334
335	// allocate memory for buffer descriptors
336	stream->bd_area = alloc_mem(&bd_virt_base, &bd_phys_base, ICH_BD_COUNT * sizeof(ich_bd), 0, "ich_ac97 buffer descriptor");
337	if (stream->bd_area < B_OK)
338		goto err;
339
340	// set physical buffer descriptor base address
341	ich_reg_write_32(cookie, stream->regbase, (uint32)bd_phys_base);
342
343	// setup descriptor pointers
344	for (i = 0; i < ICH_BD_COUNT; i++)
345		stream->bd[i] = (ich_bd *) ((char *)bd_virt_base + i * sizeof(ich_bd));
346
347	return B_OK;
348
349err:
350	return B_ERROR;
351}
352
353
354status_t
355ichaudio_stream_detach(audio_drv_t *drv, void *_cookie, int stream_id)
356{
357	ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie;
358	ichaudio_stream *stream = &cookie->stream[stream_id];
359
360	stream_reset(cookie, stream->regbase);
361
362	if (stream->buffer_area > 0) delete_area(stream->buffer_area);
363	if (stream->bd_area > 0) delete_area(stream->bd_area);
364
365	return B_OK;
366}
367
368
369status_t
370ichaudio_stream_control(audio_drv_t *drv, void *_cookie, int stream_id, int op)
371{
372}
373
374
375status_t
376ichaudio_stream_set_buffers(audio_drv_t *drv, void *_cookie, int stream_id, uint32 *buffer_size, stream_buffer_desc_t *desc)
377{
378	ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie;
379	ichaudio_stream *stream = &cookie->stream[stream_id];
380
381	void *buffer_virt_base;
382	void *buffer_phys_base;
383	area_id buffer_area;
384	int i;
385
386	// round down (could force another size here)
387	*buffer_size &= ~3;
388
389	// allocate memory buffers
390	buffer_area = alloc_mem(&buffer_virt_base, &buffer_phys_base, 2 * *buffer_size, B_READ_AREA | B_WRITE_AREA, "ich_ac97 buffers");
391
392	// report buffers
393	desc[0].base = (char *)buffer_virt_base;
394	desc[0].stride = 4;
395	desc[1].base = (char *)buffer_virt_base + 2;
396	desc[1].stride = 4;
397
398	// initalize buffer descriptors
399	for (i = 0; i < ICH_BD_COUNT; i++) {
400		stream->bd[i]->buffer = (uint32)buffer_phys_base + (i % 2) * *buffer_size;
401		stream->bd[i]->length = *buffer_size / GET_HW_SAMPLE_SIZE(cookie);
402		stream->bd[i]->flags = ICH_BDC_FLAG_IOC;
403	}
404
405	// free old buffer memory
406	if (stream->buffer_area > 0)
407		delete_area(stream->buffer_area);
408
409	stream->buffer_area = buffer_area;
410	return B_OK;
411}
412
413
414status_t
415ichaudio_stream_set_frame_rate(audio_drv_t *drv, void *_cookie, int stream_id, uint32 *frame_rate)
416{
417}
418
419