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 %ld, num channels %ld, buffer length %ld ****************\n",
301		stream->sample_size, stream->num_channels, stream->buffer_length);
302
303	/* Calculate total size of all buffers (aligned to size of B_PAGE_SIZE) */
304	alloc = bufferSize * stream->num_buffers;
305	alloc = PAGE_ALIGN(alloc);
306
307	/* Allocate memory for buffers */
308	stream->buffer_area = create_area("geode buffers", (void**)&buffer,
309		B_ANY_KERNEL_ADDRESS, alloc, B_32_BIT_CONTIGUOUS,
310		B_READ_AREA | B_WRITE_AREA);
311		// TODO: The rest of the code doesn't deal correctly with physical
312		// addresses > 4 GB, so we have to force 32 bit addresses here.
313	if (stream->buffer_area < B_OK)
314		return stream->buffer_area;
315
316	/* Get the physical address of memory */
317	rc = get_memory_map(buffer, alloc, &pe, 1);
318	if (rc != B_OK) {
319		delete_area(stream->buffer_area);
320		return rc;
321	}
322
323	phys_addr_t bufferPhysicalAddress = pe.address;
324
325	dprintf("%s(%s): Allocated %lu bytes for %ld buffers\n", __func__, desc,
326		alloc, stream->num_buffers);
327
328	/* Store pointers (both virtual/physical) */
329	for (index = 0; index < stream->num_buffers; index++) {
330		stream->buffers[index] = buffer + (index * bufferSize);
331		stream->physical_buffers[index] = bufferPhysicalAddress
332			+ (index * bufferSize);
333	}
334
335	/* Now allocate BDL for buffer range */
336	alloc = stream->num_buffers * sizeof(struct acc_prd) + 1;
337	alloc = PAGE_ALIGN(alloc);
338
339	stream->buffer_descriptors_area = create_area("geode buffer descriptors",
340		(void**)&bufferDescriptors, B_ANY_KERNEL_ADDRESS, alloc,
341		B_32_BIT_CONTIGUOUS, 0);
342		// TODO: The rest of the code doesn't deal correctly with physical
343		// addresses > 4 GB, so we have to force 32 bit addresses here.
344	if (stream->buffer_descriptors_area < B_OK) {
345		delete_area(stream->buffer_area);
346		return stream->buffer_descriptors_area;
347	}
348
349	/* Get the physical address of memory */
350	rc = get_memory_map(bufferDescriptors, alloc, &pe, 1);
351	if (rc != B_OK) {
352		delete_area(stream->buffer_area);
353		delete_area(stream->buffer_descriptors_area);
354		return rc;
355	}
356
357	stream->physical_buffer_descriptors = pe.address;
358
359	dprintf("%s(%s): Allocated %ld bytes for %ld BDLEs\n", __func__, desc,
360		alloc, stream->num_buffers);
361
362	/* Setup buffer descriptor list (BDL) entries */
363	for (index = 0; index < stream->num_buffers; index++, bufferDescriptors++) {
364		bufferDescriptors->address = stream->physical_buffers[index];
365		bufferDescriptors->ctrlsize = bufferSize | ACC_BMx_PRD_CTRL_EOP;
366			// we want an interrupt after every buffer
367	}
368	bufferDescriptors->address = stream->physical_buffer_descriptors;
369	bufferDescriptors->ctrlsize = ACC_BMx_PRD_CTRL_JMP;
370
371	for (index = 0; index < sizeof(kRates) / sizeof(kRates[0]); index++) {
372		if (kRates[index].multi_rate == stream->sample_rate) {
373			stream->rate = kRates[index].rate;
374			break;
375		}
376	}
377
378	/* Configure stream registers */
379	dprintf("IRA: %s: setup stream SR=%ld\n", __func__, stream->rate);
380
381	stream->Write32(STREAM_PRD, stream->physical_buffer_descriptors);
382
383	ac97_set_rate(stream->controller->ac97, stream->ac97_rate_reg, stream->rate);
384	snooze(1000);
385	return B_OK;
386}
387
388
389//	#pragma mark - public controller functions
390
391
392/*! Setup hardware for use; detect codecs; etc */
393status_t
394geode_hw_init(geode_controller* controller)
395{
396	uint16 cmd;
397	status_t status;
398
399	cmd = (gPci->read_pci_config)(controller->pci_info.bus,
400		controller->pci_info.device, controller->pci_info.function, PCI_command, 2);
401	if (!(cmd & PCI_command_master)) {
402		(gPci->write_pci_config)(controller->pci_info.bus,
403			controller->pci_info.device, controller->pci_info.function,
404				PCI_command, 2, cmd | PCI_command_master);
405		dprintf("geode: enabling PCI bus mastering\n");
406	}
407
408	controller->nabmbar = controller->pci_info.u.h0.base_registers[0];
409
410	/* Absolute minimum hw is online; we can now install interrupt handler */
411	controller->irq = controller->pci_info.u.h0.interrupt_line;
412	status = install_io_interrupt_handler(controller->irq,
413		(interrupt_handler)geode_interrupt_handler, controller, 0);
414	if (status != B_OK)
415		goto error;
416
417	/* Get controller into valid state */
418	status = reset_controller(controller);
419	if (status != B_OK) {
420		dprintf("geode: reset_controller failed\n");
421		goto reset_failed;
422	}
423
424	/* attach the codec */
425	ac97_attach(&controller->ac97, (codec_reg_read)geode_codec_read,
426		(codec_reg_write)geode_codec_write, controller,
427		controller->pci_info.u.h0.subsystem_vendor_id,
428		controller->pci_info.u.h0.subsystem_id);
429
430	snooze(1000);
431
432	controller->multi = (geode_multi*)calloc(1, sizeof(geode_multi));
433        if (controller->multi == NULL)
434                return B_NO_MEMORY;
435
436	controller->playback_stream = geode_stream_new(controller, STREAM_PLAYBACK);
437        controller->record_stream = geode_stream_new(controller, STREAM_RECORD);
438
439	return B_OK;
440
441reset_failed:
442	remove_io_interrupt_handler(controller->irq,
443		(interrupt_handler)geode_interrupt_handler, controller);
444error:
445	dprintf("geode: ERROR: %s(%ld)\n", strerror(status), status);
446
447	return status;
448}
449
450
451/*! Stop any activity */
452void
453geode_hw_stop(geode_controller* controller)
454{
455	int index;
456
457	/* Stop all audio streams */
458	for (index = 0; index < GEODE_MAX_STREAMS; index++) {
459		if (controller->streams[index] && controller->streams[index]->running)
460			geode_stream_stop(controller->streams[index]);
461	}
462}
463
464
465/*! Free resources */
466void
467geode_hw_uninit(geode_controller* controller)
468{
469	if (controller == NULL)
470		return;
471
472	/* Stop all audio streams */
473	geode_hw_stop(controller);
474
475	reset_controller(controller);
476
477	remove_io_interrupt_handler(controller->irq,
478		(interrupt_handler)geode_interrupt_handler, controller);
479
480	free(controller->multi);
481
482	geode_stream_delete(controller->playback_stream);
483        geode_stream_delete(controller->record_stream);
484
485}
486
487