diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2014-12-25 12:49:12 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2015-04-01 11:21:39 -0400 |
commit | 1ada656f67b0ada37309199997b9e4da9411ef7c (patch) | |
tree | 92a2737a503a93c61437771933be102c00d6966e /arch/mips/bmips | |
parent | 9c24ce29b2b8c60d4bcca90c0a4da54b28f0b4e7 (diff) |
MIPS: BMIPS: Rewrite DMA code to use "dma-ranges" property
This is a more standardized way of handling DMA remapping, and it is
suitable for the memory map found on BCM3384.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: jaedon.shin@gmail.com
Cc: abrestic@chromium.org
Cc: tglx@linutronix.de
Cc: jason@lakedaemon.net
Cc: jogo@openwrt.org
Cc: arnd@arndb.de
Cc: computersforpeace@gmail.com
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8850/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/bmips')
-rw-r--r-- | arch/mips/bmips/dma.c | 100 |
1 files changed, 68 insertions, 32 deletions
diff --git a/arch/mips/bmips/dma.c b/arch/mips/bmips/dma.c index ea42012fd4f5..04790f4e1805 100644 --- a/arch/mips/bmips/dma.c +++ b/arch/mips/bmips/dma.c | |||
@@ -6,76 +6,112 @@ | |||
6 | * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com> | 6 | * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define pr_fmt(fmt) "bmips-dma: " fmt | ||
10 | |||
9 | #include <linux/device.h> | 11 | #include <linux/device.h> |
10 | #include <linux/dma-direction.h> | 12 | #include <linux/dma-direction.h> |
11 | #include <linux/dma-mapping.h> | 13 | #include <linux/dma-mapping.h> |
12 | #include <linux/init.h> | 14 | #include <linux/init.h> |
13 | #include <linux/mm.h> | 15 | #include <linux/io.h> |
14 | #include <linux/of.h> | 16 | #include <linux/of.h> |
15 | #include <linux/pci.h> | 17 | #include <linux/printk.h> |
18 | #include <linux/slab.h> | ||
16 | #include <linux/types.h> | 19 | #include <linux/types.h> |
17 | #include <dma-coherence.h> | 20 | #include <dma-coherence.h> |
18 | 21 | ||
19 | /* | 22 | /* |
20 | * BCM3384 has configurable address translation windows which allow the | 23 | * BCM338x has configurable address translation windows which allow the |
21 | * peripherals' DMA addresses to be different from the Zephyr-visible | 24 | * peripherals' DMA addresses to be different from the Zephyr-visible |
22 | * physical addresses. e.g. usb_dma_addr = zephyr_pa ^ 0x08000000 | 25 | * physical addresses. e.g. usb_dma_addr = zephyr_pa ^ 0x08000000 |
23 | * | 26 | * |
24 | * If our DT "memory" node has a "dma-xor-mask" property we will enable this | 27 | * If the "brcm,ubus" node has a "dma-ranges" property we will enable this |
25 | * translation using the provided offset. | 28 | * translation globally using the provided information. This implements a |
29 | * very limited subset of "dma-ranges" support and it will probably be | ||
30 | * replaced by a more generic version later. | ||
26 | */ | 31 | */ |
27 | static u32 bcm3384_dma_xor_mask; | ||
28 | static u32 bcm3384_dma_xor_limit = 0xffffffff; | ||
29 | 32 | ||
30 | /* | 33 | struct bmips_dma_range { |
31 | * PCI collapses the memory hole at 0x10000000 - 0x1fffffff. | 34 | u32 child_addr; |
32 | * On systems with a dma-xor-mask, this range is guaranteed to live above | 35 | u32 parent_addr; |
33 | * the dma-xor-limit. | 36 | u32 size; |
34 | */ | 37 | }; |
35 | #define BCM3384_MEM_HOLE_PA 0x10000000 | ||
36 | #define BCM3384_MEM_HOLE_SIZE 0x10000000 | ||
37 | 38 | ||
38 | static dma_addr_t bcm3384_phys_to_dma(struct device *dev, phys_addr_t pa) | 39 | static struct bmips_dma_range *bmips_dma_ranges; |
40 | |||
41 | #define FLUSH_RAC 0x100 | ||
42 | |||
43 | static dma_addr_t bmips_phys_to_dma(struct device *dev, phys_addr_t pa) | ||
39 | { | 44 | { |
40 | if (dev && dev_is_pci(dev) && | 45 | struct bmips_dma_range *r; |
41 | pa >= (BCM3384_MEM_HOLE_PA + BCM3384_MEM_HOLE_SIZE)) | 46 | |
42 | return pa - BCM3384_MEM_HOLE_SIZE; | 47 | for (r = bmips_dma_ranges; r && r->size; r++) { |
43 | if (pa <= bcm3384_dma_xor_limit) | 48 | if (pa >= r->child_addr && |
44 | return pa ^ bcm3384_dma_xor_mask; | 49 | pa < (r->child_addr + r->size)) |
50 | return pa - r->child_addr + r->parent_addr; | ||
51 | } | ||
45 | return pa; | 52 | return pa; |
46 | } | 53 | } |
47 | 54 | ||
48 | dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) | 55 | dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) |
49 | { | 56 | { |
50 | return bcm3384_phys_to_dma(dev, virt_to_phys(addr)); | 57 | return bmips_phys_to_dma(dev, virt_to_phys(addr)); |
51 | } | 58 | } |
52 | 59 | ||
53 | dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) | 60 | dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) |
54 | { | 61 | { |
55 | return bcm3384_phys_to_dma(dev, page_to_phys(page)); | 62 | return bmips_phys_to_dma(dev, page_to_phys(page)); |
56 | } | 63 | } |
57 | 64 | ||
58 | unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr) | 65 | unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr) |
59 | { | 66 | { |
60 | if (dev && dev_is_pci(dev) && | 67 | struct bmips_dma_range *r; |
61 | dma_addr >= BCM3384_MEM_HOLE_PA) | 68 | |
62 | return dma_addr + BCM3384_MEM_HOLE_SIZE; | 69 | for (r = bmips_dma_ranges; r && r->size; r++) { |
63 | if ((dma_addr ^ bcm3384_dma_xor_mask) <= bcm3384_dma_xor_limit) | 70 | if (dma_addr >= r->parent_addr && |
64 | return dma_addr ^ bcm3384_dma_xor_mask; | 71 | dma_addr < (r->parent_addr + r->size)) |
72 | return dma_addr - r->parent_addr + r->child_addr; | ||
73 | } | ||
65 | return dma_addr; | 74 | return dma_addr; |
66 | } | 75 | } |
67 | 76 | ||
68 | static int __init bcm3384_init_dma_xor(void) | 77 | static int __init bmips_init_dma_ranges(void) |
69 | { | 78 | { |
70 | struct device_node *np = of_find_node_by_type(NULL, "memory"); | 79 | struct device_node *np = |
80 | of_find_compatible_node(NULL, NULL, "brcm,ubus"); | ||
81 | const __be32 *data; | ||
82 | struct bmips_dma_range *r; | ||
83 | int len; | ||
71 | 84 | ||
72 | if (!np) | 85 | if (!np) |
73 | return 0; | 86 | return 0; |
74 | 87 | ||
75 | of_property_read_u32(np, "dma-xor-mask", &bcm3384_dma_xor_mask); | 88 | data = of_get_property(np, "dma-ranges", &len); |
76 | of_property_read_u32(np, "dma-xor-limit", &bcm3384_dma_xor_limit); | 89 | if (!data) |
90 | goto out_good; | ||
91 | |||
92 | len /= sizeof(*data) * 3; | ||
93 | if (!len) | ||
94 | goto out_bad; | ||
95 | |||
96 | /* add a dummy (zero) entry at the end as a sentinel */ | ||
97 | bmips_dma_ranges = kzalloc(sizeof(struct bmips_dma_range) * (len + 1), | ||
98 | GFP_KERNEL); | ||
99 | if (!bmips_dma_ranges) | ||
100 | goto out_bad; | ||
77 | 101 | ||
102 | for (r = bmips_dma_ranges; len; len--, r++) { | ||
103 | r->child_addr = be32_to_cpup(data++); | ||
104 | r->parent_addr = be32_to_cpup(data++); | ||
105 | r->size = be32_to_cpup(data++); | ||
106 | } | ||
107 | |||
108 | out_good: | ||
78 | of_node_put(np); | 109 | of_node_put(np); |
79 | return 0; | 110 | return 0; |
111 | |||
112 | out_bad: | ||
113 | pr_err("error parsing dma-ranges property\n"); | ||
114 | of_node_put(np); | ||
115 | return -EINVAL; | ||
80 | } | 116 | } |
81 | arch_initcall(bcm3384_init_dma_xor); | 117 | arch_initcall(bmips_init_dma_ranges); |