kernel: update linux 3.8 to 3.8.2
[openwrt.git] / target / linux / mvebu / patches-3.8 / 033-arm_mvebu_add_functions_to_alloc_free_pcie.patch
1 This commit adds two functions armada_370_xp_alloc_pcie_window() and
2 armada_370_xp_free_pcie_window() that respectively allocate and free
3 an address decoding window pointing to either a memory or I/O region
4 of a PCIe device.
5
6 Those functions will be used by the PCIe driver to create and remove
7 those regions depending on the PCIe devices that are detected.
8
9 Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
10 ---
11  arch/arm/mach-mvebu/addr-map.c |  156 ++++++++++++++++++++++++++++++++++++++--
12  arch/arm/mach-mvebu/common.h   |    4 ++
13  2 files changed, 156 insertions(+), 4 deletions(-)
14
15 --- a/arch/arm/mach-mvebu/addr-map.c
16 +++ b/arch/arm/mach-mvebu/addr-map.c
17 @@ -24,14 +24,10 @@
18  #define ARMADA_XP_TARGET_DEV_BUS       1
19  #define   ARMADA_XP_ATTR_DEV_BOOTROM    0x1D
20  #define ARMADA_XP_TARGET_ETH1          3
21 -#define ARMADA_XP_TARGET_PCIE_0_2      4
22  #define ARMADA_XP_TARGET_ETH0          7
23 -#define ARMADA_XP_TARGET_PCIE_1_3      8
24  
25  #define ARMADA_370_TARGET_DEV_BUS       1
26  #define   ARMADA_370_ATTR_DEV_BOOTROM   0x1D
27 -#define ARMADA_370_TARGET_PCIE_0        4
28 -#define ARMADA_370_TARGET_PCIE_1        8
29  
30  #define ARMADA_WINDOW_8_PLUS_OFFSET       0x90
31  #define ARMADA_SDRAM_ADDR_DECODING_OFFSET 0x180
32 @@ -89,6 +85,158 @@ static struct __initdata orion_addr_map_
33         .win_cfg_base = armada_cfg_base,
34  };
35  
36 +#ifdef CONFIG_PCI
37 +/*
38 + * PCIe windows allocation code.
39 + */
40 +#define ARMADA_370_XP_PCIE_MEM_START 0xC0000000
41 +#define ARMADA_370_XP_PCIE_MEM_END   (ARMADA_370_XP_PCIE_MEM_START + SZ_256M)
42 +#define ARMADA_370_XP_PCIE_IO_START  0xF2000000
43 +#define ARMADA_370_XP_PCIE_IO_END    (ARMADA_370_XP_PCIE_IO_START + SZ_1M)
44 +
45 +static unsigned long armada_370_xp_pcie_memaddr = ARMADA_370_XP_PCIE_MEM_START;
46 +static unsigned long armada_370_xp_pcie_ioaddr = ARMADA_370_XP_PCIE_IO_START;
47 +
48 +/*
49 + * This structure and the following arrays allow to map a PCIe (port,
50 + * lane) tuple to the corresponding (target, attribute) tuple needed
51 + * to configure an address decoding window for the given PCIe (port,
52 + * lane).
53 + */
54 +struct pcie_mapping {
55 +       int port;
56 +       int lane;
57 +       u8  target;
58 +       u8  attr;
59 +};
60 +
61 +struct pcie_mapping armada_xp_pcie_mappings[] = {
62 +       { .port = 0, .lane = 0, .target = 4, .attr = 0xE0 },
63 +       { .port = 0, .lane = 1, .target = 4, .attr = 0xD0 },
64 +       { .port = 0, .lane = 2, .target = 4, .attr = 0xB0 },
65 +       { .port = 0, .lane = 3, .target = 4, .attr = 0x70 },
66 +       { .port = 1, .lane = 0, .target = 8, .attr = 0xE0 },
67 +       { .port = 1, .lane = 1, .target = 8, .attr = 0xD0 },
68 +       { .port = 1, .lane = 2, .target = 8, .attr = 0xB0 },
69 +       { .port = 1, .lane = 3, .target = 8, .attr = 0x70 },
70 +       { .port = 2, .lane = 0, .target = 4, .attr = 0xF0 },
71 +       { .port = 3, .lane = 0, .target = 8, .attr = 0xF0 },
72 +       { .port = -1 },
73 +};
74 +
75 +struct pcie_mapping armada_370_pcie_mappings[] = {
76 +       { .port = 0, .lane = 0, .target = 4, .attr = 0xE0 },
77 +       { .port = 1, .lane = 0, .target = 8, .attr = 0xE0 },
78 +       { .port = -1 },
79 +};
80 +
81 +/*
82 + * This function finds an available physical address range between
83 + * ARMADA_370_XP_PCIE_MEM_START and ARMADA_370_XP_PCIE_MEM_END (for
84 + * PCIe memory regions) or between ARMADA_370_XP_PCIE_IO_START and
85 + * ARMADA_370_XP_PCIE_IO_END (for PCIe I/O regions) and creates an
86 + * address decoding window from this allocated address pointing to the
87 + * right PCIe device.
88 + *
89 + * An error code is returned, the allocated base address is returned
90 + * through the 'outbase' argument.
91 + */
92 +int __init armada_370_xp_alloc_pcie_window(int pcie_port, int pcie_lane,
93 +                                          int type, u32 size,
94 +                                          unsigned long *outbase)
95 +{
96 +       struct pcie_mapping *mapping, *mappings;
97 +       u8 target, attr;
98 +       u32 base;
99 +       int ret;
100 +
101 +       if (of_machine_is_compatible("marvell,armadaxp"))
102 +               mappings = armada_xp_pcie_mappings;
103 +       else if (of_machine_is_compatible("marvell,armada370"))
104 +               mappings = armada_370_pcie_mappings;
105 +       else
106 +               return -ENODEV;
107 +
108 +       for (mapping = mappings; mapping->port != -1; mapping++)
109 +               if (mapping->port == pcie_port && mapping->lane == pcie_lane)
110 +                       break;
111 +
112 +       if (mapping->port == -1)
113 +               return -ENODEV;
114 +
115 +       target = mapping->target;
116 +       attr = mapping->attr;
117 +
118 +       if (type == IORESOURCE_MEM) {
119 +               /*
120 +                * Bit 3 of the attributes indicates that it is a
121 +                * memory region, as opposed to an I/O region
122 +                */
123 +               attr |= (1 << 3);
124 +
125 +               if (armada_370_xp_pcie_memaddr + size >
126 +                   ARMADA_370_XP_PCIE_MEM_END)
127 +                       return -ENOMEM;
128 +
129 +               base = armada_370_xp_pcie_memaddr;
130 +               armada_370_xp_pcie_memaddr += size;
131 +
132 +               ret = orion_alloc_cpu_win(&addr_map_cfg, base, size, target,
133 +                                         attr, -1);
134 +               if (ret) {
135 +                       armada_370_xp_pcie_memaddr -= size;
136 +                       return ret;
137 +               }
138 +       } else if (type == IORESOURCE_IO) {
139 +               if (armada_370_xp_pcie_ioaddr + size >
140 +                   ARMADA_370_XP_PCIE_IO_END)
141 +                       return -ENOMEM;
142 +
143 +               base = armada_370_xp_pcie_ioaddr;
144 +               armada_370_xp_pcie_ioaddr += size;
145 +
146 +               ret = orion_alloc_cpu_win(&addr_map_cfg, base, size, target,
147 +                                         attr, -1);
148 +               if (ret) {
149 +                       armada_370_xp_pcie_ioaddr -= size;
150 +                       return ret;
151 +               }
152 +       } else
153 +               return -ENODEV;
154 +
155 +       *outbase = base;
156 +       return 0;
157 +}
158 +
159 +/*
160 + * Frees an address decoding window previously allocated by
161 + * armada_370_xp_alloc_pcie_window(). Note that only the last window
162 + * allocated for a given type (MEM or IO) can be freed, due to the
163 + * simplicity of the allocator. This is however sufficient to handle
164 + * the error cases when initializing one PCIe device.
165 + */
166 +int __init armada_370_xp_free_pcie_window(int type, unsigned long base,
167 +                                         u32 size)
168 +{
169 +       if (type == IORESOURCE_MEM) {
170 +               /* We can only free the last allocated window */
171 +               if (base + size != armada_370_xp_pcie_memaddr)
172 +                       return -EINVAL;
173 +               orion_free_cpu_win(&addr_map_cfg, base);
174 +               armada_370_xp_pcie_memaddr -= size;
175 +       } else if (type == IORESOURCE_IO) {
176 +               /* We can only free the last allocated window */
177 +               if (base + size != armada_370_xp_pcie_ioaddr)
178 +                       return -EINVAL;
179 +               orion_free_cpu_win(&addr_map_cfg, base);
180 +               armada_370_xp_pcie_ioaddr -= size;
181 +       } else
182 +               return -EINVAL;
183 +
184 +       return 0;
185 +}
186 +#endif
187 +
188  static int __init armada_setup_cpu_mbus(void)
189  {
190         struct device_node *np;
191 --- a/arch/arm/mach-mvebu/common.h
192 +++ b/arch/arm/mach-mvebu/common.h
193 @@ -25,4 +25,8 @@ int armada_370_xp_coherency_init(void);
194  int armada_370_xp_pmsu_init(void);
195  void armada_xp_secondary_startup(void);
196  extern struct smp_operations armada_xp_smp_ops;
197 +
198 +int armada_370_xp_alloc_pcie_window(int pcie_port, int pcie_lane,
199 +                                   int type, u32 size, unsigned long *outbase);
200 +int armada_370_xp_free_pcie_window(int type, unsigned long base, u32 size);
201  #endif