19b3452d1SSebastian Andrzej Siewior #include <linux/device.h> 29b3452d1SSebastian Andrzej Siewior #include <linux/dma-mapping.h> 39b3452d1SSebastian Andrzej Siewior #include <linux/dmaengine.h> 49b3452d1SSebastian Andrzej Siewior #include <linux/sizes.h> 59b3452d1SSebastian Andrzej Siewior #include <linux/platform_device.h> 69b3452d1SSebastian Andrzej Siewior #include <linux/of.h> 79b3452d1SSebastian Andrzej Siewior 89b3452d1SSebastian Andrzej Siewior #include "musb_core.h" 99b3452d1SSebastian Andrzej Siewior 109b3452d1SSebastian Andrzej Siewior #define RNDIS_REG(x) (0x80 + ((x - 1) * 4)) 119b3452d1SSebastian Andrzej Siewior 129b3452d1SSebastian Andrzej Siewior #define EP_MODE_AUTOREG_NONE 0 139b3452d1SSebastian Andrzej Siewior #define EP_MODE_AUTOREG_ALL_NEOP 1 149b3452d1SSebastian Andrzej Siewior #define EP_MODE_AUTOREG_ALWAYS 3 159b3452d1SSebastian Andrzej Siewior 169b3452d1SSebastian Andrzej Siewior #define EP_MODE_DMA_TRANSPARENT 0 179b3452d1SSebastian Andrzej Siewior #define EP_MODE_DMA_RNDIS 1 189b3452d1SSebastian Andrzej Siewior #define EP_MODE_DMA_GEN_RNDIS 3 199b3452d1SSebastian Andrzej Siewior 209b3452d1SSebastian Andrzej Siewior #define USB_CTRL_TX_MODE 0x70 219b3452d1SSebastian Andrzej Siewior #define USB_CTRL_RX_MODE 0x74 229b3452d1SSebastian Andrzej Siewior #define USB_CTRL_AUTOREQ 0xd0 239b3452d1SSebastian Andrzej Siewior #define USB_TDOWN 0xd8 249b3452d1SSebastian Andrzej Siewior 259b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel { 269b3452d1SSebastian Andrzej Siewior struct dma_channel channel; 279b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 289b3452d1SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep; 299b3452d1SSebastian Andrzej Siewior struct dma_chan *dc; 309b3452d1SSebastian Andrzej Siewior dma_cookie_t cookie; 319b3452d1SSebastian Andrzej Siewior u8 port_num; 329b3452d1SSebastian Andrzej Siewior u8 is_tx; 339b3452d1SSebastian Andrzej Siewior u8 is_allocated; 349b3452d1SSebastian Andrzej Siewior u8 usb_toggle; 359b3452d1SSebastian Andrzej Siewior 369b3452d1SSebastian Andrzej Siewior dma_addr_t buf_addr; 379b3452d1SSebastian Andrzej Siewior u32 total_len; 389b3452d1SSebastian Andrzej Siewior u32 prog_len; 399b3452d1SSebastian Andrzej Siewior u32 transferred; 409b3452d1SSebastian Andrzej Siewior u32 packet_sz; 41a655f481SSebastian Andrzej Siewior struct list_head tx_check; 42*1af54b7aSGeorge Cherian struct work_struct dma_completion; 439b3452d1SSebastian Andrzej Siewior }; 449b3452d1SSebastian Andrzej Siewior 459b3452d1SSebastian Andrzej Siewior #define MUSB_DMA_NUM_CHANNELS 15 469b3452d1SSebastian Andrzej Siewior 479b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller { 489b3452d1SSebastian Andrzej Siewior struct dma_controller controller; 499b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; 509b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; 519b3452d1SSebastian Andrzej Siewior struct musb *musb; 52a655f481SSebastian Andrzej Siewior struct hrtimer early_tx; 53a655f481SSebastian Andrzej Siewior struct list_head early_tx_list; 549b3452d1SSebastian Andrzej Siewior u32 rx_mode; 559b3452d1SSebastian Andrzej Siewior u32 tx_mode; 569b3452d1SSebastian Andrzej Siewior u32 auto_req; 579b3452d1SSebastian Andrzej Siewior }; 589b3452d1SSebastian Andrzej Siewior 599b3452d1SSebastian Andrzej Siewior static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) 609b3452d1SSebastian Andrzej Siewior { 619b3452d1SSebastian Andrzej Siewior u16 csr; 629b3452d1SSebastian Andrzej Siewior u8 toggle; 639b3452d1SSebastian Andrzej Siewior 649b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) 659b3452d1SSebastian Andrzej Siewior return; 669b3452d1SSebastian Andrzej Siewior if (!is_host_active(cppi41_channel->controller->musb)) 679b3452d1SSebastian Andrzej Siewior return; 689b3452d1SSebastian Andrzej Siewior 699b3452d1SSebastian Andrzej Siewior csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); 709b3452d1SSebastian Andrzej Siewior toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; 719b3452d1SSebastian Andrzej Siewior 729b3452d1SSebastian Andrzej Siewior cppi41_channel->usb_toggle = toggle; 739b3452d1SSebastian Andrzej Siewior } 749b3452d1SSebastian Andrzej Siewior 759b3452d1SSebastian Andrzej Siewior static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) 769b3452d1SSebastian Andrzej Siewior { 779b3452d1SSebastian Andrzej Siewior u16 csr; 789b3452d1SSebastian Andrzej Siewior u8 toggle; 799b3452d1SSebastian Andrzej Siewior 809b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) 819b3452d1SSebastian Andrzej Siewior return; 829b3452d1SSebastian Andrzej Siewior if (!is_host_active(cppi41_channel->controller->musb)) 839b3452d1SSebastian Andrzej Siewior return; 849b3452d1SSebastian Andrzej Siewior 859b3452d1SSebastian Andrzej Siewior csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); 869b3452d1SSebastian Andrzej Siewior toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; 879b3452d1SSebastian Andrzej Siewior 889b3452d1SSebastian Andrzej Siewior /* 899b3452d1SSebastian Andrzej Siewior * AM335x Advisory 1.0.13: Due to internal synchronisation error the 909b3452d1SSebastian Andrzej Siewior * data toggle may reset from DATA1 to DATA0 during receiving data from 919b3452d1SSebastian Andrzej Siewior * more than one endpoint. 929b3452d1SSebastian Andrzej Siewior */ 939b3452d1SSebastian Andrzej Siewior if (!toggle && toggle == cppi41_channel->usb_toggle) { 949b3452d1SSebastian Andrzej Siewior csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; 959b3452d1SSebastian Andrzej Siewior musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); 969b3452d1SSebastian Andrzej Siewior dev_dbg(cppi41_channel->controller->musb->controller, 979b3452d1SSebastian Andrzej Siewior "Restoring DATA1 toggle.\n"); 989b3452d1SSebastian Andrzej Siewior } 999b3452d1SSebastian Andrzej Siewior 1009b3452d1SSebastian Andrzej Siewior cppi41_channel->usb_toggle = toggle; 1019b3452d1SSebastian Andrzej Siewior } 1029b3452d1SSebastian Andrzej Siewior 103a655f481SSebastian Andrzej Siewior static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) 104a655f481SSebastian Andrzej Siewior { 105a655f481SSebastian Andrzej Siewior u8 epnum = hw_ep->epnum; 106a655f481SSebastian Andrzej Siewior struct musb *musb = hw_ep->musb; 107a655f481SSebastian Andrzej Siewior void __iomem *epio = musb->endpoints[epnum].regs; 108a655f481SSebastian Andrzej Siewior u16 csr; 109a655f481SSebastian Andrzej Siewior 110a655f481SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_TXCSR); 111a655f481SSebastian Andrzej Siewior if (csr & MUSB_TXCSR_TXPKTRDY) 112a655f481SSebastian Andrzej Siewior return false; 113a655f481SSebastian Andrzej Siewior return true; 114a655f481SSebastian Andrzej Siewior } 115a655f481SSebastian Andrzej Siewior 116*1af54b7aSGeorge Cherian static bool is_isoc(struct musb_hw_ep *hw_ep, bool in) 117*1af54b7aSGeorge Cherian { 118*1af54b7aSGeorge Cherian if (in && hw_ep->in_qh) { 119*1af54b7aSGeorge Cherian if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC) 120*1af54b7aSGeorge Cherian return true; 121*1af54b7aSGeorge Cherian } else if (hw_ep->out_qh) { 122*1af54b7aSGeorge Cherian if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC) 123*1af54b7aSGeorge Cherian return true; 124*1af54b7aSGeorge Cherian } 125*1af54b7aSGeorge Cherian return false; 126*1af54b7aSGeorge Cherian } 127*1af54b7aSGeorge Cherian 128d373a853SSebastian Andrzej Siewior static void cppi41_dma_callback(void *private_data); 129d373a853SSebastian Andrzej Siewior 130a655f481SSebastian Andrzej Siewior static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) 1319b3452d1SSebastian Andrzej Siewior { 1329b3452d1SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 1339b3452d1SSebastian Andrzej Siewior struct musb *musb = hw_ep->musb; 1349b3452d1SSebastian Andrzej Siewior 135d373a853SSebastian Andrzej Siewior if (!cppi41_channel->prog_len) { 1369b3452d1SSebastian Andrzej Siewior 1379b3452d1SSebastian Andrzej Siewior /* done, complete */ 1389b3452d1SSebastian Andrzej Siewior cppi41_channel->channel.actual_len = 1399b3452d1SSebastian Andrzej Siewior cppi41_channel->transferred; 1409b3452d1SSebastian Andrzej Siewior cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; 1419b3452d1SSebastian Andrzej Siewior musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); 1429b3452d1SSebastian Andrzej Siewior } else { 1439b3452d1SSebastian Andrzej Siewior /* next iteration, reload */ 1449b3452d1SSebastian Andrzej Siewior struct dma_chan *dc = cppi41_channel->dc; 1459b3452d1SSebastian Andrzej Siewior struct dma_async_tx_descriptor *dma_desc; 1469b3452d1SSebastian Andrzej Siewior enum dma_transfer_direction direction; 1479b3452d1SSebastian Andrzej Siewior u16 csr; 1489b3452d1SSebastian Andrzej Siewior u32 remain_bytes; 1499b3452d1SSebastian Andrzej Siewior void __iomem *epio = cppi41_channel->hw_ep->regs; 1509b3452d1SSebastian Andrzej Siewior 1519b3452d1SSebastian Andrzej Siewior cppi41_channel->buf_addr += cppi41_channel->packet_sz; 1529b3452d1SSebastian Andrzej Siewior 1539b3452d1SSebastian Andrzej Siewior remain_bytes = cppi41_channel->total_len; 1549b3452d1SSebastian Andrzej Siewior remain_bytes -= cppi41_channel->transferred; 1559b3452d1SSebastian Andrzej Siewior remain_bytes = min(remain_bytes, cppi41_channel->packet_sz); 1569b3452d1SSebastian Andrzej Siewior cppi41_channel->prog_len = remain_bytes; 1579b3452d1SSebastian Andrzej Siewior 1589b3452d1SSebastian Andrzej Siewior direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV 1599b3452d1SSebastian Andrzej Siewior : DMA_DEV_TO_MEM; 1609b3452d1SSebastian Andrzej Siewior dma_desc = dmaengine_prep_slave_single(dc, 1619b3452d1SSebastian Andrzej Siewior cppi41_channel->buf_addr, 1629b3452d1SSebastian Andrzej Siewior remain_bytes, 1639b3452d1SSebastian Andrzej Siewior direction, 1649b3452d1SSebastian Andrzej Siewior DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 165d373a853SSebastian Andrzej Siewior if (WARN_ON(!dma_desc)) 1669b3452d1SSebastian Andrzej Siewior return; 1679b3452d1SSebastian Andrzej Siewior 1689b3452d1SSebastian Andrzej Siewior dma_desc->callback = cppi41_dma_callback; 169a655f481SSebastian Andrzej Siewior dma_desc->callback_param = &cppi41_channel->channel; 1709b3452d1SSebastian Andrzej Siewior cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); 1719b3452d1SSebastian Andrzej Siewior dma_async_issue_pending(dc); 1729b3452d1SSebastian Andrzej Siewior 1739b3452d1SSebastian Andrzej Siewior if (!cppi41_channel->is_tx) { 1749b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_RXCSR); 1759b3452d1SSebastian Andrzej Siewior csr |= MUSB_RXCSR_H_REQPKT; 1769b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 1779b3452d1SSebastian Andrzej Siewior } 1789b3452d1SSebastian Andrzej Siewior } 179d373a853SSebastian Andrzej Siewior } 180d373a853SSebastian Andrzej Siewior 181*1af54b7aSGeorge Cherian static void cppi_trans_done_work(struct work_struct *work) 182*1af54b7aSGeorge Cherian { 183*1af54b7aSGeorge Cherian unsigned long flags; 184*1af54b7aSGeorge Cherian struct cppi41_dma_channel *cppi41_channel = 185*1af54b7aSGeorge Cherian container_of(work, struct cppi41_dma_channel, dma_completion); 186*1af54b7aSGeorge Cherian struct cppi41_dma_controller *controller = cppi41_channel->controller; 187*1af54b7aSGeorge Cherian struct musb *musb = controller->musb; 188*1af54b7aSGeorge Cherian struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 189*1af54b7aSGeorge Cherian bool empty; 190*1af54b7aSGeorge Cherian 191*1af54b7aSGeorge Cherian if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) { 192*1af54b7aSGeorge Cherian spin_lock_irqsave(&musb->lock, flags); 193*1af54b7aSGeorge Cherian cppi41_trans_done(cppi41_channel); 194*1af54b7aSGeorge Cherian spin_unlock_irqrestore(&musb->lock, flags); 195*1af54b7aSGeorge Cherian } else { 196*1af54b7aSGeorge Cherian empty = musb_is_tx_fifo_empty(hw_ep); 197*1af54b7aSGeorge Cherian if (empty) { 198*1af54b7aSGeorge Cherian spin_lock_irqsave(&musb->lock, flags); 199*1af54b7aSGeorge Cherian cppi41_trans_done(cppi41_channel); 200*1af54b7aSGeorge Cherian spin_unlock_irqrestore(&musb->lock, flags); 201*1af54b7aSGeorge Cherian } else { 202*1af54b7aSGeorge Cherian schedule_work(&cppi41_channel->dma_completion); 203*1af54b7aSGeorge Cherian } 204*1af54b7aSGeorge Cherian } 205*1af54b7aSGeorge Cherian } 206*1af54b7aSGeorge Cherian 207a655f481SSebastian Andrzej Siewior static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) 208a655f481SSebastian Andrzej Siewior { 209a655f481SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 210a655f481SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel, *n; 211a655f481SSebastian Andrzej Siewior struct musb *musb; 212a655f481SSebastian Andrzej Siewior unsigned long flags; 213a655f481SSebastian Andrzej Siewior enum hrtimer_restart ret = HRTIMER_NORESTART; 214a655f481SSebastian Andrzej Siewior 215a655f481SSebastian Andrzej Siewior controller = container_of(timer, struct cppi41_dma_controller, 216a655f481SSebastian Andrzej Siewior early_tx); 217a655f481SSebastian Andrzej Siewior musb = controller->musb; 218a655f481SSebastian Andrzej Siewior 219a655f481SSebastian Andrzej Siewior spin_lock_irqsave(&musb->lock, flags); 220a655f481SSebastian Andrzej Siewior list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, 221a655f481SSebastian Andrzej Siewior tx_check) { 222a655f481SSebastian Andrzej Siewior bool empty; 223a655f481SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 224a655f481SSebastian Andrzej Siewior 225a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 226a655f481SSebastian Andrzej Siewior if (empty) { 227a655f481SSebastian Andrzej Siewior list_del_init(&cppi41_channel->tx_check); 228a655f481SSebastian Andrzej Siewior cppi41_trans_done(cppi41_channel); 229a655f481SSebastian Andrzej Siewior } 230a655f481SSebastian Andrzej Siewior } 231a655f481SSebastian Andrzej Siewior 232a655f481SSebastian Andrzej Siewior if (!list_empty(&controller->early_tx_list)) { 233a655f481SSebastian Andrzej Siewior ret = HRTIMER_RESTART; 234a655f481SSebastian Andrzej Siewior hrtimer_forward_now(&controller->early_tx, 235a655f481SSebastian Andrzej Siewior ktime_set(0, 150 * NSEC_PER_USEC)); 236a655f481SSebastian Andrzej Siewior } 237a655f481SSebastian Andrzej Siewior 238a655f481SSebastian Andrzej Siewior spin_unlock_irqrestore(&musb->lock, flags); 239a655f481SSebastian Andrzej Siewior return ret; 240a655f481SSebastian Andrzej Siewior } 241a655f481SSebastian Andrzej Siewior 242d373a853SSebastian Andrzej Siewior static void cppi41_dma_callback(void *private_data) 243d373a853SSebastian Andrzej Siewior { 244d373a853SSebastian Andrzej Siewior struct dma_channel *channel = private_data; 245d373a853SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 246d373a853SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 247d373a853SSebastian Andrzej Siewior struct musb *musb = hw_ep->musb; 248d373a853SSebastian Andrzej Siewior unsigned long flags; 249d373a853SSebastian Andrzej Siewior struct dma_tx_state txstate; 250d373a853SSebastian Andrzej Siewior u32 transferred; 251a655f481SSebastian Andrzej Siewior bool empty; 252d373a853SSebastian Andrzej Siewior 253d373a853SSebastian Andrzej Siewior spin_lock_irqsave(&musb->lock, flags); 254d373a853SSebastian Andrzej Siewior 255d373a853SSebastian Andrzej Siewior dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, 256d373a853SSebastian Andrzej Siewior &txstate); 257d373a853SSebastian Andrzej Siewior transferred = cppi41_channel->prog_len - txstate.residue; 258d373a853SSebastian Andrzej Siewior cppi41_channel->transferred += transferred; 259d373a853SSebastian Andrzej Siewior 260d373a853SSebastian Andrzej Siewior dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", 261d373a853SSebastian Andrzej Siewior hw_ep->epnum, cppi41_channel->transferred, 262d373a853SSebastian Andrzej Siewior cppi41_channel->total_len); 263d373a853SSebastian Andrzej Siewior 264d373a853SSebastian Andrzej Siewior update_rx_toggle(cppi41_channel); 265d373a853SSebastian Andrzej Siewior 266d373a853SSebastian Andrzej Siewior if (cppi41_channel->transferred == cppi41_channel->total_len || 267d373a853SSebastian Andrzej Siewior transferred < cppi41_channel->packet_sz) 268d373a853SSebastian Andrzej Siewior cppi41_channel->prog_len = 0; 269d373a853SSebastian Andrzej Siewior 270*1af54b7aSGeorge Cherian if (!cppi41_channel->is_tx) { 271*1af54b7aSGeorge Cherian if (is_isoc(hw_ep, 1)) 272*1af54b7aSGeorge Cherian schedule_work(&cppi41_channel->dma_completion); 273*1af54b7aSGeorge Cherian else 274*1af54b7aSGeorge Cherian cppi41_trans_done(cppi41_channel); 275*1af54b7aSGeorge Cherian goto out; 276*1af54b7aSGeorge Cherian } 277*1af54b7aSGeorge Cherian 278a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 279a655f481SSebastian Andrzej Siewior if (empty) { 280a655f481SSebastian Andrzej Siewior cppi41_trans_done(cppi41_channel); 281a655f481SSebastian Andrzej Siewior } else { 282a655f481SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 283a655f481SSebastian Andrzej Siewior /* 284a655f481SSebastian Andrzej Siewior * On AM335x it has been observed that the TX interrupt fires 285a655f481SSebastian Andrzej Siewior * too early that means the TXFIFO is not yet empty but the DMA 286a655f481SSebastian Andrzej Siewior * engine says that it is done with the transfer. We don't 287a655f481SSebastian Andrzej Siewior * receive a FIFO empty interrupt so the only thing we can do is 288a655f481SSebastian Andrzej Siewior * to poll for the bit. On HS it usually takes 2us, on FS around 289a655f481SSebastian Andrzej Siewior * 110us - 150us depending on the transfer size. 290a655f481SSebastian Andrzej Siewior * We spin on HS (no longer than than 25us and setup a timer on 291a655f481SSebastian Andrzej Siewior * FS to check for the bit and complete the transfer. 292a655f481SSebastian Andrzej Siewior */ 293a655f481SSebastian Andrzej Siewior controller = cppi41_channel->controller; 294d373a853SSebastian Andrzej Siewior 295a655f481SSebastian Andrzej Siewior if (musb->g.speed == USB_SPEED_HIGH) { 296a655f481SSebastian Andrzej Siewior unsigned wait = 25; 297a655f481SSebastian Andrzej Siewior 298a655f481SSebastian Andrzej Siewior do { 299a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 300a655f481SSebastian Andrzej Siewior if (empty) 301a655f481SSebastian Andrzej Siewior break; 302a655f481SSebastian Andrzej Siewior wait--; 303a655f481SSebastian Andrzej Siewior if (!wait) 304a655f481SSebastian Andrzej Siewior break; 305a655f481SSebastian Andrzej Siewior udelay(1); 306a655f481SSebastian Andrzej Siewior } while (1); 307a655f481SSebastian Andrzej Siewior 308a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 309a655f481SSebastian Andrzej Siewior if (empty) { 310a655f481SSebastian Andrzej Siewior cppi41_trans_done(cppi41_channel); 311a655f481SSebastian Andrzej Siewior goto out; 312a655f481SSebastian Andrzej Siewior } 313a655f481SSebastian Andrzej Siewior } 314*1af54b7aSGeorge Cherian if (is_isoc(hw_ep, 0)) { 315*1af54b7aSGeorge Cherian schedule_work(&cppi41_channel->dma_completion); 316*1af54b7aSGeorge Cherian goto out; 317*1af54b7aSGeorge Cherian } 318a655f481SSebastian Andrzej Siewior list_add_tail(&cppi41_channel->tx_check, 319a655f481SSebastian Andrzej Siewior &controller->early_tx_list); 320a655f481SSebastian Andrzej Siewior if (!hrtimer_active(&controller->early_tx)) { 321a655f481SSebastian Andrzej Siewior hrtimer_start_range_ns(&controller->early_tx, 322a655f481SSebastian Andrzej Siewior ktime_set(0, 140 * NSEC_PER_USEC), 323a655f481SSebastian Andrzej Siewior 40 * NSEC_PER_USEC, 324a655f481SSebastian Andrzej Siewior HRTIMER_MODE_REL); 325a655f481SSebastian Andrzej Siewior } 326a655f481SSebastian Andrzej Siewior } 327a655f481SSebastian Andrzej Siewior out: 3289b3452d1SSebastian Andrzej Siewior spin_unlock_irqrestore(&musb->lock, flags); 3299b3452d1SSebastian Andrzej Siewior } 3309b3452d1SSebastian Andrzej Siewior 3319b3452d1SSebastian Andrzej Siewior static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old) 3329b3452d1SSebastian Andrzej Siewior { 3339b3452d1SSebastian Andrzej Siewior unsigned shift; 3349b3452d1SSebastian Andrzej Siewior 3359b3452d1SSebastian Andrzej Siewior shift = (ep - 1) * 2; 3369b3452d1SSebastian Andrzej Siewior old &= ~(3 << shift); 3379b3452d1SSebastian Andrzej Siewior old |= mode << shift; 3389b3452d1SSebastian Andrzej Siewior return old; 3399b3452d1SSebastian Andrzej Siewior } 3409b3452d1SSebastian Andrzej Siewior 3419b3452d1SSebastian Andrzej Siewior static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, 3429b3452d1SSebastian Andrzej Siewior unsigned mode) 3439b3452d1SSebastian Andrzej Siewior { 3449b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 3459b3452d1SSebastian Andrzej Siewior u32 port; 3469b3452d1SSebastian Andrzej Siewior u32 new_mode; 3479b3452d1SSebastian Andrzej Siewior u32 old_mode; 3489b3452d1SSebastian Andrzej Siewior 3499b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) 3509b3452d1SSebastian Andrzej Siewior old_mode = controller->tx_mode; 3519b3452d1SSebastian Andrzej Siewior else 3529b3452d1SSebastian Andrzej Siewior old_mode = controller->rx_mode; 3539b3452d1SSebastian Andrzej Siewior port = cppi41_channel->port_num; 3549b3452d1SSebastian Andrzej Siewior new_mode = update_ep_mode(port, mode, old_mode); 3559b3452d1SSebastian Andrzej Siewior 3569b3452d1SSebastian Andrzej Siewior if (new_mode == old_mode) 3579b3452d1SSebastian Andrzej Siewior return; 3589b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) { 3599b3452d1SSebastian Andrzej Siewior controller->tx_mode = new_mode; 3609b3452d1SSebastian Andrzej Siewior musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, 3619b3452d1SSebastian Andrzej Siewior new_mode); 3629b3452d1SSebastian Andrzej Siewior } else { 3639b3452d1SSebastian Andrzej Siewior controller->rx_mode = new_mode; 3649b3452d1SSebastian Andrzej Siewior musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, 3659b3452d1SSebastian Andrzej Siewior new_mode); 3669b3452d1SSebastian Andrzej Siewior } 3679b3452d1SSebastian Andrzej Siewior } 3689b3452d1SSebastian Andrzej Siewior 3699b3452d1SSebastian Andrzej Siewior static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, 3709b3452d1SSebastian Andrzej Siewior unsigned mode) 3719b3452d1SSebastian Andrzej Siewior { 3729b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 3739b3452d1SSebastian Andrzej Siewior u32 port; 3749b3452d1SSebastian Andrzej Siewior u32 new_mode; 3759b3452d1SSebastian Andrzej Siewior u32 old_mode; 3769b3452d1SSebastian Andrzej Siewior 3779b3452d1SSebastian Andrzej Siewior old_mode = controller->auto_req; 3789b3452d1SSebastian Andrzej Siewior port = cppi41_channel->port_num; 3799b3452d1SSebastian Andrzej Siewior new_mode = update_ep_mode(port, mode, old_mode); 3809b3452d1SSebastian Andrzej Siewior 3819b3452d1SSebastian Andrzej Siewior if (new_mode == old_mode) 3829b3452d1SSebastian Andrzej Siewior return; 3839b3452d1SSebastian Andrzej Siewior controller->auto_req = new_mode; 3849b3452d1SSebastian Andrzej Siewior musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); 3859b3452d1SSebastian Andrzej Siewior } 3869b3452d1SSebastian Andrzej Siewior 3879b3452d1SSebastian Andrzej Siewior static bool cppi41_configure_channel(struct dma_channel *channel, 3889b3452d1SSebastian Andrzej Siewior u16 packet_sz, u8 mode, 3899b3452d1SSebastian Andrzej Siewior dma_addr_t dma_addr, u32 len) 3909b3452d1SSebastian Andrzej Siewior { 3919b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 3929b3452d1SSebastian Andrzej Siewior struct dma_chan *dc = cppi41_channel->dc; 3939b3452d1SSebastian Andrzej Siewior struct dma_async_tx_descriptor *dma_desc; 3949b3452d1SSebastian Andrzej Siewior enum dma_transfer_direction direction; 3959b3452d1SSebastian Andrzej Siewior struct musb *musb = cppi41_channel->controller->musb; 3969b3452d1SSebastian Andrzej Siewior unsigned use_gen_rndis = 0; 3979b3452d1SSebastian Andrzej Siewior 3989b3452d1SSebastian Andrzej Siewior dev_dbg(musb->controller, 3999b3452d1SSebastian Andrzej Siewior "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", 4009b3452d1SSebastian Andrzej Siewior cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), 4019b3452d1SSebastian Andrzej Siewior packet_sz, mode, (unsigned long long) dma_addr, 4029b3452d1SSebastian Andrzej Siewior len, cppi41_channel->is_tx); 4039b3452d1SSebastian Andrzej Siewior 4049b3452d1SSebastian Andrzej Siewior cppi41_channel->buf_addr = dma_addr; 4059b3452d1SSebastian Andrzej Siewior cppi41_channel->total_len = len; 4069b3452d1SSebastian Andrzej Siewior cppi41_channel->transferred = 0; 4079b3452d1SSebastian Andrzej Siewior cppi41_channel->packet_sz = packet_sz; 4089b3452d1SSebastian Andrzej Siewior 4099b3452d1SSebastian Andrzej Siewior /* 4109b3452d1SSebastian Andrzej Siewior * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more 4119b3452d1SSebastian Andrzej Siewior * than max packet size at a time. 4129b3452d1SSebastian Andrzej Siewior */ 4139b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) 4149b3452d1SSebastian Andrzej Siewior use_gen_rndis = 1; 4159b3452d1SSebastian Andrzej Siewior 4169b3452d1SSebastian Andrzej Siewior if (use_gen_rndis) { 4179b3452d1SSebastian Andrzej Siewior /* RNDIS mode */ 4189b3452d1SSebastian Andrzej Siewior if (len > packet_sz) { 4199b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, 4209b3452d1SSebastian Andrzej Siewior RNDIS_REG(cppi41_channel->port_num), len); 4219b3452d1SSebastian Andrzej Siewior /* gen rndis */ 4229b3452d1SSebastian Andrzej Siewior cppi41_set_dma_mode(cppi41_channel, 4239b3452d1SSebastian Andrzej Siewior EP_MODE_DMA_GEN_RNDIS); 4249b3452d1SSebastian Andrzej Siewior 4259b3452d1SSebastian Andrzej Siewior /* auto req */ 4269b3452d1SSebastian Andrzej Siewior cppi41_set_autoreq_mode(cppi41_channel, 4279b3452d1SSebastian Andrzej Siewior EP_MODE_AUTOREG_ALL_NEOP); 4289b3452d1SSebastian Andrzej Siewior } else { 4299b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, 4309b3452d1SSebastian Andrzej Siewior RNDIS_REG(cppi41_channel->port_num), 0); 4319b3452d1SSebastian Andrzej Siewior cppi41_set_dma_mode(cppi41_channel, 4329b3452d1SSebastian Andrzej Siewior EP_MODE_DMA_TRANSPARENT); 4339b3452d1SSebastian Andrzej Siewior cppi41_set_autoreq_mode(cppi41_channel, 4349b3452d1SSebastian Andrzej Siewior EP_MODE_AUTOREG_NONE); 4359b3452d1SSebastian Andrzej Siewior } 4369b3452d1SSebastian Andrzej Siewior } else { 4379b3452d1SSebastian Andrzej Siewior /* fallback mode */ 4389b3452d1SSebastian Andrzej Siewior cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT); 4399b3452d1SSebastian Andrzej Siewior cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE); 4409b3452d1SSebastian Andrzej Siewior len = min_t(u32, packet_sz, len); 4419b3452d1SSebastian Andrzej Siewior } 4429b3452d1SSebastian Andrzej Siewior cppi41_channel->prog_len = len; 4439b3452d1SSebastian Andrzej Siewior direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; 4449b3452d1SSebastian Andrzej Siewior dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction, 4459b3452d1SSebastian Andrzej Siewior DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 4469b3452d1SSebastian Andrzej Siewior if (!dma_desc) 4479b3452d1SSebastian Andrzej Siewior return false; 4489b3452d1SSebastian Andrzej Siewior 4499b3452d1SSebastian Andrzej Siewior dma_desc->callback = cppi41_dma_callback; 4509b3452d1SSebastian Andrzej Siewior dma_desc->callback_param = channel; 4519b3452d1SSebastian Andrzej Siewior cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); 4529b3452d1SSebastian Andrzej Siewior 4539b3452d1SSebastian Andrzej Siewior save_rx_toggle(cppi41_channel); 4549b3452d1SSebastian Andrzej Siewior dma_async_issue_pending(dc); 4559b3452d1SSebastian Andrzej Siewior return true; 4569b3452d1SSebastian Andrzej Siewior } 4579b3452d1SSebastian Andrzej Siewior 4589b3452d1SSebastian Andrzej Siewior static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c, 4599b3452d1SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep, u8 is_tx) 4609b3452d1SSebastian Andrzej Siewior { 4619b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = container_of(c, 4629b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller, controller); 4639b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = NULL; 4649b3452d1SSebastian Andrzej Siewior u8 ch_num = hw_ep->epnum - 1; 4659b3452d1SSebastian Andrzej Siewior 4669b3452d1SSebastian Andrzej Siewior if (ch_num >= MUSB_DMA_NUM_CHANNELS) 4679b3452d1SSebastian Andrzej Siewior return NULL; 4689b3452d1SSebastian Andrzej Siewior 4699b3452d1SSebastian Andrzej Siewior if (is_tx) 4709b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->tx_channel[ch_num]; 4719b3452d1SSebastian Andrzej Siewior else 4729b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->rx_channel[ch_num]; 4739b3452d1SSebastian Andrzej Siewior 4749b3452d1SSebastian Andrzej Siewior if (!cppi41_channel->dc) 4759b3452d1SSebastian Andrzej Siewior return NULL; 4769b3452d1SSebastian Andrzej Siewior 4779b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_allocated) 4789b3452d1SSebastian Andrzej Siewior return NULL; 4799b3452d1SSebastian Andrzej Siewior 4809b3452d1SSebastian Andrzej Siewior cppi41_channel->hw_ep = hw_ep; 4819b3452d1SSebastian Andrzej Siewior cppi41_channel->is_allocated = 1; 4829b3452d1SSebastian Andrzej Siewior 4839b3452d1SSebastian Andrzej Siewior return &cppi41_channel->channel; 4849b3452d1SSebastian Andrzej Siewior } 4859b3452d1SSebastian Andrzej Siewior 4869b3452d1SSebastian Andrzej Siewior static void cppi41_dma_channel_release(struct dma_channel *channel) 4879b3452d1SSebastian Andrzej Siewior { 4889b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 4899b3452d1SSebastian Andrzej Siewior 4909b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_allocated) { 4919b3452d1SSebastian Andrzej Siewior cppi41_channel->is_allocated = 0; 4929b3452d1SSebastian Andrzej Siewior channel->status = MUSB_DMA_STATUS_FREE; 4939b3452d1SSebastian Andrzej Siewior channel->actual_len = 0; 4949b3452d1SSebastian Andrzej Siewior } 4959b3452d1SSebastian Andrzej Siewior } 4969b3452d1SSebastian Andrzej Siewior 4979b3452d1SSebastian Andrzej Siewior static int cppi41_dma_channel_program(struct dma_channel *channel, 4989b3452d1SSebastian Andrzej Siewior u16 packet_sz, u8 mode, 4999b3452d1SSebastian Andrzej Siewior dma_addr_t dma_addr, u32 len) 5009b3452d1SSebastian Andrzej Siewior { 5019b3452d1SSebastian Andrzej Siewior int ret; 502f82503f5SGeorge Cherian struct cppi41_dma_channel *cppi41_channel = channel->private_data; 503f82503f5SGeorge Cherian int hb_mult = 0; 5049b3452d1SSebastian Andrzej Siewior 5059b3452d1SSebastian Andrzej Siewior BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || 5069b3452d1SSebastian Andrzej Siewior channel->status == MUSB_DMA_STATUS_BUSY); 5079b3452d1SSebastian Andrzej Siewior 508f82503f5SGeorge Cherian if (is_host_active(cppi41_channel->controller->musb)) { 509f82503f5SGeorge Cherian if (cppi41_channel->is_tx) 510f82503f5SGeorge Cherian hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; 511f82503f5SGeorge Cherian else 512f82503f5SGeorge Cherian hb_mult = cppi41_channel->hw_ep->in_qh->hb_mult; 513f82503f5SGeorge Cherian } 514f82503f5SGeorge Cherian 5159b3452d1SSebastian Andrzej Siewior channel->status = MUSB_DMA_STATUS_BUSY; 5169b3452d1SSebastian Andrzej Siewior channel->actual_len = 0; 517f82503f5SGeorge Cherian 518f82503f5SGeorge Cherian if (hb_mult) 519f82503f5SGeorge Cherian packet_sz = hb_mult * (packet_sz & 0x7FF); 520f82503f5SGeorge Cherian 5219b3452d1SSebastian Andrzej Siewior ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len); 5229b3452d1SSebastian Andrzej Siewior if (!ret) 5239b3452d1SSebastian Andrzej Siewior channel->status = MUSB_DMA_STATUS_FREE; 5249b3452d1SSebastian Andrzej Siewior 5259b3452d1SSebastian Andrzej Siewior return ret; 5269b3452d1SSebastian Andrzej Siewior } 5279b3452d1SSebastian Andrzej Siewior 5289b3452d1SSebastian Andrzej Siewior static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, 5299b3452d1SSebastian Andrzej Siewior void *buf, u32 length) 5309b3452d1SSebastian Andrzej Siewior { 5319b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 5329b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 5339b3452d1SSebastian Andrzej Siewior struct musb *musb = controller->musb; 5349b3452d1SSebastian Andrzej Siewior 5359b3452d1SSebastian Andrzej Siewior if (is_host_active(musb)) { 5369b3452d1SSebastian Andrzej Siewior WARN_ON(1); 5379b3452d1SSebastian Andrzej Siewior return 1; 5389b3452d1SSebastian Andrzej Siewior } 539a655f481SSebastian Andrzej Siewior if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK) 540a655f481SSebastian Andrzej Siewior return 0; 54113266feaSSebastian Andrzej Siewior if (cppi41_channel->is_tx) 54213266feaSSebastian Andrzej Siewior return 1; 54313266feaSSebastian Andrzej Siewior /* AM335x Advisory 1.0.13. No workaround for device RX mode */ 5449b3452d1SSebastian Andrzej Siewior return 0; 5459b3452d1SSebastian Andrzej Siewior } 5469b3452d1SSebastian Andrzej Siewior 5479b3452d1SSebastian Andrzej Siewior static int cppi41_dma_channel_abort(struct dma_channel *channel) 5489b3452d1SSebastian Andrzej Siewior { 5499b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 5509b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 5519b3452d1SSebastian Andrzej Siewior struct musb *musb = controller->musb; 5529b3452d1SSebastian Andrzej Siewior void __iomem *epio = cppi41_channel->hw_ep->regs; 5539b3452d1SSebastian Andrzej Siewior int tdbit; 5549b3452d1SSebastian Andrzej Siewior int ret; 5559b3452d1SSebastian Andrzej Siewior unsigned is_tx; 5569b3452d1SSebastian Andrzej Siewior u16 csr; 5579b3452d1SSebastian Andrzej Siewior 5589b3452d1SSebastian Andrzej Siewior is_tx = cppi41_channel->is_tx; 5599b3452d1SSebastian Andrzej Siewior dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n", 5609b3452d1SSebastian Andrzej Siewior cppi41_channel->port_num, is_tx); 5619b3452d1SSebastian Andrzej Siewior 5629b3452d1SSebastian Andrzej Siewior if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) 5639b3452d1SSebastian Andrzej Siewior return 0; 5649b3452d1SSebastian Andrzej Siewior 565a655f481SSebastian Andrzej Siewior list_del_init(&cppi41_channel->tx_check); 5669b3452d1SSebastian Andrzej Siewior if (is_tx) { 5679b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_TXCSR); 5689b3452d1SSebastian Andrzej Siewior csr &= ~MUSB_TXCSR_DMAENAB; 5699b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_TXCSR, csr); 5709b3452d1SSebastian Andrzej Siewior } else { 5719b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_RXCSR); 5729b3452d1SSebastian Andrzej Siewior csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB); 5739b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 5749b3452d1SSebastian Andrzej Siewior 5759b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_RXCSR); 5769b3452d1SSebastian Andrzej Siewior if (csr & MUSB_RXCSR_RXPKTRDY) { 5779b3452d1SSebastian Andrzej Siewior csr |= MUSB_RXCSR_FLUSHFIFO; 5789b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 5799b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 5809b3452d1SSebastian Andrzej Siewior } 5819b3452d1SSebastian Andrzej Siewior } 5829b3452d1SSebastian Andrzej Siewior 5839b3452d1SSebastian Andrzej Siewior tdbit = 1 << cppi41_channel->port_num; 5849b3452d1SSebastian Andrzej Siewior if (is_tx) 5859b3452d1SSebastian Andrzej Siewior tdbit <<= 16; 5869b3452d1SSebastian Andrzej Siewior 5879b3452d1SSebastian Andrzej Siewior do { 5889b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); 5899b3452d1SSebastian Andrzej Siewior ret = dmaengine_terminate_all(cppi41_channel->dc); 5909b3452d1SSebastian Andrzej Siewior } while (ret == -EAGAIN); 5919b3452d1SSebastian Andrzej Siewior 5929b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); 5939b3452d1SSebastian Andrzej Siewior 5949b3452d1SSebastian Andrzej Siewior if (is_tx) { 5959b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_TXCSR); 5969b3452d1SSebastian Andrzej Siewior if (csr & MUSB_TXCSR_TXPKTRDY) { 5979b3452d1SSebastian Andrzej Siewior csr |= MUSB_TXCSR_FLUSHFIFO; 5989b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_TXCSR, csr); 5999b3452d1SSebastian Andrzej Siewior } 6009b3452d1SSebastian Andrzej Siewior } 6019b3452d1SSebastian Andrzej Siewior 6029b3452d1SSebastian Andrzej Siewior cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; 6039b3452d1SSebastian Andrzej Siewior return 0; 6049b3452d1SSebastian Andrzej Siewior } 6059b3452d1SSebastian Andrzej Siewior 6069b3452d1SSebastian Andrzej Siewior static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl) 6079b3452d1SSebastian Andrzej Siewior { 6089b3452d1SSebastian Andrzej Siewior struct dma_chan *dc; 6099b3452d1SSebastian Andrzej Siewior int i; 6109b3452d1SSebastian Andrzej Siewior 6119b3452d1SSebastian Andrzej Siewior for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) { 6129b3452d1SSebastian Andrzej Siewior dc = ctrl->tx_channel[i].dc; 6139b3452d1SSebastian Andrzej Siewior if (dc) 6149b3452d1SSebastian Andrzej Siewior dma_release_channel(dc); 6159b3452d1SSebastian Andrzej Siewior dc = ctrl->rx_channel[i].dc; 6169b3452d1SSebastian Andrzej Siewior if (dc) 6179b3452d1SSebastian Andrzej Siewior dma_release_channel(dc); 6189b3452d1SSebastian Andrzej Siewior } 6199b3452d1SSebastian Andrzej Siewior } 6209b3452d1SSebastian Andrzej Siewior 6219b3452d1SSebastian Andrzej Siewior static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) 6229b3452d1SSebastian Andrzej Siewior { 6239b3452d1SSebastian Andrzej Siewior cppi41_release_all_dma_chans(controller); 6249b3452d1SSebastian Andrzej Siewior } 6259b3452d1SSebastian Andrzej Siewior 6269b3452d1SSebastian Andrzej Siewior static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) 6279b3452d1SSebastian Andrzej Siewior { 6289b3452d1SSebastian Andrzej Siewior struct musb *musb = controller->musb; 6299b3452d1SSebastian Andrzej Siewior struct device *dev = musb->controller; 6309b3452d1SSebastian Andrzej Siewior struct device_node *np = dev->of_node; 6319b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel; 6329b3452d1SSebastian Andrzej Siewior int count; 6339b3452d1SSebastian Andrzej Siewior int i; 6349b3452d1SSebastian Andrzej Siewior int ret; 6359b3452d1SSebastian Andrzej Siewior 6369b3452d1SSebastian Andrzej Siewior count = of_property_count_strings(np, "dma-names"); 6379b3452d1SSebastian Andrzej Siewior if (count < 0) 6389b3452d1SSebastian Andrzej Siewior return count; 6399b3452d1SSebastian Andrzej Siewior 6409b3452d1SSebastian Andrzej Siewior for (i = 0; i < count; i++) { 6419b3452d1SSebastian Andrzej Siewior struct dma_chan *dc; 6429b3452d1SSebastian Andrzej Siewior struct dma_channel *musb_dma; 6439b3452d1SSebastian Andrzej Siewior const char *str; 6449b3452d1SSebastian Andrzej Siewior unsigned is_tx; 6459b3452d1SSebastian Andrzej Siewior unsigned int port; 6469b3452d1SSebastian Andrzej Siewior 6479b3452d1SSebastian Andrzej Siewior ret = of_property_read_string_index(np, "dma-names", i, &str); 6489b3452d1SSebastian Andrzej Siewior if (ret) 6499b3452d1SSebastian Andrzej Siewior goto err; 6509b3452d1SSebastian Andrzej Siewior if (!strncmp(str, "tx", 2)) 6519b3452d1SSebastian Andrzej Siewior is_tx = 1; 6529b3452d1SSebastian Andrzej Siewior else if (!strncmp(str, "rx", 2)) 6539b3452d1SSebastian Andrzej Siewior is_tx = 0; 6549b3452d1SSebastian Andrzej Siewior else { 6559b3452d1SSebastian Andrzej Siewior dev_err(dev, "Wrong dmatype %s\n", str); 6569b3452d1SSebastian Andrzej Siewior goto err; 6579b3452d1SSebastian Andrzej Siewior } 6589b3452d1SSebastian Andrzej Siewior ret = kstrtouint(str + 2, 0, &port); 6599b3452d1SSebastian Andrzej Siewior if (ret) 6609b3452d1SSebastian Andrzej Siewior goto err; 6619b3452d1SSebastian Andrzej Siewior 66248054147SSebastian Andrzej Siewior ret = -EINVAL; 6639b3452d1SSebastian Andrzej Siewior if (port > MUSB_DMA_NUM_CHANNELS || !port) 6649b3452d1SSebastian Andrzej Siewior goto err; 6659b3452d1SSebastian Andrzej Siewior if (is_tx) 6669b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->tx_channel[port - 1]; 6679b3452d1SSebastian Andrzej Siewior else 6689b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->rx_channel[port - 1]; 6699b3452d1SSebastian Andrzej Siewior 6709b3452d1SSebastian Andrzej Siewior cppi41_channel->controller = controller; 6719b3452d1SSebastian Andrzej Siewior cppi41_channel->port_num = port; 6729b3452d1SSebastian Andrzej Siewior cppi41_channel->is_tx = is_tx; 673a655f481SSebastian Andrzej Siewior INIT_LIST_HEAD(&cppi41_channel->tx_check); 674*1af54b7aSGeorge Cherian INIT_WORK(&cppi41_channel->dma_completion, 675*1af54b7aSGeorge Cherian cppi_trans_done_work); 6769b3452d1SSebastian Andrzej Siewior 6779b3452d1SSebastian Andrzej Siewior musb_dma = &cppi41_channel->channel; 6789b3452d1SSebastian Andrzej Siewior musb_dma->private_data = cppi41_channel; 6799b3452d1SSebastian Andrzej Siewior musb_dma->status = MUSB_DMA_STATUS_FREE; 6809b3452d1SSebastian Andrzej Siewior musb_dma->max_len = SZ_4M; 6819b3452d1SSebastian Andrzej Siewior 6829b3452d1SSebastian Andrzej Siewior dc = dma_request_slave_channel(dev, str); 6839b3452d1SSebastian Andrzej Siewior if (!dc) { 6845ae477b0SRahul Bedarkar dev_err(dev, "Failed to request %s.\n", str); 68548054147SSebastian Andrzej Siewior ret = -EPROBE_DEFER; 6869b3452d1SSebastian Andrzej Siewior goto err; 6879b3452d1SSebastian Andrzej Siewior } 6889b3452d1SSebastian Andrzej Siewior cppi41_channel->dc = dc; 6899b3452d1SSebastian Andrzej Siewior } 6909b3452d1SSebastian Andrzej Siewior return 0; 6919b3452d1SSebastian Andrzej Siewior err: 6929b3452d1SSebastian Andrzej Siewior cppi41_release_all_dma_chans(controller); 69348054147SSebastian Andrzej Siewior return ret; 6949b3452d1SSebastian Andrzej Siewior } 6959b3452d1SSebastian Andrzej Siewior 6969b3452d1SSebastian Andrzej Siewior void dma_controller_destroy(struct dma_controller *c) 6979b3452d1SSebastian Andrzej Siewior { 6989b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = container_of(c, 6999b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller, controller); 7009b3452d1SSebastian Andrzej Siewior 701a655f481SSebastian Andrzej Siewior hrtimer_cancel(&controller->early_tx); 7029b3452d1SSebastian Andrzej Siewior cppi41_dma_controller_stop(controller); 7039b3452d1SSebastian Andrzej Siewior kfree(controller); 7049b3452d1SSebastian Andrzej Siewior } 7059b3452d1SSebastian Andrzej Siewior 7069b3452d1SSebastian Andrzej Siewior struct dma_controller *dma_controller_create(struct musb *musb, 7079b3452d1SSebastian Andrzej Siewior void __iomem *base) 7089b3452d1SSebastian Andrzej Siewior { 7099b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 71048054147SSebastian Andrzej Siewior int ret = 0; 7119b3452d1SSebastian Andrzej Siewior 7129b3452d1SSebastian Andrzej Siewior if (!musb->controller->of_node) { 7139b3452d1SSebastian Andrzej Siewior dev_err(musb->controller, "Need DT for the DMA engine.\n"); 7149b3452d1SSebastian Andrzej Siewior return NULL; 7159b3452d1SSebastian Andrzej Siewior } 7169b3452d1SSebastian Andrzej Siewior 7179b3452d1SSebastian Andrzej Siewior controller = kzalloc(sizeof(*controller), GFP_KERNEL); 7189b3452d1SSebastian Andrzej Siewior if (!controller) 7199b3452d1SSebastian Andrzej Siewior goto kzalloc_fail; 7209b3452d1SSebastian Andrzej Siewior 721a655f481SSebastian Andrzej Siewior hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 722a655f481SSebastian Andrzej Siewior controller->early_tx.function = cppi41_recheck_tx_req; 723a655f481SSebastian Andrzej Siewior INIT_LIST_HEAD(&controller->early_tx_list); 7249b3452d1SSebastian Andrzej Siewior controller->musb = musb; 7259b3452d1SSebastian Andrzej Siewior 7269b3452d1SSebastian Andrzej Siewior controller->controller.channel_alloc = cppi41_dma_channel_allocate; 7279b3452d1SSebastian Andrzej Siewior controller->controller.channel_release = cppi41_dma_channel_release; 7289b3452d1SSebastian Andrzej Siewior controller->controller.channel_program = cppi41_dma_channel_program; 7299b3452d1SSebastian Andrzej Siewior controller->controller.channel_abort = cppi41_dma_channel_abort; 7309b3452d1SSebastian Andrzej Siewior controller->controller.is_compatible = cppi41_is_compatible; 7319b3452d1SSebastian Andrzej Siewior 7329b3452d1SSebastian Andrzej Siewior ret = cppi41_dma_controller_start(controller); 7339b3452d1SSebastian Andrzej Siewior if (ret) 7349b3452d1SSebastian Andrzej Siewior goto plat_get_fail; 7359b3452d1SSebastian Andrzej Siewior return &controller->controller; 7369b3452d1SSebastian Andrzej Siewior 7379b3452d1SSebastian Andrzej Siewior plat_get_fail: 7389b3452d1SSebastian Andrzej Siewior kfree(controller); 7399b3452d1SSebastian Andrzej Siewior kzalloc_fail: 74048054147SSebastian Andrzej Siewior if (ret == -EPROBE_DEFER) 74148054147SSebastian Andrzej Siewior return ERR_PTR(ret); 7429b3452d1SSebastian Andrzej Siewior return NULL; 7439b3452d1SSebastian Andrzej Siewior } 744