static int __devexit mpc52xx_lpbfifo_remove(struct platform_device *op) { if (lpbfifo.dev != &op->dev) return 0; /* Put FIFO in reset */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); /* Release the bestcomm transmit task */ free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo); bcom_gen_bd_tx_release(lpbfifo.bcom_tx_task); /* Release the bestcomm receive task */ free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); free_irq(lpbfifo.irq, &lpbfifo); iounmap(lpbfifo.regs); lpbfifo.regs = NULL; lpbfifo.dev = NULL; return 0; }
static int __devexit mpc52xx_lpbfifo_remove(struct platform_device *op) { if (lpbfifo.dev != &op->dev) return 0; out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo); bcom_gen_bd_tx_release(lpbfifo.bcom_tx_task); free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); free_irq(lpbfifo.irq, &lpbfifo); iounmap(lpbfifo.regs); lpbfifo.regs = NULL; lpbfifo.dev = NULL; return 0; }
/** * 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 int __devinit mpc52xx_lpbfifo_probe(struct platform_device *op) { struct resource res; int rc = -ENOMEM; if (lpbfifo.dev != NULL) return -ENOSPC; lpbfifo.irq = irq_of_parse_and_map(op->dev.of_node, 0); if (!lpbfifo.irq) return -ENODEV; if (of_address_to_resource(op->dev.of_node, 0, &res)) return -ENODEV; lpbfifo.regs_phys = res.start; lpbfifo.regs = of_iomap(op->dev.of_node, 0); if (!lpbfifo.regs) return -ENOMEM; spin_lock_init(&lpbfifo.lock); /* Put FIFO into reset */ out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); /* Register the interrupt handler */ rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_irq, 0, "mpc52xx-lpbfifo", &lpbfifo); if (rc) goto err_irq; /* Request the Bestcomm receive (fifo --> memory) task and IRQ */ lpbfifo.bcom_rx_task = bcom_gen_bd_rx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC, 16*1024*1024); if (!lpbfifo.bcom_rx_task) goto err_bcom_rx; rc = request_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), mpc52xx_lpbfifo_bcom_irq, 0, "mpc52xx-lpbfifo-rx", &lpbfifo); if (rc) goto err_bcom_rx_irq; lpbfifo.dma_irqs_enabled = 1; /* Request the Bestcomm transmit (memory --> fifo) task and IRQ */ lpbfifo.bcom_tx_task = bcom_gen_bd_tx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC); if (!lpbfifo.bcom_tx_task) goto err_bcom_tx; lpbfifo.dev = &op->dev; return 0; err_bcom_tx: free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); err_bcom_rx_irq: bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); err_bcom_rx: err_irq: iounmap(lpbfifo.regs); lpbfifo.regs = NULL; dev_err(&op->dev, "mpc52xx_lpbfifo_probe() failed\n"); return -ENODEV; }
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); }