/** * mpc52xx_lpbfifo_kick - Trigger the next block of data to be transferred */ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) { size_t transfer_size = req->size - req->pos; struct bcom_bd *bd; void __iomem *reg; u32 *data; int i; int bit_fields; int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; int poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; /* Set and clear the reset bits; is good practice in User Manual */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); /* set master enable bit */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000001); if (!dma) { /* While the FIFO can be setup for transfer sizes as large as * 16M-1, the FIFO itself is only 512 bytes deep and it does * not generate interrupts for FIFO full events (only transfer * complete will raise an IRQ). Therefore when not using * Bestcomm to drive the FIFO it needs to either be polled, or * transfers need to constrained to the size of the fifo. * * This driver restricts the size of the transfer */ if (transfer_size > 512) transfer_size = 512; /* Load the FIFO with data */ if (write) { reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; data = req->data + req->pos; for (i = 0; i < transfer_size; i += 4) out_be32(reg, *data++); } /* Unmask both error and completion irqs */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000301); } else { /* Choose the correct direction * * Configure the watermarks so DMA will always complete correctly. * It may be worth experimenting with the ALARM value to see if * there is a performance impacit. However, if it is wrong there * is a risk of DMA not transferring the last chunk of data */ if (write) { out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1e4); out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 7); lpbfifo.bcom_cur_task = lpbfifo.bcom_tx_task; } else { out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1ff); out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0); lpbfifo.bcom_cur_task = lpbfifo.bcom_rx_task; if (poll_dma) { if (lpbfifo.dma_irqs_enabled) { disable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); lpbfifo.dma_irqs_enabled = 0; } } else { if (!lpbfifo.dma_irqs_enabled) { enable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); lpbfifo.dma_irqs_enabled = 1; } } } bd = bcom_prepare_next_buffer(lpbfifo.bcom_cur_task); bd->status = transfer_size; if (!write) { /* * In the DMA read case, the DMA doesn't complete, * possibly due to incorrect watermarks in the ALARM * and CONTROL regs. For now instead of trying to * determine the right watermarks that will make this * work, just increase the number of bytes the FIFO is * expecting. * * When submitting another operation, the FIFO will get * reset, so the condition of the FIFO waiting for a * non-existent 4 bytes will get cleared. */ transfer_size += 4; /* BLECH! */ } bd->data[0] = req->data_phys + req->pos; bcom_submit_next_buffer(lpbfifo.bcom_cur_task, NULL); /* error irq & master enabled bit */ bit_fields = 0x00000201; /* Unmask irqs */ if (write && (!poll_dma)) bit_fields |= 0x00000100; /* completion irq too */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, bit_fields); } /* Set transfer size, width, chip select and READ mode */ out_be32(lpbfifo.regs + LPBFIFO_REG_START_ADDRESS, req->offset + req->pos); out_be32(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, transfer_size); bit_fields = req->cs << 24 | 0x000008; if (!write) bit_fields |= 0x010000; /* read mode */ out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bit_fields); /* Kick it off */ out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); if (dma) bcom_enable(lpbfifo.bcom_cur_task); }
static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) { size_t transfer_size = req->size - req->pos; struct bcom_bd *bd; void __iomem *reg; u32 *data; int i; int bit_fields; int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; int poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; /* */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); /* */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000001); if (!dma) { /* */ if (transfer_size > 512) transfer_size = 512; /* */ if (write) { reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; data = req->data + req->pos; for (i = 0; i < transfer_size; i += 4) out_be32(reg, *data++); } /* */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000301); } else { /* */ if (write) { out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1e4); out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 7); lpbfifo.bcom_cur_task = lpbfifo.bcom_tx_task; } else { out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1ff); out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0); lpbfifo.bcom_cur_task = lpbfifo.bcom_rx_task; if (poll_dma) { if (lpbfifo.dma_irqs_enabled) { disable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); lpbfifo.dma_irqs_enabled = 0; } } else { if (!lpbfifo.dma_irqs_enabled) { enable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); lpbfifo.dma_irqs_enabled = 1; } } } bd = bcom_prepare_next_buffer(lpbfifo.bcom_cur_task); bd->status = transfer_size; if (!write) { /* */ transfer_size += 4; /* */ } bd->data[0] = req->data_phys + req->pos; bcom_submit_next_buffer(lpbfifo.bcom_cur_task, NULL); /* */ bit_fields = 0x00000201; /* */ if (write && (!poll_dma)) bit_fields |= 0x00000100; /* */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, bit_fields); } /* */ out_be32(lpbfifo.regs + LPBFIFO_REG_START_ADDRESS, req->offset + req->pos); out_be32(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, transfer_size); bit_fields = req->cs << 24 | 0x000008; if (!write) bit_fields |= 0x010000; /* */ out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bit_fields); /* */ out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); if (dma) bcom_enable(lpbfifo.bcom_cur_task); }