162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MUSB OTG driver - support for Mentor's DMA controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2005 Mentor Graphics Corporation 662306a36Sopenharmony_ci * Copyright (C) 2005-2007 by Texas Instruments 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/interrupt.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include "musb_core.h" 1362306a36Sopenharmony_ci#include "musb_dma.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \ 1662306a36Sopenharmony_ci (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define musb_read_hsdma_addr(mbase, bchannel) \ 1962306a36Sopenharmony_ci musb_readl(mbase, \ 2062306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS)) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define musb_write_hsdma_addr(mbase, bchannel, addr) \ 2362306a36Sopenharmony_ci musb_writel(mbase, \ 2462306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \ 2562306a36Sopenharmony_ci addr) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define musb_read_hsdma_count(mbase, bchannel) \ 2862306a36Sopenharmony_ci musb_readl(mbase, \ 2962306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define musb_write_hsdma_count(mbase, bchannel, len) \ 3262306a36Sopenharmony_ci musb_writel(mbase, \ 3362306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \ 3462306a36Sopenharmony_ci len) 3562306a36Sopenharmony_ci/* control register (16-bit): */ 3662306a36Sopenharmony_ci#define MUSB_HSDMA_ENABLE_SHIFT 0 3762306a36Sopenharmony_ci#define MUSB_HSDMA_TRANSMIT_SHIFT 1 3862306a36Sopenharmony_ci#define MUSB_HSDMA_MODE1_SHIFT 2 3962306a36Sopenharmony_ci#define MUSB_HSDMA_IRQENABLE_SHIFT 3 4062306a36Sopenharmony_ci#define MUSB_HSDMA_ENDPOINT_SHIFT 4 4162306a36Sopenharmony_ci#define MUSB_HSDMA_BUSERROR_SHIFT 8 4262306a36Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_SHIFT 9 4362306a36Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT) 4462306a36Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_UNSPEC 0 4562306a36Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_INCR4 1 4662306a36Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_INCR8 2 4762306a36Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_INCR16 3 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define MUSB_HSDMA_CHANNELS 8 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct musb_dma_controller; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct musb_dma_channel { 5462306a36Sopenharmony_ci struct dma_channel channel; 5562306a36Sopenharmony_ci struct musb_dma_controller *controller; 5662306a36Sopenharmony_ci u32 start_addr; 5762306a36Sopenharmony_ci u32 len; 5862306a36Sopenharmony_ci u16 max_packet_sz; 5962306a36Sopenharmony_ci u8 idx; 6062306a36Sopenharmony_ci u8 epnum; 6162306a36Sopenharmony_ci u8 transmit; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct musb_dma_controller { 6562306a36Sopenharmony_ci struct dma_controller controller; 6662306a36Sopenharmony_ci struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS]; 6762306a36Sopenharmony_ci void *private_data; 6862306a36Sopenharmony_ci void __iomem *base; 6962306a36Sopenharmony_ci u8 channel_count; 7062306a36Sopenharmony_ci u8 used_channels; 7162306a36Sopenharmony_ci int irq; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void dma_channel_release(struct dma_channel *channel); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic void dma_controller_stop(struct musb_dma_controller *controller) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct musb *musb = controller->private_data; 7962306a36Sopenharmony_ci struct dma_channel *channel; 8062306a36Sopenharmony_ci u8 bit; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (controller->used_channels != 0) { 8362306a36Sopenharmony_ci dev_err(musb->controller, 8462306a36Sopenharmony_ci "Stopping DMA controller while channel active\n"); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { 8762306a36Sopenharmony_ci if (controller->used_channels & (1 << bit)) { 8862306a36Sopenharmony_ci channel = &controller->channel[bit].channel; 8962306a36Sopenharmony_ci dma_channel_release(channel); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (!controller->used_channels) 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct dma_channel *dma_channel_allocate(struct dma_controller *c, 9962306a36Sopenharmony_ci struct musb_hw_ep *hw_ep, u8 transmit) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct musb_dma_controller *controller = container_of(c, 10262306a36Sopenharmony_ci struct musb_dma_controller, controller); 10362306a36Sopenharmony_ci struct musb_dma_channel *musb_channel = NULL; 10462306a36Sopenharmony_ci struct dma_channel *channel = NULL; 10562306a36Sopenharmony_ci u8 bit; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { 10862306a36Sopenharmony_ci if (!(controller->used_channels & (1 << bit))) { 10962306a36Sopenharmony_ci controller->used_channels |= (1 << bit); 11062306a36Sopenharmony_ci musb_channel = &(controller->channel[bit]); 11162306a36Sopenharmony_ci musb_channel->controller = controller; 11262306a36Sopenharmony_ci musb_channel->idx = bit; 11362306a36Sopenharmony_ci musb_channel->epnum = hw_ep->epnum; 11462306a36Sopenharmony_ci musb_channel->transmit = transmit; 11562306a36Sopenharmony_ci channel = &(musb_channel->channel); 11662306a36Sopenharmony_ci channel->private_data = musb_channel; 11762306a36Sopenharmony_ci channel->status = MUSB_DMA_STATUS_FREE; 11862306a36Sopenharmony_ci channel->max_len = 0x100000; 11962306a36Sopenharmony_ci /* Tx => mode 1; Rx => mode 0 */ 12062306a36Sopenharmony_ci channel->desired_mode = transmit; 12162306a36Sopenharmony_ci channel->actual_len = 0; 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return channel; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void dma_channel_release(struct dma_channel *channel) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci channel->actual_len = 0; 13462306a36Sopenharmony_ci musb_channel->start_addr = 0; 13562306a36Sopenharmony_ci musb_channel->len = 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci musb_channel->controller->used_channels &= 13862306a36Sopenharmony_ci ~(1 << musb_channel->idx); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci channel->status = MUSB_DMA_STATUS_UNKNOWN; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void configure_channel(struct dma_channel *channel, 14462306a36Sopenharmony_ci u16 packet_sz, u8 mode, 14562306a36Sopenharmony_ci dma_addr_t dma_addr, u32 len) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 14862306a36Sopenharmony_ci struct musb_dma_controller *controller = musb_channel->controller; 14962306a36Sopenharmony_ci struct musb *musb = controller->private_data; 15062306a36Sopenharmony_ci void __iomem *mbase = controller->base; 15162306a36Sopenharmony_ci u8 bchannel = musb_channel->idx; 15262306a36Sopenharmony_ci u16 csr = 0; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci musb_dbg(musb, "%p, pkt_sz %d, addr %pad, len %d, mode %d", 15562306a36Sopenharmony_ci channel, packet_sz, &dma_addr, len, mode); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (mode) { 15862306a36Sopenharmony_ci csr |= 1 << MUSB_HSDMA_MODE1_SHIFT; 15962306a36Sopenharmony_ci BUG_ON(len < packet_sz); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci csr |= MUSB_HSDMA_BURSTMODE_INCR16 16262306a36Sopenharmony_ci << MUSB_HSDMA_BURSTMODE_SHIFT; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT) 16562306a36Sopenharmony_ci | (1 << MUSB_HSDMA_ENABLE_SHIFT) 16662306a36Sopenharmony_ci | (1 << MUSB_HSDMA_IRQENABLE_SHIFT) 16762306a36Sopenharmony_ci | (musb_channel->transmit 16862306a36Sopenharmony_ci ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT) 16962306a36Sopenharmony_ci : 0); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* address/count */ 17262306a36Sopenharmony_ci musb_write_hsdma_addr(mbase, bchannel, dma_addr); 17362306a36Sopenharmony_ci musb_write_hsdma_count(mbase, bchannel, len); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* control (this should start things) */ 17662306a36Sopenharmony_ci musb_writew(mbase, 17762306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), 17862306a36Sopenharmony_ci csr); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int dma_channel_program(struct dma_channel *channel, 18262306a36Sopenharmony_ci u16 packet_sz, u8 mode, 18362306a36Sopenharmony_ci dma_addr_t dma_addr, u32 len) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 18662306a36Sopenharmony_ci struct musb_dma_controller *controller = musb_channel->controller; 18762306a36Sopenharmony_ci struct musb *musb = controller->private_data; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci musb_dbg(musb, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d", 19062306a36Sopenharmony_ci musb_channel->epnum, 19162306a36Sopenharmony_ci musb_channel->transmit ? "Tx" : "Rx", 19262306a36Sopenharmony_ci packet_sz, &dma_addr, len, mode); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || 19562306a36Sopenharmony_ci channel->status == MUSB_DMA_STATUS_BUSY); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * The DMA engine in RTL1.8 and above cannot handle 19962306a36Sopenharmony_ci * DMA addresses that are not aligned to a 4 byte boundary. 20062306a36Sopenharmony_ci * It ends up masking the last two bits of the address 20162306a36Sopenharmony_ci * programmed in DMA_ADDR. 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Fail such DMA transfers, so that the backup PIO mode 20462306a36Sopenharmony_ci * can carry out the transfer 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4)) 20762306a36Sopenharmony_ci return false; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci channel->actual_len = 0; 21062306a36Sopenharmony_ci musb_channel->start_addr = dma_addr; 21162306a36Sopenharmony_ci musb_channel->len = len; 21262306a36Sopenharmony_ci musb_channel->max_packet_sz = packet_sz; 21362306a36Sopenharmony_ci channel->status = MUSB_DMA_STATUS_BUSY; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci configure_channel(channel, packet_sz, mode, dma_addr, len); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return true; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int dma_channel_abort(struct dma_channel *channel) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 22362306a36Sopenharmony_ci void __iomem *mbase = musb_channel->controller->base; 22462306a36Sopenharmony_ci struct musb *musb = musb_channel->controller->private_data; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci u8 bchannel = musb_channel->idx; 22762306a36Sopenharmony_ci int offset; 22862306a36Sopenharmony_ci u16 csr; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (channel->status == MUSB_DMA_STATUS_BUSY) { 23162306a36Sopenharmony_ci if (musb_channel->transmit) { 23262306a36Sopenharmony_ci offset = musb->io.ep_offset(musb_channel->epnum, 23362306a36Sopenharmony_ci MUSB_TXCSR); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * The programming guide says that we must clear 23762306a36Sopenharmony_ci * the DMAENAB bit before the DMAMODE bit... 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci csr = musb_readw(mbase, offset); 24062306a36Sopenharmony_ci csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); 24162306a36Sopenharmony_ci musb_writew(mbase, offset, csr); 24262306a36Sopenharmony_ci csr &= ~MUSB_TXCSR_DMAMODE; 24362306a36Sopenharmony_ci musb_writew(mbase, offset, csr); 24462306a36Sopenharmony_ci } else { 24562306a36Sopenharmony_ci offset = musb->io.ep_offset(musb_channel->epnum, 24662306a36Sopenharmony_ci MUSB_RXCSR); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci csr = musb_readw(mbase, offset); 24962306a36Sopenharmony_ci csr &= ~(MUSB_RXCSR_AUTOCLEAR | 25062306a36Sopenharmony_ci MUSB_RXCSR_DMAENAB | 25162306a36Sopenharmony_ci MUSB_RXCSR_DMAMODE); 25262306a36Sopenharmony_ci musb_writew(mbase, offset, csr); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci musb_writew(mbase, 25662306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), 25762306a36Sopenharmony_ci 0); 25862306a36Sopenharmony_ci musb_write_hsdma_addr(mbase, bchannel, 0); 25962306a36Sopenharmony_ci musb_write_hsdma_count(mbase, bchannel, 0); 26062306a36Sopenharmony_ci channel->status = MUSB_DMA_STATUS_FREE; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciirqreturn_t dma_controller_irq(int irq, void *private_data) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct musb_dma_controller *controller = private_data; 26962306a36Sopenharmony_ci struct musb *musb = controller->private_data; 27062306a36Sopenharmony_ci struct musb_dma_channel *musb_channel; 27162306a36Sopenharmony_ci struct dma_channel *channel; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci void __iomem *mbase = controller->base; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci irqreturn_t retval = IRQ_NONE; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci unsigned long flags; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci u8 bchannel; 28062306a36Sopenharmony_ci u8 int_hsdma; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci u32 addr, count; 28362306a36Sopenharmony_ci u16 csr; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci spin_lock_irqsave(&musb->lock, flags); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci int_hsdma = musb_clearb(mbase, MUSB_HSDMA_INTR); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!int_hsdma) { 29062306a36Sopenharmony_ci musb_dbg(musb, "spurious DMA irq"); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { 29362306a36Sopenharmony_ci musb_channel = (struct musb_dma_channel *) 29462306a36Sopenharmony_ci &(controller->channel[bchannel]); 29562306a36Sopenharmony_ci channel = &musb_channel->channel; 29662306a36Sopenharmony_ci if (channel->status == MUSB_DMA_STATUS_BUSY) { 29762306a36Sopenharmony_ci count = musb_read_hsdma_count(mbase, bchannel); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (count == 0) 30062306a36Sopenharmony_ci int_hsdma |= (1 << bchannel); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci musb_dbg(musb, "int_hsdma = 0x%x", int_hsdma); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!int_hsdma) 30762306a36Sopenharmony_ci goto done; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { 31162306a36Sopenharmony_ci if (int_hsdma & (1 << bchannel)) { 31262306a36Sopenharmony_ci musb_channel = (struct musb_dma_channel *) 31362306a36Sopenharmony_ci &(controller->channel[bchannel]); 31462306a36Sopenharmony_ci channel = &musb_channel->channel; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci csr = musb_readw(mbase, 31762306a36Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, 31862306a36Sopenharmony_ci MUSB_HSDMA_CONTROL)); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) { 32162306a36Sopenharmony_ci musb_channel->channel.status = 32262306a36Sopenharmony_ci MUSB_DMA_STATUS_BUS_ABORT; 32362306a36Sopenharmony_ci } else { 32462306a36Sopenharmony_ci addr = musb_read_hsdma_addr(mbase, 32562306a36Sopenharmony_ci bchannel); 32662306a36Sopenharmony_ci channel->actual_len = addr 32762306a36Sopenharmony_ci - musb_channel->start_addr; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci musb_dbg(musb, "ch %p, 0x%x -> 0x%x (%zu / %d) %s", 33062306a36Sopenharmony_ci channel, musb_channel->start_addr, 33162306a36Sopenharmony_ci addr, channel->actual_len, 33262306a36Sopenharmony_ci musb_channel->len, 33362306a36Sopenharmony_ci (channel->actual_len 33462306a36Sopenharmony_ci < musb_channel->len) ? 33562306a36Sopenharmony_ci "=> reconfig 0" : "=> complete"); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci channel->status = MUSB_DMA_STATUS_FREE; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* completed */ 34062306a36Sopenharmony_ci if (musb_channel->transmit && 34162306a36Sopenharmony_ci (!channel->desired_mode || 34262306a36Sopenharmony_ci (channel->actual_len % 34362306a36Sopenharmony_ci musb_channel->max_packet_sz))) { 34462306a36Sopenharmony_ci u8 epnum = musb_channel->epnum; 34562306a36Sopenharmony_ci int offset = musb->io.ep_offset(epnum, 34662306a36Sopenharmony_ci MUSB_TXCSR); 34762306a36Sopenharmony_ci u16 txcsr; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * The programming guide says that we 35162306a36Sopenharmony_ci * must clear DMAENAB before DMAMODE. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci musb_ep_select(mbase, epnum); 35462306a36Sopenharmony_ci txcsr = musb_readw(mbase, offset); 35562306a36Sopenharmony_ci if (channel->desired_mode == 1) { 35662306a36Sopenharmony_ci txcsr &= ~(MUSB_TXCSR_DMAENAB 35762306a36Sopenharmony_ci | MUSB_TXCSR_AUTOSET); 35862306a36Sopenharmony_ci musb_writew(mbase, offset, txcsr); 35962306a36Sopenharmony_ci /* Send out the packet */ 36062306a36Sopenharmony_ci txcsr &= ~MUSB_TXCSR_DMAMODE; 36162306a36Sopenharmony_ci txcsr |= MUSB_TXCSR_DMAENAB; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci txcsr |= MUSB_TXCSR_TXPKTRDY; 36462306a36Sopenharmony_ci musb_writew(mbase, offset, txcsr); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci musb_dma_completion(musb, musb_channel->epnum, 36762306a36Sopenharmony_ci musb_channel->transmit); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci retval = IRQ_HANDLED; 37362306a36Sopenharmony_cidone: 37462306a36Sopenharmony_ci spin_unlock_irqrestore(&musb->lock, flags); 37562306a36Sopenharmony_ci return retval; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_controller_irq); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_civoid musbhs_dma_controller_destroy(struct dma_controller *c) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct musb_dma_controller *controller = container_of(c, 38262306a36Sopenharmony_ci struct musb_dma_controller, controller); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci dma_controller_stop(controller); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (controller->irq) 38762306a36Sopenharmony_ci free_irq(controller->irq, c); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci kfree(controller); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(musbhs_dma_controller_destroy); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic struct musb_dma_controller * 39462306a36Sopenharmony_cidma_controller_alloc(struct musb *musb, void __iomem *base) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct musb_dma_controller *controller; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci controller = kzalloc(sizeof(*controller), GFP_KERNEL); 39962306a36Sopenharmony_ci if (!controller) 40062306a36Sopenharmony_ci return NULL; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci controller->channel_count = MUSB_HSDMA_CHANNELS; 40362306a36Sopenharmony_ci controller->private_data = musb; 40462306a36Sopenharmony_ci controller->base = base; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci controller->controller.channel_alloc = dma_channel_allocate; 40762306a36Sopenharmony_ci controller->controller.channel_release = dma_channel_release; 40862306a36Sopenharmony_ci controller->controller.channel_program = dma_channel_program; 40962306a36Sopenharmony_ci controller->controller.channel_abort = dma_channel_abort; 41062306a36Sopenharmony_ci return controller; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistruct dma_controller * 41462306a36Sopenharmony_cimusbhs_dma_controller_create(struct musb *musb, void __iomem *base) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct musb_dma_controller *controller; 41762306a36Sopenharmony_ci struct device *dev = musb->controller; 41862306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 41962306a36Sopenharmony_ci int irq = platform_get_irq_byname(pdev, "dma"); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (irq <= 0) { 42262306a36Sopenharmony_ci dev_err(dev, "No DMA interrupt line!\n"); 42362306a36Sopenharmony_ci return NULL; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci controller = dma_controller_alloc(musb, base); 42762306a36Sopenharmony_ci if (!controller) 42862306a36Sopenharmony_ci return NULL; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (request_irq(irq, dma_controller_irq, 0, 43162306a36Sopenharmony_ci dev_name(musb->controller), controller)) { 43262306a36Sopenharmony_ci dev_err(dev, "request_irq %d failed!\n", irq); 43362306a36Sopenharmony_ci musb_dma_controller_destroy(&controller->controller); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return NULL; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci controller->irq = irq; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return &controller->controller; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(musbhs_dma_controller_create); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistruct dma_controller * 44562306a36Sopenharmony_cimusbhs_dma_controller_create_noirq(struct musb *musb, void __iomem *base) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct musb_dma_controller *controller; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci controller = dma_controller_alloc(musb, base); 45062306a36Sopenharmony_ci if (!controller) 45162306a36Sopenharmony_ci return NULL; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return &controller->controller; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(musbhs_dma_controller_create_noirq); 456