|
@@ -614,3 +614,140 @@ static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
|
|
/* Free the node and update curr, if non-circular queue */
|
|
/* Free the node and update curr, if non-circular queue */
|
|
if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) {
|
|
if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) {
|
|
chan->curr = buff->next;
|
|
chan->curr = buff->next;
|
|
|
|
+ s3c64xx_dma_freebuff(buff);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Update 'next' */
|
|
|
|
+ buff = chan->next;
|
|
|
|
+ if (chan->next == chan->end) {
|
|
|
|
+ chan->next = chan->curr;
|
|
|
|
+ if (!(chan->flags & S3C2410_DMAF_CIRCULAR))
|
|
|
|
+ chan->end = NULL;
|
|
|
|
+ } else {
|
|
|
|
+ chan->next = buff->next;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return IRQ_HANDLED;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct bus_type dma_subsys = {
|
|
|
|
+ .name = "s3c64xx-dma",
|
|
|
|
+ .dev_name = "s3c64xx-dma",
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
|
|
|
|
+ int irq, unsigned int base)
|
|
|
|
+{
|
|
|
|
+ struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno];
|
|
|
|
+ struct s3c64xx_dmac *dmac;
|
|
|
|
+ char clkname[16];
|
|
|
|
+ void __iomem *regs;
|
|
|
|
+ void __iomem *regptr;
|
|
|
|
+ int err, ch;
|
|
|
|
+
|
|
|
|
+ dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL);
|
|
|
|
+ if (!dmac) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to alloc mem\n", __func__);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dmac->dev.id = chno / 8;
|
|
|
|
+ dmac->dev.bus = &dma_subsys;
|
|
|
|
+
|
|
|
|
+ err = device_register(&dmac->dev);
|
|
|
|
+ if (err) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to register device\n", __func__);
|
|
|
|
+ goto err_alloc;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ regs = ioremap(base, 0x200);
|
|
|
|
+ if (!regs) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to ioremap()\n", __func__);
|
|
|
|
+ err = -ENXIO;
|
|
|
|
+ goto err_dev;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ snprintf(clkname, sizeof(clkname), "dma%d", dmac->dev.id);
|
|
|
|
+
|
|
|
|
+ dmac->clk = clk_get(NULL, clkname);
|
|
|
|
+ if (IS_ERR(dmac->clk)) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname);
|
|
|
|
+ err = PTR_ERR(dmac->clk);
|
|
|
|
+ goto err_map;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clk_enable(dmac->clk);
|
|
|
|
+
|
|
|
|
+ dmac->regs = regs;
|
|
|
|
+ dmac->chanbase = chbase;
|
|
|
|
+ dmac->channels = chptr;
|
|
|
|
+
|
|
|
|
+ err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to get irq\n", __func__);
|
|
|
|
+ goto err_clk;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ regptr = regs + PL080_Cx_BASE(0);
|
|
|
|
+
|
|
|
|
+ for (ch = 0; ch < 8; ch++, chptr++) {
|
|
|
|
+ pr_debug("%s: registering DMA %d (%p)\n",
|
|
|
|
+ __func__, chno + ch, regptr);
|
|
|
|
+
|
|
|
|
+ chptr->bit = 1 << ch;
|
|
|
|
+ chptr->number = chno + ch;
|
|
|
|
+ chptr->dmac = dmac;
|
|
|
|
+ chptr->regs = regptr;
|
|
|
|
+ regptr += PL080_Cx_STRIDE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* for the moment, permanently enable the controller */
|
|
|
|
+ writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
|
|
|
|
+
|
|
|
|
+ printk(KERN_INFO "PL080: IRQ %d, at %p, channels %d..%d\n",
|
|
|
|
+ irq, regs, chno, chno+8);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+err_clk:
|
|
|
|
+ clk_disable(dmac->clk);
|
|
|
|
+ clk_put(dmac->clk);
|
|
|
|
+err_map:
|
|
|
|
+ iounmap(regs);
|
|
|
|
+err_dev:
|
|
|
|
+ device_unregister(&dmac->dev);
|
|
|
|
+err_alloc:
|
|
|
|
+ kfree(dmac);
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int __init s3c64xx_dma_init(void)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ printk(KERN_INFO "%s: Registering DMA channels\n", __func__);
|
|
|
|
+
|
|
|
|
+ dma_pool = dma_pool_create("DMA-LLI", NULL, sizeof(struct pl080s_lli), 16, 0);
|
|
|
|
+ if (!dma_pool) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to create pool\n", __func__);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = subsys_system_register(&dma_subsys, NULL);
|
|
|
|
+ if (ret) {
|
|
|
|
+ printk(KERN_ERR "%s: failed to create subsys\n", __func__);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Set all DMA configuration to be DMA, not SDMA */
|
|
|
|
+ writel(0xffffff, S3C64XX_SDMA_SEL);
|
|
|
|
+
|
|
|
|
+ /* Register standard DMA controllers */
|
|
|
|
+ s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000);
|
|
|
|
+ s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+arch_initcall(s3c64xx_dma_init);
|