/** Turn of DMA channel configured by EnableDma(). @param Channel DMA Channel to configure @param SuccesMask Bits in DMA4_CSR register indicate EFI_SUCCESS @param ErrorMask Bits in DMA4_CSR register indicate EFI_DEVICE_ERROR @retval EFI_SUCCESS DMA hardware disabled @retval EFI_INVALID_PARAMETER Channel is not valid @retval EFI_DEVICE_ERROR The system hardware could not map the requested information. **/ EFI_STATUS EFIAPI DisableDmaChannel ( IN UINTN Channel, IN UINT32 SuccessMask, IN UINT32 ErrorMask ) { EFI_STATUS Status = EFI_SUCCESS; UINT32 Reg; if (Channel > DMA4_MAX_CHANNEL) { return EFI_INVALID_PARAMETER; } do { Reg = MmioRead32 (DMA4_CSR(Channel)); if ((Reg & ErrorMask) != 0) { Status = EFI_DEVICE_ERROR; DEBUG ((EFI_D_ERROR, "DMA Error (%d) %x\n", Channel, Reg)); break; } } while ((Reg & SuccessMask) != SuccessMask); // Disable all status bits and clear them MmioWrite32 (DMA4_CICR (Channel), 0); MmioWrite32 (DMA4_CSR (Channel), DMA4_CSR_RESET); MmioAnd32 (DMA4_CCR(0), ~(DMA4_CCR_ENABLE | DMA4_CCR_RD_ACTIVE | DMA4_CCR_WR_ACTIVE)); return Status; }
static int omap3_setup_dma(SIM_HBA *hba, paddr_t paddr, int len, int dir) { SIM_MMC_EXT *ext; omap3_ext_t *omap3; dma4_param *param; ext = (SIM_MMC_EXT *)hba->ext; omap3 = (omap3_ext_t *)ext->handle; // // Initialize Tx DMA channel // param = (dma4_param *)(omap3->dma_base + DMA4_CCR(omap3->dma_chnl)); len = omap3_setup_pio(hba, len, dir); if (len > 0) { // Clear all status bits param->csr = 0x1FFE; param->cen = len >> 2; param->cfn = 1; // Number of frames param->cse = 1; param->cde = 1; param->cicr = 0; // We don't want any interrupts if (dir == MMC_DIR_IN) { // setup receive SDMA channel param->csdp = (2 << 0) // DATA_TYPE = 0x2: 32 bit element | (0 << 2) // RD_ADD_TRSLT = 0: Not used | (0 << 6) // SRC_PACKED = 0x0: Cannot pack source data | (0 << 7) // SRC_BURST_EN = 0x0: Cannot burst source | (0 << 9) // WR_ADD_TRSLT = 0: Undefined | (0 << 13) // DST_PACKED = 0x0: No packing | (3 << 14) // DST_BURST_EN = 0x3: Burst at 16x32 bits | (1 << 16) // WRITE_MODE = 0x1: Write posted | (0 << 18) // DST_ENDIAN_LOCK = 0x0: Endianness adapt | (0 << 19) // DST_ENDIAN = 0x0: Little Endian type at destination | (0 << 20) // SRC_ENDIAN_LOCK = 0x0: Endianness adapt | (0 << 21); // SRC_ENDIAN = 0x0: Little endian type at source param->ccr = DMA4_CCR_SYNCHRO_CONTROL(omap3->dma_rreq) // Synchro control bits | (1 << 5) // FS = 1: Packet mode with BS = 0x1 | (0 << 6) // READ_PRIORITY = 0x0: Low priority on read side | (0 << 7) // ENABLE = 0x0: The logical channel is disabled. | (0 << 8) // DMA4_CCRi[8] SUSPEND_SENSITIVE = 0 | (0 << 12) // DMA4_CCRi[13:12] SRC_AMODE = 0x0: Constant address mode | (1 << 14) // DMA4_CCRi[15:14] DST_AMODE = 0x1: Post-incremented address mode | (1 << 18) // DMA4_CCRi[18] BS = 0x1: Packet mode with FS = 0x1 | (1 << 24) // DMA4_CCRi[24] SEL_SRC_DST_SYNC = 0x1: Transfer is triggered by the source. The packet element number is specified in the DMA4_CSFI register. | (0 << 25); // DMA4_CCRi[25] BUFFERING_DISABLE = 0x0 param->cssa = omap3->mmc_pbase + OMAP3_MMCHS_DATA; param->cdsa = paddr; param->csf = omap3->blksz >> 2; } else {
/** * ti_sdma_deactivate_channel - deactivates a channel * @ch: the channel to deactivate * * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_deactivate_channel(unsigned int ch) { struct ti_sdma_softc *sc = ti_sdma_sc; unsigned int j; unsigned int addr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); /* First check if the channel is currently active */ if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EBUSY); } /* Mark the channel as inactive */ sc->sc_active_channels &= ~(1 << ch); /* Disable all DMA interrupts for the channel. */ ti_sdma_write_4(sc, DMA4_CICR(ch), 0); /* Make sure the DMA transfer is stopped. */ ti_sdma_write_4(sc, DMA4_CCR(ch), 0); /* Clear the CSR register and IRQ status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK); for (j = 0; j < NUM_DMA_IRQS; j++) { ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch)); } /* Clear all the channel registers, this should abort any transaction */ for (addr = DMA4_CCR(ch); addr <= DMA4_COLOR(ch); addr += 4) ti_sdma_write_4(sc, addr, 0x00000000); TI_SDMA_UNLOCK(sc); return 0; }
/** * ti_sdma_stop_xfer - stops any currently active transfers * @ch: the channel number to set the endianess of * * This function call is effectively a NOP if no transaction is in progress. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_stop_xfer(unsigned int ch) { struct ti_sdma_softc *sc = ti_sdma_sc; unsigned int j; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } /* Disable all DMA interrupts for the channel. */ ti_sdma_write_4(sc, DMA4_CICR(ch), 0); /* Make sure the DMA transfer is stopped. */ ti_sdma_write_4(sc, DMA4_CCR(ch), 0); /* Clear the CSR register and IRQ status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK); for (j = 0; j < NUM_DMA_IRQS; j++) { ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch)); } /* Configuration registers need to be re-written on the next xfer */ sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return (0); }
/** * ti_sdma_start_xfer_packet - starts a packet DMA transfer * @ch: the channel number to use for the transfer * @src_paddr: the source physical address * @dst_paddr: the destination physical address * @frmcnt: the number of frames to transfer * @elmcnt: the number of elements in a frame, an element is either an 8, 16 * or 32-bit value as defined by ti_sdma_set_xfer_burst() * @pktsize: the number of elements in each transfer packet * * The @frmcnt and @elmcnt define the overall number of bytes to transfer, * typically @frmcnt is 1 and @elmcnt contains the total number of elements. * @pktsize is the size of each individual packet, there might be multiple * packets per transfer. i.e. for the following with element size of 32-bits * * frmcnt = 1, elmcnt = 512, pktsize = 128 * * Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes * Packets transfered = 128 / 512 = 4 * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr, unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt, unsigned int pktsize) { struct ti_sdma_softc *sc = ti_sdma_sc; struct ti_sdma_channel *channel; uint32_t ccr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } channel = &sc->sc_channel[ch]; /* a) Write the CSDP register */ if (channel->need_reg_write) ti_sdma_write_4(sc, DMA4_CSDP(ch), channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1)); /* b) Set the number of elements to transfer CEN[23:0] */ ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt); /* c) Set the number of frames to transfer CFN[15:0] */ ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt); /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */ ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr); ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr); /* e) Write the CCR register */ ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr | DMA4_CCR_PACKET_TRANS); /* f) - Set the source element index increment CSEI[15:0] */ ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001); /* - Set the packet size, this is dependent on the sync source */ if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1)) ti_sdma_write_4(sc, DMA4_CSF(ch), pktsize); else ti_sdma_write_4(sc, DMA4_CDE(ch), pktsize); /* - Set the destination frame index increment CDFI[31:0] */ ti_sdma_write_4(sc, DMA4_CDF(ch), 0x0001); /* Clear the status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE); /* Write the start-bit and away we go */ ccr = ti_sdma_read_4(sc, DMA4_CCR(ch)); ccr |= (1 << 7); ti_sdma_write_4(sc, DMA4_CCR(ch), ccr); /* Clear the reg write flag */ channel->need_reg_write = 0; TI_SDMA_UNLOCK(sc); return (0); }
/** * ti_sdma_activate_channel - activates a DMA channel * @ch: upon return contains the channel allocated * @callback: a callback function to associate with the channel * @data: optional data supplied when the callback is called * * Simply activates a channel be enabling and writing default values to the * channel's register set. It doesn't start a transaction, just populates the * internal data structures and sets defaults. * * Note this function doesn't enable interrupts, for that you need to call * ti_sdma_enable_channel_irq(). If not using IRQ to detect the end of the * transfer, you can use ti_sdma_status_poll() to detect a change in the * status. * * A channel must be activated before any of the other DMA functions can be * called on it. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * 0 on success, otherwise an error code */ int ti_sdma_activate_channel(unsigned int *ch, void (*callback)(unsigned int ch, uint32_t status, void *data), void *data) { struct ti_sdma_softc *sc = ti_sdma_sc; struct ti_sdma_channel *channel = NULL; uint32_t addr; unsigned int i; /* Sanity check */ if (sc == NULL) return (ENOMEM); if (ch == NULL) return (EINVAL); TI_SDMA_LOCK(sc); /* Check to see if all channels are in use */ if (sc->sc_active_channels == 0xffffffff) { TI_SDMA_UNLOCK(sc); return (ENOMEM); } /* Find the first non-active channel */ for (i = 0; i < NUM_DMA_CHANNELS; i++) { if (!(sc->sc_active_channels & (0x1 << i))) { sc->sc_active_channels |= (0x1 << i); *ch = i; break; } } /* Get the channel struct and populate the fields */ channel = &sc->sc_channel[*ch]; channel->callback = callback; channel->callback_data = data; channel->need_reg_write = 1; /* Set the default configuration for the DMA channel */ channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2) | DMA4_CSDP_SRC_BURST_MODE(0) | DMA4_CSDP_DST_BURST_MODE(0) | DMA4_CSDP_SRC_ENDIANISM(0) | DMA4_CSDP_DST_ENDIANISM(0) | DMA4_CSDP_WRITE_MODE(0) | DMA4_CSDP_SRC_PACKED(0) | DMA4_CSDP_DST_PACKED(0); channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1) | DMA4_CCR_SRC_ADDRESS_MODE(1) | DMA4_CCR_READ_PRIORITY(0) | DMA4_CCR_WRITE_PRIORITY(0) | DMA4_CCR_SYNC_TRIGGER(0) | DMA4_CCR_FRAME_SYNC(0) | DMA4_CCR_BLOCK_SYNC(0); channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE | DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE; /* Clear all the channel registers, this should abort any transaction */ for (addr = DMA4_CCR(*ch); addr <= DMA4_COLOR(*ch); addr += 4) ti_sdma_write_4(sc, addr, 0x00000000); TI_SDMA_UNLOCK(sc); return 0; }
/** Configure OMAP DMA Channel @param Channel DMA Channel to configure @param Dma4 Pointer to structure used to initialize DMA registers for the Channel @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. @retval EFI_INVALID_PARAMETER Channel is not valid @retval EFI_DEVICE_ERROR The system hardware could not map the requested information. **/ EFI_STATUS EFIAPI EnableDmaChannel ( IN UINTN Channel, IN OMAP_DMA4 *DMA4 ) { UINT32 RegVal; if (Channel > DMA4_MAX_CHANNEL) { return EFI_INVALID_PARAMETER; } /* 1) Configure the transfer parameters in the logical DMA registers */ /*-------------------------------------------------------------------*/ /* a) Set the data type CSDP[1:0], the Read/Write Port access type CSDP[8:7]/[15:14], the Source/dest endianism CSDP[21]/CSDP[19], write mode CSDP[17:16], source/dest packed or nonpacked CSDP[6]/CSDP[13] */ // Read CSDP RegVal = MmioRead32 (DMA4_CSDP (Channel)); // Build reg RegVal = ((RegVal & ~ 0x3) | DMA4->DataType ); RegVal = ((RegVal & ~(0x3 << 7)) | (DMA4->ReadPortAccessType << 7)); RegVal = ((RegVal & ~(0x3 << 14)) | (DMA4->WritePortAccessType << 14)); RegVal = ((RegVal & ~(0x1 << 21)) | (DMA4->SourceEndiansim << 21)); RegVal = ((RegVal & ~(0x1 << 19)) | (DMA4->DestinationEndianism << 19)); RegVal = ((RegVal & ~(0x3 << 16)) | (DMA4->WriteMode << 16)); RegVal = ((RegVal & ~(0x1 << 6)) | (DMA4->SourcePacked << 6)); RegVal = ((RegVal & ~(0x1 << 13)) | (DMA4->DestinationPacked << 13)); // Write CSDP MmioWrite32 (DMA4_CSDP (Channel), RegVal); /* b) Set the number of element per frame CEN[23:0]*/ MmioWrite32 (DMA4_CEN (Channel), DMA4->NumberOfElementPerFrame); /* c) Set the number of frame per block CFN[15:0]*/ MmioWrite32 (DMA4_CFN (Channel), DMA4->NumberOfFramePerTransferBlock); /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0]*/ MmioWrite32 (DMA4_CSSA (Channel), DMA4->SourceStartAddress); MmioWrite32 (DMA4_CDSA (Channel), DMA4->DestinationStartAddress); /* e) Set the Read Port addressing mode CCR[13:12], the Write Port addressing mode CCR[15:14], read/write priority CCR[6]/CCR[26] I changed LCH CCR[20:19]=00 and CCR[4:0]=00000 to LCH CCR[20:19]= DMA4->WriteRequestNumber and CCR[4:0]=DMA4->ReadRequestNumber */ // Read CCR RegVal = MmioRead32 (DMA4_CCR (Channel)); // Build reg RegVal = ((RegVal & ~0x1f) | DMA4->ReadRequestNumber); RegVal = ((RegVal & ~(BIT20 | BIT19)) | DMA4->WriteRequestNumber << 19); RegVal = ((RegVal & ~(0x3 << 12)) | (DMA4->ReadPortAccessMode << 12)); RegVal = ((RegVal & ~(0x3 << 14)) | (DMA4->WritePortAccessMode << 14)); RegVal = ((RegVal & ~(0x1 << 6)) | (DMA4->ReadPriority << 6)); RegVal = ((RegVal & ~(0x1 << 26)) | (DMA4->WritePriority << 26)); // Write CCR MmioWrite32 (DMA4_CCR (Channel), RegVal); /* f)- Set the source element index CSEI[15:0]*/ MmioWrite32 (DMA4_CSEI (Channel), DMA4->SourceElementIndex); /* - Set the source frame index CSFI[15:0]*/ MmioWrite32 (DMA4_CSFI (Channel), DMA4->SourceFrameIndex); /* - Set the destination element index CDEI[15:0]*/ MmioWrite32 (DMA4_CDEI (Channel), DMA4->DestinationElementIndex); /* - Set the destination frame index CDFI[31:0]*/ MmioWrite32 (DMA4_CDFI (Channel), DMA4->DestinationFrameIndex); MmioWrite32 (DMA4_CDFI (Channel), DMA4->DestinationFrameIndex); // Enable all the status bits since we are polling MmioWrite32 (DMA4_CICR (Channel), DMA4_CICR_ENABLE_ALL); MmioWrite32 (DMA4_CSR (Channel), DMA4_CSR_RESET); /* 2) Start the DMA transfer by Setting the enable bit CCR[7]=1 */ /*--------------------------------------------------------------*/ //write enable bit MmioOr32 (DMA4_CCR(Channel), DMA4_CCR_ENABLE); //Launch transfer return EFI_SUCCESS; }