maestro.c revision 65543
150477Speter/*- 238465Smsmith * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp> 3239058Sae * All rights reserved. 4114379Speter * 540834Smsmith * Redistribution and use in source and binary forms, with or without 639178Smsmith * modification, are permitted provided that the following conditions 7211678Simp * are met: 8136895Sru * 1. Redistributions of source code must retain the above copyright 9136895Sru * notice, this list of conditions and the following disclaimer. 10219691Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11219691Smarcel * notice, this list of conditions and the following disclaimer in the 12136895Sru * documentation and/or other materials provided with the distribution. 13136895Sru * 14211817Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15134458Siedowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16211678Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17209920Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18209920Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19219691Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20134458Siedowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21114379Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22114379Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2368548Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2468548Sbenno * SUCH DAMAGE. 2568548Sbenno * 2668548Sbenno * $Id: maestro.c,v 1.12 2000/09/06 03:32:34 taku Exp $ 27239058Sae * $FreeBSD: head/sys/dev/sound/pci/maestro.c 65543 2000-09-06 20:10:55Z cg $ 28239058Sae */ 29239058Sae 30239058Sae/* 31239058Sae * Credits: 32239058Sae * 33239058Sae * Part of this code (especially in many magic numbers) was heavily inspired 34239058Sae * by the Linux driver originally written by 35239058Sae * Alan Cox <alan.cox@linux.org>, modified heavily by 36239058Sae * Zach Brown <zab@zabbo.net>. 37239058Sae * 38239058Sae * busdma()-ize and buffer size reduction were suggested by 39163893Smarcel * Cameron Grant <gandalf@vilnya.demon.co.uk>. 40163893Smarcel * Also he showed me the way to use busdma() suite. 41163893Smarcel * 42163893Smarcel * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500 43200460Smarcel * were looked at by 44200460Smarcel * Munehiro Matsuda <haro@tk.kubota.co.jp>, 45200460Smarcel * who brought patches based on the Linux driver with some simplification. 46200460Smarcel */ 47200460Smarcel 4839178Smsmith#include <dev/sound/pcm/sound.h> 49125561Sru#include <dev/sound/pcm/ac97.h> 5039178Smsmith#include <pci/pcireg.h> 5139178Smsmith#include <pci/pcivar.h> 52125561Sru 5339178Smsmith#include <dev/sound/pci/maestro_reg.h> 5439178Smsmith 5540875Smsmith#define inline __inline 5640875Smsmith 57125561Sru/* 5840875Smsmith * PCI IDs of supported chips: 59222417Sjulian * 60222417Sjulian * MAESTRO-1 0x01001285 61222417Sjulian * MAESTRO-2 0x1968125d 62222417Sjulian * MAESTRO-2E 0x1978125d 63222417Sjulian */ 6474850Sru 6574850Sru#define MAESTRO_1_PCI_ID 0x01001285 66222417Sjulian#define MAESTRO_2_PCI_ID 0x1968125d 67242688Sdteske#define MAESTRO_2E_PCI_ID 0x1978125d 68222417Sjulian 6940875Smsmith#define NEC_SUBID1 0x80581033 /* Taken from Linux driver */ 7060704Sdcs#define NEC_SUBID2 0x803c1033 /* NEC VersaProNX VA26D */ 71199210Sattilio 72199210Sattilio#ifndef AGG_MAXPLAYCH 73199210Sattilio# define AGG_MAXPLAYCH 4 74199210Sattilio#endif 7574850Sru 76272696Savg#define AGG_BUFSIZ 4096 77272696Savg 78272696Savg 79/* ----------------------------- 80 * Data structures. 81 */ 82struct agg_chinfo { 83 struct agg_info *parent; 84 pcm_channel *channel; 85 snd_dbuf *buffer; 86 bus_addr_t offset; 87 u_int32_t blocksize; 88 int dir; 89 u_int num; 90 u_int16_t aputype; 91 u_int16_t wcreg_tpl; 92}; 93 94struct agg_info { 95 device_t dev; 96 struct resource *reg; 97 int regid; 98 99 bus_space_tag_t st; 100 bus_space_handle_t sh; 101 bus_dma_tag_t parent_dmat; 102 103 struct resource *irq; 104 int irqid; 105 void *ih; 106 107 u_int8_t *stat; 108 bus_addr_t baseaddr; 109 110 struct ac97_info *codec; 111 112 u_int playchns, active; 113 struct agg_chinfo pch[AGG_MAXPLAYCH]; 114 struct agg_chinfo rch; 115}; 116 117 118static u_int32_t agg_rdcodec(void *, int); 119static void agg_wrcodec(void *, int, u_int32_t); 120 121static inline void ringbus_setdest(struct agg_info*, int, int); 122 123static inline u_int16_t wp_rdreg(struct agg_info*, u_int16_t); 124static inline void wp_wrreg(struct agg_info*, u_int16_t, u_int16_t); 125static inline u_int16_t wp_rdapu(struct agg_info*, int, u_int16_t); 126static inline void wp_wrapu(struct agg_info*, int, u_int16_t, u_int16_t); 127static inline void wp_settimer(struct agg_info*, u_int); 128static inline void wp_starttimer(struct agg_info*); 129static inline void wp_stoptimer(struct agg_info*); 130 131static inline u_int16_t wc_rdreg(struct agg_info*, u_int16_t); 132static inline void wc_wrreg(struct agg_info*, u_int16_t, u_int16_t); 133static inline u_int16_t wc_rdchctl(struct agg_info*, int); 134static inline void wc_wrchctl(struct agg_info*, int, u_int16_t); 135 136static inline void agg_power(struct agg_info*, int); 137 138static void agg_init(struct agg_info*); 139static u_int32_t agg_ac97_init(void *); 140 141static void aggch_start_dac(struct agg_chinfo*); 142static void aggch_stop_dac(struct agg_chinfo*); 143 144static inline void suppress_jitter(struct agg_chinfo*); 145 146static inline u_int calc_timer_freq(struct agg_chinfo*); 147static void set_timer(struct agg_info*); 148 149static pcmchan_init_t aggch_init; 150static pcmchan_free_t aggch_free; 151static pcmchan_setformat_t aggch_setplayformat; 152static pcmchan_setspeed_t aggch_setspeed; 153static pcmchan_setblocksize_t aggch_setblocksize; 154static pcmchan_trigger_t aggch_trigger; 155static pcmchan_getptr_t aggch_getplayptr; 156static pcmchan_getcaps_t aggch_getcaps; 157 158static void agg_intr(void *); 159static int agg_probe(device_t); 160static int agg_attach(device_t); 161static int agg_detach(device_t); 162static int agg_suspend(device_t); 163static int agg_resume(device_t); 164static int agg_shutdown(device_t); 165 166static void *dma_malloc(struct agg_info*, u_int32_t, bus_addr_t*); 167static void dma_free(struct agg_info*, void *); 168 169/* ----------------------------- 170 * Subsystems. 171 */ 172 173/* Codec/Ringbus */ 174 175static u_int32_t 176agg_rdcodec(void *sc, int regno) 177{ 178 struct agg_info *ess = sc; 179 unsigned t; 180 181 /* We have to wait for a SAFE time to write addr/data */ 182 for (t = 0; t < 20; t++) { 183 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 184 & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) 185 break; 186 DELAY(2); /* 20.8us / 13 */ 187 } 188 if (t == 20) 189 device_printf(ess->dev, "agg_rdcodec() PROGLESS timed out.\n"); 190 191 bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, 192 CODEC_CMD_READ | regno); 193 DELAY(21); /* AC97 cycle = 20.8usec */ 194 195 /* Wait for data retrieve */ 196 for (t = 0; t < 20; t++) { 197 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 198 & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE) 199 break; 200 DELAY(2); /* 20.8us / 13 */ 201 } 202 if (t == 20) 203 /* Timed out, but perform dummy read. */ 204 device_printf(ess->dev, "agg_rdcodec() RW_DONE timed out.\n"); 205 206 return bus_space_read_2(ess->st, ess->sh, PORT_CODEC_REG); 207} 208 209static void 210agg_wrcodec(void *sc, int regno, u_int32_t data) 211{ 212 unsigned t; 213 struct agg_info *ess = sc; 214 215 /* We have to wait for a SAFE time to write addr/data */ 216 for (t = 0; t < 20; t++) { 217 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 218 & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) 219 break; 220 DELAY(2); /* 20.8us / 13 */ 221 } 222 if (t == 20) { 223 /* Timed out. Abort writing. */ 224 device_printf(ess->dev, "agg_wrcodec() PROGLESS timed out.\n"); 225 return; 226 } 227 228 bus_space_write_2(ess->st, ess->sh, PORT_CODEC_REG, data); 229 bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, 230 CODEC_CMD_WRITE | regno); 231} 232 233static inline void 234ringbus_setdest(struct agg_info *ess, int src, int dest) 235{ 236 u_int32_t data; 237 238 data = bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL); 239 data &= ~(0xfU << src); 240 data |= (0xfU & dest) << src; 241 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, data); 242} 243 244/* Wave Processor */ 245 246static inline u_int16_t 247wp_rdreg(struct agg_info *ess, u_int16_t reg) 248{ 249 bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); 250 return bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA); 251} 252 253static inline void 254wp_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data) 255{ 256 bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); 257 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); 258} 259 260static inline void 261apu_setindex(struct agg_info *ess, u_int16_t reg) 262{ 263 int t; 264 265 wp_wrreg(ess, WPREG_CRAM_PTR, reg); 266 /* Sometimes WP fails to set apu register index. */ 267 for (t = 0; t < 1000; t++) { 268 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == reg) 269 break; 270 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, reg); 271 } 272 if (t == 1000) 273 device_printf(ess->dev, "apu_setindex() timed out.\n"); 274} 275 276static inline u_int16_t 277wp_rdapu(struct agg_info *ess, int ch, u_int16_t reg) 278{ 279 u_int16_t ret; 280 281 apu_setindex(ess, ((unsigned)ch << 4) + reg); 282 ret = wp_rdreg(ess, WPREG_DATA_PORT); 283 return ret; 284} 285 286static inline void 287wp_wrapu(struct agg_info *ess, int ch, u_int16_t reg, u_int16_t data) 288{ 289 int t; 290 291 apu_setindex(ess, ((unsigned)ch << 4) + reg); 292 wp_wrreg(ess, WPREG_DATA_PORT, data); 293 for (t = 0; t < 1000; t++) { 294 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == data) 295 break; 296 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); 297 } 298 if (t == 1000) 299 device_printf(ess->dev, "wp_wrapu() timed out.\n"); 300} 301 302static inline void 303wp_settimer(struct agg_info *ess, u_int freq) 304{ 305 u_int clock = 48000 << 2; 306 u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0; 307 308 RANGE(divide, 4, 32 << 8); 309 310 for (; divide > 32 << 1; divide >>= 1) 311 prescale++; 312 divide = (divide + 1) >> 1; 313 314 for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1) 315 prescale++; 316 317 wp_wrreg(ess, WPREG_TIMER_ENABLE, 0); 318 wp_wrreg(ess, WPREG_TIMER_FREQ, 319 (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1)); 320 wp_wrreg(ess, WPREG_TIMER_ENABLE, 1); 321} 322 323static inline void 324wp_starttimer(struct agg_info *ess) 325{ 326 wp_wrreg(ess, WPREG_TIMER_START, 1); 327} 328 329static inline void 330wp_stoptimer(struct agg_info *ess) 331{ 332 wp_wrreg(ess, WPREG_TIMER_START, 0); 333 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 334} 335 336/* WaveCache */ 337 338static inline u_int16_t 339wc_rdreg(struct agg_info *ess, u_int16_t reg) 340{ 341 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); 342 return bus_space_read_2(ess->st, ess->sh, PORT_WAVCACHE_DATA); 343} 344 345static inline void 346wc_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data) 347{ 348 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); 349 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_DATA, data); 350} 351 352static inline u_int16_t 353wc_rdchctl(struct agg_info *ess, int ch) 354{ 355 return wc_rdreg(ess, ch << 3); 356} 357 358static inline void 359wc_wrchctl(struct agg_info *ess, int ch, u_int16_t data) 360{ 361 wc_wrreg(ess, ch << 3, data); 362} 363 364/* Power management */ 365 366static inline void 367agg_power(struct agg_info *ess, int status) 368{ 369 u_int8_t data; 370 371 data = pci_read_config(ess->dev, CONF_PM_PTR, 1); 372 if (pci_read_config(ess->dev, data, 1) == PPMI_CID) 373 pci_write_config(ess->dev, data + PM_CTRL, status, 1); 374} 375 376 377/* ----------------------------- 378 * Controller. 379 */ 380 381static inline void 382agg_initcodec(struct agg_info* ess) 383{ 384 u_int16_t data; 385 386 if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL) 387 & RINGBUS_CTRL_ACLINK_ENABLED) { 388 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 389 DELAY(104); /* 20.8us * (4 + 1) */ 390 } 391 /* XXX - 2nd codec should be looked at. */ 392 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 393 RINGBUS_CTRL_AC97_SWRESET); 394 DELAY(2); 395 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 396 RINGBUS_CTRL_ACLINK_ENABLED); 397 DELAY(21); 398 399 agg_rdcodec(ess, 0); 400 if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 401 & CODEC_STAT_MASK) { 402 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 403 DELAY(21); 404 405 /* Try cold reset. */ 406 device_printf(ess->dev, "will perform cold reset.\n"); 407 data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR); 408 if (pci_read_config(ess->dev, 0x58, 2) & 1) 409 data |= 0x10; 410 data |= 0x009 & 411 ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA); 412 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6); 413 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 414 data | 0x009); 415 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000); 416 DELAY(2); 417 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001); 418 DELAY(1); 419 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009); 420 DELAY(500000); 421 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data); 422 DELAY(84); /* 20.8us * 4 */ 423 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 424 RINGBUS_CTRL_ACLINK_ENABLED); 425 DELAY(21); 426 } 427} 428 429static void 430agg_init(struct agg_info* ess) 431{ 432 u_int32_t data; 433 434 /* Setup PCI config registers. */ 435 436 /* Disable all legacy emulations. */ 437 data = pci_read_config(ess->dev, CONF_LEGACY, 2); 438 data |= LEGACY_DISABLED; 439 pci_write_config(ess->dev, CONF_LEGACY, data, 2); 440 441 /* Disconnect from CHI. (Makes Dell inspiron 7500 work?) 442 * Enable posted write. 443 * Prefer PCI timing rather than that of ISA. 444 * Don't swap L/R. */ 445 data = pci_read_config(ess->dev, CONF_MAESTRO, 4); 446 data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING; 447 data &= ~MAESTRO_SWAP_LR; 448 pci_write_config(ess->dev, CONF_MAESTRO, data, 4); 449 450 /* Reset direct sound. */ 451 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 452 HOSTINT_CTRL_DSOUND_RESET); 453 DELAY(10000); /* XXX - too long? */ 454 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 455 DELAY(10000); 456 457 /* Enable direct sound interruption. */ 458 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 459 HOSTINT_CTRL_DSOUND_INT_ENABLED); 460 461 /* Setup Wave Processor. */ 462 463 /* Enable WaveCache, set DMA base address. */ 464 wp_wrreg(ess, WPREG_WAVE_ROMRAM, 465 WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED); 466 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL, 467 WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB); 468 469 for (data = WAVCACHE_PCMBAR; data < WAVCACHE_PCMBAR + 4; data++) 470 wc_wrreg(ess, data, ess->baseaddr >> WAVCACHE_BASEADDR_SHIFT); 471 472 /* Setup Codec/Ringbus. */ 473 agg_initcodec(ess); 474 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 475 RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED); 476 477 wp_wrreg(ess, WPREG_BASE, 0x8500); /* Parallel I/O */ 478 ringbus_setdest(ess, RINGBUS_SRC_ADC, 479 RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN); 480 ringbus_setdest(ess, RINGBUS_SRC_DSOUND, 481 RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC); 482 483 /* Setup ASSP. Needed for Dell Inspiron 7500? */ 484 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00); 485 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03); 486 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00); 487 488 /* 489 * Setup GPIO. 490 * There seems to be speciality with NEC systems. 491 */ 492 switch (pci_get_subvendor(ess->dev) 493 | (pci_get_subdevice(ess->dev) << 16)) { 494 case NEC_SUBID1: 495 case NEC_SUBID2: 496 /* Matthew Braithwaite <matt@braithwaite.net> reported that 497 * NEC Versa LX doesn't need GPIO operation. */ 498 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0x9ff); 499 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 500 bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 0x600); 501 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x200); 502 break; 503 } 504} 505 506/* Channel controller. */ 507 508static void 509aggch_start_dac(struct agg_chinfo *ch) 510{ 511 u_int wpwa = APU_USE_SYSMEM | (ch->offset >> 9); 512 u_int size = AGG_BUFSIZ >> 1; 513 u_int speed = ch->channel->speed; 514 u_int offset = ch->offset >> 1; 515 u_int cp = ch->buffer->rp >> 1; 516 u_int16_t apuch = ch->num << 1; 517 u_int dv; 518 int pan = 0; 519 520 switch (ch->aputype) { 521 case APUTYPE_16BITSTEREO: 522 wpwa >>= 1; 523 size >>= 1; 524 offset >>= 1; 525 cp >>= 1; 526 /* FALLTHROUGH */ 527 case APUTYPE_8BITSTEREO: 528 pan = 8; 529 apuch++; 530 break; 531 case APUTYPE_8BITLINEAR: 532 speed >>= 1; 533 break; 534 } 535 536 dv = (((speed % 48000) << 16) + 24000) / 48000 537 + ((speed / 48000) << 16); 538 539 do { 540 wp_wrapu(ch->parent, apuch, APUREG_WAVESPACE, wpwa & 0xff00); 541 wp_wrapu(ch->parent, apuch, APUREG_CURPTR, offset + cp); 542 wp_wrapu(ch->parent, apuch, APUREG_ENDPTR, offset + size); 543 wp_wrapu(ch->parent, apuch, APUREG_LOOPLEN, size); 544 wp_wrapu(ch->parent, apuch, APUREG_AMPLITUDE, 0xe800); 545 wp_wrapu(ch->parent, apuch, APUREG_POSITION, 0x8f00 546 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 547 | ((PAN_FRONT + pan) << APU_PAN_SHIFT)); 548 wp_wrapu(ch->parent, apuch, APUREG_FREQ_LOBYTE, APU_plus6dB 549 | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT)); 550 wp_wrapu(ch->parent, apuch, APUREG_FREQ_HIWORD, dv >> 8); 551 552 if (ch->aputype == APUTYPE_16BITSTEREO) 553 wpwa |= APU_STEREO >> 1; 554 pan = -pan; 555 } while (pan < 0 && apuch--); 556 557 wc_wrchctl(ch->parent, apuch, ch->wcreg_tpl); 558 wc_wrchctl(ch->parent, apuch + 1, ch->wcreg_tpl); 559 560 wp_wrapu(ch->parent, apuch, APUREG_APUTYPE, 561 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 562 if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) 563 wp_wrapu(ch->parent, apuch + 1, APUREG_APUTYPE, 564 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 565} 566 567static void 568aggch_stop_dac(struct agg_chinfo *ch) 569{ 570 wp_wrapu(ch->parent, (ch->num << 1), APUREG_APUTYPE, 571 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 572 wp_wrapu(ch->parent, (ch->num << 1) + 1, APUREG_APUTYPE, 573 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 574} 575 576/* 577 * Stereo jitter suppressor. 578 * Sometimes playback pointers differ in stereo-paired channels. 579 * Calling this routine within intr fixes the problem. 580 */ 581static inline void 582suppress_jitter(struct agg_chinfo *ch) 583{ 584 if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) { 585 int cp, diff, halfsize = AGG_BUFSIZ >> 2; 586 587 if (ch->aputype == APUTYPE_16BITSTEREO) 588 halfsize >>= 1; 589 cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR); 590 diff = wp_rdapu(ch->parent, (ch->num << 1) + 1, APUREG_CURPTR); 591 diff -= cp; 592 if (diff >> 1 && diff > -halfsize && diff < halfsize) 593 bus_space_write_2(ch->parent->st, ch->parent->sh, 594 PORT_DSP_DATA, cp); 595 } 596} 597 598static inline u_int 599calc_timer_freq(struct agg_chinfo *ch) 600{ 601 u_int ss = 2; 602 603 if (ch->aputype == APUTYPE_16BITSTEREO) 604 ss <<= 1; 605 if (ch->aputype == APUTYPE_8BITLINEAR) 606 ss >>= 1; 607 608 return (ch->channel->speed * ss + ch->blocksize - 1) / ch->blocksize; 609} 610 611static void 612set_timer(struct agg_info *ess) 613{ 614 int i; 615 u_int freq = 0; 616 617 for (i = 0; i < ess->playchns; i++) 618 if ((ess->active & (1 << i)) && 619 (freq < calc_timer_freq(ess->pch + i))) 620 freq = calc_timer_freq(ess->pch + i); 621 622 wp_settimer(ess, freq); 623} 624 625 626/* ----------------------------- 627 * Newpcm glue. 628 */ 629 630static u_int32_t 631agg_ac97_init(void *sc) 632{ 633 struct agg_info *ess = sc; 634 635 return (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) & CODEC_STAT_MASK)? 0 : 1; 636} 637 638static void * 639aggch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 640{ 641 struct agg_info *ess = devinfo; 642 struct agg_chinfo *ch; 643 bus_addr_t physaddr; 644 645 ch = (dir == PCMDIR_PLAY)? ess->pch + ess->playchns : &ess->rch; 646 647 ch->parent = ess; 648 ch->channel = c; 649 ch->buffer = b; 650 ch->num = ess->playchns; 651 ch->dir = dir; 652 653 b->buf = dma_malloc(ess, AGG_BUFSIZ, &physaddr); 654 if (b->buf == NULL) 655 return NULL; 656 657 ch->offset = physaddr - ess->baseaddr; 658 if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) { 659 device_printf(ess->dev, 660 "offset %#x exceeds limit. ", ch->offset); 661 dma_free(ess, b->buf); 662 b->buf = NULL; 663 return NULL; 664 } 665 666 b->bufsize = AGG_BUFSIZ; 667 ch->wcreg_tpl = (physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK; 668 669 if (dir == PCMDIR_PLAY) { 670 ess->playchns++; 671 if (bootverbose) 672 device_printf(ess->dev, "pch[%d].offset = %#x\n", ch->num, ch->offset); 673 } else if (bootverbose) 674 device_printf(ess->dev, "rch.offset = %#x\n", ch->offset); 675 676 return ch; 677} 678 679static int 680aggch_free(void *data) 681{ 682 struct agg_chinfo *ch = data; 683 struct agg_info *ess = ch->parent; 684 685 /* free up buffer - called after channel stopped */ 686 dma_free(ess, ch->buffer->buf); 687 688 /* return 0 if ok */ 689 return 0; 690} 691 692static int 693aggch_setplayformat(void *data, u_int32_t format) 694{ 695 struct agg_chinfo *ch = data; 696 u_int16_t wcreg_tpl; 697 u_int16_t aputype = APUTYPE_16BITLINEAR; 698 699 wcreg_tpl = ch->wcreg_tpl & WAVCACHE_CHCTL_ADDRTAG_MASK; 700 701 if (format & AFMT_STEREO) { 702 wcreg_tpl |= WAVCACHE_CHCTL_STEREO; 703 aputype += 1; 704 } 705 if (format & AFMT_U8 || format & AFMT_S8) { 706 aputype += 2; 707 if (format & AFMT_U8) 708 wcreg_tpl |= WAVCACHE_CHCTL_U8; 709 } 710 if (format & AFMT_BIGENDIAN || format & AFMT_U16_LE) { 711 format &= ~AFMT_BIGENDIAN & ~AFMT_U16_LE; 712 format |= AFMT_S16_LE; 713 } 714 ch->wcreg_tpl = wcreg_tpl; 715 ch->aputype = aputype; 716 return format; 717} 718 719static int 720aggch_setspeed(void *data, u_int32_t speed) 721{ 722 return speed; 723} 724 725static int 726aggch_setblocksize(void *data, u_int32_t blocksize) 727{ 728 return ((struct agg_chinfo*)data)->blocksize = blocksize; 729} 730 731static int 732aggch_trigger(void *data, int go) 733{ 734 struct agg_chinfo *ch = data; 735 736 switch (go) { 737 case PCMTRIG_EMLDMAWR: 738 return 0; 739 case PCMTRIG_START: 740 ch->parent->active |= (1 << ch->num); 741 if (ch->dir == PCMDIR_PLAY) 742 aggch_start_dac(ch); 743#if 0 /* XXX - RECORDING */ 744 else 745 aggch_start_adc(ch); 746#endif 747 break; 748 case PCMTRIG_ABORT: 749 case PCMTRIG_STOP: 750 ch->parent->active &= ~(1 << ch->num); 751 if (ch->dir == PCMDIR_PLAY) 752 aggch_stop_dac(ch); 753#if 0 /* XXX - RECORDING */ 754 else 755 aggch_stop_adc(ch); 756#endif 757 break; 758 } 759 760 if (ch->parent->active) { 761 set_timer(ch->parent); 762 wp_starttimer(ch->parent); 763 } else 764 wp_stoptimer(ch->parent); 765 766 return 0; 767} 768 769static int 770aggch_getplayptr(void *data) 771{ 772 struct agg_chinfo *ch = data; 773 u_int cp; 774 775 cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR); 776 if (ch->aputype == APUTYPE_16BITSTEREO) 777 cp = (0xffff << 2) & ((cp << 2) - ch->offset); 778 else 779 cp = (0xffff << 1) & ((cp << 1) - ch->offset); 780 781 return cp; 782} 783 784static pcmchan_caps * 785aggch_getcaps(void *data) 786{ 787 static u_int32_t playfmt[] = { 788 AFMT_U8, 789 AFMT_STEREO | AFMT_U8, 790 AFMT_S8, 791 AFMT_STEREO | AFMT_S8, 792 AFMT_S16_LE, 793 AFMT_STEREO | AFMT_S16_LE, 794 0 795 }; 796 static pcmchan_caps playcaps = {2000, 96000, playfmt, 0}; 797 798 static u_int32_t recfmt[] = { 799 AFMT_S8, 800 AFMT_STEREO | AFMT_S8, 801 AFMT_S16_LE, 802 AFMT_STEREO | AFMT_S16_LE, 803 0 804 }; 805 static pcmchan_caps reccaps = {4000, 48000, recfmt, 0}; 806 807 return (((struct agg_chinfo*)data)->dir == PCMDIR_PLAY)? 808 &playcaps : &reccaps; 809} 810 811 812/* ----------------------------- 813 * Bus space. 814 */ 815 816static void 817agg_intr(void *sc) 818{ 819 struct agg_info* ess = sc; 820 u_int16_t status; 821 int i; 822 823 status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT); 824 if (!status) 825 return; 826 827 /* Acknowledge all. */ 828 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 829 bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0); 830#if 0 /* XXX - HWVOL */ 831 if (status & HOSTINT_STAT_HWVOL) { 832 u_int delta; 833 delta = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER) 834 - 0x88; 835 if (delta & 0x11) 836 mixer_set(device_get_softc(ess->dev), 837 SOUND_MIXER_VOLUME, 0); 838 else { 839 mixer_set(device_get_softc(ess->dev), 840 SOUND_MIXER_VOLUME, 841 mixer_get(device_get_softc(ess->dev), 842 SOUND_MIXER_VOLUME) 843 + ((delta >> 5) & 0x7) - 4 844 + ((delta << 7) & 0x700) - 0x400); 845 } 846 bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER, 0x88); 847 } 848#endif /* XXX - HWVOL */ 849 850 for (i = 0; i < ess->playchns; i++) 851 if (ess->active & (1 << i)) { 852 suppress_jitter(ess->pch + i); 853 chn_intr(ess->pch[i].channel); 854 } 855#if 0 /* XXX - RECORDING */ 856 if (ess->active & (1 << i)) 857 chn_intr(ess->rch.channel); 858#endif 859} 860 861static void 862setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 863{ 864 bus_addr_t *phys = arg; 865 866 *phys = error? 0 : segs->ds_addr; 867 868 if (bootverbose) { 869 printf("setmap (%lx, %lx), nseg=%d, error=%d\n", 870 (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len, 871 nseg, error); 872 } 873} 874 875static void * 876dma_malloc(struct agg_info *sc, u_int32_t sz, bus_addr_t *phys) 877{ 878 void *buf; 879 bus_dmamap_t map; 880 881 if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map)) 882 return NULL; 883 if (bus_dmamap_load(sc->parent_dmat, map, buf, sz, setmap, phys, 0) 884 || !*phys) { 885 bus_dmamem_free(sc->parent_dmat, buf, map); 886 return NULL; 887 } 888 return buf; 889} 890 891static void 892dma_free(struct agg_info *sc, void *buf) 893{ 894 bus_dmamem_free(sc->parent_dmat, buf, NULL); 895} 896 897static int 898agg_probe(device_t dev) 899{ 900 char *s = NULL; 901 902 switch (pci_get_devid(dev)) { 903 case MAESTRO_1_PCI_ID: 904 s = "ESS Technology Maestro-1"; 905 break; 906 907 case MAESTRO_2_PCI_ID: 908 s = "ESS Technology Maestro-2"; 909 break; 910 911 case MAESTRO_2E_PCI_ID: 912 s = "ESS Technology Maestro-2E"; 913 break; 914 } 915 916 if (s != NULL && pci_get_class(dev) == PCIC_MULTIMEDIA) { 917 device_set_desc(dev, s); 918 return 0; 919 } 920 return ENXIO; 921} 922 923static int 924agg_attach(device_t dev) 925{ 926 struct agg_info *ess = NULL; 927 u_int32_t data; 928 int mapped = 0; 929 int regid = PCIR_MAPS; 930 struct resource *reg = NULL; 931 struct ac97_info *codec = NULL; 932 int irqid = 0; 933 struct resource *irq = NULL; 934 void *ih = NULL; 935 char status[SND_STATUSLEN]; 936 static pcm_channel agg_pchtpl = { 937 aggch_init, 938 NULL, /* setdir */ 939 aggch_setplayformat, 940 aggch_setspeed, 941 aggch_setblocksize, 942 aggch_trigger, 943 aggch_getplayptr, 944 aggch_getcaps, 945 aggch_free, /* free */ 946 NULL, /* nop1 */ 947 NULL, /* nop2 */ 948 NULL, /* nop3 */ 949 NULL, /* nop4 */ 950 NULL, /* nop5 */ 951 NULL, /* nop6 */ 952 NULL, /* nop7 */ 953 }; 954 955 if ((ess = malloc(sizeof *ess, M_DEVBUF, M_NOWAIT)) == NULL) { 956 device_printf(dev, "cannot allocate softc\n"); 957 return ENXIO; 958 } 959 bzero(ess, sizeof *ess); 960 ess->dev = dev; 961 962 if (bus_dma_tag_create(/*parent*/NULL, 963 /*alignment*/1 << WAVCACHE_BASEADDR_SHIFT, 964 /*boundary*/WPWA_MAXADDR + 1, 965 /*lowaddr*/MAESTRO_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, 966 /*filter*/NULL, /*filterarg*/NULL, 967 /*maxsize*/AGG_BUFSIZ * 2, /*nsegments*/1, /*maxsegz*/0x3ffff, 968 /*flags*/0, &ess->parent_dmat) != 0) { 969 device_printf(dev, "unable to create dma tag\n"); 970 goto bad; 971 } 972 973 ess->stat = dma_malloc(ess, AGG_BUFSIZ, &ess->baseaddr); 974 if (ess->stat == NULL) { 975 device_printf(dev, "cannot allocate status buffer\n"); 976 goto bad; 977 } 978 if (bootverbose) 979 device_printf(dev, "Maestro DMA base: %#x\n", ess->baseaddr); 980 981 agg_power(ess, PPMI_D0); 982 DELAY(100000); 983 984 data = pci_read_config(dev, PCIR_COMMAND, 2); 985 data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN); 986 pci_write_config(dev, PCIR_COMMAND, data, 2); 987 data = pci_read_config(dev, PCIR_COMMAND, 2); 988 989 if (data & PCIM_CMD_PORTEN) { 990 reg = bus_alloc_resource(dev, SYS_RES_IOPORT, ®id, 991 0, BUS_SPACE_UNRESTRICTED, 256, RF_ACTIVE); 992 if (reg != NULL) { 993 ess->reg = reg; 994 ess->regid = regid; 995 ess->st = rman_get_bustag(reg); 996 ess->sh = rman_get_bushandle(reg); 997 mapped++; 998 } 999 } 1000 if (mapped == 0) { 1001 device_printf(dev, "unable to map register space\n"); 1002 goto bad; 1003 } 1004 1005 agg_init(ess); 1006 if (agg_rdcodec(ess, 0) == 0x80) { 1007 device_printf(dev, "PT101 codec detected!\n"); 1008 goto bad; 1009 } 1010 codec = ac97_create(dev, ess, agg_ac97_init, agg_rdcodec, agg_wrcodec); 1011 if (codec == NULL) 1012 goto bad; 1013 if (mixer_init(dev, &ac97_mixer, codec) == -1) 1014 goto bad; 1015 ess->codec = codec; 1016 1017 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid, 1018 0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE | RF_SHAREABLE); 1019 if (irq == NULL 1020 || bus_setup_intr(dev, irq, INTR_TYPE_TTY, agg_intr, ess, &ih)) { 1021 device_printf(dev, "unable to map interrupt\n"); 1022 goto bad; 1023 } 1024 ess->irq = irq; 1025 ess->irqid = irqid; 1026 ess->ih = ih; 1027 1028 snprintf(status, SND_STATUSLEN, "at I/O port 0x%lx irq %ld", 1029 rman_get_start(reg), rman_get_start(irq)); 1030 1031 if (pcm_register(dev, ess, AGG_MAXPLAYCH, 1)) 1032 goto bad; 1033 1034 for (data = 0; data < AGG_MAXPLAYCH; data++) 1035 pcm_addchan(dev, PCMDIR_PLAY, &agg_pchtpl, ess); 1036#if 0 /* XXX - RECORDING */ 1037 pcm_addchan(dev, PCMDIR_REC, &agg_rchtpl, ess); 1038#endif 1039 pcm_setstatus(dev, status); 1040 1041 return 0; 1042 1043 bad: 1044 if (ih != NULL) 1045 bus_teardown_intr(dev, irq, ih); 1046 if (irq != NULL) 1047 bus_release_resource(dev, SYS_RES_IRQ, irqid, irq); 1048 if (codec != NULL) 1049 free(codec, M_DEVBUF); 1050 if (reg != NULL) 1051 bus_release_resource(dev, SYS_RES_IOPORT, regid, reg); 1052 if (ess != NULL) { 1053 agg_power(ess, PPMI_D3); 1054 if (ess->stat != NULL) 1055 dma_free(ess, ess->stat); 1056 if (ess->parent_dmat != NULL) 1057 bus_dma_tag_destroy(ess->parent_dmat); 1058 free(ess, M_DEVBUF); 1059 } 1060 1061 return ENXIO; 1062} 1063 1064static int 1065agg_detach(device_t dev) 1066{ 1067 struct agg_info *ess = pcm_getdevinfo(dev); 1068 int r; 1069 1070 r = pcm_unregister(dev); 1071 if (r) 1072 return r; 1073 1074 ess = pcm_getdevinfo(dev); 1075 dma_free(ess, ess->stat); 1076 1077 /* Power down everything except clock and vref. */ 1078 agg_wrcodec(ess, AC97_REG_POWER, 0xd700); 1079 DELAY(20); 1080 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 1081 agg_power(ess, PPMI_D3); 1082 1083 bus_teardown_intr(dev, ess->irq, ess->ih); 1084 bus_release_resource(dev, SYS_RES_IRQ, ess->irqid, ess->irq); 1085 bus_release_resource(dev, SYS_RES_IOPORT, ess->regid, ess->reg); 1086 bus_dma_tag_destroy(ess->parent_dmat); 1087 free(ess, M_DEVBUF); 1088 return 0; 1089} 1090 1091static int 1092agg_suspend(device_t dev) 1093{ 1094 struct agg_info *ess = pcm_getdevinfo(dev); 1095 int i, x; 1096 1097 x = spltty(); 1098 wp_stoptimer(ess); 1099 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1100 1101 for (i = 0; i < ess->playchns; i++) 1102 aggch_stop_dac(ess->pch + i); 1103 1104#if 0 /* XXX - RECORDING */ 1105 aggch_stop_adc(&ess->rch); 1106#endif 1107 splx(x); 1108 /* Power down everything except clock. */ 1109 agg_wrcodec(ess, AC97_REG_POWER, 0xdf00); 1110 DELAY(20); 1111 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 1112 DELAY(1); 1113 agg_power(ess, PPMI_D3); 1114 1115 return 0; 1116} 1117 1118static int 1119agg_resume(device_t dev) 1120{ 1121 int i, x; 1122 struct agg_info *ess = pcm_getdevinfo(dev); 1123 1124 agg_power(ess, PPMI_D0); 1125 DELAY(100000); 1126 agg_init(ess); 1127 if (mixer_reinit(dev)) { 1128 device_printf(dev, "unable to reinitialize the mixer\n"); 1129 return ENXIO; 1130 } 1131 1132 x = spltty(); 1133 for (i = 0; i < ess->playchns; i++) 1134 if (ess->active & (1 << i)) 1135 aggch_start_dac(ess->pch + i); 1136#if 0 /* XXX - RECORDING */ 1137 if (ess->active & (1 << i)) 1138 aggch_start_adc(&ess->rch); 1139#endif 1140 if (ess->active) { 1141 set_timer(ess); 1142 wp_starttimer(ess); 1143 } 1144 splx(x); 1145 return 0; 1146} 1147 1148static int 1149agg_shutdown(device_t dev) 1150{ 1151 struct agg_info *ess = pcm_getdevinfo(dev); 1152 int i; 1153 1154 wp_stoptimer(ess); 1155 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1156 1157 for (i = 0; i < ess->playchns; i++) 1158 aggch_stop_dac(ess->pch + i); 1159 1160#if 0 /* XXX - RECORDING */ 1161 aggch_stop_adc(&ess->rch); 1162#endif 1163 return 0; 1164} 1165 1166 1167static device_method_t agg_methods[] = { 1168 DEVMETHOD(device_probe, agg_probe), 1169 DEVMETHOD(device_attach, agg_attach), 1170 DEVMETHOD(device_detach, agg_detach), 1171 DEVMETHOD(device_suspend, agg_suspend), 1172 DEVMETHOD(device_resume, agg_resume), 1173 DEVMETHOD(device_shutdown, agg_shutdown), 1174 1175 { 0, 0 } 1176}; 1177 1178static driver_t agg_driver = { 1179 "pcm", 1180 agg_methods, 1181 sizeof(snddev_info), 1182}; 1183 1184static devclass_t pcm_devclass; 1185 1186DRIVER_MODULE(snd_maestro, pci, agg_driver, pcm_devclass, 0, 0); 1187MODULE_DEPEND(snd_maestro, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 1188MODULE_VERSION(snd_maestro, 1); 1189