/* * vx_release_pseudo_dma - disable the pseudo-DMA mode */ static void vx_release_pseudo_dma(vx_core_t *_chip) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Disable DMA and 16-bit accesses */ chip->regDIALOG &= ~(VXP_DLG_DMAWRITE_SEL_MASK| VXP_DLG_DMAREAD_SEL_MASK| VXP_DLG_DMA16_SEL_MASK); vx_outb(chip, DIALOG, chip->regDIALOG); /* HREQ pin disabled. */ vx_outb(chip, ICR, 0); }
/* * reset codec bit */ static void vxp_reset_codec(vx_core_t *_chip) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Set the reset CODEC bit to 1. */ vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_CODEC_RESET_MASK); vx_inb(chip, CDSP); snd_vx_delay(_chip, 10); /* Set the reset CODEC bit to 0. */ chip->regCDSP &= ~VXP_CDSP_CODEC_RESET_MASK; vx_outb(chip, CDSP, chip->regCDSP); vx_inb(chip, CDSP); snd_vx_delay(_chip, 1); }
static void vxp_reset_dsp(vx_core_t *_chip) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* set the reset dsp bit to 1 */ vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_DSP_RESET_MASK); vx_inb(chip, CDSP); mdelay(XX_DSP_RESET_WAIT_TIME); /* reset the bit */ chip->regCDSP &= ~VXP_CDSP_DSP_RESET_MASK; vx_outb(chip, CDSP, chip->regCDSP); vx_inb(chip, CDSP); mdelay(XX_DSP_RESET_WAIT_TIME); }
/* * reset codec bit */ static void vxp_reset_codec(struct vx_core *_chip) { struct snd_vxpocket *chip = to_vxpocket(_chip); /* Set the reset CODEC bit to 1. */ vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_CODEC_RESET_MASK); vx_inb(chip, CDSP); msleep(10); /* Set the reset CODEC bit to 0. */ chip->regCDSP &= ~VXP_CDSP_CODEC_RESET_MASK; vx_outb(chip, CDSP, chip->regCDSP); vx_inb(chip, CDSP); msleep(1); }
/* * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. * @do_write: 0 = read, 1 = set up for DMA write */ static void vx_setup_pseudo_dma(vx_core_t *_chip, int do_write) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Interrupt mode and HREQ pin enabled for host transmit / receive data transfers */ vx_outb(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ); /* Reset the pseudo-dma register */ vx_inb(chip, ISR); vx_outb(chip, ISR, 0); /* Select DMA in read/write transfer mode and in 16-bit accesses */ chip->regDIALOG |= VXP_DLG_DMA16_SEL_MASK; chip->regDIALOG |= do_write ? VXP_DLG_DMAWRITE_SEL_MASK : VXP_DLG_DMAREAD_SEL_MASK; vx_outb(chip, DIALOG, chip->regDIALOG); }
/* * vx_validate_irq - enable/disable IRQ */ static void vxp_validate_irq(vx_core_t *_chip, int enable) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Set the interrupt enable bit to 1 in CDSP register */ if (enable) chip->regCDSP |= VXP_CDSP_VALID_IRQ_MASK; else chip->regCDSP &= ~VXP_CDSP_VALID_IRQ_MASK; vx_outb(chip, CDSP, chip->regCDSP); }
/* * vx_test_and_ack - test and acknowledge interrupt * * called from irq hander, too * * spinlock held! */ static int vxp_test_and_ack(vx_core_t *_chip) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* not booted yet? */ if (! (_chip->chip_status & VX_STAT_XILINX_LOADED)) return -ENXIO; if (! (vx_inb(chip, DIALOG) & VXP_DLG_MEMIRQ_MASK)) return -EIO; /* ok, interrupts generated, now ack it */ /* set ACQUIT bit up and down */ vx_outb(chip, DIALOG, chip->regDIALOG | VXP_DLG_ACK_MEMIRQ_MASK); /* useless read just to spend some time and maintain * the ACQUIT signal up for a while ( a bus cycle ) */ vx_inb(chip, DIALOG); vx_outb(chip, DIALOG, chip->regDIALOG & ~VXP_DLG_ACK_MEMIRQ_MASK); return 0; }
/** * snd_vx_boot_xilinx - boot up the xilinx interface * @boot: the boot record to load */ int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) { unsigned int i; int no_fillup = vx_has_new_dsp(chip); /* check the length of boot image */ snd_assert(boot->length > 0, return -EINVAL); snd_assert(boot->length % 3 == 0, return -EINVAL); snd_assert(boot->image, return -EINVAL); #if 0 { /* more strict check */ unsigned int c = ((u32)boot->image[0] << 16) | ((u32)boot->image[1] << 8) | boot->image[2]; snd_assert(boot->length == (c + 2) * 3, return -EINVAL); } #endif /* reset dsp */ vx_reset_dsp(chip); udelay(END_OF_RESET_WAIT_TIME); /* another wait? */ /* download boot strap */ for (i = 0; i < 0x600; i += 3) { if (i >= boot->length) { if (no_fillup) break; if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { snd_printk(KERN_ERR "dsp boot failed at %d\n", i); return -EIO; } vx_outb(chip, TXH, 0); vx_outb(chip, TXM, 0); vx_outb(chip, TXL, 0); } else { unsigned char image[3]; if (copy_from_user(image, boot->image + i, 3)) return -EFAULT; if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { snd_printk(KERN_ERR "dsp boot failed at %d\n", i); return -EIO; } vx_outb(chip, TXH, image[0]); vx_outb(chip, TXM, image[1]); vx_outb(chip, TXL, image[2]); } } return 0; }
/** * snd_vx_boot_xilinx - boot up the xilinx interface * @boot: the boot record to load */ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot) { unsigned int i; int no_fillup = vx_has_new_dsp(chip); /* check the length of boot image */ snd_assert(boot->size > 0, return -EINVAL); snd_assert(boot->size % 3 == 0, return -EINVAL); #if 0 { /* more strict check */ unsigned int c = ((u32)boot->data[0] << 16) | ((u32)boot->data[1] << 8) | boot->data[2]; snd_assert(boot->size == (c + 2) * 3, return -EINVAL); } #endif /* reset dsp */ vx_reset_dsp(chip); udelay(END_OF_RESET_WAIT_TIME); /* another wait? */ /* download boot strap */ for (i = 0; i < 0x600; i += 3) { if (i >= boot->size) { if (no_fillup) break; if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { snd_printk(KERN_ERR "dsp boot failed at %d\n", i); return -EIO; } vx_outb(chip, TXH, 0); vx_outb(chip, TXM, 0); vx_outb(chip, TXL, 0); } else { unsigned char *image = boot->data + i; if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { snd_printk(KERN_ERR "dsp boot failed at %d\n", i); return -EIO; } vx_outb(chip, TXH, image[0]); vx_outb(chip, TXM, image[1]); vx_outb(chip, TXL, image[2]); } } return 0; }
/* * vx_load_xilinx_binary - load the xilinx binary image * the binary image is the binary array converted from the bitstream file. */ static int vxp_load_xilinx_binary(vx_core_t *_chip, const struct firmware *fw) { struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; unsigned int i; int c; int regCSUER, regRUER; unsigned char *image; unsigned char data; /* Switch to programmation mode */ chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK; vx_outb(chip, DIALOG, chip->regDIALOG); /* Save register CSUER and RUER */ regCSUER = vx_inb(chip, CSUER); regRUER = vx_inb(chip, RUER); /* reset HF0 and HF1 */ vx_outb(chip, ICR, 0); /* Wait for answer HF2 equal to 1 */ snd_printdd(KERN_DEBUG "check ISR_HF2\n"); if (vx_check_isr(_chip, ISR_HF2, ISR_HF2, 20) < 0) goto _error; /* set HF1 for loading xilinx binary */ vx_outb(chip, ICR, ICR_HF1); image = fw->data; for (i = 0; i < fw->size; i++, image++) { data = *image; if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0) goto _error; vx_outb(chip, TXL, data); /* wait for reading */ if (vx_wait_for_rx_full(_chip) < 0) goto _error; c = vx_inb(chip, RXL); if (c != (int)data) snd_printk(KERN_ERR "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n", i, c, (int)data); } /* reset HF1 */ vx_outb(chip, ICR, 0); /* wait for HF3 */ if (vx_check_isr(_chip, ISR_HF3, ISR_HF3, 20) < 0) goto _error; /* read the number of bytes received */ if (vx_wait_for_rx_full(_chip) < 0) goto _error; c = (int)vx_inb(chip, RXH) << 16; c |= (int)vx_inb(chip, RXM) << 8; c |= vx_inb(chip, RXL); snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, fw->size); vx_outb(chip, ICR, ICR_HF0); /* TEMPO 250ms : wait until Xilinx is downloaded */ snd_vx_delay(_chip, 300); /* test magical word */ if (vx_check_magic(_chip) < 0) goto _error; /* Restore register 0x0E and 0x0F (thus replacing COR and FCSR) */ vx_outb(chip, CSUER, regCSUER); vx_outb(chip, RUER, regRUER); /* Reset the Xilinx's signal enabling IO access */ chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK; vx_outb(chip, DIALOG, chip->regDIALOG); vx_inb(chip, DIALOG); snd_vx_delay(_chip, 10); chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK; vx_outb(chip, DIALOG, chip->regDIALOG); vx_inb(chip, DIALOG); /* Reset of the Codec */ vxp_reset_codec(_chip); vx_reset_dsp(_chip); return 0; _error: vx_outb(chip, CSUER, regCSUER); vx_outb(chip, RUER, regRUER); chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK; vx_outb(chip, DIALOG, chip->regDIALOG); return -EIO; }
/* * vx_send_msg_nolock - send a DSP message and read back the status * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * * this function doesn't call spinlock at all. */ int vx_send_msg_nolock(vx_core_t *chip, struct vx_rmh *rmh) { int i, err; if (chip->chip_status & VX_STAT_IS_STALE) return -EBUSY; if ((err = vx_reset_chk(chip)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n"); return err; } #if 0 printk(KERN_DEBUG "rmh: cmd = 0x%06x, length = %d, stype = %d\n", rmh->Cmd[0], rmh->LgCmd, rmh->DspStat); if (rmh->LgCmd > 1) { printk(KERN_DEBUG " "); for (i = 1; i < rmh->LgCmd; i++) printk("0x%06x ", rmh->Cmd[i]); printk("\n"); } #endif /* Check bit M is set according to length of the command */ if (rmh->LgCmd > 1) rmh->Cmd[0] |= MASK_MORE_THAN_1_WORD_COMMAND; else rmh->Cmd[0] &= MASK_1_WORD_COMMAND; /* Wait for TX empty */ if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n"); return err; } /* Write Cmd[0] */ vx_outb(chip, TXH, (rmh->Cmd[0] >> 16) & 0xff); vx_outb(chip, TXM, (rmh->Cmd[0] >> 8) & 0xff); vx_outb(chip, TXL, rmh->Cmd[0] & 0xff); /* Trigger irq MESSAGE */ if ((err = vx_send_irq_dsp(chip, IRQ_MESSAGE)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n"); return err; } /* Wait for CHK = 1 */ if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) return err; /* If error, get error value from RX */ if (vx_inb(chip, ISR) & ISR_ERR) { if ((err = vx_wait_for_rx_full(chip)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n"); return err; } err = vx_inb(chip, RXH) << 16; err |= vx_inb(chip, RXM) << 8; err |= vx_inb(chip, RXL); snd_printd(KERN_DEBUG "msg got error = 0x%x at cmd[0]\n", err); err = -(VX_ERR_MASK | err); return err; } /* Send the other words */ if (rmh->LgCmd > 1) { for (i = 1; i < rmh->LgCmd; i++) { /* Wait for TX ready */ if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n"); return err; } /* Write Cmd[i] */ vx_outb(chip, TXH, (rmh->Cmd[i] >> 16) & 0xff); vx_outb(chip, TXM, (rmh->Cmd[i] >> 8) & 0xff); vx_outb(chip, TXL, rmh->Cmd[i] & 0xff); /* Trigger irq MESS_READ_NEXT */ if ((err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n"); return err; } } /* Wait for TX empty */ if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) { snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n"); return err; } /* End of transfer */ err = vx_transfer_end(chip, IRQ_MESS_READ_END); if (err < 0) return err; } return vx_read_status(chip, rmh); }