]>
Commit | Line | Data |
---|---|---|
a3a0f8c8 DV |
1 | /* |
2 | * This program is free software; you can redistribute it and/or | |
3 | * modify it under the terms of the GNU General Public License | |
4 | * as published by the Free Software Foundation; either version | |
5 | * 2 of the License, or (at your option) any later version. | |
6 | * | |
7 | * Portions Copyright (C) Cisco Systems, Inc. | |
8 | */ | |
9 | #ifndef __ASM_MACH_POWERTV_IOREMAP_H | |
10 | #define __ASM_MACH_POWERTV_IOREMAP_H | |
11 | ||
12 | #include <linux/types.h> | |
ca36c36b DV |
13 | #include <linux/log2.h> |
14 | #include <linux/compiler.h> | |
a3a0f8c8 | 15 | |
ca36c36b DV |
16 | #include <asm/pgtable-bits.h> |
17 | #include <asm/addrspace.h> | |
18 | ||
19 | /* We're going to mess with bits, so get sizes */ | |
20 | #define IOR_BPC 8 /* Bits per char */ | |
21 | #define IOR_PHYS_BITS (IOR_BPC * sizeof(phys_addr_t)) | |
22 | #define IOR_DMA_BITS (IOR_BPC * sizeof(dma_addr_t)) | |
a3a0f8c8 DV |
23 | |
24 | /* | |
ca36c36b DV |
25 | * Define the granularity of physical/DMA mapping in terms of the number |
26 | * of bits that defines the offset within a grain. These will be the | |
27 | * least significant bits of the address. The rest of a physical or DMA | |
28 | * address will be used to index into an appropriate table to find the | |
29 | * offset to add to the address to yield the corresponding DMA or physical | |
30 | * address, respectively. | |
31 | */ | |
32 | #define IOR_LSBITS 22 /* Bits in a grain */ | |
33 | ||
a3a0f8c8 | 34 | /* |
ca36c36b DV |
35 | * Compute the number of most significant address bits after removing those |
36 | * used for the offset within a grain and then compute the number of table | |
37 | * entries for the conversion. | |
a3a0f8c8 | 38 | */ |
ca36c36b DV |
39 | #define IOR_PHYS_MSBITS (IOR_PHYS_BITS - IOR_LSBITS) |
40 | #define IOR_NUM_PHYS_TO_DMA ((phys_addr_t) 1 << IOR_PHYS_MSBITS) | |
41 | ||
42 | #define IOR_DMA_MSBITS (IOR_DMA_BITS - IOR_LSBITS) | |
43 | #define IOR_NUM_DMA_TO_PHYS ((dma_addr_t) 1 << IOR_DMA_MSBITS) | |
a3a0f8c8 DV |
44 | |
45 | /* | |
ca36c36b DV |
46 | * Define data structures used as elements in the arrays for the conversion |
47 | * between physical and DMA addresses. We do some slightly fancy math to | |
48 | * compute the width of the offset element of the conversion tables so | |
49 | * that we can have the smallest conversion tables. Next, round up the | |
50 | * sizes to the next higher power of two, i.e. the offset element will have | |
51 | * 8, 16, 32, 64, etc. bits. This eliminates the need to mask off any | |
52 | * bits. Finally, we compute a shift value that puts the most significant | |
53 | * bits of the offset into the most significant bits of the offset element. | |
54 | * This makes it more efficient on processors without barrel shifters and | |
55 | * easier to see the values if the conversion table is dumped in binary. | |
a3a0f8c8 | 56 | */ |
ca36c36b DV |
57 | #define _IOR_OFFSET_WIDTH(n) (1 << order_base_2(n)) |
58 | #define IOR_OFFSET_WIDTH(n) \ | |
59 | (_IOR_OFFSET_WIDTH(n) < 8 ? 8 : _IOR_OFFSET_WIDTH(n)) | |
60 | ||
61 | #define IOR_PHYS_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_PHYS_MSBITS) | |
62 | #define IOR_PHYS_SHIFT (IOR_PHYS_BITS - IOR_PHYS_OFFSET_BITS) | |
63 | ||
64 | #define IOR_DMA_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_DMA_MSBITS) | |
65 | #define IOR_DMA_SHIFT (IOR_DMA_BITS - IOR_DMA_OFFSET_BITS) | |
66 | ||
67 | struct ior_phys_to_dma { | |
68 | dma_addr_t offset:IOR_DMA_OFFSET_BITS __packed | |
69 | __aligned((IOR_DMA_OFFSET_BITS / IOR_BPC)); | |
70 | }; | |
71 | ||
72 | struct ior_dma_to_phys { | |
73 | dma_addr_t offset:IOR_PHYS_OFFSET_BITS __packed | |
74 | __aligned((IOR_PHYS_OFFSET_BITS / IOR_BPC)); | |
75 | }; | |
76 | ||
77 | extern struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA]; | |
78 | extern struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS]; | |
79 | ||
80 | static inline dma_addr_t _phys_to_dma_offset_raw(phys_addr_t phys) | |
a3a0f8c8 | 81 | { |
ca36c36b | 82 | return (dma_addr_t)_ior_phys_to_dma[phys >> IOR_LSBITS].offset; |
a3a0f8c8 DV |
83 | } |
84 | ||
ca36c36b | 85 | static inline dma_addr_t _dma_to_phys_offset_raw(dma_addr_t dma) |
a3a0f8c8 | 86 | { |
ca36c36b DV |
87 | return (dma_addr_t)_ior_dma_to_phys[dma >> IOR_LSBITS].offset; |
88 | } | |
a3a0f8c8 | 89 | |
ca36c36b DV |
90 | /* These are not portable and should not be used in drivers. Drivers should |
91 | * be using ioremap() and friends to map physical addreses to virtual | |
92 | * addresses and dma_map*() and friends to map virtual addresses into DMA | |
93 | * addresses and back. | |
94 | */ | |
95 | static inline dma_addr_t phys_to_dma(phys_addr_t phys) | |
96 | { | |
97 | return phys + (_phys_to_dma_offset_raw(phys) << IOR_PHYS_SHIFT); | |
98 | } | |
a3a0f8c8 | 99 | |
ca36c36b DV |
100 | static inline phys_addr_t dma_to_phys(dma_addr_t dma) |
101 | { | |
102 | return dma + (_dma_to_phys_offset_raw(dma) << IOR_DMA_SHIFT); | |
a3a0f8c8 DV |
103 | } |
104 | ||
ca36c36b DV |
105 | extern void ioremap_add_map(dma_addr_t phys, phys_addr_t alias, |
106 | dma_addr_t size); | |
107 | ||
a3a0f8c8 DV |
108 | /* |
109 | * Allow physical addresses to be fixed up to help peripherals located | |
110 | * outside the low 32-bit range -- generic pass-through version. | |
111 | */ | |
112 | static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) | |
113 | { | |
114 | return phys_addr; | |
115 | } | |
116 | ||
ca36c36b DV |
117 | /* |
118 | * Handle the special case of addresses the area aliased into the first | |
119 | * 512 MiB of the processor's physical address space. These turn into either | |
120 | * kseg0 or kseg1 addresses, depending on flags. | |
121 | */ | |
122 | static inline void __iomem *plat_ioremap(phys_t start, unsigned long size, | |
a3a0f8c8 DV |
123 | unsigned long flags) |
124 | { | |
ca36c36b DV |
125 | phys_addr_t start_offset; |
126 | void __iomem *result = NULL; | |
127 | ||
128 | /* Start by checking to see whether this is an aliased address */ | |
129 | start_offset = _dma_to_phys_offset_raw(start); | |
130 | ||
131 | /* | |
132 | * If: | |
133 | * o the memory is aliased into the first 512 MiB, and | |
134 | * o the start and end are in the same RAM bank, and | |
135 | * o we don't have a zero size or wrap around, and | |
136 | * o we are supposed to create an uncached mapping, | |
137 | * handle this is a kseg0 or kseg1 address | |
138 | */ | |
139 | if (start_offset != 0) { | |
140 | phys_addr_t last; | |
141 | dma_addr_t dma_to_phys_offset; | |
142 | ||
143 | last = start + size - 1; | |
144 | dma_to_phys_offset = | |
145 | _dma_to_phys_offset_raw(last) << IOR_DMA_SHIFT; | |
146 | ||
147 | if (dma_to_phys_offset == start_offset && | |
148 | size != 0 && start <= last) { | |
149 | phys_t adjusted_start; | |
150 | adjusted_start = start + start_offset; | |
151 | if (flags == _CACHE_UNCACHED) | |
152 | result = (void __iomem *) (unsigned long) | |
153 | CKSEG1ADDR(adjusted_start); | |
154 | else | |
155 | result = (void __iomem *) (unsigned long) | |
156 | CKSEG0ADDR(adjusted_start); | |
157 | } | |
158 | } | |
159 | ||
160 | return result; | |
a3a0f8c8 DV |
161 | } |
162 | ||
163 | static inline int plat_iounmap(const volatile void __iomem *addr) | |
164 | { | |
165 | return 0; | |
166 | } | |
167 | #endif /* __ASM_MACH_POWERTV_IOREMAP_H */ |