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; 421af54b7aSGeorge 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 1161af54b7aSGeorge Cherian static bool is_isoc(struct musb_hw_ep *hw_ep, bool in) 1171af54b7aSGeorge Cherian { 1181af54b7aSGeorge Cherian if (in && hw_ep->in_qh) { 1191af54b7aSGeorge Cherian if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC) 1201af54b7aSGeorge Cherian return true; 1211af54b7aSGeorge Cherian } else if (hw_ep->out_qh) { 1221af54b7aSGeorge Cherian if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC) 1231af54b7aSGeorge Cherian return true; 1241af54b7aSGeorge Cherian } 1251af54b7aSGeorge Cherian return false; 1261af54b7aSGeorge Cherian } 1271af54b7aSGeorge 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 135aecbc31dSGeorge Cherian if (!cppi41_channel->prog_len || 136aecbc31dSGeorge Cherian (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) { 1379b3452d1SSebastian Andrzej Siewior 1389b3452d1SSebastian Andrzej Siewior /* done, complete */ 1399b3452d1SSebastian Andrzej Siewior cppi41_channel->channel.actual_len = 1409b3452d1SSebastian Andrzej Siewior cppi41_channel->transferred; 1419b3452d1SSebastian Andrzej Siewior cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; 142*ff3fcac9SDaniel Mack cppi41_channel->channel.rx_packet_done = true; 1439b3452d1SSebastian Andrzej Siewior musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); 1449b3452d1SSebastian Andrzej Siewior } else { 1459b3452d1SSebastian Andrzej Siewior /* next iteration, reload */ 1469b3452d1SSebastian Andrzej Siewior struct dma_chan *dc = cppi41_channel->dc; 1479b3452d1SSebastian Andrzej Siewior struct dma_async_tx_descriptor *dma_desc; 1489b3452d1SSebastian Andrzej Siewior enum dma_transfer_direction direction; 1499b3452d1SSebastian Andrzej Siewior u16 csr; 1509b3452d1SSebastian Andrzej Siewior u32 remain_bytes; 1519b3452d1SSebastian Andrzej Siewior void __iomem *epio = cppi41_channel->hw_ep->regs; 1529b3452d1SSebastian Andrzej Siewior 1539b3452d1SSebastian Andrzej Siewior cppi41_channel->buf_addr += cppi41_channel->packet_sz; 1549b3452d1SSebastian Andrzej Siewior 1559b3452d1SSebastian Andrzej Siewior remain_bytes = cppi41_channel->total_len; 1569b3452d1SSebastian Andrzej Siewior remain_bytes -= cppi41_channel->transferred; 1579b3452d1SSebastian Andrzej Siewior remain_bytes = min(remain_bytes, cppi41_channel->packet_sz); 1589b3452d1SSebastian Andrzej Siewior cppi41_channel->prog_len = remain_bytes; 1599b3452d1SSebastian Andrzej Siewior 1609b3452d1SSebastian Andrzej Siewior direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV 1619b3452d1SSebastian Andrzej Siewior : DMA_DEV_TO_MEM; 1629b3452d1SSebastian Andrzej Siewior dma_desc = dmaengine_prep_slave_single(dc, 1639b3452d1SSebastian Andrzej Siewior cppi41_channel->buf_addr, 1649b3452d1SSebastian Andrzej Siewior remain_bytes, 1659b3452d1SSebastian Andrzej Siewior direction, 1669b3452d1SSebastian Andrzej Siewior DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 167d373a853SSebastian Andrzej Siewior if (WARN_ON(!dma_desc)) 1689b3452d1SSebastian Andrzej Siewior return; 1699b3452d1SSebastian Andrzej Siewior 1709b3452d1SSebastian Andrzej Siewior dma_desc->callback = cppi41_dma_callback; 171a655f481SSebastian Andrzej Siewior dma_desc->callback_param = &cppi41_channel->channel; 1729b3452d1SSebastian Andrzej Siewior cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); 1739b3452d1SSebastian Andrzej Siewior dma_async_issue_pending(dc); 1749b3452d1SSebastian Andrzej Siewior 1759b3452d1SSebastian Andrzej Siewior if (!cppi41_channel->is_tx) { 1769b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_RXCSR); 1779b3452d1SSebastian Andrzej Siewior csr |= MUSB_RXCSR_H_REQPKT; 1789b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 1799b3452d1SSebastian Andrzej Siewior } 1809b3452d1SSebastian Andrzej Siewior } 181d373a853SSebastian Andrzej Siewior } 182d373a853SSebastian Andrzej Siewior 1831af54b7aSGeorge Cherian static void cppi_trans_done_work(struct work_struct *work) 1841af54b7aSGeorge Cherian { 1851af54b7aSGeorge Cherian unsigned long flags; 1861af54b7aSGeorge Cherian struct cppi41_dma_channel *cppi41_channel = 1871af54b7aSGeorge Cherian container_of(work, struct cppi41_dma_channel, dma_completion); 1881af54b7aSGeorge Cherian struct cppi41_dma_controller *controller = cppi41_channel->controller; 1891af54b7aSGeorge Cherian struct musb *musb = controller->musb; 1901af54b7aSGeorge Cherian struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 1911af54b7aSGeorge Cherian bool empty; 1921af54b7aSGeorge Cherian 1931af54b7aSGeorge Cherian if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) { 1941af54b7aSGeorge Cherian spin_lock_irqsave(&musb->lock, flags); 1951af54b7aSGeorge Cherian cppi41_trans_done(cppi41_channel); 1961af54b7aSGeorge Cherian spin_unlock_irqrestore(&musb->lock, flags); 1971af54b7aSGeorge Cherian } else { 1981af54b7aSGeorge Cherian empty = musb_is_tx_fifo_empty(hw_ep); 1991af54b7aSGeorge Cherian if (empty) { 2001af54b7aSGeorge Cherian spin_lock_irqsave(&musb->lock, flags); 2011af54b7aSGeorge Cherian cppi41_trans_done(cppi41_channel); 2021af54b7aSGeorge Cherian spin_unlock_irqrestore(&musb->lock, flags); 2031af54b7aSGeorge Cherian } else { 2041af54b7aSGeorge Cherian schedule_work(&cppi41_channel->dma_completion); 2051af54b7aSGeorge Cherian } 2061af54b7aSGeorge Cherian } 2071af54b7aSGeorge Cherian } 2081af54b7aSGeorge Cherian 209a655f481SSebastian Andrzej Siewior static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) 210a655f481SSebastian Andrzej Siewior { 211a655f481SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 212a655f481SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel, *n; 213a655f481SSebastian Andrzej Siewior struct musb *musb; 214a655f481SSebastian Andrzej Siewior unsigned long flags; 215a655f481SSebastian Andrzej Siewior enum hrtimer_restart ret = HRTIMER_NORESTART; 216a655f481SSebastian Andrzej Siewior 217a655f481SSebastian Andrzej Siewior controller = container_of(timer, struct cppi41_dma_controller, 218a655f481SSebastian Andrzej Siewior early_tx); 219a655f481SSebastian Andrzej Siewior musb = controller->musb; 220a655f481SSebastian Andrzej Siewior 221a655f481SSebastian Andrzej Siewior spin_lock_irqsave(&musb->lock, flags); 222a655f481SSebastian Andrzej Siewior list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, 223a655f481SSebastian Andrzej Siewior tx_check) { 224a655f481SSebastian Andrzej Siewior bool empty; 225a655f481SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 226a655f481SSebastian Andrzej Siewior 227a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 228a655f481SSebastian Andrzej Siewior if (empty) { 229a655f481SSebastian Andrzej Siewior list_del_init(&cppi41_channel->tx_check); 230a655f481SSebastian Andrzej Siewior cppi41_trans_done(cppi41_channel); 231a655f481SSebastian Andrzej Siewior } 232a655f481SSebastian Andrzej Siewior } 233a655f481SSebastian Andrzej Siewior 234a655f481SSebastian Andrzej Siewior if (!list_empty(&controller->early_tx_list)) { 235a655f481SSebastian Andrzej Siewior ret = HRTIMER_RESTART; 236a655f481SSebastian Andrzej Siewior hrtimer_forward_now(&controller->early_tx, 237a655f481SSebastian Andrzej Siewior ktime_set(0, 150 * NSEC_PER_USEC)); 238a655f481SSebastian Andrzej Siewior } 239a655f481SSebastian Andrzej Siewior 240a655f481SSebastian Andrzej Siewior spin_unlock_irqrestore(&musb->lock, flags); 241a655f481SSebastian Andrzej Siewior return ret; 242a655f481SSebastian Andrzej Siewior } 243a655f481SSebastian Andrzej Siewior 244d373a853SSebastian Andrzej Siewior static void cppi41_dma_callback(void *private_data) 245d373a853SSebastian Andrzej Siewior { 246d373a853SSebastian Andrzej Siewior struct dma_channel *channel = private_data; 247d373a853SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 248d373a853SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; 249d373a853SSebastian Andrzej Siewior struct musb *musb = hw_ep->musb; 250d373a853SSebastian Andrzej Siewior unsigned long flags; 251d373a853SSebastian Andrzej Siewior struct dma_tx_state txstate; 252d373a853SSebastian Andrzej Siewior u32 transferred; 253a655f481SSebastian Andrzej Siewior bool empty; 254d373a853SSebastian Andrzej Siewior 255d373a853SSebastian Andrzej Siewior spin_lock_irqsave(&musb->lock, flags); 256d373a853SSebastian Andrzej Siewior 257d373a853SSebastian Andrzej Siewior dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, 258d373a853SSebastian Andrzej Siewior &txstate); 259d373a853SSebastian Andrzej Siewior transferred = cppi41_channel->prog_len - txstate.residue; 260d373a853SSebastian Andrzej Siewior cppi41_channel->transferred += transferred; 261d373a853SSebastian Andrzej Siewior 262d373a853SSebastian Andrzej Siewior dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", 263d373a853SSebastian Andrzej Siewior hw_ep->epnum, cppi41_channel->transferred, 264d373a853SSebastian Andrzej Siewior cppi41_channel->total_len); 265d373a853SSebastian Andrzej Siewior 266d373a853SSebastian Andrzej Siewior update_rx_toggle(cppi41_channel); 267d373a853SSebastian Andrzej Siewior 268d373a853SSebastian Andrzej Siewior if (cppi41_channel->transferred == cppi41_channel->total_len || 269d373a853SSebastian Andrzej Siewior transferred < cppi41_channel->packet_sz) 270d373a853SSebastian Andrzej Siewior cppi41_channel->prog_len = 0; 271d373a853SSebastian Andrzej Siewior 2721af54b7aSGeorge Cherian if (!cppi41_channel->is_tx) { 2731af54b7aSGeorge Cherian if (is_isoc(hw_ep, 1)) 2741af54b7aSGeorge Cherian schedule_work(&cppi41_channel->dma_completion); 2751af54b7aSGeorge Cherian else 2761af54b7aSGeorge Cherian cppi41_trans_done(cppi41_channel); 2771af54b7aSGeorge Cherian goto out; 2781af54b7aSGeorge Cherian } 2791af54b7aSGeorge Cherian 280a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 281a655f481SSebastian Andrzej Siewior if (empty) { 282a655f481SSebastian Andrzej Siewior cppi41_trans_done(cppi41_channel); 283a655f481SSebastian Andrzej Siewior } else { 284a655f481SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 285a655f481SSebastian Andrzej Siewior /* 286a655f481SSebastian Andrzej Siewior * On AM335x it has been observed that the TX interrupt fires 287a655f481SSebastian Andrzej Siewior * too early that means the TXFIFO is not yet empty but the DMA 288a655f481SSebastian Andrzej Siewior * engine says that it is done with the transfer. We don't 289a655f481SSebastian Andrzej Siewior * receive a FIFO empty interrupt so the only thing we can do is 290a655f481SSebastian Andrzej Siewior * to poll for the bit. On HS it usually takes 2us, on FS around 291a655f481SSebastian Andrzej Siewior * 110us - 150us depending on the transfer size. 292a655f481SSebastian Andrzej Siewior * We spin on HS (no longer than than 25us and setup a timer on 293a655f481SSebastian Andrzej Siewior * FS to check for the bit and complete the transfer. 294a655f481SSebastian Andrzej Siewior */ 295a655f481SSebastian Andrzej Siewior controller = cppi41_channel->controller; 296d373a853SSebastian Andrzej Siewior 297a655f481SSebastian Andrzej Siewior if (musb->g.speed == USB_SPEED_HIGH) { 298a655f481SSebastian Andrzej Siewior unsigned wait = 25; 299a655f481SSebastian Andrzej Siewior 300a655f481SSebastian Andrzej Siewior do { 301a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 302a655f481SSebastian Andrzej Siewior if (empty) 303a655f481SSebastian Andrzej Siewior break; 304a655f481SSebastian Andrzej Siewior wait--; 305a655f481SSebastian Andrzej Siewior if (!wait) 306a655f481SSebastian Andrzej Siewior break; 307a655f481SSebastian Andrzej Siewior udelay(1); 308a655f481SSebastian Andrzej Siewior } while (1); 309a655f481SSebastian Andrzej Siewior 310a655f481SSebastian Andrzej Siewior empty = musb_is_tx_fifo_empty(hw_ep); 311a655f481SSebastian Andrzej Siewior if (empty) { 312a655f481SSebastian Andrzej Siewior cppi41_trans_done(cppi41_channel); 313a655f481SSebastian Andrzej Siewior goto out; 314a655f481SSebastian Andrzej Siewior } 315a655f481SSebastian Andrzej Siewior } 3161af54b7aSGeorge Cherian if (is_isoc(hw_ep, 0)) { 3171af54b7aSGeorge Cherian schedule_work(&cppi41_channel->dma_completion); 3181af54b7aSGeorge Cherian goto out; 3191af54b7aSGeorge Cherian } 320a655f481SSebastian Andrzej Siewior list_add_tail(&cppi41_channel->tx_check, 321a655f481SSebastian Andrzej Siewior &controller->early_tx_list); 322a655f481SSebastian Andrzej Siewior if (!hrtimer_active(&controller->early_tx)) { 323a655f481SSebastian Andrzej Siewior hrtimer_start_range_ns(&controller->early_tx, 324a655f481SSebastian Andrzej Siewior ktime_set(0, 140 * NSEC_PER_USEC), 325a655f481SSebastian Andrzej Siewior 40 * NSEC_PER_USEC, 326a655f481SSebastian Andrzej Siewior HRTIMER_MODE_REL); 327a655f481SSebastian Andrzej Siewior } 328a655f481SSebastian Andrzej Siewior } 329a655f481SSebastian Andrzej Siewior out: 3309b3452d1SSebastian Andrzej Siewior spin_unlock_irqrestore(&musb->lock, flags); 3319b3452d1SSebastian Andrzej Siewior } 3329b3452d1SSebastian Andrzej Siewior 3339b3452d1SSebastian Andrzej Siewior static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old) 3349b3452d1SSebastian Andrzej Siewior { 3359b3452d1SSebastian Andrzej Siewior unsigned shift; 3369b3452d1SSebastian Andrzej Siewior 3379b3452d1SSebastian Andrzej Siewior shift = (ep - 1) * 2; 3389b3452d1SSebastian Andrzej Siewior old &= ~(3 << shift); 3399b3452d1SSebastian Andrzej Siewior old |= mode << shift; 3409b3452d1SSebastian Andrzej Siewior return old; 3419b3452d1SSebastian Andrzej Siewior } 3429b3452d1SSebastian Andrzej Siewior 3439b3452d1SSebastian Andrzej Siewior static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, 3449b3452d1SSebastian Andrzej Siewior unsigned mode) 3459b3452d1SSebastian Andrzej Siewior { 3469b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 3479b3452d1SSebastian Andrzej Siewior u32 port; 3489b3452d1SSebastian Andrzej Siewior u32 new_mode; 3499b3452d1SSebastian Andrzej Siewior u32 old_mode; 3509b3452d1SSebastian Andrzej Siewior 3519b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) 3529b3452d1SSebastian Andrzej Siewior old_mode = controller->tx_mode; 3539b3452d1SSebastian Andrzej Siewior else 3549b3452d1SSebastian Andrzej Siewior old_mode = controller->rx_mode; 3559b3452d1SSebastian Andrzej Siewior port = cppi41_channel->port_num; 3569b3452d1SSebastian Andrzej Siewior new_mode = update_ep_mode(port, mode, old_mode); 3579b3452d1SSebastian Andrzej Siewior 3589b3452d1SSebastian Andrzej Siewior if (new_mode == old_mode) 3599b3452d1SSebastian Andrzej Siewior return; 3609b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) { 3619b3452d1SSebastian Andrzej Siewior controller->tx_mode = new_mode; 3629b3452d1SSebastian Andrzej Siewior musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, 3639b3452d1SSebastian Andrzej Siewior new_mode); 3649b3452d1SSebastian Andrzej Siewior } else { 3659b3452d1SSebastian Andrzej Siewior controller->rx_mode = new_mode; 3669b3452d1SSebastian Andrzej Siewior musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, 3679b3452d1SSebastian Andrzej Siewior new_mode); 3689b3452d1SSebastian Andrzej Siewior } 3699b3452d1SSebastian Andrzej Siewior } 3709b3452d1SSebastian Andrzej Siewior 3719b3452d1SSebastian Andrzej Siewior static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, 3729b3452d1SSebastian Andrzej Siewior unsigned mode) 3739b3452d1SSebastian Andrzej Siewior { 3749b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 3759b3452d1SSebastian Andrzej Siewior u32 port; 3769b3452d1SSebastian Andrzej Siewior u32 new_mode; 3779b3452d1SSebastian Andrzej Siewior u32 old_mode; 3789b3452d1SSebastian Andrzej Siewior 3799b3452d1SSebastian Andrzej Siewior old_mode = controller->auto_req; 3809b3452d1SSebastian Andrzej Siewior port = cppi41_channel->port_num; 3819b3452d1SSebastian Andrzej Siewior new_mode = update_ep_mode(port, mode, old_mode); 3829b3452d1SSebastian Andrzej Siewior 3839b3452d1SSebastian Andrzej Siewior if (new_mode == old_mode) 3849b3452d1SSebastian Andrzej Siewior return; 3859b3452d1SSebastian Andrzej Siewior controller->auto_req = new_mode; 3869b3452d1SSebastian Andrzej Siewior musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); 3879b3452d1SSebastian Andrzej Siewior } 3889b3452d1SSebastian Andrzej Siewior 3899b3452d1SSebastian Andrzej Siewior static bool cppi41_configure_channel(struct dma_channel *channel, 3909b3452d1SSebastian Andrzej Siewior u16 packet_sz, u8 mode, 3919b3452d1SSebastian Andrzej Siewior dma_addr_t dma_addr, u32 len) 3929b3452d1SSebastian Andrzej Siewior { 3939b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 3949b3452d1SSebastian Andrzej Siewior struct dma_chan *dc = cppi41_channel->dc; 3959b3452d1SSebastian Andrzej Siewior struct dma_async_tx_descriptor *dma_desc; 3969b3452d1SSebastian Andrzej Siewior enum dma_transfer_direction direction; 3979b3452d1SSebastian Andrzej Siewior struct musb *musb = cppi41_channel->controller->musb; 3989b3452d1SSebastian Andrzej Siewior unsigned use_gen_rndis = 0; 3999b3452d1SSebastian Andrzej Siewior 4009b3452d1SSebastian Andrzej Siewior dev_dbg(musb->controller, 4019b3452d1SSebastian Andrzej Siewior "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", 4029b3452d1SSebastian Andrzej Siewior cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), 4039b3452d1SSebastian Andrzej Siewior packet_sz, mode, (unsigned long long) dma_addr, 4049b3452d1SSebastian Andrzej Siewior len, cppi41_channel->is_tx); 4059b3452d1SSebastian Andrzej Siewior 4069b3452d1SSebastian Andrzej Siewior cppi41_channel->buf_addr = dma_addr; 4079b3452d1SSebastian Andrzej Siewior cppi41_channel->total_len = len; 4089b3452d1SSebastian Andrzej Siewior cppi41_channel->transferred = 0; 4099b3452d1SSebastian Andrzej Siewior cppi41_channel->packet_sz = packet_sz; 4109b3452d1SSebastian Andrzej Siewior 4119b3452d1SSebastian Andrzej Siewior /* 4129b3452d1SSebastian Andrzej Siewior * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more 4139b3452d1SSebastian Andrzej Siewior * than max packet size at a time. 4149b3452d1SSebastian Andrzej Siewior */ 4159b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_tx) 4169b3452d1SSebastian Andrzej Siewior use_gen_rndis = 1; 4179b3452d1SSebastian Andrzej Siewior 4189b3452d1SSebastian Andrzej Siewior if (use_gen_rndis) { 4199b3452d1SSebastian Andrzej Siewior /* RNDIS mode */ 4209b3452d1SSebastian Andrzej Siewior if (len > packet_sz) { 4219b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, 4229b3452d1SSebastian Andrzej Siewior RNDIS_REG(cppi41_channel->port_num), len); 4239b3452d1SSebastian Andrzej Siewior /* gen rndis */ 4249b3452d1SSebastian Andrzej Siewior cppi41_set_dma_mode(cppi41_channel, 4259b3452d1SSebastian Andrzej Siewior EP_MODE_DMA_GEN_RNDIS); 4269b3452d1SSebastian Andrzej Siewior 4279b3452d1SSebastian Andrzej Siewior /* auto req */ 4289b3452d1SSebastian Andrzej Siewior cppi41_set_autoreq_mode(cppi41_channel, 4299b3452d1SSebastian Andrzej Siewior EP_MODE_AUTOREG_ALL_NEOP); 4309b3452d1SSebastian Andrzej Siewior } else { 4319b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, 4329b3452d1SSebastian Andrzej Siewior RNDIS_REG(cppi41_channel->port_num), 0); 4339b3452d1SSebastian Andrzej Siewior cppi41_set_dma_mode(cppi41_channel, 4349b3452d1SSebastian Andrzej Siewior EP_MODE_DMA_TRANSPARENT); 4359b3452d1SSebastian Andrzej Siewior cppi41_set_autoreq_mode(cppi41_channel, 4369b3452d1SSebastian Andrzej Siewior EP_MODE_AUTOREG_NONE); 4379b3452d1SSebastian Andrzej Siewior } 4389b3452d1SSebastian Andrzej Siewior } else { 4399b3452d1SSebastian Andrzej Siewior /* fallback mode */ 4409b3452d1SSebastian Andrzej Siewior cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT); 4419b3452d1SSebastian Andrzej Siewior cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE); 4429b3452d1SSebastian Andrzej Siewior len = min_t(u32, packet_sz, len); 4439b3452d1SSebastian Andrzej Siewior } 4449b3452d1SSebastian Andrzej Siewior cppi41_channel->prog_len = len; 4459b3452d1SSebastian Andrzej Siewior direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; 4469b3452d1SSebastian Andrzej Siewior dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction, 4479b3452d1SSebastian Andrzej Siewior DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 4489b3452d1SSebastian Andrzej Siewior if (!dma_desc) 4499b3452d1SSebastian Andrzej Siewior return false; 4509b3452d1SSebastian Andrzej Siewior 4519b3452d1SSebastian Andrzej Siewior dma_desc->callback = cppi41_dma_callback; 4529b3452d1SSebastian Andrzej Siewior dma_desc->callback_param = channel; 4539b3452d1SSebastian Andrzej Siewior cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); 454*ff3fcac9SDaniel Mack cppi41_channel->channel.rx_packet_done = false; 4559b3452d1SSebastian Andrzej Siewior 4569b3452d1SSebastian Andrzej Siewior save_rx_toggle(cppi41_channel); 4579b3452d1SSebastian Andrzej Siewior dma_async_issue_pending(dc); 4589b3452d1SSebastian Andrzej Siewior return true; 4599b3452d1SSebastian Andrzej Siewior } 4609b3452d1SSebastian Andrzej Siewior 4619b3452d1SSebastian Andrzej Siewior static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c, 4629b3452d1SSebastian Andrzej Siewior struct musb_hw_ep *hw_ep, u8 is_tx) 4639b3452d1SSebastian Andrzej Siewior { 4649b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = container_of(c, 4659b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller, controller); 4669b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = NULL; 4679b3452d1SSebastian Andrzej Siewior u8 ch_num = hw_ep->epnum - 1; 4689b3452d1SSebastian Andrzej Siewior 4699b3452d1SSebastian Andrzej Siewior if (ch_num >= MUSB_DMA_NUM_CHANNELS) 4709b3452d1SSebastian Andrzej Siewior return NULL; 4719b3452d1SSebastian Andrzej Siewior 4729b3452d1SSebastian Andrzej Siewior if (is_tx) 4739b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->tx_channel[ch_num]; 4749b3452d1SSebastian Andrzej Siewior else 4759b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->rx_channel[ch_num]; 4769b3452d1SSebastian Andrzej Siewior 4779b3452d1SSebastian Andrzej Siewior if (!cppi41_channel->dc) 4789b3452d1SSebastian Andrzej Siewior return NULL; 4799b3452d1SSebastian Andrzej Siewior 4809b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_allocated) 4819b3452d1SSebastian Andrzej Siewior return NULL; 4829b3452d1SSebastian Andrzej Siewior 4839b3452d1SSebastian Andrzej Siewior cppi41_channel->hw_ep = hw_ep; 4849b3452d1SSebastian Andrzej Siewior cppi41_channel->is_allocated = 1; 4859b3452d1SSebastian Andrzej Siewior 4869b3452d1SSebastian Andrzej Siewior return &cppi41_channel->channel; 4879b3452d1SSebastian Andrzej Siewior } 4889b3452d1SSebastian Andrzej Siewior 4899b3452d1SSebastian Andrzej Siewior static void cppi41_dma_channel_release(struct dma_channel *channel) 4909b3452d1SSebastian Andrzej Siewior { 4919b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 4929b3452d1SSebastian Andrzej Siewior 4939b3452d1SSebastian Andrzej Siewior if (cppi41_channel->is_allocated) { 4949b3452d1SSebastian Andrzej Siewior cppi41_channel->is_allocated = 0; 4959b3452d1SSebastian Andrzej Siewior channel->status = MUSB_DMA_STATUS_FREE; 4969b3452d1SSebastian Andrzej Siewior channel->actual_len = 0; 4979b3452d1SSebastian Andrzej Siewior } 4989b3452d1SSebastian Andrzej Siewior } 4999b3452d1SSebastian Andrzej Siewior 5009b3452d1SSebastian Andrzej Siewior static int cppi41_dma_channel_program(struct dma_channel *channel, 5019b3452d1SSebastian Andrzej Siewior u16 packet_sz, u8 mode, 5029b3452d1SSebastian Andrzej Siewior dma_addr_t dma_addr, u32 len) 5039b3452d1SSebastian Andrzej Siewior { 5049b3452d1SSebastian Andrzej Siewior int ret; 505f82503f5SGeorge Cherian struct cppi41_dma_channel *cppi41_channel = channel->private_data; 506f82503f5SGeorge Cherian int hb_mult = 0; 5079b3452d1SSebastian Andrzej Siewior 5089b3452d1SSebastian Andrzej Siewior BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || 5099b3452d1SSebastian Andrzej Siewior channel->status == MUSB_DMA_STATUS_BUSY); 5109b3452d1SSebastian Andrzej Siewior 511f82503f5SGeorge Cherian if (is_host_active(cppi41_channel->controller->musb)) { 512f82503f5SGeorge Cherian if (cppi41_channel->is_tx) 513f82503f5SGeorge Cherian hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; 514f82503f5SGeorge Cherian else 515f82503f5SGeorge Cherian hb_mult = cppi41_channel->hw_ep->in_qh->hb_mult; 516f82503f5SGeorge Cherian } 517f82503f5SGeorge Cherian 5189b3452d1SSebastian Andrzej Siewior channel->status = MUSB_DMA_STATUS_BUSY; 5199b3452d1SSebastian Andrzej Siewior channel->actual_len = 0; 520f82503f5SGeorge Cherian 521f82503f5SGeorge Cherian if (hb_mult) 522f82503f5SGeorge Cherian packet_sz = hb_mult * (packet_sz & 0x7FF); 523f82503f5SGeorge Cherian 5249b3452d1SSebastian Andrzej Siewior ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len); 5259b3452d1SSebastian Andrzej Siewior if (!ret) 5269b3452d1SSebastian Andrzej Siewior channel->status = MUSB_DMA_STATUS_FREE; 5279b3452d1SSebastian Andrzej Siewior 5289b3452d1SSebastian Andrzej Siewior return ret; 5299b3452d1SSebastian Andrzej Siewior } 5309b3452d1SSebastian Andrzej Siewior 5319b3452d1SSebastian Andrzej Siewior static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, 5329b3452d1SSebastian Andrzej Siewior void *buf, u32 length) 5339b3452d1SSebastian Andrzej Siewior { 5349b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 5359b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 5369b3452d1SSebastian Andrzej Siewior struct musb *musb = controller->musb; 5379b3452d1SSebastian Andrzej Siewior 5389b3452d1SSebastian Andrzej Siewior if (is_host_active(musb)) { 5399b3452d1SSebastian Andrzej Siewior WARN_ON(1); 5409b3452d1SSebastian Andrzej Siewior return 1; 5419b3452d1SSebastian Andrzej Siewior } 542a655f481SSebastian Andrzej Siewior if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK) 543a655f481SSebastian Andrzej Siewior return 0; 54413266feaSSebastian Andrzej Siewior if (cppi41_channel->is_tx) 54513266feaSSebastian Andrzej Siewior return 1; 54613266feaSSebastian Andrzej Siewior /* AM335x Advisory 1.0.13. No workaround for device RX mode */ 5479b3452d1SSebastian Andrzej Siewior return 0; 5489b3452d1SSebastian Andrzej Siewior } 5499b3452d1SSebastian Andrzej Siewior 5509b3452d1SSebastian Andrzej Siewior static int cppi41_dma_channel_abort(struct dma_channel *channel) 5519b3452d1SSebastian Andrzej Siewior { 5529b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel = channel->private_data; 5539b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = cppi41_channel->controller; 5549b3452d1SSebastian Andrzej Siewior struct musb *musb = controller->musb; 5559b3452d1SSebastian Andrzej Siewior void __iomem *epio = cppi41_channel->hw_ep->regs; 5569b3452d1SSebastian Andrzej Siewior int tdbit; 5579b3452d1SSebastian Andrzej Siewior int ret; 5589b3452d1SSebastian Andrzej Siewior unsigned is_tx; 5599b3452d1SSebastian Andrzej Siewior u16 csr; 5609b3452d1SSebastian Andrzej Siewior 5619b3452d1SSebastian Andrzej Siewior is_tx = cppi41_channel->is_tx; 5629b3452d1SSebastian Andrzej Siewior dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n", 5639b3452d1SSebastian Andrzej Siewior cppi41_channel->port_num, is_tx); 5649b3452d1SSebastian Andrzej Siewior 5659b3452d1SSebastian Andrzej Siewior if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) 5669b3452d1SSebastian Andrzej Siewior return 0; 5679b3452d1SSebastian Andrzej Siewior 568a655f481SSebastian Andrzej Siewior list_del_init(&cppi41_channel->tx_check); 5699b3452d1SSebastian Andrzej Siewior if (is_tx) { 5709b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_TXCSR); 5719b3452d1SSebastian Andrzej Siewior csr &= ~MUSB_TXCSR_DMAENAB; 5729b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_TXCSR, csr); 5739b3452d1SSebastian Andrzej Siewior } else { 5749b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_RXCSR); 5759b3452d1SSebastian Andrzej Siewior csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB); 5769b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 5779b3452d1SSebastian Andrzej Siewior 5789b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_RXCSR); 5799b3452d1SSebastian Andrzej Siewior if (csr & MUSB_RXCSR_RXPKTRDY) { 5809b3452d1SSebastian Andrzej Siewior csr |= MUSB_RXCSR_FLUSHFIFO; 5819b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 5829b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_RXCSR, csr); 5839b3452d1SSebastian Andrzej Siewior } 5849b3452d1SSebastian Andrzej Siewior } 5859b3452d1SSebastian Andrzej Siewior 5869b3452d1SSebastian Andrzej Siewior tdbit = 1 << cppi41_channel->port_num; 5879b3452d1SSebastian Andrzej Siewior if (is_tx) 5889b3452d1SSebastian Andrzej Siewior tdbit <<= 16; 5899b3452d1SSebastian Andrzej Siewior 5909b3452d1SSebastian Andrzej Siewior do { 5919b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); 5929b3452d1SSebastian Andrzej Siewior ret = dmaengine_terminate_all(cppi41_channel->dc); 5939b3452d1SSebastian Andrzej Siewior } while (ret == -EAGAIN); 5949b3452d1SSebastian Andrzej Siewior 5959b3452d1SSebastian Andrzej Siewior musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); 5969b3452d1SSebastian Andrzej Siewior 5979b3452d1SSebastian Andrzej Siewior if (is_tx) { 5989b3452d1SSebastian Andrzej Siewior csr = musb_readw(epio, MUSB_TXCSR); 5999b3452d1SSebastian Andrzej Siewior if (csr & MUSB_TXCSR_TXPKTRDY) { 6009b3452d1SSebastian Andrzej Siewior csr |= MUSB_TXCSR_FLUSHFIFO; 6019b3452d1SSebastian Andrzej Siewior musb_writew(epio, MUSB_TXCSR, csr); 6029b3452d1SSebastian Andrzej Siewior } 6039b3452d1SSebastian Andrzej Siewior } 6049b3452d1SSebastian Andrzej Siewior 6059b3452d1SSebastian Andrzej Siewior cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; 6069b3452d1SSebastian Andrzej Siewior return 0; 6079b3452d1SSebastian Andrzej Siewior } 6089b3452d1SSebastian Andrzej Siewior 6099b3452d1SSebastian Andrzej Siewior static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl) 6109b3452d1SSebastian Andrzej Siewior { 6119b3452d1SSebastian Andrzej Siewior struct dma_chan *dc; 6129b3452d1SSebastian Andrzej Siewior int i; 6139b3452d1SSebastian Andrzej Siewior 6149b3452d1SSebastian Andrzej Siewior for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) { 6159b3452d1SSebastian Andrzej Siewior dc = ctrl->tx_channel[i].dc; 6169b3452d1SSebastian Andrzej Siewior if (dc) 6179b3452d1SSebastian Andrzej Siewior dma_release_channel(dc); 6189b3452d1SSebastian Andrzej Siewior dc = ctrl->rx_channel[i].dc; 6199b3452d1SSebastian Andrzej Siewior if (dc) 6209b3452d1SSebastian Andrzej Siewior dma_release_channel(dc); 6219b3452d1SSebastian Andrzej Siewior } 6229b3452d1SSebastian Andrzej Siewior } 6239b3452d1SSebastian Andrzej Siewior 6249b3452d1SSebastian Andrzej Siewior static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) 6259b3452d1SSebastian Andrzej Siewior { 6269b3452d1SSebastian Andrzej Siewior cppi41_release_all_dma_chans(controller); 6279b3452d1SSebastian Andrzej Siewior } 6289b3452d1SSebastian Andrzej Siewior 6299b3452d1SSebastian Andrzej Siewior static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) 6309b3452d1SSebastian Andrzej Siewior { 6319b3452d1SSebastian Andrzej Siewior struct musb *musb = controller->musb; 6329b3452d1SSebastian Andrzej Siewior struct device *dev = musb->controller; 6339b3452d1SSebastian Andrzej Siewior struct device_node *np = dev->of_node; 6349b3452d1SSebastian Andrzej Siewior struct cppi41_dma_channel *cppi41_channel; 6359b3452d1SSebastian Andrzej Siewior int count; 6369b3452d1SSebastian Andrzej Siewior int i; 6379b3452d1SSebastian Andrzej Siewior int ret; 6389b3452d1SSebastian Andrzej Siewior 6399b3452d1SSebastian Andrzej Siewior count = of_property_count_strings(np, "dma-names"); 6409b3452d1SSebastian Andrzej Siewior if (count < 0) 6419b3452d1SSebastian Andrzej Siewior return count; 6429b3452d1SSebastian Andrzej Siewior 6439b3452d1SSebastian Andrzej Siewior for (i = 0; i < count; i++) { 6449b3452d1SSebastian Andrzej Siewior struct dma_chan *dc; 6459b3452d1SSebastian Andrzej Siewior struct dma_channel *musb_dma; 6469b3452d1SSebastian Andrzej Siewior const char *str; 6479b3452d1SSebastian Andrzej Siewior unsigned is_tx; 6489b3452d1SSebastian Andrzej Siewior unsigned int port; 6499b3452d1SSebastian Andrzej Siewior 6509b3452d1SSebastian Andrzej Siewior ret = of_property_read_string_index(np, "dma-names", i, &str); 6519b3452d1SSebastian Andrzej Siewior if (ret) 6529b3452d1SSebastian Andrzej Siewior goto err; 6539b3452d1SSebastian Andrzej Siewior if (!strncmp(str, "tx", 2)) 6549b3452d1SSebastian Andrzej Siewior is_tx = 1; 6559b3452d1SSebastian Andrzej Siewior else if (!strncmp(str, "rx", 2)) 6569b3452d1SSebastian Andrzej Siewior is_tx = 0; 6579b3452d1SSebastian Andrzej Siewior else { 6589b3452d1SSebastian Andrzej Siewior dev_err(dev, "Wrong dmatype %s\n", str); 6599b3452d1SSebastian Andrzej Siewior goto err; 6609b3452d1SSebastian Andrzej Siewior } 6619b3452d1SSebastian Andrzej Siewior ret = kstrtouint(str + 2, 0, &port); 6629b3452d1SSebastian Andrzej Siewior if (ret) 6639b3452d1SSebastian Andrzej Siewior goto err; 6649b3452d1SSebastian Andrzej Siewior 66548054147SSebastian Andrzej Siewior ret = -EINVAL; 6669b3452d1SSebastian Andrzej Siewior if (port > MUSB_DMA_NUM_CHANNELS || !port) 6679b3452d1SSebastian Andrzej Siewior goto err; 6689b3452d1SSebastian Andrzej Siewior if (is_tx) 6699b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->tx_channel[port - 1]; 6709b3452d1SSebastian Andrzej Siewior else 6719b3452d1SSebastian Andrzej Siewior cppi41_channel = &controller->rx_channel[port - 1]; 6729b3452d1SSebastian Andrzej Siewior 6739b3452d1SSebastian Andrzej Siewior cppi41_channel->controller = controller; 6749b3452d1SSebastian Andrzej Siewior cppi41_channel->port_num = port; 6759b3452d1SSebastian Andrzej Siewior cppi41_channel->is_tx = is_tx; 676a655f481SSebastian Andrzej Siewior INIT_LIST_HEAD(&cppi41_channel->tx_check); 6771af54b7aSGeorge Cherian INIT_WORK(&cppi41_channel->dma_completion, 6781af54b7aSGeorge Cherian cppi_trans_done_work); 6799b3452d1SSebastian Andrzej Siewior 6809b3452d1SSebastian Andrzej Siewior musb_dma = &cppi41_channel->channel; 6819b3452d1SSebastian Andrzej Siewior musb_dma->private_data = cppi41_channel; 6829b3452d1SSebastian Andrzej Siewior musb_dma->status = MUSB_DMA_STATUS_FREE; 6839b3452d1SSebastian Andrzej Siewior musb_dma->max_len = SZ_4M; 6849b3452d1SSebastian Andrzej Siewior 6859b3452d1SSebastian Andrzej Siewior dc = dma_request_slave_channel(dev, str); 6869b3452d1SSebastian Andrzej Siewior if (!dc) { 6875ae477b0SRahul Bedarkar dev_err(dev, "Failed to request %s.\n", str); 68848054147SSebastian Andrzej Siewior ret = -EPROBE_DEFER; 6899b3452d1SSebastian Andrzej Siewior goto err; 6909b3452d1SSebastian Andrzej Siewior } 6919b3452d1SSebastian Andrzej Siewior cppi41_channel->dc = dc; 6929b3452d1SSebastian Andrzej Siewior } 6939b3452d1SSebastian Andrzej Siewior return 0; 6949b3452d1SSebastian Andrzej Siewior err: 6959b3452d1SSebastian Andrzej Siewior cppi41_release_all_dma_chans(controller); 69648054147SSebastian Andrzej Siewior return ret; 6979b3452d1SSebastian Andrzej Siewior } 6989b3452d1SSebastian Andrzej Siewior 6999b3452d1SSebastian Andrzej Siewior void dma_controller_destroy(struct dma_controller *c) 7009b3452d1SSebastian Andrzej Siewior { 7019b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller = container_of(c, 7029b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller, controller); 7039b3452d1SSebastian Andrzej Siewior 704a655f481SSebastian Andrzej Siewior hrtimer_cancel(&controller->early_tx); 7059b3452d1SSebastian Andrzej Siewior cppi41_dma_controller_stop(controller); 7069b3452d1SSebastian Andrzej Siewior kfree(controller); 7079b3452d1SSebastian Andrzej Siewior } 7089b3452d1SSebastian Andrzej Siewior 7099b3452d1SSebastian Andrzej Siewior struct dma_controller *dma_controller_create(struct musb *musb, 7109b3452d1SSebastian Andrzej Siewior void __iomem *base) 7119b3452d1SSebastian Andrzej Siewior { 7129b3452d1SSebastian Andrzej Siewior struct cppi41_dma_controller *controller; 71348054147SSebastian Andrzej Siewior int ret = 0; 7149b3452d1SSebastian Andrzej Siewior 7159b3452d1SSebastian Andrzej Siewior if (!musb->controller->of_node) { 7169b3452d1SSebastian Andrzej Siewior dev_err(musb->controller, "Need DT for the DMA engine.\n"); 7179b3452d1SSebastian Andrzej Siewior return NULL; 7189b3452d1SSebastian Andrzej Siewior } 7199b3452d1SSebastian Andrzej Siewior 7209b3452d1SSebastian Andrzej Siewior controller = kzalloc(sizeof(*controller), GFP_KERNEL); 7219b3452d1SSebastian Andrzej Siewior if (!controller) 7229b3452d1SSebastian Andrzej Siewior goto kzalloc_fail; 7239b3452d1SSebastian Andrzej Siewior 724a655f481SSebastian Andrzej Siewior hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 725a655f481SSebastian Andrzej Siewior controller->early_tx.function = cppi41_recheck_tx_req; 726a655f481SSebastian Andrzej Siewior INIT_LIST_HEAD(&controller->early_tx_list); 7279b3452d1SSebastian Andrzej Siewior controller->musb = musb; 7289b3452d1SSebastian Andrzej Siewior 7299b3452d1SSebastian Andrzej Siewior controller->controller.channel_alloc = cppi41_dma_channel_allocate; 7309b3452d1SSebastian Andrzej Siewior controller->controller.channel_release = cppi41_dma_channel_release; 7319b3452d1SSebastian Andrzej Siewior controller->controller.channel_program = cppi41_dma_channel_program; 7329b3452d1SSebastian Andrzej Siewior controller->controller.channel_abort = cppi41_dma_channel_abort; 7339b3452d1SSebastian Andrzej Siewior controller->controller.is_compatible = cppi41_is_compatible; 7349b3452d1SSebastian Andrzej Siewior 7359b3452d1SSebastian Andrzej Siewior ret = cppi41_dma_controller_start(controller); 7369b3452d1SSebastian Andrzej Siewior if (ret) 7379b3452d1SSebastian Andrzej Siewior goto plat_get_fail; 7389b3452d1SSebastian Andrzej Siewior return &controller->controller; 7399b3452d1SSebastian Andrzej Siewior 7409b3452d1SSebastian Andrzej Siewior plat_get_fail: 7419b3452d1SSebastian Andrzej Siewior kfree(controller); 7429b3452d1SSebastian Andrzej Siewior kzalloc_fail: 74348054147SSebastian Andrzej Siewior if (ret == -EPROBE_DEFER) 74448054147SSebastian Andrzej Siewior return ERR_PTR(ret); 7459b3452d1SSebastian Andrzej Siewior return NULL; 7469b3452d1SSebastian Andrzej Siewior } 747