int yds_write_codec(void *sc_, u_int8_t reg, u_int16_t data) { struct yds_codec_softc *sc = sc_; YWRITE2(sc->sc, AC97_CMD_ADDR, AC97_CMD_WRITE | AC97_ID(sc->id) | reg); YWRITE2(sc->sc, AC97_CMD_DATA, data); if (yds_ready_codec(sc)) { printf("%s: yds_write_codec timeout\n", sc->sc->sc_dev.dv_xname); return EIO; } return 0; }
static int yds_write_codec(void *sc_, uint8_t reg, uint16_t data) { struct yds_codec_softc *sc; sc = sc_; YWRITE2(sc->sc, AC97_CMD_ADDR, AC97_CMD_WRITE | AC97_ID(sc->id) | reg); YWRITE2(sc->sc, AC97_CMD_DATA, data); if (yds_ready_codec(sc)) { aprint_error_dev(sc->sc->sc_dev, "yds_write_codec timeout\n"); return EIO; } return 0; }
static int yds_download_mcode(struct yds_softc *sc) { static struct { const uint32_t *mcode; size_t size; } ctrls[] = { {yds_ds1_ctrl_mcode, sizeof(yds_ds1_ctrl_mcode)}, {yds_ds1e_ctrl_mcode, sizeof(yds_ds1e_ctrl_mcode)}, }; u_int ctrl; const uint32_t *p; size_t size; int dstype; if (sc->sc_flags & YDS_CAP_MCODE_1) dstype = YDS_DS_1; else if (sc->sc_flags & YDS_CAP_MCODE_1E) dstype = YDS_DS_1E; else return 1; /* unknown */ if (yds_disable_dsp(sc)) return 1; /* Software reset */ YWRITE4(sc, YDS_MODE, YDS_MODE_RESET); YWRITE4(sc, YDS_MODE, 0); YWRITE4(sc, YDS_MAPOF_REC, 0); YWRITE4(sc, YDS_MAPOF_EFFECT, 0); YWRITE4(sc, YDS_PLAY_CTRLBASE, 0); YWRITE4(sc, YDS_REC_CTRLBASE, 0); YWRITE4(sc, YDS_EFFECT_CTRLBASE, 0); YWRITE4(sc, YDS_WORK_BASE, 0); ctrl = YREAD2(sc, YDS_GLOBAL_CONTROL); YWRITE2(sc, YDS_GLOBAL_CONTROL, ctrl & ~0x0007); /* Download DSP microcode. */ p = yds_dsp_mcode; size = sizeof(yds_dsp_mcode); YWRITEREGION4(sc, YDS_DSP_INSTRAM, p, size); /* Download CONTROL microcode. */ p = ctrls[dstype].mcode; size = ctrls[dstype].size; YWRITEREGION4(sc, YDS_CTRL_INSTRAM, p, size); yds_enable_dsp(sc); delay(10 * 1000); /* nessesary on my 724F (??) */ return 0; }
int yds_read_codec(void *sc_, u_int8_t reg, u_int16_t *data) { struct yds_codec_softc *sc = sc_; YWRITE2(sc->sc, AC97_CMD_ADDR, AC97_CMD_READ | AC97_ID(sc->id) | reg); if (yds_ready_codec(sc)) { printf("%s: yds_read_codec timeout\n", sc->sc->sc_dev.dv_xname); return EIO; } if (PCI_PRODUCT(sc->sc->sc_id) == PCI_PRODUCT_YAMAHA_YMF744 && sc->sc->sc_revision < 2) { int i; for (i = 0; i < 600; i++) YREAD2(sc->sc, sc->status_data); } *data = YREAD2(sc->sc, sc->status_data); return 0; }
static int yds_read_codec(void *sc_, uint8_t reg, uint16_t *data) { struct yds_codec_softc *sc; sc = sc_; YWRITE2(sc->sc, AC97_CMD_ADDR, AC97_CMD_READ | AC97_ID(sc->id) | reg); if (yds_ready_codec(sc)) { aprint_error_dev(sc->sc->sc_dev, "yds_read_codec timeout\n"); return EIO; } if (PCI_PRODUCT(sc->sc->sc_id) == PCI_PRODUCT_YAMAHA_YMF744B && sc->sc->sc_revision < 2) { int i; for (i=0; i<600; i++) (void)YREAD2(sc->sc, sc->status_data); } *data = YREAD2(sc->sc, sc->status_data); return 0; }
void yds_attach(struct device *parent, struct device *self, void *aux) { struct yds_softc *sc = (struct yds_softc *)self; struct pci_attach_args *pa = (struct pci_attach_args *)aux; pci_chipset_tag_t pc = pa->pa_pc; char const *intrstr; pci_intr_handle_t ih; bus_size_t size; pcireg_t reg; int i; /* Map register to memory */ if (pci_mapreg_map(pa, YDS_PCI_MBA, PCI_MAPREG_TYPE_MEM, 0, &sc->memt, &sc->memh, NULL, &size, 0)) { printf(": can't map mem space\n"); return; } /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { printf(": couldn't map interrupt\n"); bus_space_unmap(sc->memt, sc->memh, size); return; } intrstr = pci_intr_string(pc, ih); sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE, yds_intr, sc, self->dv_xname); if (sc->sc_ih == NULL) { printf(": couldn't establish interrupt"); if (intrstr != NULL) printf(" at %s", intrstr); printf("\n"); bus_space_unmap(sc->memt, sc->memh, size); return; } printf(": %s\n", intrstr); sc->sc_dmatag = pa->pa_dmat; sc->sc_pc = pc; sc->sc_pcitag = pa->pa_tag; sc->sc_id = pa->pa_id; sc->sc_revision = PCI_REVISION(pa->pa_class); sc->sc_flags = yds_get_dstype(sc->sc_id); if (sc->sc_dev.dv_cfdata->cf_flags & YDS_CAP_LEGACY_SMOD_DISABLE) sc->sc_flags |= YDS_CAP_LEGACY_SMOD_DISABLE; #ifdef AUDIO_DEBUG if (ydsdebug) printf("%s: chip has %b\n", sc->sc_dev.dv_xname, YDS_CAP_BITS, sc->sc_flags); #endif /* Disable legacy mode */ reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_LEGACY); pci_conf_write(pc, pa->pa_tag, YDS_PCI_LEGACY, reg & YDS_PCI_LEGACY_LAD); /* Mute all volumes */ for (i = 0x80; i < 0xc0; i += 2) YWRITE2(sc, i, 0); sc->sc_legacy_iot = pa->pa_iot; mountroothook_establish(yds_attachhook, sc); }
static int yds_download_mcode(struct yds_softc *sc) { u_int ctrl; const u_int32_t *p; size_t size; u_char *buf; size_t buflen; int error; struct yds_firmware *yf; error = loadfirmware("yds", &buf, &buflen); if (error) return 1; yf = (struct yds_firmware *)buf; if (sc->sc_flags & YDS_CAP_MCODE_1) { p = (u_int32_t *)&yf->data[ntohl(yf->dsplen)]; size = ntohl(yf->ds1len); } else if (sc->sc_flags & YDS_CAP_MCODE_1E) { p = (u_int32_t *)&yf->data[ntohl(yf->dsplen) + ntohl(yf->ds1len)]; size = ntohl(yf->ds1elen); } else { free(buf, M_DEVBUF); return 1; /* unknown */ } if (size > buflen) { printf("%s: old firmware file, update please\n", sc->sc_dev.dv_xname); free(buf, M_DEVBUF); return 1; } if (yds_disable_dsp(sc)) { free(buf, M_DEVBUF); return 1; } /* Software reset */ YWRITE4(sc, YDS_MODE, YDS_MODE_RESET); YWRITE4(sc, YDS_MODE, 0); YWRITE4(sc, YDS_MAPOF_REC, 0); YWRITE4(sc, YDS_MAPOF_EFFECT, 0); YWRITE4(sc, YDS_PLAY_CTRLBASE, 0); YWRITE4(sc, YDS_REC_CTRLBASE, 0); YWRITE4(sc, YDS_EFFECT_CTRLBASE, 0); YWRITE4(sc, YDS_WORK_BASE, 0); ctrl = YREAD2(sc, YDS_GLOBAL_CONTROL); YWRITE2(sc, YDS_GLOBAL_CONTROL, ctrl & ~0x0007); /* Download DSP microcode. */ nswaph((u_int32_t *)&yf->data[0], ntohl(yf->dsplen)); YWRITEREGION4(sc, YDS_DSP_INSTRAM, (u_int32_t *)&yf->data[0], ntohl(yf->dsplen)); /* Download CONTROL microcode. */ nswaph((u_int32_t *)p, size); YWRITEREGION4(sc, YDS_CTRL_INSTRAM, p, size); yds_enable_dsp(sc); delay(10*1000); /* neccesary on my 724F (??) */ free(buf, M_DEVBUF); return 0; }
static void yds_attach(device_t parent, device_t self, void *aux) { struct yds_softc *sc; struct pci_attach_args *pa; pci_chipset_tag_t pc; char const *intrstr; pci_intr_handle_t ih; pcireg_t reg; struct yds_codec_softc *codec; int i, r, to; int revision; int ac97_id2; char intrbuf[PCI_INTRSTR_LEN]; sc = device_private(self); sc->sc_dev = self; pa = (struct pci_attach_args *)aux; pc = pa->pa_pc; revision = PCI_REVISION(pa->pa_class); pci_aprint_devinfo(pa, NULL); /* Map register to memory */ if (pci_mapreg_map(pa, YDS_PCI_MBA, PCI_MAPREG_TYPE_MEM, 0, &sc->memt, &sc->memh, NULL, NULL)) { aprint_error_dev(self, "can't map memory space\n"); return; } /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { aprint_error_dev(self, "couldn't map interrupt\n"); return; } mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_AUDIO); /* XXX IPL_NONE? */ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, yds_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } aprint_normal_dev(self, "interrupting at %s\n", intrstr); sc->sc_dmatag = pa->pa_dmat; sc->sc_pc = pc; sc->sc_pcitag = pa->pa_tag; sc->sc_id = pa->pa_id; sc->sc_revision = revision; sc->sc_flags = yds_get_dstype(sc->sc_id); #ifdef AUDIO_DEBUG if (ydsdebug) { char bits[80]; snprintb(bits, sizeof(bits), YDS_CAP_BITS, sc->sc_flags); printf("%s: chip has %s\n", device_xname(self), bits); } #endif /* Disable legacy mode */ reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_LEGACY); pci_conf_write(pc, pa->pa_tag, YDS_PCI_LEGACY, reg & YDS_PCI_LEGACY_LAD); /* Enable the device. */ reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); reg |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE); pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg); reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); /* Mute all volumes */ for (i = 0x80; i < 0xc0; i += 2) YWRITE2(sc, i, 0); /* Initialize the device */ if (yds_init(sc)) { aprint_error_dev(self, "initialize failed\n"); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } /* * Detect primary/secondary AC97 * YMF754 Hardware Specification Rev 1.01 page 24 */ reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_DSCTRL); pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg & ~YDS_DSCTRL_CRST); delay(400000); /* Needed for 740C. */ /* Primary */ for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0) break; delay(1); } if (to == AC97_TIMEOUT) { aprint_error_dev(self, "no AC97 available\n"); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } /* Secondary */ /* Secondary AC97 is used for 4ch audio. Currently unused. */ ac97_id2 = -1; if ((YREAD2(sc, YDS_ACTIVITY) & YDS_ACTIVITY_DOCKA) == 0) goto detected; #if 0 /* reset secondary... */ YWRITE2(sc, YDS_GPIO_OCTRL, YREAD2(sc, YDS_GPIO_OCTRL) & ~YDS_GPIO_GPO2); YWRITE2(sc, YDS_GPIO_FUNCE, (YREAD2(sc, YDS_GPIO_FUNCE)&(~YDS_GPIO_GPC2))|YDS_GPIO_GPE2); #endif for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY) == 0) break; delay(1); } if (to < AC97_TIMEOUT) { /* detect id */ for (ac97_id2 = 1; ac97_id2 < 4; ac97_id2++) { YWRITE2(sc, AC97_CMD_ADDR, AC97_CMD_READ | AC97_ID(ac97_id2) | 0x28); for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY) == 0) goto detected; delay(1); } } if (ac97_id2 == 4) ac97_id2 = -1; detected: ; } pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg | YDS_DSCTRL_CRST); delay (20); pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg & ~YDS_DSCTRL_CRST); delay (400000); for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0) break; delay(1); } /* * Attach ac97 codec */ for (i = 0; i < 2; i++) { static struct { int data; int addr; } statregs[] = { {AC97_STAT_DATA1, AC97_STAT_ADDR1}, {AC97_STAT_DATA2, AC97_STAT_ADDR2}, }; if (i == 1 && ac97_id2 == -1) break; /* secondary ac97 not available */ codec = &sc->sc_codec[i]; codec->sc = sc; codec->id = i == 1 ? ac97_id2 : 0; codec->status_data = statregs[i].data; codec->status_addr = statregs[i].addr; codec->host_if.arg = codec; codec->host_if.attach = yds_attach_codec; codec->host_if.read = yds_read_codec; codec->host_if.write = yds_write_codec; codec->host_if.reset = yds_reset_codec; r = ac97_attach(&codec->host_if, self, &sc->sc_lock); if (r != 0) { aprint_error_dev(self, "can't attach codec (error 0x%X)\n", r); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } } if (0 != auconv_create_encodings(yds_formats, YDS_NFORMATS, &sc->sc_encodings)) { mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } audio_attach_mi(&yds_hw_if, sc, self); sc->sc_legacy_iot = pa->pa_iot; config_defer(self, yds_configure_legacy); if (!pmf_device_register(self, yds_suspend, yds_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); }