1/*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *	J��r��me Duval (korli@users.berlios.de)
7 */
8
9
10#include "driver.h"
11
12#define ALIGN(size, align)		(((size) + align - 1) & ~(align - 1))
13#define PAGE_ALIGN(size)	(((size) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1))
14
15#define STREAM_CMD			0x0		/* Command */
16#define STREAM_STATUS			0x1		/* IRQ Status */
17#define STREAM_PRD			0x4		/* PRD Table Address */
18
19static const struct {
20	uint32 multi_rate;
21	uint32 rate;
22} kRates[] = {
23	{B_SR_8000, 8000},
24	{B_SR_11025, 11025},
25	{B_SR_16000, 16000},
26	{B_SR_22050, 22050},
27	{B_SR_32000, 32000},
28	{B_SR_44100, 44100},
29	{B_SR_48000, 48000},
30	{B_SR_88200, 88200},
31	{B_SR_96000, 96000},
32	{B_SR_176400, 176400},
33	{B_SR_192000, 192000},
34};
35
36static int
37geode_codec_wait(geode_controller *controller)
38{
39	int i;
40
41#define GCSCAUDIO_WAIT_READY_CODEC_TIMEOUT	500
42	for (i = GCSCAUDIO_WAIT_READY_CODEC_TIMEOUT; (i >= 0)
43	    && (controller->Read32(ACC_CODEC_CNTL) & ACC_CODEC_CNTL_CMD_NEW); i--)
44		snooze(10);
45
46	return (i < 0);
47}
48
49uint16
50geode_codec_read(geode_controller *controller, uint8 regno)
51{
52	int i;
53	uint32 v;
54	ASSERT(regno >= 0);
55
56	controller->Write32(ACC_CODEC_CNTL,
57		ACC_CODEC_CNTL_READ_CMD | ACC_CODEC_CNTL_CMD_NEW |
58		ACC_CODEC_REG2ADDR(regno));
59
60	if (geode_codec_wait(controller) != B_OK) {
61		dprintf("codec busy (2)\n");
62		return 0xffff;
63	}
64
65#define GCSCAUDIO_READ_CODEC_TIMEOUT	50
66	for (i = GCSCAUDIO_READ_CODEC_TIMEOUT; i >= 0; i--) {
67		v = controller->Read32(ACC_CODEC_STATUS);
68		if ((v & ACC_CODEC_STATUS_STS_NEW) &&
69		    (ACC_CODEC_ADDR2REG(v) == regno))
70			break;
71
72		snooze(10);
73	}
74
75	if (i < 0) {
76		dprintf("codec busy (3)\n");
77		return 0xffff;
78	}
79
80	return v;
81}
82
83void
84geode_codec_write(geode_controller *controller, uint8 regno, uint16 value)
85{
86	ASSERT(regno >= 0);
87
88	controller->Write32(ACC_CODEC_CNTL,
89	    ACC_CODEC_CNTL_WRITE_CMD |
90	    ACC_CODEC_CNTL_CMD_NEW |
91	    ACC_CODEC_REG2ADDR(regno) |
92	    (value & ACC_CODEC_CNTL_CMD_DATA_MASK));
93
94	if (geode_codec_wait(controller) != B_OK) {
95		dprintf("codec busy (4)\n");
96	}
97}
98
99
100//! Called with interrupts off
101static void
102stream_handle_interrupt(geode_controller* controller, geode_stream* stream)
103{
104	uint8 status;
105	uint32 position, bufferSize;
106
107	if (!stream->running)
108		return;
109
110	status = stream->Read8(STREAM_STATUS);
111
112	if (status & ACC_BMx_STATUS_BM_EOP_ERR) {
113		dprintf("geode: stream status bus master error\n");
114	}
115	if (status & ACC_BMx_STATUS_EOP) {
116		dprintf("geode: stream status end of page\n");
117	}
118
119	position = controller->Read32(ACC_BM0_PNTR + stream->dma_offset);
120	bufferSize = ALIGN(stream->sample_size * stream->num_channels * stream->buffer_length, 128);
121
122	// Buffer Completed Interrupt
123	acquire_spinlock(&stream->lock);
124
125	stream->real_time = system_time();
126	stream->frames_count += stream->buffer_length;
127	stream->buffer_cycle = 1 - (position / (bufferSize + 1)); // added 1 to avoid having 2
128
129	release_spinlock(&stream->lock);
130
131	release_sem_etc(stream->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
132}
133
134
135static int32
136geode_interrupt_handler(geode_controller* controller)
137{
138	uint16 intr = controller->Read16(ACC_IRQ_STATUS);
139	if (intr == 0)
140		return B_UNHANDLED_INTERRUPT;
141
142	for (uint32 index = 0; index < GEODE_MAX_STREAMS; index++) {
143		if (controller->streams[index]
144			&& (intr & controller->streams[index]->status) != 0) {
145			stream_handle_interrupt(controller,
146				controller->streams[index]);
147		}
148	}
149
150	return B_HANDLED_INTERRUPT;
151}
152
153
154static status_t
155reset_controller(geode_controller* controller)
156{
157	controller->Write32(ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST
158	    | ACC_CODEC_CNTL_CMD_NEW);
159
160	if (geode_codec_wait(controller) != B_OK) {
161		dprintf("codec reset busy (1)\n");
162	}
163
164	// stop streams
165
166	// stop DMA
167
168	// reset DMA position buffer
169
170	return B_OK;
171}
172
173//	#pragma mark - public stream functions
174
175
176void
177geode_stream_delete(geode_stream* stream)
178{
179	if (stream->buffer_ready_sem >= B_OK)
180		delete_sem(stream->buffer_ready_sem);
181
182	if (stream->buffer_area >= B_OK)
183		delete_area(stream->buffer_area);
184
185	if (stream->buffer_descriptors_area >= B_OK)
186		delete_area(stream->buffer_descriptors_area);
187
188	free(stream);
189}
190
191
192geode_stream*
193geode_stream_new(geode_controller* controller, int type)
194{
195	geode_stream* stream = (geode_stream*)calloc(1, sizeof(geode_stream));
196	if (stream == NULL)
197		return NULL;
198
199	stream->buffer_ready_sem = B_ERROR;
200	stream->buffer_area = B_ERROR;
201	stream->buffer_descriptors_area = B_ERROR;
202	stream->type = type;
203	stream->controller = controller;
204
205	switch (type) {
206		case STREAM_PLAYBACK:
207			stream->status = ACC_IRQ_STATUS_BM0_IRQ_STS;
208			stream->offset = 0;
209			stream->dma_offset = 0;
210			stream->ac97_rate_reg = AC97_PCM_FRONT_DAC_RATE;
211			break;
212
213		case STREAM_RECORD:
214			stream->status = ACC_IRQ_STATUS_BM1_IRQ_STS;
215			stream->offset = 0x8;
216			stream->dma_offset = 0x4;
217			stream->ac97_rate_reg = AC97_PCM_L_R_ADC_RATE;
218			break;
219
220		default:
221			dprintf("%s: Unknown stream type %d!\n", __func__, type);
222			free(stream);
223			stream = NULL;
224	}
225
226	controller->streams[controller->num_streams++] = stream;
227	return stream;
228}
229
230
231/*!	Starts a stream's DMA engine, and enables generating and receiving
232	interrupts for this stream.
233*/
234status_t
235geode_stream_start(geode_stream* stream)
236{
237	uint8 value;
238	dprintf("geode_stream_start()\n");
239	stream->buffer_ready_sem = create_sem(0, stream->type == STREAM_PLAYBACK
240		? "geode_playback_sem" : "geode_record_sem");
241	if (stream->buffer_ready_sem < B_OK)
242		return stream->buffer_ready_sem;
243
244	if (stream->type == STREAM_PLAYBACK)
245		value = ACC_BMx_CMD_WRITE;
246	else
247		value = ACC_BMx_CMD_READ;
248
249	stream->Write8(STREAM_CMD, value | ACC_BMx_CMD_BYTE_ORD_EL
250		| ACC_BMx_CMD_BM_CTL_ENABLE);
251
252	stream->running = true;
253	return B_OK;
254}
255
256
257/*!	Stops the stream's DMA engine, and turns off interrupts for this
258	stream.
259*/
260status_t
261geode_stream_stop(geode_stream* stream)
262{
263	dprintf("geode_stream_stop()\n");
264	stream->Write8(STREAM_CMD, ACC_BMx_CMD_BM_CTL_DISABLE);
265
266	stream->running = false;
267	delete_sem(stream->buffer_ready_sem);
268	stream->buffer_ready_sem = -1;
269
270	return B_OK;
271}
272
273
274status_t
275geode_stream_setup_buffers(geode_stream* stream, const char* desc)
276{
277	uint32 bufferSize, alloc;
278	uint32 index;
279	physical_entry pe;
280	struct acc_prd* bufferDescriptors;
281	uint8* buffer;
282	status_t rc;
283
284	/* Clear previously allocated memory */
285	if (stream->buffer_area >= B_OK) {
286		delete_area(stream->buffer_area);
287		stream->buffer_area = B_ERROR;
288	}
289
290	if (stream->buffer_descriptors_area >= B_OK) {
291		delete_area(stream->buffer_descriptors_area);
292		stream->buffer_descriptors_area = B_ERROR;
293	}
294
295	/* Calculate size of buffer (aligned to 128 bytes) */
296	bufferSize = stream->sample_size * stream->num_channels
297		* stream->buffer_length;
298	bufferSize = ALIGN(bufferSize, 128);
299
300	dprintf("geode: sample size %" B_PRIu32 ", num channels %" B_PRIu32 ", buffer length %"
301			B_PRIu32 "\n",
302		stream->sample_size, stream->num_channels, stream->buffer_length);
303
304	/* Calculate total size of all buffers (aligned to size of B_PAGE_SIZE) */
305	alloc = bufferSize * stream->num_buffers;
306	alloc = PAGE_ALIGN(alloc);
307
308	/* Allocate memory for buffers */
309	stream->buffer_area = create_area("geode buffers", (void**)&buffer,
310		B_ANY_KERNEL_ADDRESS, alloc, B_32_BIT_CONTIGUOUS,
311		B_READ_AREA | B_WRITE_AREA);
312		// TODO: The rest of the code doesn't deal correctly with physical
313		// addresses > 4 GB, so we have to force 32 bit addresses here.
314	if (stream->buffer_area < B_OK)
315		return stream->buffer_area;
316
317	/* Get the physical address of memory */
318	rc = get_memory_map(buffer, alloc, &pe, 1);
319	if (rc != B_OK) {
320		delete_area(stream->buffer_area);
321		return rc;
322	}
323
324	phys_addr_t bufferPhysicalAddress = pe.address;
325
326	dprintf("%s(%s): Allocated %" B_PRId32 " bytes for %" B_PRIu32 " buffers\n", __func__, desc,
327		alloc, stream->num_buffers);
328
329	/* Store pointers (both virtual/physical) */
330	for (index = 0; index < stream->num_buffers; index++) {
331		stream->buffers[index] = buffer + (index * bufferSize);
332		stream->physical_buffers[index] = bufferPhysicalAddress
333			+ (index * bufferSize);
334	}
335
336	/* Now allocate BDL for buffer range */
337	alloc = stream->num_buffers * sizeof(struct acc_prd) + 1;
338	alloc = PAGE_ALIGN(alloc);
339
340	stream->buffer_descriptors_area = create_area("geode buffer descriptors",
341		(void**)&bufferDescriptors, B_ANY_KERNEL_ADDRESS, alloc,
342		B_32_BIT_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
343		// TODO: The rest of the code doesn't deal correctly with physical
344		// addresses > 4 GB, so we have to force 32 bit addresses here.
345	if (stream->buffer_descriptors_area < B_OK) {
346		delete_area(stream->buffer_area);
347		return stream->buffer_descriptors_area;
348	}
349
350	/* Get the physical address of memory */
351	rc = get_memory_map(bufferDescriptors, alloc, &pe, 1);
352	if (rc != B_OK) {
353		delete_area(stream->buffer_area);
354		delete_area(stream->buffer_descriptors_area);
355		return rc;
356	}
357
358	stream->physical_buffer_descriptors = pe.address;
359
360	dprintf("%s(%s): Allocated %" B_PRIu32 " bytes for %" B_PRIu32 " BDLEs\n", __func__, desc,
361		alloc, stream->num_buffers);
362
363	/* Setup buffer descriptor list (BDL) entries */
364	for (index = 0; index < stream->num_buffers; index++, bufferDescriptors++) {
365		bufferDescriptors->address = stream->physical_buffers[index];
366		bufferDescriptors->ctrlsize = bufferSize | ACC_BMx_PRD_CTRL_EOP;
367			// we want an interrupt after every buffer
368	}
369	bufferDescriptors->address = stream->physical_buffer_descriptors;
370	bufferDescriptors->ctrlsize = ACC_BMx_PRD_CTRL_JMP;
371
372	for (index = 0; index < sizeof(kRates) / sizeof(kRates[0]); index++) {
373		if (kRates[index].multi_rate == stream->sample_rate) {
374			stream->rate = kRates[index].rate;
375			break;
376		}
377	}
378
379	/* Configure stream registers */
380	dprintf("IRA: %s: setup stream SR=%" B_PRIu32 "\n", __func__, stream->rate);
381
382	stream->Write32(STREAM_PRD, stream->physical_buffer_descriptors);
383
384	ac97_set_rate(stream->controller->ac97, stream->ac97_rate_reg, stream->rate);
385	snooze(1000);
386	return B_OK;
387}
388
389
390//	#pragma mark - public controller functions
391
392
393/*! Setup hardware for use; detect codecs; etc */
394status_t
395geode_hw_init(geode_controller* controller)
396{
397	uint16 cmd;
398	status_t status;
399
400	cmd = (gPci->read_pci_config)(controller->pci_info.bus,
401		controller->pci_info.device, controller->pci_info.function, PCI_command, 2);
402	if (!(cmd & PCI_command_master)) {
403		(gPci->write_pci_config)(controller->pci_info.bus,
404			controller->pci_info.device, controller->pci_info.function,
405				PCI_command, 2, cmd | PCI_command_master);
406		dprintf("geode: enabling PCI bus mastering\n");
407	}
408
409	controller->nabmbar = controller->pci_info.u.h0.base_registers[0];
410
411	/* Absolute minimum hw is online; we can now install interrupt handler */
412	controller->irq = controller->pci_info.u.h0.interrupt_line;
413	status = install_io_interrupt_handler(controller->irq,
414		(interrupt_handler)geode_interrupt_handler, controller, 0);
415	if (status != B_OK)
416		goto error;
417
418	/* Get controller into valid state */
419	status = reset_controller(controller);
420	if (status != B_OK) {
421		dprintf("geode: reset_controller failed\n");
422		goto reset_failed;
423	}
424
425	/* attach the codec */
426	ac97_attach(&controller->ac97, (codec_reg_read)geode_codec_read,
427		(codec_reg_write)geode_codec_write, controller,
428		controller->pci_info.u.h0.subsystem_vendor_id,
429		controller->pci_info.u.h0.subsystem_id);
430
431	snooze(1000);
432
433	controller->multi = (geode_multi*)calloc(1, sizeof(geode_multi));
434        if (controller->multi == NULL)
435                return B_NO_MEMORY;
436
437	controller->playback_stream = geode_stream_new(controller, STREAM_PLAYBACK);
438        controller->record_stream = geode_stream_new(controller, STREAM_RECORD);
439
440	return B_OK;
441
442reset_failed:
443	remove_io_interrupt_handler(controller->irq,
444		(interrupt_handler)geode_interrupt_handler, controller);
445error:
446	dprintf("geode: ERROR: %s(%" B_PRId32 ")\n", strerror(status), status);
447
448	return status;
449}
450
451
452/*! Stop any activity */
453void
454geode_hw_stop(geode_controller* controller)
455{
456	int index;
457
458	/* Stop all audio streams */
459	for (index = 0; index < GEODE_MAX_STREAMS; index++) {
460		if (controller->streams[index] && controller->streams[index]->running)
461			geode_stream_stop(controller->streams[index]);
462	}
463}
464
465
466/*! Free resources */
467void
468geode_hw_uninit(geode_controller* controller)
469{
470	if (controller == NULL)
471		return;
472
473	/* Stop all audio streams */
474	geode_hw_stop(controller);
475
476	reset_controller(controller);
477
478	remove_io_interrupt_handler(controller->irq,
479		(interrupt_handler)geode_interrupt_handler, controller);
480
481	free(controller->multi);
482
483	geode_stream_delete(controller->playback_stream);
484        geode_stream_delete(controller->record_stream);
485
486}
487
488