18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * MUSB OTG driver - support for Mentor's DMA controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2005 Mentor Graphics Corporation 68c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 by Texas Instruments 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include "musb_core.h" 138c2ecf20Sopenharmony_ci#include "musb_dma.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \ 168c2ecf20Sopenharmony_ci (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset) 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define musb_read_hsdma_addr(mbase, bchannel) \ 198c2ecf20Sopenharmony_ci musb_readl(mbase, \ 208c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS)) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define musb_write_hsdma_addr(mbase, bchannel, addr) \ 238c2ecf20Sopenharmony_ci musb_writel(mbase, \ 248c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \ 258c2ecf20Sopenharmony_ci addr) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define musb_read_hsdma_count(mbase, bchannel) \ 288c2ecf20Sopenharmony_ci musb_readl(mbase, \ 298c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT)) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define musb_write_hsdma_count(mbase, bchannel, len) \ 328c2ecf20Sopenharmony_ci musb_writel(mbase, \ 338c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \ 348c2ecf20Sopenharmony_ci len) 358c2ecf20Sopenharmony_ci/* control register (16-bit): */ 368c2ecf20Sopenharmony_ci#define MUSB_HSDMA_ENABLE_SHIFT 0 378c2ecf20Sopenharmony_ci#define MUSB_HSDMA_TRANSMIT_SHIFT 1 388c2ecf20Sopenharmony_ci#define MUSB_HSDMA_MODE1_SHIFT 2 398c2ecf20Sopenharmony_ci#define MUSB_HSDMA_IRQENABLE_SHIFT 3 408c2ecf20Sopenharmony_ci#define MUSB_HSDMA_ENDPOINT_SHIFT 4 418c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BUSERROR_SHIFT 8 428c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_SHIFT 9 438c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT) 448c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_UNSPEC 0 458c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_INCR4 1 468c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_INCR8 2 478c2ecf20Sopenharmony_ci#define MUSB_HSDMA_BURSTMODE_INCR16 3 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define MUSB_HSDMA_CHANNELS 8 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct musb_dma_controller; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct musb_dma_channel { 548c2ecf20Sopenharmony_ci struct dma_channel channel; 558c2ecf20Sopenharmony_ci struct musb_dma_controller *controller; 568c2ecf20Sopenharmony_ci u32 start_addr; 578c2ecf20Sopenharmony_ci u32 len; 588c2ecf20Sopenharmony_ci u16 max_packet_sz; 598c2ecf20Sopenharmony_ci u8 idx; 608c2ecf20Sopenharmony_ci u8 epnum; 618c2ecf20Sopenharmony_ci u8 transmit; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct musb_dma_controller { 658c2ecf20Sopenharmony_ci struct dma_controller controller; 668c2ecf20Sopenharmony_ci struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS]; 678c2ecf20Sopenharmony_ci void *private_data; 688c2ecf20Sopenharmony_ci void __iomem *base; 698c2ecf20Sopenharmony_ci u8 channel_count; 708c2ecf20Sopenharmony_ci u8 used_channels; 718c2ecf20Sopenharmony_ci int irq; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void dma_channel_release(struct dma_channel *channel); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic void dma_controller_stop(struct musb_dma_controller *controller) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct musb *musb = controller->private_data; 798c2ecf20Sopenharmony_ci struct dma_channel *channel; 808c2ecf20Sopenharmony_ci u8 bit; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (controller->used_channels != 0) { 838c2ecf20Sopenharmony_ci dev_err(musb->controller, 848c2ecf20Sopenharmony_ci "Stopping DMA controller while channel active\n"); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { 878c2ecf20Sopenharmony_ci if (controller->used_channels & (1 << bit)) { 888c2ecf20Sopenharmony_ci channel = &controller->channel[bit].channel; 898c2ecf20Sopenharmony_ci dma_channel_release(channel); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!controller->used_channels) 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic struct dma_channel *dma_channel_allocate(struct dma_controller *c, 998c2ecf20Sopenharmony_ci struct musb_hw_ep *hw_ep, u8 transmit) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct musb_dma_controller *controller = container_of(c, 1028c2ecf20Sopenharmony_ci struct musb_dma_controller, controller); 1038c2ecf20Sopenharmony_ci struct musb_dma_channel *musb_channel = NULL; 1048c2ecf20Sopenharmony_ci struct dma_channel *channel = NULL; 1058c2ecf20Sopenharmony_ci u8 bit; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { 1088c2ecf20Sopenharmony_ci if (!(controller->used_channels & (1 << bit))) { 1098c2ecf20Sopenharmony_ci controller->used_channels |= (1 << bit); 1108c2ecf20Sopenharmony_ci musb_channel = &(controller->channel[bit]); 1118c2ecf20Sopenharmony_ci musb_channel->controller = controller; 1128c2ecf20Sopenharmony_ci musb_channel->idx = bit; 1138c2ecf20Sopenharmony_ci musb_channel->epnum = hw_ep->epnum; 1148c2ecf20Sopenharmony_ci musb_channel->transmit = transmit; 1158c2ecf20Sopenharmony_ci channel = &(musb_channel->channel); 1168c2ecf20Sopenharmony_ci channel->private_data = musb_channel; 1178c2ecf20Sopenharmony_ci channel->status = MUSB_DMA_STATUS_FREE; 1188c2ecf20Sopenharmony_ci channel->max_len = 0x100000; 1198c2ecf20Sopenharmony_ci /* Tx => mode 1; Rx => mode 0 */ 1208c2ecf20Sopenharmony_ci channel->desired_mode = transmit; 1218c2ecf20Sopenharmony_ci channel->actual_len = 0; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return channel; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void dma_channel_release(struct dma_channel *channel) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci channel->actual_len = 0; 1348c2ecf20Sopenharmony_ci musb_channel->start_addr = 0; 1358c2ecf20Sopenharmony_ci musb_channel->len = 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci musb_channel->controller->used_channels &= 1388c2ecf20Sopenharmony_ci ~(1 << musb_channel->idx); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci channel->status = MUSB_DMA_STATUS_UNKNOWN; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void configure_channel(struct dma_channel *channel, 1448c2ecf20Sopenharmony_ci u16 packet_sz, u8 mode, 1458c2ecf20Sopenharmony_ci dma_addr_t dma_addr, u32 len) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 1488c2ecf20Sopenharmony_ci struct musb_dma_controller *controller = musb_channel->controller; 1498c2ecf20Sopenharmony_ci struct musb *musb = controller->private_data; 1508c2ecf20Sopenharmony_ci void __iomem *mbase = controller->base; 1518c2ecf20Sopenharmony_ci u8 bchannel = musb_channel->idx; 1528c2ecf20Sopenharmony_ci u16 csr = 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci musb_dbg(musb, "%p, pkt_sz %d, addr %pad, len %d, mode %d", 1558c2ecf20Sopenharmony_ci channel, packet_sz, &dma_addr, len, mode); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (mode) { 1588c2ecf20Sopenharmony_ci csr |= 1 << MUSB_HSDMA_MODE1_SHIFT; 1598c2ecf20Sopenharmony_ci BUG_ON(len < packet_sz); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci csr |= MUSB_HSDMA_BURSTMODE_INCR16 1628c2ecf20Sopenharmony_ci << MUSB_HSDMA_BURSTMODE_SHIFT; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT) 1658c2ecf20Sopenharmony_ci | (1 << MUSB_HSDMA_ENABLE_SHIFT) 1668c2ecf20Sopenharmony_ci | (1 << MUSB_HSDMA_IRQENABLE_SHIFT) 1678c2ecf20Sopenharmony_ci | (musb_channel->transmit 1688c2ecf20Sopenharmony_ci ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT) 1698c2ecf20Sopenharmony_ci : 0); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* address/count */ 1728c2ecf20Sopenharmony_ci musb_write_hsdma_addr(mbase, bchannel, dma_addr); 1738c2ecf20Sopenharmony_ci musb_write_hsdma_count(mbase, bchannel, len); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* control (this should start things) */ 1768c2ecf20Sopenharmony_ci musb_writew(mbase, 1778c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), 1788c2ecf20Sopenharmony_ci csr); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int dma_channel_program(struct dma_channel *channel, 1828c2ecf20Sopenharmony_ci u16 packet_sz, u8 mode, 1838c2ecf20Sopenharmony_ci dma_addr_t dma_addr, u32 len) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 1868c2ecf20Sopenharmony_ci struct musb_dma_controller *controller = musb_channel->controller; 1878c2ecf20Sopenharmony_ci struct musb *musb = controller->private_data; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci musb_dbg(musb, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d", 1908c2ecf20Sopenharmony_ci musb_channel->epnum, 1918c2ecf20Sopenharmony_ci musb_channel->transmit ? "Tx" : "Rx", 1928c2ecf20Sopenharmony_ci packet_sz, &dma_addr, len, mode); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || 1958c2ecf20Sopenharmony_ci channel->status == MUSB_DMA_STATUS_BUSY); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * The DMA engine in RTL1.8 and above cannot handle 1998c2ecf20Sopenharmony_ci * DMA addresses that are not aligned to a 4 byte boundary. 2008c2ecf20Sopenharmony_ci * It ends up masking the last two bits of the address 2018c2ecf20Sopenharmony_ci * programmed in DMA_ADDR. 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * Fail such DMA transfers, so that the backup PIO mode 2048c2ecf20Sopenharmony_ci * can carry out the transfer 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4)) 2078c2ecf20Sopenharmony_ci return false; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci channel->actual_len = 0; 2108c2ecf20Sopenharmony_ci musb_channel->start_addr = dma_addr; 2118c2ecf20Sopenharmony_ci musb_channel->len = len; 2128c2ecf20Sopenharmony_ci musb_channel->max_packet_sz = packet_sz; 2138c2ecf20Sopenharmony_ci channel->status = MUSB_DMA_STATUS_BUSY; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci configure_channel(channel, packet_sz, mode, dma_addr, len); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return true; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int dma_channel_abort(struct dma_channel *channel) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct musb_dma_channel *musb_channel = channel->private_data; 2238c2ecf20Sopenharmony_ci void __iomem *mbase = musb_channel->controller->base; 2248c2ecf20Sopenharmony_ci struct musb *musb = musb_channel->controller->private_data; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci u8 bchannel = musb_channel->idx; 2278c2ecf20Sopenharmony_ci int offset; 2288c2ecf20Sopenharmony_ci u16 csr; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (channel->status == MUSB_DMA_STATUS_BUSY) { 2318c2ecf20Sopenharmony_ci if (musb_channel->transmit) { 2328c2ecf20Sopenharmony_ci offset = musb->io.ep_offset(musb_channel->epnum, 2338c2ecf20Sopenharmony_ci MUSB_TXCSR); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * The programming guide says that we must clear 2378c2ecf20Sopenharmony_ci * the DMAENAB bit before the DMAMODE bit... 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci csr = musb_readw(mbase, offset); 2408c2ecf20Sopenharmony_ci csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); 2418c2ecf20Sopenharmony_ci musb_writew(mbase, offset, csr); 2428c2ecf20Sopenharmony_ci csr &= ~MUSB_TXCSR_DMAMODE; 2438c2ecf20Sopenharmony_ci musb_writew(mbase, offset, csr); 2448c2ecf20Sopenharmony_ci } else { 2458c2ecf20Sopenharmony_ci offset = musb->io.ep_offset(musb_channel->epnum, 2468c2ecf20Sopenharmony_ci MUSB_RXCSR); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci csr = musb_readw(mbase, offset); 2498c2ecf20Sopenharmony_ci csr &= ~(MUSB_RXCSR_AUTOCLEAR | 2508c2ecf20Sopenharmony_ci MUSB_RXCSR_DMAENAB | 2518c2ecf20Sopenharmony_ci MUSB_RXCSR_DMAMODE); 2528c2ecf20Sopenharmony_ci musb_writew(mbase, offset, csr); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci musb_writew(mbase, 2568c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), 2578c2ecf20Sopenharmony_ci 0); 2588c2ecf20Sopenharmony_ci musb_write_hsdma_addr(mbase, bchannel, 0); 2598c2ecf20Sopenharmony_ci musb_write_hsdma_count(mbase, bchannel, 0); 2608c2ecf20Sopenharmony_ci channel->status = MUSB_DMA_STATUS_FREE; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ciirqreturn_t dma_controller_irq(int irq, void *private_data) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct musb_dma_controller *controller = private_data; 2698c2ecf20Sopenharmony_ci struct musb *musb = controller->private_data; 2708c2ecf20Sopenharmony_ci struct musb_dma_channel *musb_channel; 2718c2ecf20Sopenharmony_ci struct dma_channel *channel; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci void __iomem *mbase = controller->base; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci irqreturn_t retval = IRQ_NONE; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci unsigned long flags; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci u8 bchannel; 2808c2ecf20Sopenharmony_ci u8 int_hsdma; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci u32 addr, count; 2838c2ecf20Sopenharmony_ci u16 csr; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci spin_lock_irqsave(&musb->lock, flags); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci int_hsdma = musb_clearb(mbase, MUSB_HSDMA_INTR); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!int_hsdma) { 2908c2ecf20Sopenharmony_ci musb_dbg(musb, "spurious DMA irq"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { 2938c2ecf20Sopenharmony_ci musb_channel = (struct musb_dma_channel *) 2948c2ecf20Sopenharmony_ci &(controller->channel[bchannel]); 2958c2ecf20Sopenharmony_ci channel = &musb_channel->channel; 2968c2ecf20Sopenharmony_ci if (channel->status == MUSB_DMA_STATUS_BUSY) { 2978c2ecf20Sopenharmony_ci count = musb_read_hsdma_count(mbase, bchannel); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (count == 0) 3008c2ecf20Sopenharmony_ci int_hsdma |= (1 << bchannel); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci musb_dbg(musb, "int_hsdma = 0x%x", int_hsdma); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (!int_hsdma) 3078c2ecf20Sopenharmony_ci goto done; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { 3118c2ecf20Sopenharmony_ci if (int_hsdma & (1 << bchannel)) { 3128c2ecf20Sopenharmony_ci musb_channel = (struct musb_dma_channel *) 3138c2ecf20Sopenharmony_ci &(controller->channel[bchannel]); 3148c2ecf20Sopenharmony_ci channel = &musb_channel->channel; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci csr = musb_readw(mbase, 3178c2ecf20Sopenharmony_ci MUSB_HSDMA_CHANNEL_OFFSET(bchannel, 3188c2ecf20Sopenharmony_ci MUSB_HSDMA_CONTROL)); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) { 3218c2ecf20Sopenharmony_ci musb_channel->channel.status = 3228c2ecf20Sopenharmony_ci MUSB_DMA_STATUS_BUS_ABORT; 3238c2ecf20Sopenharmony_ci } else { 3248c2ecf20Sopenharmony_ci u8 devctl; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci addr = musb_read_hsdma_addr(mbase, 3278c2ecf20Sopenharmony_ci bchannel); 3288c2ecf20Sopenharmony_ci channel->actual_len = addr 3298c2ecf20Sopenharmony_ci - musb_channel->start_addr; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci musb_dbg(musb, "ch %p, 0x%x -> 0x%x (%zu / %d) %s", 3328c2ecf20Sopenharmony_ci channel, musb_channel->start_addr, 3338c2ecf20Sopenharmony_ci addr, channel->actual_len, 3348c2ecf20Sopenharmony_ci musb_channel->len, 3358c2ecf20Sopenharmony_ci (channel->actual_len 3368c2ecf20Sopenharmony_ci < musb_channel->len) ? 3378c2ecf20Sopenharmony_ci "=> reconfig 0" : "=> complete"); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci devctl = musb_readb(mbase, MUSB_DEVCTL); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci channel->status = MUSB_DMA_STATUS_FREE; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* completed */ 3448c2ecf20Sopenharmony_ci if (musb_channel->transmit && 3458c2ecf20Sopenharmony_ci (!channel->desired_mode || 3468c2ecf20Sopenharmony_ci (channel->actual_len % 3478c2ecf20Sopenharmony_ci musb_channel->max_packet_sz))) { 3488c2ecf20Sopenharmony_ci u8 epnum = musb_channel->epnum; 3498c2ecf20Sopenharmony_ci int offset = musb->io.ep_offset(epnum, 3508c2ecf20Sopenharmony_ci MUSB_TXCSR); 3518c2ecf20Sopenharmony_ci u16 txcsr; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * The programming guide says that we 3558c2ecf20Sopenharmony_ci * must clear DMAENAB before DMAMODE. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci musb_ep_select(mbase, epnum); 3588c2ecf20Sopenharmony_ci txcsr = musb_readw(mbase, offset); 3598c2ecf20Sopenharmony_ci if (channel->desired_mode == 1) { 3608c2ecf20Sopenharmony_ci txcsr &= ~(MUSB_TXCSR_DMAENAB 3618c2ecf20Sopenharmony_ci | MUSB_TXCSR_AUTOSET); 3628c2ecf20Sopenharmony_ci musb_writew(mbase, offset, txcsr); 3638c2ecf20Sopenharmony_ci /* Send out the packet */ 3648c2ecf20Sopenharmony_ci txcsr &= ~MUSB_TXCSR_DMAMODE; 3658c2ecf20Sopenharmony_ci txcsr |= MUSB_TXCSR_DMAENAB; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci txcsr |= MUSB_TXCSR_TXPKTRDY; 3688c2ecf20Sopenharmony_ci musb_writew(mbase, offset, txcsr); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci musb_dma_completion(musb, musb_channel->epnum, 3718c2ecf20Sopenharmony_ci musb_channel->transmit); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci retval = IRQ_HANDLED; 3778c2ecf20Sopenharmony_cidone: 3788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&musb->lock, flags); 3798c2ecf20Sopenharmony_ci return retval; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dma_controller_irq); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_civoid musbhs_dma_controller_destroy(struct dma_controller *c) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct musb_dma_controller *controller = container_of(c, 3868c2ecf20Sopenharmony_ci struct musb_dma_controller, controller); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci dma_controller_stop(controller); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (controller->irq) 3918c2ecf20Sopenharmony_ci free_irq(controller->irq, c); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci kfree(controller); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(musbhs_dma_controller_destroy); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct musb_dma_controller * 3988c2ecf20Sopenharmony_cidma_controller_alloc(struct musb *musb, void __iomem *base) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct musb_dma_controller *controller; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci controller = kzalloc(sizeof(*controller), GFP_KERNEL); 4038c2ecf20Sopenharmony_ci if (!controller) 4048c2ecf20Sopenharmony_ci return NULL; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci controller->channel_count = MUSB_HSDMA_CHANNELS; 4078c2ecf20Sopenharmony_ci controller->private_data = musb; 4088c2ecf20Sopenharmony_ci controller->base = base; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci controller->controller.channel_alloc = dma_channel_allocate; 4118c2ecf20Sopenharmony_ci controller->controller.channel_release = dma_channel_release; 4128c2ecf20Sopenharmony_ci controller->controller.channel_program = dma_channel_program; 4138c2ecf20Sopenharmony_ci controller->controller.channel_abort = dma_channel_abort; 4148c2ecf20Sopenharmony_ci return controller; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistruct dma_controller * 4188c2ecf20Sopenharmony_cimusbhs_dma_controller_create(struct musb *musb, void __iomem *base) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct musb_dma_controller *controller; 4218c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 4228c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 4238c2ecf20Sopenharmony_ci int irq = platform_get_irq_byname(pdev, "dma"); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (irq <= 0) { 4268c2ecf20Sopenharmony_ci dev_err(dev, "No DMA interrupt line!\n"); 4278c2ecf20Sopenharmony_ci return NULL; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci controller = dma_controller_alloc(musb, base); 4318c2ecf20Sopenharmony_ci if (!controller) 4328c2ecf20Sopenharmony_ci return NULL; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (request_irq(irq, dma_controller_irq, 0, 4358c2ecf20Sopenharmony_ci dev_name(musb->controller), controller)) { 4368c2ecf20Sopenharmony_ci dev_err(dev, "request_irq %d failed!\n", irq); 4378c2ecf20Sopenharmony_ci musb_dma_controller_destroy(&controller->controller); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return NULL; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci controller->irq = irq; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return &controller->controller; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(musbhs_dma_controller_create); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistruct dma_controller * 4498c2ecf20Sopenharmony_cimusbhs_dma_controller_create_noirq(struct musb *musb, void __iomem *base) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct musb_dma_controller *controller; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci controller = dma_controller_alloc(musb, base); 4548c2ecf20Sopenharmony_ci if (!controller) 4558c2ecf20Sopenharmony_ci return NULL; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return &controller->controller; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(musbhs_dma_controller_create_noirq); 460