diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 17:28:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 17:28:38 -0500 |
commit | dfc1ebe76663d582a01c9dc572395cf8086d01de (patch) | |
tree | 54a5ac91214a90f82c27b6e38099a4470837729e /drivers/dma | |
parent | acc952c1f373bf3f66cc7a10680eee1762bed40b (diff) | |
parent | b001befe58691ef3627458cd814e8cee7f845c5f (diff) |
Merge tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Device tree conversions for samsung and tegra
Both platforms had some initial device tree support, but this adds
much more to actually make it usable.
* tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (45 commits)
ARM: dts: Add intial dts file for EXYNOS4210 SoC, SMDKV310 and ORIGEN
ARM: EXYNOS: Add Exynos4 device tree enabled board file
rtc: rtc-s3c: Add device tree support
input: samsung-keypad: Add device tree support
ARM: S5PV210: Modify platform data for pl330 driver
ARM: S5PC100: Modify platform data for pl330 driver
ARM: S5P64x0: Modify platform data for pl330 driver
ARM: EXYNOS: Add a alias for pdma clocks
ARM: EXYNOS: Limit usage of pl330 device instance to non-dt build
ARM: SAMSUNG: Add device tree support for pl330 dma engine wrappers
DMA: PL330: Add device tree support
ARM: EXYNOS: Modify platform data for pl330 driver
DMA: PL330: Infer transfer direction from transfer request instead of platform data
DMA: PL330: move filter function into driver
serial: samsung: Fix build for non-Exynos4210 devices
serial: samsung: add device tree support
serial: samsung: merge probe() function from all SoC specific extensions
serial: samsung: merge all SoC specific port reset functions
ARM: SAMSUNG: register uart clocks to clock lookup list
serial: samsung: remove all uses of get_clksrc and set_clksrc
...
Fix up fairly trivial conflicts in arch/arm/mach-s3c2440/clock.c and
drivers/tty/serial/Kconfig both due to just adding code close to
changes.
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/pl330.c | 99 |
1 files changed, 53 insertions, 46 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 2d8d1b041d95..09adcfcd953e 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/amba/pl330.h> | 19 | #include <linux/amba/pl330.h> |
20 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
21 | #include <linux/scatterlist.h> | 21 | #include <linux/scatterlist.h> |
22 | #include <linux/of.h> | ||
22 | 23 | ||
23 | #define NR_DEFAULT_DESC 16 | 24 | #define NR_DEFAULT_DESC 16 |
24 | 25 | ||
@@ -116,6 +117,9 @@ struct dma_pl330_desc { | |||
116 | struct dma_pl330_chan *pchan; | 117 | struct dma_pl330_chan *pchan; |
117 | }; | 118 | }; |
118 | 119 | ||
120 | /* forward declaration */ | ||
121 | static struct amba_driver pl330_driver; | ||
122 | |||
119 | static inline struct dma_pl330_chan * | 123 | static inline struct dma_pl330_chan * |
120 | to_pchan(struct dma_chan *ch) | 124 | to_pchan(struct dma_chan *ch) |
121 | { | 125 | { |
@@ -267,6 +271,32 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err) | |||
267 | tasklet_schedule(&pch->task); | 271 | tasklet_schedule(&pch->task); |
268 | } | 272 | } |
269 | 273 | ||
274 | bool pl330_filter(struct dma_chan *chan, void *param) | ||
275 | { | ||
276 | u8 *peri_id; | ||
277 | |||
278 | if (chan->device->dev->driver != &pl330_driver.drv) | ||
279 | return false; | ||
280 | |||
281 | #ifdef CONFIG_OF | ||
282 | if (chan->device->dev->of_node) { | ||
283 | const __be32 *prop_value; | ||
284 | phandle phandle; | ||
285 | struct device_node *node; | ||
286 | |||
287 | prop_value = ((struct property *)param)->value; | ||
288 | phandle = be32_to_cpup(prop_value++); | ||
289 | node = of_find_node_by_phandle(phandle); | ||
290 | return ((chan->private == node) && | ||
291 | (chan->chan_id == be32_to_cpup(prop_value))); | ||
292 | } | ||
293 | #endif | ||
294 | |||
295 | peri_id = chan->private; | ||
296 | return *peri_id == (unsigned)param; | ||
297 | } | ||
298 | EXPORT_SYMBOL(pl330_filter); | ||
299 | |||
270 | static int pl330_alloc_chan_resources(struct dma_chan *chan) | 300 | static int pl330_alloc_chan_resources(struct dma_chan *chan) |
271 | { | 301 | { |
272 | struct dma_pl330_chan *pch = to_pchan(chan); | 302 | struct dma_pl330_chan *pch = to_pchan(chan); |
@@ -497,7 +527,7 @@ pluck_desc(struct dma_pl330_dmac *pdmac) | |||
497 | static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) | 527 | static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) |
498 | { | 528 | { |
499 | struct dma_pl330_dmac *pdmac = pch->dmac; | 529 | struct dma_pl330_dmac *pdmac = pch->dmac; |
500 | struct dma_pl330_peri *peri = pch->chan.private; | 530 | u8 *peri_id = pch->chan.private; |
501 | struct dma_pl330_desc *desc; | 531 | struct dma_pl330_desc *desc; |
502 | 532 | ||
503 | /* Pluck one desc from the pool of DMAC */ | 533 | /* Pluck one desc from the pool of DMAC */ |
@@ -522,13 +552,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) | |||
522 | desc->txd.cookie = 0; | 552 | desc->txd.cookie = 0; |
523 | async_tx_ack(&desc->txd); | 553 | async_tx_ack(&desc->txd); |
524 | 554 | ||
525 | if (peri) { | 555 | desc->req.peri = peri_id ? pch->chan.chan_id : 0; |
526 | desc->req.rqtype = peri->rqtype; | ||
527 | desc->req.peri = pch->chan.chan_id; | ||
528 | } else { | ||
529 | desc->req.rqtype = MEMTOMEM; | ||
530 | desc->req.peri = 0; | ||
531 | } | ||
532 | 556 | ||
533 | dma_async_tx_descriptor_init(&desc->txd, &pch->chan); | 557 | dma_async_tx_descriptor_init(&desc->txd, &pch->chan); |
534 | 558 | ||
@@ -615,12 +639,14 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( | |||
615 | case DMA_TO_DEVICE: | 639 | case DMA_TO_DEVICE: |
616 | desc->rqcfg.src_inc = 1; | 640 | desc->rqcfg.src_inc = 1; |
617 | desc->rqcfg.dst_inc = 0; | 641 | desc->rqcfg.dst_inc = 0; |
642 | desc->req.rqtype = MEMTODEV; | ||
618 | src = dma_addr; | 643 | src = dma_addr; |
619 | dst = pch->fifo_addr; | 644 | dst = pch->fifo_addr; |
620 | break; | 645 | break; |
621 | case DMA_FROM_DEVICE: | 646 | case DMA_FROM_DEVICE: |
622 | desc->rqcfg.src_inc = 0; | 647 | desc->rqcfg.src_inc = 0; |
623 | desc->rqcfg.dst_inc = 1; | 648 | desc->rqcfg.dst_inc = 1; |
649 | desc->req.rqtype = DEVTOMEM; | ||
624 | src = pch->fifo_addr; | 650 | src = pch->fifo_addr; |
625 | dst = dma_addr; | 651 | dst = dma_addr; |
626 | break; | 652 | break; |
@@ -646,16 +672,12 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, | |||
646 | { | 672 | { |
647 | struct dma_pl330_desc *desc; | 673 | struct dma_pl330_desc *desc; |
648 | struct dma_pl330_chan *pch = to_pchan(chan); | 674 | struct dma_pl330_chan *pch = to_pchan(chan); |
649 | struct dma_pl330_peri *peri = chan->private; | ||
650 | struct pl330_info *pi; | 675 | struct pl330_info *pi; |
651 | int burst; | 676 | int burst; |
652 | 677 | ||
653 | if (unlikely(!pch || !len)) | 678 | if (unlikely(!pch || !len)) |
654 | return NULL; | 679 | return NULL; |
655 | 680 | ||
656 | if (peri && peri->rqtype != MEMTOMEM) | ||
657 | return NULL; | ||
658 | |||
659 | pi = &pch->dmac->pif; | 681 | pi = &pch->dmac->pif; |
660 | 682 | ||
661 | desc = __pl330_prep_dma_memcpy(pch, dst, src, len); | 683 | desc = __pl330_prep_dma_memcpy(pch, dst, src, len); |
@@ -664,6 +686,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, | |||
664 | 686 | ||
665 | desc->rqcfg.src_inc = 1; | 687 | desc->rqcfg.src_inc = 1; |
666 | desc->rqcfg.dst_inc = 1; | 688 | desc->rqcfg.dst_inc = 1; |
689 | desc->req.rqtype = MEMTOMEM; | ||
667 | 690 | ||
668 | /* Select max possible burst size */ | 691 | /* Select max possible burst size */ |
669 | burst = pi->pcfg.data_bus_width / 8; | 692 | burst = pi->pcfg.data_bus_width / 8; |
@@ -692,25 +715,14 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
692 | { | 715 | { |
693 | struct dma_pl330_desc *first, *desc = NULL; | 716 | struct dma_pl330_desc *first, *desc = NULL; |
694 | struct dma_pl330_chan *pch = to_pchan(chan); | 717 | struct dma_pl330_chan *pch = to_pchan(chan); |
695 | struct dma_pl330_peri *peri = chan->private; | ||
696 | struct scatterlist *sg; | 718 | struct scatterlist *sg; |
697 | unsigned long flags; | 719 | unsigned long flags; |
698 | int i; | 720 | int i; |
699 | dma_addr_t addr; | 721 | dma_addr_t addr; |
700 | 722 | ||
701 | if (unlikely(!pch || !sgl || !sg_len || !peri)) | 723 | if (unlikely(!pch || !sgl || !sg_len)) |
702 | return NULL; | 724 | return NULL; |
703 | 725 | ||
704 | /* Make sure the direction is consistent */ | ||
705 | if ((direction == DMA_TO_DEVICE && | ||
706 | peri->rqtype != MEMTODEV) || | ||
707 | (direction == DMA_FROM_DEVICE && | ||
708 | peri->rqtype != DEVTOMEM)) { | ||
709 | dev_err(pch->dmac->pif.dev, "%s:%d Invalid Direction\n", | ||
710 | __func__, __LINE__); | ||
711 | return NULL; | ||
712 | } | ||
713 | |||
714 | addr = pch->fifo_addr; | 726 | addr = pch->fifo_addr; |
715 | 727 | ||
716 | first = NULL; | 728 | first = NULL; |
@@ -750,11 +762,13 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
750 | if (direction == DMA_TO_DEVICE) { | 762 | if (direction == DMA_TO_DEVICE) { |
751 | desc->rqcfg.src_inc = 1; | 763 | desc->rqcfg.src_inc = 1; |
752 | desc->rqcfg.dst_inc = 0; | 764 | desc->rqcfg.dst_inc = 0; |
765 | desc->req.rqtype = MEMTODEV; | ||
753 | fill_px(&desc->px, | 766 | fill_px(&desc->px, |
754 | addr, sg_dma_address(sg), sg_dma_len(sg)); | 767 | addr, sg_dma_address(sg), sg_dma_len(sg)); |
755 | } else { | 768 | } else { |
756 | desc->rqcfg.src_inc = 0; | 769 | desc->rqcfg.src_inc = 0; |
757 | desc->rqcfg.dst_inc = 1; | 770 | desc->rqcfg.dst_inc = 1; |
771 | desc->req.rqtype = DEVTOMEM; | ||
758 | fill_px(&desc->px, | 772 | fill_px(&desc->px, |
759 | sg_dma_address(sg), addr, sg_dma_len(sg)); | 773 | sg_dma_address(sg), addr, sg_dma_len(sg)); |
760 | } | 774 | } |
@@ -856,32 +870,16 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
856 | INIT_LIST_HEAD(&pd->channels); | 870 | INIT_LIST_HEAD(&pd->channels); |
857 | 871 | ||
858 | /* Initialize channel parameters */ | 872 | /* Initialize channel parameters */ |
859 | num_chan = max(pdat ? pdat->nr_valid_peri : 0, (u8)pi->pcfg.num_chan); | 873 | num_chan = max(pdat ? pdat->nr_valid_peri : (u8)pi->pcfg.num_peri, |
874 | (u8)pi->pcfg.num_chan); | ||
860 | pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); | 875 | pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); |
861 | 876 | ||
862 | for (i = 0; i < num_chan; i++) { | 877 | for (i = 0; i < num_chan; i++) { |
863 | pch = &pdmac->peripherals[i]; | 878 | pch = &pdmac->peripherals[i]; |
864 | if (pdat) { | 879 | if (!adev->dev.of_node) |
865 | struct dma_pl330_peri *peri = &pdat->peri[i]; | 880 | pch->chan.private = pdat ? &pdat->peri_id[i] : NULL; |
866 | 881 | else | |
867 | switch (peri->rqtype) { | 882 | pch->chan.private = adev->dev.of_node; |
868 | case MEMTOMEM: | ||
869 | dma_cap_set(DMA_MEMCPY, pd->cap_mask); | ||
870 | break; | ||
871 | case MEMTODEV: | ||
872 | case DEVTOMEM: | ||
873 | dma_cap_set(DMA_SLAVE, pd->cap_mask); | ||
874 | dma_cap_set(DMA_CYCLIC, pd->cap_mask); | ||
875 | break; | ||
876 | default: | ||
877 | dev_err(&adev->dev, "DEVTODEV Not Supported\n"); | ||
878 | continue; | ||
879 | } | ||
880 | pch->chan.private = peri; | ||
881 | } else { | ||
882 | dma_cap_set(DMA_MEMCPY, pd->cap_mask); | ||
883 | pch->chan.private = NULL; | ||
884 | } | ||
885 | 883 | ||
886 | INIT_LIST_HEAD(&pch->work_list); | 884 | INIT_LIST_HEAD(&pch->work_list); |
887 | spin_lock_init(&pch->lock); | 885 | spin_lock_init(&pch->lock); |
@@ -894,6 +892,15 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
894 | } | 892 | } |
895 | 893 | ||
896 | pd->dev = &adev->dev; | 894 | pd->dev = &adev->dev; |
895 | if (pdat) { | ||
896 | pd->cap_mask = pdat->cap_mask; | ||
897 | } else { | ||
898 | dma_cap_set(DMA_MEMCPY, pd->cap_mask); | ||
899 | if (pi->pcfg.num_peri) { | ||
900 | dma_cap_set(DMA_SLAVE, pd->cap_mask); | ||
901 | dma_cap_set(DMA_CYCLIC, pd->cap_mask); | ||
902 | } | ||
903 | } | ||
897 | 904 | ||
898 | pd->device_alloc_chan_resources = pl330_alloc_chan_resources; | 905 | pd->device_alloc_chan_resources = pl330_alloc_chan_resources; |
899 | pd->device_free_chan_resources = pl330_free_chan_resources; | 906 | pd->device_free_chan_resources = pl330_free_chan_resources; |