Commit | Line | Data |
---|---|---|
512254ba DD |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 2004-2009 Cavium Networks | |
7 | * Copyright (C) 2008 Wind River Systems | |
8 | */ | |
9 | ||
10 | #include <linux/init.h> | |
11 | #include <linux/irq.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/platform_device.h> | |
14 | ||
15 | #include <asm/octeon/octeon.h> | |
16 | #include <asm/octeon/cvmx-rnm-defs.h> | |
17 | ||
18 | static struct octeon_cf_data octeon_cf_data; | |
19 | ||
20 | static int __init octeon_cf_device_init(void) | |
21 | { | |
22 | union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg; | |
23 | unsigned long base_ptr, region_base, region_size; | |
24 | struct platform_device *pd; | |
25 | struct resource cf_resources[3]; | |
26 | unsigned int num_resources; | |
27 | int i; | |
28 | int ret = 0; | |
29 | ||
30 | /* Setup octeon-cf platform device if present. */ | |
31 | base_ptr = 0; | |
32 | if (octeon_bootinfo->major_version == 1 | |
33 | && octeon_bootinfo->minor_version >= 1) { | |
34 | if (octeon_bootinfo->compact_flash_common_base_addr) | |
35 | base_ptr = | |
36 | octeon_bootinfo->compact_flash_common_base_addr; | |
37 | } else { | |
38 | base_ptr = 0x1d000800; | |
39 | } | |
40 | ||
41 | if (!base_ptr) | |
42 | return ret; | |
43 | ||
44 | /* Find CS0 region. */ | |
45 | for (i = 0; i < 8; i++) { | |
46 | mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i)); | |
47 | region_base = mio_boot_reg_cfg.s.base << 16; | |
48 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | |
49 | if (mio_boot_reg_cfg.s.en && base_ptr >= region_base | |
50 | && base_ptr < region_base + region_size) | |
51 | break; | |
52 | } | |
53 | if (i >= 7) { | |
54 | /* i and i + 1 are CS0 and CS1, both must be less than 8. */ | |
55 | goto out; | |
56 | } | |
57 | octeon_cf_data.base_region = i; | |
58 | octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width; | |
59 | octeon_cf_data.base_region_bias = base_ptr - region_base; | |
60 | memset(cf_resources, 0, sizeof(cf_resources)); | |
61 | num_resources = 0; | |
62 | cf_resources[num_resources].flags = IORESOURCE_MEM; | |
63 | cf_resources[num_resources].start = region_base; | |
64 | cf_resources[num_resources].end = region_base + region_size - 1; | |
65 | num_resources++; | |
66 | ||
67 | ||
68 | if (!(base_ptr & 0xfffful)) { | |
69 | /* | |
70 | * Boot loader signals availability of DMA (true_ide | |
71 | * mode) by setting low order bits of base_ptr to | |
72 | * zero. | |
73 | */ | |
74 | ||
75 | /* Asume that CS1 immediately follows. */ | |
76 | mio_boot_reg_cfg.u64 = | |
77 | cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1)); | |
78 | region_base = mio_boot_reg_cfg.s.base << 16; | |
79 | region_size = (mio_boot_reg_cfg.s.size + 1) << 16; | |
80 | if (!mio_boot_reg_cfg.s.en) | |
81 | goto out; | |
82 | ||
83 | cf_resources[num_resources].flags = IORESOURCE_MEM; | |
84 | cf_resources[num_resources].start = region_base; | |
85 | cf_resources[num_resources].end = region_base + region_size - 1; | |
86 | num_resources++; | |
87 | ||
88 | octeon_cf_data.dma_engine = 0; | |
89 | cf_resources[num_resources].flags = IORESOURCE_IRQ; | |
90 | cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA; | |
91 | cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA; | |
92 | num_resources++; | |
93 | } else { | |
94 | octeon_cf_data.dma_engine = -1; | |
95 | } | |
96 | ||
97 | pd = platform_device_alloc("pata_octeon_cf", -1); | |
98 | if (!pd) { | |
99 | ret = -ENOMEM; | |
100 | goto out; | |
101 | } | |
102 | pd->dev.platform_data = &octeon_cf_data; | |
103 | ||
104 | ret = platform_device_add_resources(pd, cf_resources, num_resources); | |
105 | if (ret) | |
106 | goto fail; | |
107 | ||
108 | ret = platform_device_add(pd); | |
109 | if (ret) | |
110 | goto fail; | |
111 | ||
112 | return ret; | |
113 | fail: | |
114 | platform_device_put(pd); | |
115 | out: | |
116 | return ret; | |
117 | } | |
118 | device_initcall(octeon_cf_device_init); | |
119 | ||
120 | /* Octeon Random Number Generator. */ | |
121 | static int __init octeon_rng_device_init(void) | |
122 | { | |
123 | struct platform_device *pd; | |
124 | int ret = 0; | |
125 | ||
126 | struct resource rng_resources[] = { | |
127 | { | |
128 | .flags = IORESOURCE_MEM, | |
129 | .start = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS), | |
130 | .end = XKPHYS_TO_PHYS(CVMX_RNM_CTL_STATUS) + 0xf | |
131 | }, { | |
132 | .flags = IORESOURCE_MEM, | |
133 | .start = cvmx_build_io_address(8, 0), | |
134 | .end = cvmx_build_io_address(8, 0) + 0x7 | |
135 | } | |
136 | }; | |
137 | ||
138 | pd = platform_device_alloc("octeon_rng", -1); | |
139 | if (!pd) { | |
140 | ret = -ENOMEM; | |
141 | goto out; | |
142 | } | |
143 | ||
144 | ret = platform_device_add_resources(pd, rng_resources, | |
145 | ARRAY_SIZE(rng_resources)); | |
146 | if (ret) | |
147 | goto fail; | |
148 | ||
149 | ret = platform_device_add(pd); | |
150 | if (ret) | |
151 | goto fail; | |
152 | ||
153 | return ret; | |
154 | fail: | |
155 | platform_device_put(pd); | |
156 | ||
157 | out: | |
158 | return ret; | |
159 | } | |
160 | device_initcall(octeon_rng_device_init); | |
161 | ||
0f7e64a3 DD |
162 | /* Octeon SMI/MDIO interface. */ |
163 | static int __init octeon_mdiobus_device_init(void) | |
164 | { | |
165 | struct platform_device *pd; | |
166 | int ret = 0; | |
167 | ||
168 | if (octeon_is_simulation()) | |
169 | return 0; /* No mdio in the simulator. */ | |
170 | ||
171 | /* The bus number is the platform_device id. */ | |
172 | pd = platform_device_alloc("mdio-octeon", 0); | |
173 | if (!pd) { | |
174 | ret = -ENOMEM; | |
175 | goto out; | |
176 | } | |
177 | ||
178 | ret = platform_device_add(pd); | |
179 | if (ret) | |
180 | goto fail; | |
181 | ||
182 | return ret; | |
183 | fail: | |
184 | platform_device_put(pd); | |
185 | ||
186 | out: | |
187 | return ret; | |
188 | ||
189 | } | |
190 | device_initcall(octeon_mdiobus_device_init); | |
191 | ||
24479d9f DD |
192 | /* Octeon mgmt port Ethernet interface. */ |
193 | static int __init octeon_mgmt_device_init(void) | |
194 | { | |
195 | struct platform_device *pd; | |
196 | int ret = 0; | |
197 | int port, num_ports; | |
198 | ||
199 | struct resource mgmt_port_resource = { | |
200 | .flags = IORESOURCE_IRQ, | |
201 | .start = -1, | |
202 | .end = -1 | |
203 | }; | |
204 | ||
205 | if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX)) | |
206 | return 0; | |
207 | ||
208 | if (OCTEON_IS_MODEL(OCTEON_CN56XX)) | |
209 | num_ports = 1; | |
210 | else | |
211 | num_ports = 2; | |
212 | ||
213 | for (port = 0; port < num_ports; port++) { | |
214 | pd = platform_device_alloc("octeon_mgmt", port); | |
215 | if (!pd) { | |
216 | ret = -ENOMEM; | |
217 | goto out; | |
218 | } | |
219 | switch (port) { | |
220 | case 0: | |
221 | mgmt_port_resource.start = OCTEON_IRQ_MII0; | |
222 | break; | |
223 | case 1: | |
224 | mgmt_port_resource.start = OCTEON_IRQ_MII1; | |
225 | break; | |
226 | default: | |
227 | BUG(); | |
228 | } | |
229 | mgmt_port_resource.end = mgmt_port_resource.start; | |
230 | ||
231 | ret = platform_device_add_resources(pd, &mgmt_port_resource, 1); | |
232 | ||
233 | if (ret) | |
234 | goto fail; | |
235 | ||
236 | ret = platform_device_add(pd); | |
237 | if (ret) | |
238 | goto fail; | |
239 | } | |
240 | return ret; | |
241 | fail: | |
242 | platform_device_put(pd); | |
243 | ||
244 | out: | |
245 | return ret; | |
246 | ||
247 | } | |
248 | device_initcall(octeon_mgmt_device_init); | |
249 | ||
512254ba DD |
250 | MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); |
251 | MODULE_LICENSE("GPL"); | |
252 | MODULE_DESCRIPTION("Platform driver for Octeon SOC"); |