📄 mpsc.c
字号:
static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val){ u32 v; v = readl(pi->sdma_base + SDMA_SDCM); if (val) v |= val; else v = 0; wmb(); writel(v, pi->sdma_base + SDMA_SDCM); wmb();}static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi){ return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;}static void mpsc_sdma_start_tx(struct mpsc_port_info *pi){ struct mpsc_tx_desc *txre, *txre_p; /* If tx isn't running & there's a desc ready to go, start it */ if (!mpsc_sdma_tx_active(pi)) { txre = (struct mpsc_tx_desc *)(pi->txr + (pi->txr_tail * MPSC_TXRE_SIZE)); dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, DMA_FROM_DEVICE);#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ invalidate_dcache_range((ulong)txre, (ulong)txre + MPSC_TXRE_SIZE);#endif if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) { txre_p = (struct mpsc_tx_desc *) (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE)); mpsc_sdma_set_tx_ring(pi, txre_p); mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD); } }}static void mpsc_sdma_stop(struct mpsc_port_info *pi){ pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line); /* Abort any SDMA transfers */ mpsc_sdma_cmd(pi, 0); mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT); /* Clear the SDMA current and first TX and RX pointers */ mpsc_sdma_set_tx_ring(pi, NULL); mpsc_sdma_set_rx_ring(pi, NULL); /* Disable interrupts */ mpsc_sdma_intr_mask(pi, 0xf); mpsc_sdma_intr_ack(pi);}/* ****************************************************************************** * * Multi-Protocol Serial Controller Routines (MPSC) * ****************************************************************************** */static void mpsc_hw_init(struct mpsc_port_info *pi){ u32 v; pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line); /* Set up clock routing */ if (pi->mirror_regs) { v = pi->shared_regs->MPSC_MRR_m; v &= ~0x1c7; pi->shared_regs->MPSC_MRR_m = v; writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR); v = pi->shared_regs->MPSC_RCRR_m; v = (v & ~0xf0f) | 0x100; pi->shared_regs->MPSC_RCRR_m = v; writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR); v = pi->shared_regs->MPSC_TCRR_m; v = (v & ~0xf0f) | 0x100; pi->shared_regs->MPSC_TCRR_m = v; writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR); } else { v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR); v &= ~0x1c7; writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR); v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR); v = (v & ~0xf0f) | 0x100; writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR); v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR); v = (v & ~0xf0f) | 0x100; writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR); } /* Put MPSC in UART mode & enabel Tx/Rx egines */ writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL); /* No preamble, 16x divider, low-latency, */ writel(0x04400400, pi->mpsc_base + MPSC_MMCRH); if (pi->mirror_regs) { pi->MPSC_CHR_1_m = 0; pi->MPSC_CHR_2_m = 0; } writel(0, pi->mpsc_base + MPSC_CHR_1); writel(0, pi->mpsc_base + MPSC_CHR_2); writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3); writel(0, pi->mpsc_base + MPSC_CHR_4); writel(0, pi->mpsc_base + MPSC_CHR_5); writel(0, pi->mpsc_base + MPSC_CHR_6); writel(0, pi->mpsc_base + MPSC_CHR_7); writel(0, pi->mpsc_base + MPSC_CHR_8); writel(0, pi->mpsc_base + MPSC_CHR_9); writel(0, pi->mpsc_base + MPSC_CHR_10);}static void mpsc_enter_hunt(struct mpsc_port_info *pi){ pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line); if (pi->mirror_regs) { writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH, pi->mpsc_base + MPSC_CHR_2); /* Erratum prevents reading CHR_2 so just delay for a while */ udelay(100); } else { writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH, pi->mpsc_base + MPSC_CHR_2); while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH) udelay(10); }}static void mpsc_freeze(struct mpsc_port_info *pi){ u32 v; pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line); v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : readl(pi->mpsc_base + MPSC_MPCR); v |= MPSC_MPCR_FRZ; if (pi->mirror_regs) pi->MPSC_MPCR_m = v; writel(v, pi->mpsc_base + MPSC_MPCR);}static void mpsc_unfreeze(struct mpsc_port_info *pi){ u32 v; v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : readl(pi->mpsc_base + MPSC_MPCR); v &= ~MPSC_MPCR_FRZ; if (pi->mirror_regs) pi->MPSC_MPCR_m = v; writel(v, pi->mpsc_base + MPSC_MPCR); pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);}static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len){ u32 v; pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len); v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : readl(pi->mpsc_base + MPSC_MPCR); v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12); if (pi->mirror_regs) pi->MPSC_MPCR_m = v; writel(v, pi->mpsc_base + MPSC_MPCR);}static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len){ u32 v; pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n", pi->port.line, len); v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : readl(pi->mpsc_base + MPSC_MPCR); v = (v & ~(1 << 14)) | ((len & 0x1) << 14); if (pi->mirror_regs) pi->MPSC_MPCR_m = v; writel(v, pi->mpsc_base + MPSC_MPCR);}static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p){ u32 v; pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p); v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m : readl(pi->mpsc_base + MPSC_CHR_2); p &= 0x3; v = (v & ~0xc000c) | (p << 18) | (p << 2); if (pi->mirror_regs) pi->MPSC_CHR_2_m = v; writel(v, pi->mpsc_base + MPSC_CHR_2);}/* ****************************************************************************** * * Driver Init Routines * ****************************************************************************** */static void mpsc_init_hw(struct mpsc_port_info *pi){ pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line); mpsc_brg_init(pi, pi->brg_clk_src); mpsc_brg_enable(pi); mpsc_sdma_init(pi, dma_get_cache_alignment()); /* burst a cacheline */ mpsc_sdma_stop(pi); mpsc_hw_init(pi);}static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi){ int rc = 0; pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n", pi->port.line); if (!pi->dma_region) { if (!dma_supported(pi->port.dev, 0xffffffff)) { printk(KERN_ERR "MPSC: Inadequate DMA support\n"); rc = -ENXIO; } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE, &pi->dma_region_p, GFP_KERNEL)) == NULL) { printk(KERN_ERR "MPSC: Can't alloc Desc region\n"); rc = -ENOMEM; } } return rc;}static void mpsc_free_ring_mem(struct mpsc_port_info *pi){ pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line); if (pi->dma_region) { dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE, pi->dma_region, pi->dma_region_p); pi->dma_region = NULL; pi->dma_region_p = (dma_addr_t)NULL; }}static void mpsc_init_rings(struct mpsc_port_info *pi){ struct mpsc_rx_desc *rxre; struct mpsc_tx_desc *txre; dma_addr_t dp, dp_p; u8 *bp, *bp_p; int i; pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line); BUG_ON(pi->dma_region == NULL); memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE); /* * Descriptors & buffers are multiples of cacheline size and must be * cacheline aligned. */ dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment()); dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment()); /* * Partition dma region into rx ring descriptor, rx buffers, * tx ring descriptors, and tx buffers. */ pi->rxr = dp; pi->rxr_p = dp_p; dp += MPSC_RXR_SIZE; dp_p += MPSC_RXR_SIZE; pi->rxb = (u8 *)dp; pi->rxb_p = (u8 *)dp_p; dp += MPSC_RXB_SIZE; dp_p += MPSC_RXB_SIZE; pi->rxr_posn = 0; pi->txr = dp; pi->txr_p = dp_p; dp += MPSC_TXR_SIZE; dp_p += MPSC_TXR_SIZE; pi->txb = (u8 *)dp; pi->txb_p = (u8 *)dp_p; pi->txr_head = 0; pi->txr_tail = 0; /* Init rx ring descriptors */ dp = pi->rxr; dp_p = pi->rxr_p; bp = pi->rxb; bp_p = pi->rxb_p; for (i = 0; i < MPSC_RXR_ENTRIES; i++) { rxre = (struct mpsc_rx_desc *)dp; rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE); rxre->bytecnt = cpu_to_be16(0); rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F | SDMA_DESC_CMDSTAT_L); rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE); rxre->buf_ptr = cpu_to_be32(bp_p); dp += MPSC_RXRE_SIZE; dp_p += MPSC_RXRE_SIZE; bp += MPSC_RXBE_SIZE; bp_p += MPSC_RXBE_SIZE; } rxre->link = cpu_to_be32(pi->rxr_p); /* Wrap last back to first */ /* Init tx ring descriptors */ dp = pi->txr; dp_p = pi->txr_p; bp = pi->txb; bp_p = pi->txb_p; for (i = 0; i < MPSC_TXR_ENTRIES; i++) { txre = (struct mpsc_tx_desc *)dp; txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE); txre->buf_ptr = cpu_to_be32(bp_p); dp += MPSC_TXRE_SIZE; dp_p += MPSC_TXRE_SIZE; bp += MPSC_TXBE_SIZE; bp_p += MPSC_TXBE_SIZE; } txre->link = cpu_to_be32(pi->txr_p); /* Wrap last back to first */ dma_cache_sync(pi->port.dev, (void *)pi->dma_region, MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ flush_dcache_range((ulong)pi->dma_region, (ulong)pi->dma_region + MPSC_DMA_ALLOC_SIZE);#endif return;}static void mpsc_uninit_rings(struct mpsc_port_info *pi){ pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line); BUG_ON(pi->dma_region == NULL); pi->rxr = 0; pi->rxr_p = 0; pi->rxb = NULL; pi->rxb_p = NULL; pi->rxr_posn = 0; pi->txr = 0; pi->txr_p = 0; pi->txb = NULL; pi->txb_p = NULL; pi->txr_head = 0; pi->txr_tail = 0;}static int mpsc_make_ready(struct mpsc_port_info *pi){ int rc; pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line); if (!pi->ready) { mpsc_init_hw(pi); if ((rc = mpsc_alloc_ring_mem(pi))) return rc; mpsc_init_rings(pi); pi->ready = 1; } return 0;}/* ****************************************************************************** * * Interrupt Handling Routines * ****************************************************************************** */static int mpsc_rx_intr(struct mpsc_port_info *pi){ struct mpsc_rx_desc *rxre; struct tty_struct *tty = pi->port.info->tty; u32 cmdstat, bytes_in, i; int rc = 0; u8 *bp; char flag = TTY_NORMAL; pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE)); dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE);#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ invalidate_dcache_range((ulong)rxre, (ulong)rxre + MPSC_RXRE_SIZE);#endif /* * Loop through Rx descriptors handling ones that have been completed. */ while (!((cmdstat = be32_to_cpu(rxre->cmdstat)) & SDMA_DESC_CMDSTAT_O)) { bytes_in = be16_to_cpu(rxre->bytecnt); /* Following use of tty struct directly is deprecated */ if (unlikely(tty_buffer_request_room(tty, bytes_in) < bytes_in)) { if (tty->low_latency) tty_flip_buffer_push(tty); /* * If this failed then we will throw away the bytes * but must do so to clear interrupts. */ } bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE); dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE, DMA_FROM_DEVICE);#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ invalidate_dcache_range((ulong)bp, (ulong)bp + MPSC_RXBE_SIZE);#endif /* * Other than for parity error, the manual provides little * info on what data will be in a frame flagged by any of * these errors. For parity error, it is the last byte in * the buffer that had the error. As for the rest, I guess * we'll assume there is no data in the buffer. * If there is...it gets lost. */ if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR | SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) { pi->port.icount.rx++; if (cmdstat & SDMA_DESC_CMDSTAT_BR) { /* Break */ pi->port.icount.brk++; if (uart_handle_break(&pi->port)) goto next_frame; } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) { pi->port.icount.frame++; } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) { pi->port.icount.overrun++; } cmdstat &= pi->port.read_status_mask; if (cmdstat & SDMA_DESC_CMDSTAT_BR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -