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