Merge branch 'v6v7' into devel
[linux/fpc-iii.git] / arch / arm / plat-samsung / s3c-pl330.c
blobb4ff8d74ac40d21bc0bec763e050385938530252
1 /* linux/arch/arm/plat-samsung/s3c-pl330.c
3 * Copyright (C) 2010 Samsung Electronics Co. Ltd.
4 * Jaswinder Singh <jassi.brar@samsung.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/interrupt.h>
15 #include <linux/io.h>
16 #include <linux/slab.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <linux/err.h>
21 #include <asm/hardware/pl330.h>
23 #include <plat/s3c-pl330-pdata.h>
25 /**
26 * struct s3c_pl330_dmac - Logical representation of a PL330 DMAC.
27 * @busy_chan: Number of channels currently busy.
28 * @peri: List of IDs of peripherals this DMAC can work with.
29 * @node: To attach to the global list of DMACs.
30 * @pi: PL330 configuration info for the DMAC.
31 * @kmcache: Pool to quickly allocate xfers for all channels in the dmac.
32 * @clk: Pointer of DMAC operation clock.
34 struct s3c_pl330_dmac {
35 unsigned busy_chan;
36 enum dma_ch *peri;
37 struct list_head node;
38 struct pl330_info *pi;
39 struct kmem_cache *kmcache;
40 struct clk *clk;
43 /**
44 * struct s3c_pl330_xfer - A request submitted by S3C DMA clients.
45 * @token: Xfer ID provided by the client.
46 * @node: To attach to the list of xfers on a channel.
47 * @px: Xfer for PL330 core.
48 * @chan: Owner channel of this xfer.
50 struct s3c_pl330_xfer {
51 void *token;
52 struct list_head node;
53 struct pl330_xfer px;
54 struct s3c_pl330_chan *chan;
57 /**
58 * struct s3c_pl330_chan - Logical channel to communicate with
59 * a Physical peripheral.
60 * @pl330_chan_id: Token of a hardware channel thread of PL330 DMAC.
61 * NULL if the channel is available to be acquired.
62 * @id: ID of the peripheral that this channel can communicate with.
63 * @options: Options specified by the client.
64 * @sdaddr: Address provided via s3c2410_dma_devconfig.
65 * @node: To attach to the global list of channels.
66 * @lrq: Pointer to the last submitted pl330_req to PL330 core.
67 * @xfer_list: To manage list of xfers enqueued.
68 * @req: Two requests to communicate with the PL330 engine.
69 * @callback_fn: Callback function to the client.
70 * @rqcfg: Channel configuration for the xfers.
71 * @xfer_head: Pointer to the xfer to be next excecuted.
72 * @dmac: Pointer to the DMAC that manages this channel, NULL if the
73 * channel is available to be acquired.
74 * @client: Client of this channel. NULL if the
75 * channel is available to be acquired.
77 struct s3c_pl330_chan {
78 void *pl330_chan_id;
79 enum dma_ch id;
80 unsigned int options;
81 unsigned long sdaddr;
82 struct list_head node;
83 struct pl330_req *lrq;
84 struct list_head xfer_list;
85 struct pl330_req req[2];
86 s3c2410_dma_cbfn_t callback_fn;
87 struct pl330_reqcfg rqcfg;
88 struct s3c_pl330_xfer *xfer_head;
89 struct s3c_pl330_dmac *dmac;
90 struct s3c2410_dma_client *client;
93 /* All DMACs in the platform */
94 static LIST_HEAD(dmac_list);
96 /* All channels to peripherals in the platform */
97 static LIST_HEAD(chan_list);
100 * Since we add resources(DMACs and Channels) to the global pool,
101 * we need to guard access to the resources using a global lock
103 static DEFINE_SPINLOCK(res_lock);
105 /* Returns the channel with ID 'id' in the chan_list */
106 static struct s3c_pl330_chan *id_to_chan(const enum dma_ch id)
108 struct s3c_pl330_chan *ch;
110 list_for_each_entry(ch, &chan_list, node)
111 if (ch->id == id)
112 return ch;
114 return NULL;
117 /* Allocate a new channel with ID 'id' and add to chan_list */
118 static void chan_add(const enum dma_ch id)
120 struct s3c_pl330_chan *ch = id_to_chan(id);
122 /* Return if the channel already exists */
123 if (ch)
124 return;
126 ch = kmalloc(sizeof(*ch), GFP_KERNEL);
127 /* Return silently to work with other channels */
128 if (!ch)
129 return;
131 ch->id = id;
132 ch->dmac = NULL;
134 list_add_tail(&ch->node, &chan_list);
137 /* If the channel is not yet acquired by any client */
138 static bool chan_free(struct s3c_pl330_chan *ch)
140 if (!ch)
141 return false;
143 /* Channel points to some DMAC only when it's acquired */
144 return ch->dmac ? false : true;
148 * Returns 0 is peripheral i/f is invalid or not present on the dmac.
149 * Index + 1, otherwise.
151 static unsigned iface_of_dmac(struct s3c_pl330_dmac *dmac, enum dma_ch ch_id)
153 enum dma_ch *id = dmac->peri;
154 int i;
156 /* Discount invalid markers */
157 if (ch_id == DMACH_MAX)
158 return 0;
160 for (i = 0; i < PL330_MAX_PERI; i++)
161 if (id[i] == ch_id)
162 return i + 1;
164 return 0;
167 /* If all channel threads of the DMAC are busy */
168 static inline bool dmac_busy(struct s3c_pl330_dmac *dmac)
170 struct pl330_info *pi = dmac->pi;
172 return (dmac->busy_chan < pi->pcfg.num_chan) ? false : true;
176 * Returns the number of free channels that
177 * can be handled by this dmac only.
179 static unsigned ch_onlyby_dmac(struct s3c_pl330_dmac *dmac)
181 enum dma_ch *id = dmac->peri;
182 struct s3c_pl330_dmac *d;
183 struct s3c_pl330_chan *ch;
184 unsigned found, count = 0;
185 enum dma_ch p;
186 int i;
188 for (i = 0; i < PL330_MAX_PERI; i++) {
189 p = id[i];
190 ch = id_to_chan(p);
192 if (p == DMACH_MAX || !chan_free(ch))
193 continue;
195 found = 0;
196 list_for_each_entry(d, &dmac_list, node) {
197 if (d != dmac && iface_of_dmac(d, ch->id)) {
198 found = 1;
199 break;
202 if (!found)
203 count++;
206 return count;
210 * Measure of suitability of 'dmac' handling 'ch'
212 * 0 indicates 'dmac' can not handle 'ch' either
213 * because it is not supported by the hardware or
214 * because all dmac channels are currently busy.
216 * >0 vlaue indicates 'dmac' has the capability.
217 * The bigger the value the more suitable the dmac.
219 #define MAX_SUIT UINT_MAX
220 #define MIN_SUIT 0
222 static unsigned suitablility(struct s3c_pl330_dmac *dmac,
223 struct s3c_pl330_chan *ch)
225 struct pl330_info *pi = dmac->pi;
226 enum dma_ch *id = dmac->peri;
227 struct s3c_pl330_dmac *d;
228 unsigned s;
229 int i;
231 s = MIN_SUIT;
232 /* If all the DMAC channel threads are busy */
233 if (dmac_busy(dmac))
234 return s;
236 for (i = 0; i < PL330_MAX_PERI; i++)
237 if (id[i] == ch->id)
238 break;
240 /* If the 'dmac' can't talk to 'ch' */
241 if (i == PL330_MAX_PERI)
242 return s;
244 s = MAX_SUIT;
245 list_for_each_entry(d, &dmac_list, node) {
247 * If some other dmac can talk to this
248 * peri and has some channel free.
250 if (d != dmac && iface_of_dmac(d, ch->id) && !dmac_busy(d)) {
251 s = 0;
252 break;
255 if (s)
256 return s;
258 s = 100;
260 /* Good if free chans are more, bad otherwise */
261 s += (pi->pcfg.num_chan - dmac->busy_chan) - ch_onlyby_dmac(dmac);
263 return s;
266 /* More than one DMAC may have capability to transfer data with the
267 * peripheral. This function assigns most suitable DMAC to manage the
268 * channel and hence communicate with the peripheral.
270 static struct s3c_pl330_dmac *map_chan_to_dmac(struct s3c_pl330_chan *ch)
272 struct s3c_pl330_dmac *d, *dmac = NULL;
273 unsigned sn, sl = MIN_SUIT;
275 list_for_each_entry(d, &dmac_list, node) {
276 sn = suitablility(d, ch);
278 if (sn == MAX_SUIT)
279 return d;
281 if (sn > sl)
282 dmac = d;
285 return dmac;
288 /* Acquire the channel for peripheral 'id' */
289 static struct s3c_pl330_chan *chan_acquire(const enum dma_ch id)
291 struct s3c_pl330_chan *ch = id_to_chan(id);
292 struct s3c_pl330_dmac *dmac;
294 /* If the channel doesn't exist or is already acquired */
295 if (!ch || !chan_free(ch)) {
296 ch = NULL;
297 goto acq_exit;
300 dmac = map_chan_to_dmac(ch);
301 /* If couldn't map */
302 if (!dmac) {
303 ch = NULL;
304 goto acq_exit;
307 dmac->busy_chan++;
308 ch->dmac = dmac;
310 acq_exit:
311 return ch;
314 /* Delete xfer from the queue */
315 static inline void del_from_queue(struct s3c_pl330_xfer *xfer)
317 struct s3c_pl330_xfer *t;
318 struct s3c_pl330_chan *ch;
319 int found;
321 if (!xfer)
322 return;
324 ch = xfer->chan;
326 /* Make sure xfer is in the queue */
327 found = 0;
328 list_for_each_entry(t, &ch->xfer_list, node)
329 if (t == xfer) {
330 found = 1;
331 break;
334 if (!found)
335 return;
337 /* If xfer is last entry in the queue */
338 if (xfer->node.next == &ch->xfer_list)
339 t = list_entry(ch->xfer_list.next,
340 struct s3c_pl330_xfer, node);
341 else
342 t = list_entry(xfer->node.next,
343 struct s3c_pl330_xfer, node);
345 /* If there was only one node left */
346 if (t == xfer)
347 ch->xfer_head = NULL;
348 else if (ch->xfer_head == xfer)
349 ch->xfer_head = t;
351 list_del(&xfer->node);
354 /* Provides pointer to the next xfer in the queue.
355 * If CIRCULAR option is set, the list is left intact,
356 * otherwise the xfer is removed from the list.
357 * Forced delete 'pluck' can be set to override the CIRCULAR option.
359 static struct s3c_pl330_xfer *get_from_queue(struct s3c_pl330_chan *ch,
360 int pluck)
362 struct s3c_pl330_xfer *xfer = ch->xfer_head;
364 if (!xfer)
365 return NULL;
367 /* If xfer is last entry in the queue */
368 if (xfer->node.next == &ch->xfer_list)
369 ch->xfer_head = list_entry(ch->xfer_list.next,
370 struct s3c_pl330_xfer, node);
371 else
372 ch->xfer_head = list_entry(xfer->node.next,
373 struct s3c_pl330_xfer, node);
375 if (pluck || !(ch->options & S3C2410_DMAF_CIRCULAR))
376 del_from_queue(xfer);
378 return xfer;
381 static inline void add_to_queue(struct s3c_pl330_chan *ch,
382 struct s3c_pl330_xfer *xfer, int front)
384 struct pl330_xfer *xt;
386 /* If queue empty */
387 if (ch->xfer_head == NULL)
388 ch->xfer_head = xfer;
390 xt = &ch->xfer_head->px;
391 /* If the head already submitted (CIRCULAR head) */
392 if (ch->options & S3C2410_DMAF_CIRCULAR &&
393 (xt == ch->req[0].x || xt == ch->req[1].x))
394 ch->xfer_head = xfer;
396 /* If this is a resubmission, it should go at the head */
397 if (front) {
398 ch->xfer_head = xfer;
399 list_add(&xfer->node, &ch->xfer_list);
400 } else {
401 list_add_tail(&xfer->node, &ch->xfer_list);
405 static inline void _finish_off(struct s3c_pl330_xfer *xfer,
406 enum s3c2410_dma_buffresult res, int ffree)
408 struct s3c_pl330_chan *ch;
410 if (!xfer)
411 return;
413 ch = xfer->chan;
415 /* Do callback */
416 if (ch->callback_fn)
417 ch->callback_fn(NULL, xfer->token, xfer->px.bytes, res);
419 /* Force Free or if buffer is not needed anymore */
420 if (ffree || !(ch->options & S3C2410_DMAF_CIRCULAR))
421 kmem_cache_free(ch->dmac->kmcache, xfer);
424 static inline int s3c_pl330_submit(struct s3c_pl330_chan *ch,
425 struct pl330_req *r)
427 struct s3c_pl330_xfer *xfer;
428 int ret = 0;
430 /* If already submitted */
431 if (r->x)
432 return 0;
434 xfer = get_from_queue(ch, 0);
435 if (xfer) {
436 r->x = &xfer->px;
438 /* Use max bandwidth for M<->M xfers */
439 if (r->rqtype == MEMTOMEM) {
440 struct pl330_info *pi = xfer->chan->dmac->pi;
441 int burst = 1 << ch->rqcfg.brst_size;
442 u32 bytes = r->x->bytes;
443 int bl;
445 bl = pi->pcfg.data_bus_width / 8;
446 bl *= pi->pcfg.data_buf_dep;
447 bl /= burst;
449 /* src/dst_burst_len can't be more than 16 */
450 if (bl > 16)
451 bl = 16;
453 while (bl > 1) {
454 if (!(bytes % (bl * burst)))
455 break;
456 bl--;
459 ch->rqcfg.brst_len = bl;
460 } else {
461 ch->rqcfg.brst_len = 1;
464 ret = pl330_submit_req(ch->pl330_chan_id, r);
466 /* If submission was successful */
467 if (!ret) {
468 ch->lrq = r; /* latest submitted req */
469 return 0;
472 r->x = NULL;
474 /* If both of the PL330 ping-pong buffers filled */
475 if (ret == -EAGAIN) {
476 dev_err(ch->dmac->pi->dev, "%s:%d!\n",
477 __func__, __LINE__);
478 /* Queue back again */
479 add_to_queue(ch, xfer, 1);
480 ret = 0;
481 } else {
482 dev_err(ch->dmac->pi->dev, "%s:%d!\n",
483 __func__, __LINE__);
484 _finish_off(xfer, S3C2410_RES_ERR, 0);
488 return ret;
491 static void s3c_pl330_rq(struct s3c_pl330_chan *ch,
492 struct pl330_req *r, enum pl330_op_err err)
494 unsigned long flags;
495 struct s3c_pl330_xfer *xfer;
496 struct pl330_xfer *xl = r->x;
497 enum s3c2410_dma_buffresult res;
499 spin_lock_irqsave(&res_lock, flags);
501 r->x = NULL;
503 s3c_pl330_submit(ch, r);
505 spin_unlock_irqrestore(&res_lock, flags);
507 /* Map result to S3C DMA API */
508 if (err == PL330_ERR_NONE)
509 res = S3C2410_RES_OK;
510 else if (err == PL330_ERR_ABORT)
511 res = S3C2410_RES_ABORT;
512 else
513 res = S3C2410_RES_ERR;
515 /* If last request had some xfer */
516 if (xl) {
517 xfer = container_of(xl, struct s3c_pl330_xfer, px);
518 _finish_off(xfer, res, 0);
519 } else {
520 dev_info(ch->dmac->pi->dev, "%s:%d No Xfer?!\n",
521 __func__, __LINE__);
525 static void s3c_pl330_rq0(void *token, enum pl330_op_err err)
527 struct pl330_req *r = token;
528 struct s3c_pl330_chan *ch = container_of(r,
529 struct s3c_pl330_chan, req[0]);
530 s3c_pl330_rq(ch, r, err);
533 static void s3c_pl330_rq1(void *token, enum pl330_op_err err)
535 struct pl330_req *r = token;
536 struct s3c_pl330_chan *ch = container_of(r,
537 struct s3c_pl330_chan, req[1]);
538 s3c_pl330_rq(ch, r, err);
541 /* Release an acquired channel */
542 static void chan_release(struct s3c_pl330_chan *ch)
544 struct s3c_pl330_dmac *dmac;
546 if (chan_free(ch))
547 return;
549 dmac = ch->dmac;
550 ch->dmac = NULL;
551 dmac->busy_chan--;
554 int s3c2410_dma_ctrl(enum dma_ch id, enum s3c2410_chan_op op)
556 struct s3c_pl330_xfer *xfer;
557 enum pl330_chan_op pl330op;
558 struct s3c_pl330_chan *ch;
559 unsigned long flags;
560 int idx, ret;
562 spin_lock_irqsave(&res_lock, flags);
564 ch = id_to_chan(id);
566 if (!ch || chan_free(ch)) {
567 ret = -EINVAL;
568 goto ctrl_exit;
571 switch (op) {
572 case S3C2410_DMAOP_START:
573 /* Make sure both reqs are enqueued */
574 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
575 s3c_pl330_submit(ch, &ch->req[idx]);
576 s3c_pl330_submit(ch, &ch->req[1 - idx]);
577 pl330op = PL330_OP_START;
578 break;
580 case S3C2410_DMAOP_STOP:
581 pl330op = PL330_OP_ABORT;
582 break;
584 case S3C2410_DMAOP_FLUSH:
585 pl330op = PL330_OP_FLUSH;
586 break;
588 case S3C2410_DMAOP_PAUSE:
589 case S3C2410_DMAOP_RESUME:
590 case S3C2410_DMAOP_TIMEOUT:
591 case S3C2410_DMAOP_STARTED:
592 spin_unlock_irqrestore(&res_lock, flags);
593 return 0;
595 default:
596 spin_unlock_irqrestore(&res_lock, flags);
597 return -EINVAL;
600 ret = pl330_chan_ctrl(ch->pl330_chan_id, pl330op);
602 if (pl330op == PL330_OP_START) {
603 spin_unlock_irqrestore(&res_lock, flags);
604 return ret;
607 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
609 /* Abort the current xfer */
610 if (ch->req[idx].x) {
611 xfer = container_of(ch->req[idx].x,
612 struct s3c_pl330_xfer, px);
614 /* Drop xfer during FLUSH */
615 if (pl330op == PL330_OP_FLUSH)
616 del_from_queue(xfer);
618 ch->req[idx].x = NULL;
620 spin_unlock_irqrestore(&res_lock, flags);
621 _finish_off(xfer, S3C2410_RES_ABORT,
622 pl330op == PL330_OP_FLUSH ? 1 : 0);
623 spin_lock_irqsave(&res_lock, flags);
626 /* Flush the whole queue */
627 if (pl330op == PL330_OP_FLUSH) {
629 if (ch->req[1 - idx].x) {
630 xfer = container_of(ch->req[1 - idx].x,
631 struct s3c_pl330_xfer, px);
633 del_from_queue(xfer);
635 ch->req[1 - idx].x = NULL;
637 spin_unlock_irqrestore(&res_lock, flags);
638 _finish_off(xfer, S3C2410_RES_ABORT, 1);
639 spin_lock_irqsave(&res_lock, flags);
642 /* Finish off the remaining in the queue */
643 xfer = ch->xfer_head;
644 while (xfer) {
646 del_from_queue(xfer);
648 spin_unlock_irqrestore(&res_lock, flags);
649 _finish_off(xfer, S3C2410_RES_ABORT, 1);
650 spin_lock_irqsave(&res_lock, flags);
652 xfer = ch->xfer_head;
656 ctrl_exit:
657 spin_unlock_irqrestore(&res_lock, flags);
659 return ret;
661 EXPORT_SYMBOL(s3c2410_dma_ctrl);
663 int s3c2410_dma_enqueue(enum dma_ch id, void *token,
664 dma_addr_t addr, int size)
666 struct s3c_pl330_chan *ch;
667 struct s3c_pl330_xfer *xfer;
668 unsigned long flags;
669 int idx, ret = 0;
671 spin_lock_irqsave(&res_lock, flags);
673 ch = id_to_chan(id);
675 /* Error if invalid or free channel */
676 if (!ch || chan_free(ch)) {
677 ret = -EINVAL;
678 goto enq_exit;
681 /* Error if size is unaligned */
682 if (ch->rqcfg.brst_size && size % (1 << ch->rqcfg.brst_size)) {
683 ret = -EINVAL;
684 goto enq_exit;
687 xfer = kmem_cache_alloc(ch->dmac->kmcache, GFP_ATOMIC);
688 if (!xfer) {
689 ret = -ENOMEM;
690 goto enq_exit;
693 xfer->token = token;
694 xfer->chan = ch;
695 xfer->px.bytes = size;
696 xfer->px.next = NULL; /* Single request */
698 /* For S3C DMA API, direction is always fixed for all xfers */
699 if (ch->req[0].rqtype == MEMTODEV) {
700 xfer->px.src_addr = addr;
701 xfer->px.dst_addr = ch->sdaddr;
702 } else {
703 xfer->px.src_addr = ch->sdaddr;
704 xfer->px.dst_addr = addr;
707 add_to_queue(ch, xfer, 0);
709 /* Try submitting on either request */
710 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
712 if (!ch->req[idx].x)
713 s3c_pl330_submit(ch, &ch->req[idx]);
714 else
715 s3c_pl330_submit(ch, &ch->req[1 - idx]);
717 spin_unlock_irqrestore(&res_lock, flags);
719 if (ch->options & S3C2410_DMAF_AUTOSTART)
720 s3c2410_dma_ctrl(id, S3C2410_DMAOP_START);
722 return 0;
724 enq_exit:
725 spin_unlock_irqrestore(&res_lock, flags);
727 return ret;
729 EXPORT_SYMBOL(s3c2410_dma_enqueue);
731 int s3c2410_dma_request(enum dma_ch id,
732 struct s3c2410_dma_client *client,
733 void *dev)
735 struct s3c_pl330_dmac *dmac;
736 struct s3c_pl330_chan *ch;
737 unsigned long flags;
738 int ret = 0;
740 spin_lock_irqsave(&res_lock, flags);
742 ch = chan_acquire(id);
743 if (!ch) {
744 ret = -EBUSY;
745 goto req_exit;
748 dmac = ch->dmac;
750 ch->pl330_chan_id = pl330_request_channel(dmac->pi);
751 if (!ch->pl330_chan_id) {
752 chan_release(ch);
753 ret = -EBUSY;
754 goto req_exit;
757 ch->client = client;
758 ch->options = 0; /* Clear any option */
759 ch->callback_fn = NULL; /* Clear any callback */
760 ch->lrq = NULL;
762 ch->rqcfg.brst_size = 2; /* Default word size */
763 ch->rqcfg.swap = SWAP_NO;
764 ch->rqcfg.scctl = SCCTRL0; /* Noncacheable and nonbufferable */
765 ch->rqcfg.dcctl = DCCTRL0; /* Noncacheable and nonbufferable */
766 ch->rqcfg.privileged = 0;
767 ch->rqcfg.insnaccess = 0;
769 /* Set invalid direction */
770 ch->req[0].rqtype = DEVTODEV;
771 ch->req[1].rqtype = ch->req[0].rqtype;
773 ch->req[0].cfg = &ch->rqcfg;
774 ch->req[1].cfg = ch->req[0].cfg;
776 ch->req[0].peri = iface_of_dmac(dmac, id) - 1; /* Original index */
777 ch->req[1].peri = ch->req[0].peri;
779 ch->req[0].token = &ch->req[0];
780 ch->req[0].xfer_cb = s3c_pl330_rq0;
781 ch->req[1].token = &ch->req[1];
782 ch->req[1].xfer_cb = s3c_pl330_rq1;
784 ch->req[0].x = NULL;
785 ch->req[1].x = NULL;
787 /* Reset xfer list */
788 INIT_LIST_HEAD(&ch->xfer_list);
789 ch->xfer_head = NULL;
791 req_exit:
792 spin_unlock_irqrestore(&res_lock, flags);
794 return ret;
796 EXPORT_SYMBOL(s3c2410_dma_request);
798 int s3c2410_dma_free(enum dma_ch id, struct s3c2410_dma_client *client)
800 struct s3c_pl330_chan *ch;
801 struct s3c_pl330_xfer *xfer;
802 unsigned long flags;
803 int ret = 0;
804 unsigned idx;
806 spin_lock_irqsave(&res_lock, flags);
808 ch = id_to_chan(id);
810 if (!ch || chan_free(ch))
811 goto free_exit;
813 /* Refuse if someone else wanted to free the channel */
814 if (ch->client != client) {
815 ret = -EBUSY;
816 goto free_exit;
819 /* Stop any active xfer, Flushe the queue and do callbacks */
820 pl330_chan_ctrl(ch->pl330_chan_id, PL330_OP_FLUSH);
822 /* Abort the submitted requests */
823 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
825 if (ch->req[idx].x) {
826 xfer = container_of(ch->req[idx].x,
827 struct s3c_pl330_xfer, px);
829 ch->req[idx].x = NULL;
830 del_from_queue(xfer);
832 spin_unlock_irqrestore(&res_lock, flags);
833 _finish_off(xfer, S3C2410_RES_ABORT, 1);
834 spin_lock_irqsave(&res_lock, flags);
837 if (ch->req[1 - idx].x) {
838 xfer = container_of(ch->req[1 - idx].x,
839 struct s3c_pl330_xfer, px);
841 ch->req[1 - idx].x = NULL;
842 del_from_queue(xfer);
844 spin_unlock_irqrestore(&res_lock, flags);
845 _finish_off(xfer, S3C2410_RES_ABORT, 1);
846 spin_lock_irqsave(&res_lock, flags);
849 /* Pluck and Abort the queued requests in order */
850 do {
851 xfer = get_from_queue(ch, 1);
853 spin_unlock_irqrestore(&res_lock, flags);
854 _finish_off(xfer, S3C2410_RES_ABORT, 1);
855 spin_lock_irqsave(&res_lock, flags);
856 } while (xfer);
858 ch->client = NULL;
860 pl330_release_channel(ch->pl330_chan_id);
862 ch->pl330_chan_id = NULL;
864 chan_release(ch);
866 free_exit:
867 spin_unlock_irqrestore(&res_lock, flags);
869 return ret;
871 EXPORT_SYMBOL(s3c2410_dma_free);
873 int s3c2410_dma_config(enum dma_ch id, int xferunit)
875 struct s3c_pl330_chan *ch;
876 struct pl330_info *pi;
877 unsigned long flags;
878 int i, dbwidth, ret = 0;
880 spin_lock_irqsave(&res_lock, flags);
882 ch = id_to_chan(id);
884 if (!ch || chan_free(ch)) {
885 ret = -EINVAL;
886 goto cfg_exit;
889 pi = ch->dmac->pi;
890 dbwidth = pi->pcfg.data_bus_width / 8;
892 /* Max size of xfer can be pcfg.data_bus_width */
893 if (xferunit > dbwidth) {
894 ret = -EINVAL;
895 goto cfg_exit;
898 i = 0;
899 while (xferunit != (1 << i))
900 i++;
902 /* If valid value */
903 if (xferunit == (1 << i))
904 ch->rqcfg.brst_size = i;
905 else
906 ret = -EINVAL;
908 cfg_exit:
909 spin_unlock_irqrestore(&res_lock, flags);
911 return ret;
913 EXPORT_SYMBOL(s3c2410_dma_config);
915 /* Options that are supported by this driver */
916 #define S3C_PL330_FLAGS (S3C2410_DMAF_CIRCULAR | S3C2410_DMAF_AUTOSTART)
918 int s3c2410_dma_setflags(enum dma_ch id, unsigned int options)
920 struct s3c_pl330_chan *ch;
921 unsigned long flags;
922 int ret = 0;
924 spin_lock_irqsave(&res_lock, flags);
926 ch = id_to_chan(id);
928 if (!ch || chan_free(ch) || options & ~(S3C_PL330_FLAGS))
929 ret = -EINVAL;
930 else
931 ch->options = options;
933 spin_unlock_irqrestore(&res_lock, flags);
935 return 0;
937 EXPORT_SYMBOL(s3c2410_dma_setflags);
939 int s3c2410_dma_set_buffdone_fn(enum dma_ch id, s3c2410_dma_cbfn_t rtn)
941 struct s3c_pl330_chan *ch;
942 unsigned long flags;
943 int ret = 0;
945 spin_lock_irqsave(&res_lock, flags);
947 ch = id_to_chan(id);
949 if (!ch || chan_free(ch))
950 ret = -EINVAL;
951 else
952 ch->callback_fn = rtn;
954 spin_unlock_irqrestore(&res_lock, flags);
956 return ret;
958 EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
960 int s3c2410_dma_devconfig(enum dma_ch id, enum s3c2410_dmasrc source,
961 unsigned long address)
963 struct s3c_pl330_chan *ch;
964 unsigned long flags;
965 int ret = 0;
967 spin_lock_irqsave(&res_lock, flags);
969 ch = id_to_chan(id);
971 if (!ch || chan_free(ch)) {
972 ret = -EINVAL;
973 goto devcfg_exit;
976 switch (source) {
977 case S3C2410_DMASRC_HW: /* P->M */
978 ch->req[0].rqtype = DEVTOMEM;
979 ch->req[1].rqtype = DEVTOMEM;
980 ch->rqcfg.src_inc = 0;
981 ch->rqcfg.dst_inc = 1;
982 break;
983 case S3C2410_DMASRC_MEM: /* M->P */
984 ch->req[0].rqtype = MEMTODEV;
985 ch->req[1].rqtype = MEMTODEV;
986 ch->rqcfg.src_inc = 1;
987 ch->rqcfg.dst_inc = 0;
988 break;
989 default:
990 ret = -EINVAL;
991 goto devcfg_exit;
994 ch->sdaddr = address;
996 devcfg_exit:
997 spin_unlock_irqrestore(&res_lock, flags);
999 return ret;
1001 EXPORT_SYMBOL(s3c2410_dma_devconfig);
1003 int s3c2410_dma_getposition(enum dma_ch id, dma_addr_t *src, dma_addr_t *dst)
1005 struct s3c_pl330_chan *ch = id_to_chan(id);
1006 struct pl330_chanstatus status;
1007 int ret;
1009 if (!ch || chan_free(ch))
1010 return -EINVAL;
1012 ret = pl330_chan_status(ch->pl330_chan_id, &status);
1013 if (ret < 0)
1014 return ret;
1016 *src = status.src_addr;
1017 *dst = status.dst_addr;
1019 return 0;
1021 EXPORT_SYMBOL(s3c2410_dma_getposition);
1023 static irqreturn_t pl330_irq_handler(int irq, void *data)
1025 if (pl330_update(data))
1026 return IRQ_HANDLED;
1027 else
1028 return IRQ_NONE;
1031 static int pl330_probe(struct platform_device *pdev)
1033 struct s3c_pl330_dmac *s3c_pl330_dmac;
1034 struct s3c_pl330_platdata *pl330pd;
1035 struct pl330_info *pl330_info;
1036 struct resource *res;
1037 int i, ret, irq;
1039 pl330pd = pdev->dev.platform_data;
1041 /* Can't do without the list of _32_ peripherals */
1042 if (!pl330pd || !pl330pd->peri) {
1043 dev_err(&pdev->dev, "platform data missing!\n");
1044 return -ENODEV;
1047 pl330_info = kzalloc(sizeof(*pl330_info), GFP_KERNEL);
1048 if (!pl330_info)
1049 return -ENOMEM;
1051 pl330_info->pl330_data = NULL;
1052 pl330_info->dev = &pdev->dev;
1054 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1055 if (!res) {
1056 ret = -ENODEV;
1057 goto probe_err1;
1060 request_mem_region(res->start, resource_size(res), pdev->name);
1062 pl330_info->base = ioremap(res->start, resource_size(res));
1063 if (!pl330_info->base) {
1064 ret = -ENXIO;
1065 goto probe_err2;
1068 irq = platform_get_irq(pdev, 0);
1069 if (irq < 0) {
1070 ret = irq;
1071 goto probe_err3;
1074 ret = request_irq(irq, pl330_irq_handler, 0,
1075 dev_name(&pdev->dev), pl330_info);
1076 if (ret)
1077 goto probe_err4;
1079 /* Allocate a new DMAC */
1080 s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL);
1081 if (!s3c_pl330_dmac) {
1082 ret = -ENOMEM;
1083 goto probe_err5;
1086 /* Get operation clock and enable it */
1087 s3c_pl330_dmac->clk = clk_get(&pdev->dev, "pdma");
1088 if (IS_ERR(s3c_pl330_dmac->clk)) {
1089 dev_err(&pdev->dev, "Cannot get operation clock.\n");
1090 ret = -EINVAL;
1091 goto probe_err6;
1093 clk_enable(s3c_pl330_dmac->clk);
1095 ret = pl330_add(pl330_info);
1096 if (ret)
1097 goto probe_err7;
1099 /* Hook the info */
1100 s3c_pl330_dmac->pi = pl330_info;
1102 /* No busy channels */
1103 s3c_pl330_dmac->busy_chan = 0;
1105 s3c_pl330_dmac->kmcache = kmem_cache_create(dev_name(&pdev->dev),
1106 sizeof(struct s3c_pl330_xfer), 0, 0, NULL);
1108 if (!s3c_pl330_dmac->kmcache) {
1109 ret = -ENOMEM;
1110 goto probe_err8;
1113 /* Get the list of peripherals */
1114 s3c_pl330_dmac->peri = pl330pd->peri;
1116 /* Attach to the list of DMACs */
1117 list_add_tail(&s3c_pl330_dmac->node, &dmac_list);
1119 /* Create a channel for each peripheral in the DMAC
1120 * that is, if it doesn't already exist
1122 for (i = 0; i < PL330_MAX_PERI; i++)
1123 if (s3c_pl330_dmac->peri[i] != DMACH_MAX)
1124 chan_add(s3c_pl330_dmac->peri[i]);
1126 printk(KERN_INFO
1127 "Loaded driver for PL330 DMAC-%d %s\n", pdev->id, pdev->name);
1128 printk(KERN_INFO
1129 "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
1130 pl330_info->pcfg.data_buf_dep,
1131 pl330_info->pcfg.data_bus_width / 8, pl330_info->pcfg.num_chan,
1132 pl330_info->pcfg.num_peri, pl330_info->pcfg.num_events);
1134 return 0;
1136 probe_err8:
1137 pl330_del(pl330_info);
1138 probe_err7:
1139 clk_disable(s3c_pl330_dmac->clk);
1140 clk_put(s3c_pl330_dmac->clk);
1141 probe_err6:
1142 kfree(s3c_pl330_dmac);
1143 probe_err5:
1144 free_irq(irq, pl330_info);
1145 probe_err4:
1146 probe_err3:
1147 iounmap(pl330_info->base);
1148 probe_err2:
1149 release_mem_region(res->start, resource_size(res));
1150 probe_err1:
1151 kfree(pl330_info);
1153 return ret;
1156 static int pl330_remove(struct platform_device *pdev)
1158 struct s3c_pl330_dmac *dmac, *d;
1159 struct s3c_pl330_chan *ch;
1160 unsigned long flags;
1161 int del, found;
1163 if (!pdev->dev.platform_data)
1164 return -EINVAL;
1166 spin_lock_irqsave(&res_lock, flags);
1168 found = 0;
1169 list_for_each_entry(d, &dmac_list, node)
1170 if (d->pi->dev == &pdev->dev) {
1171 found = 1;
1172 break;
1175 if (!found) {
1176 spin_unlock_irqrestore(&res_lock, flags);
1177 return 0;
1180 dmac = d;
1182 /* Remove all Channels that are managed only by this DMAC */
1183 list_for_each_entry(ch, &chan_list, node) {
1185 /* Only channels that are handled by this DMAC */
1186 if (iface_of_dmac(dmac, ch->id))
1187 del = 1;
1188 else
1189 continue;
1191 /* Don't remove if some other DMAC has it too */
1192 list_for_each_entry(d, &dmac_list, node)
1193 if (d != dmac && iface_of_dmac(d, ch->id)) {
1194 del = 0;
1195 break;
1198 if (del) {
1199 spin_unlock_irqrestore(&res_lock, flags);
1200 s3c2410_dma_free(ch->id, ch->client);
1201 spin_lock_irqsave(&res_lock, flags);
1202 list_del(&ch->node);
1203 kfree(ch);
1207 /* Disable operation clock */
1208 clk_disable(dmac->clk);
1209 clk_put(dmac->clk);
1211 /* Remove the DMAC */
1212 list_del(&dmac->node);
1213 kfree(dmac);
1215 spin_unlock_irqrestore(&res_lock, flags);
1217 return 0;
1220 static struct platform_driver pl330_driver = {
1221 .driver = {
1222 .owner = THIS_MODULE,
1223 .name = "s3c-pl330",
1225 .probe = pl330_probe,
1226 .remove = pl330_remove,
1229 static int __init pl330_init(void)
1231 return platform_driver_register(&pl330_driver);
1233 module_init(pl330_init);
1235 static void __exit pl330_exit(void)
1237 platform_driver_unregister(&pl330_driver);
1238 return;
1240 module_exit(pl330_exit);
1242 MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
1243 MODULE_DESCRIPTION("Driver for PL330 DMA Controller");
1244 MODULE_LICENSE("GPL");