]>
Commit | Line | Data |
---|---|---|
255ef4d9 DE |
1 | /* |
2 | * (C) Copyright 2010 | |
3 | * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de | |
4 | * | |
5 | * based on kilauea.c | |
6 | * by Stefan Roese, DENX Software Engineering, sr@denx.de. | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
255ef4d9 DE |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | #include <asm/ppc4xx.h> | |
13 | #include <asm/ppc405.h> | |
14 | #include <libfdt.h> | |
15 | #include <fdt_support.h> | |
16 | #include <asm/processor.h> | |
17 | #include <asm/io.h> | |
1221ce45 | 18 | #include <linux/errno.h> |
255ef4d9 DE |
19 | #include <asm/ppc4xx-gpio.h> |
20 | #include <flash.h> | |
21 | ||
22 | #include <pca9698.h> | |
23 | ||
24 | #include "405ex.h" | |
25 | #include <gdsys_fpga.h> | |
26 | ||
27 | #include <miiphy.h> | |
28 | #include <i2c.h> | |
255ef4d9 DE |
29 | |
30 | DECLARE_GLOBAL_DATA_PTR; | |
31 | ||
32 | #define PHYREG_CONTROL 0 | |
33 | #define PHYREG_PAGE_ADDRESS 22 | |
34 | #define PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1 16 | |
35 | #define PHYREG_PG2_COPPER_SPECIFIC_CONTROL_2 26 | |
36 | #define PHYREG_PG2_MAC_SPECIFIC_STATUS_1 17 | |
37 | #define PHYREG_PG2_MAC_SPECIFIC_CONTROL 21 | |
38 | ||
39 | #define LATCH0_BASE (CONFIG_SYS_LATCH_BASE) | |
40 | #define LATCH1_BASE (CONFIG_SYS_LATCH_BASE + 0x100) | |
41 | #define LATCH2_BASE (CONFIG_SYS_LATCH_BASE + 0x200) | |
42 | #define LATCH3_BASE (CONFIG_SYS_LATCH_BASE + 0x300) | |
43 | ||
44 | enum { | |
45 | UNITTYPE_CCD_SWITCH = 1, | |
46 | }; | |
47 | ||
48 | enum { | |
49 | HWVER_100 = 0, | |
50 | HWVER_110 = 1, | |
51 | }; | |
52 | ||
aba27acf DE |
53 | struct ihs_fpga *fpga_ptr[] = CONFIG_SYS_FPGA_PTR; |
54 | ||
255ef4d9 DE |
55 | static inline void blank_string(int size) |
56 | { | |
57 | int i; | |
58 | ||
59 | for (i = 0; i < size; i++) | |
60 | putc('\b'); | |
61 | for (i = 0; i < size; i++) | |
62 | putc(' '); | |
63 | for (i = 0; i < size; i++) | |
64 | putc('\b'); | |
65 | } | |
66 | ||
67 | /* | |
68 | * Board early initialization function | |
69 | */ | |
70 | int misc_init_r(void) | |
71 | { | |
853eaa4f SG |
72 | /* |
73 | * Note: DTT has been removed. Please use UCLASS_THERMAL. | |
74 | * | |
75 | * startup fans | |
76 | * | |
77 | * dtt_init(); | |
78 | */ | |
255ef4d9 DE |
79 | |
80 | #ifdef CONFIG_ENV_IS_IN_FLASH | |
81 | /* Monitor protection ON by default */ | |
82 | flash_protect(FLAG_PROTECT_SET, | |
83 | -CONFIG_SYS_MONITOR_LEN, | |
84 | 0xffffffff, | |
85 | &flash_info[0]); | |
86 | #endif | |
87 | ||
88 | return 0; | |
89 | } | |
90 | ||
91 | static void print_fpga_info(unsigned dev) | |
92 | { | |
aba27acf DE |
93 | u16 versions; |
94 | u16 fpga_version; | |
95 | u16 fpga_features; | |
255ef4d9 DE |
96 | int fpga_state = get_fpga_state(dev); |
97 | ||
98 | unsigned unit_type; | |
99 | unsigned hardware_version; | |
100 | unsigned feature_channels; | |
101 | unsigned feature_expansion; | |
102 | ||
aba27acf DE |
103 | FPGA_GET_REG(dev, versions, &versions); |
104 | FPGA_GET_REG(dev, fpga_version, &fpga_version); | |
105 | FPGA_GET_REG(dev, fpga_features, &fpga_features); | |
106 | ||
255ef4d9 DE |
107 | printf("FPGA%d: ", dev); |
108 | if (fpga_state & FPGA_STATE_PLATFORM) | |
109 | printf("(legacy) "); | |
110 | ||
111 | if (fpga_state & FPGA_STATE_DONE_FAILED) { | |
112 | printf(" done timed out\n"); | |
113 | return; | |
114 | } | |
115 | ||
116 | if (fpga_state & FPGA_STATE_REFLECTION_FAILED) { | |
117 | printf(" refelectione test failed\n"); | |
118 | return; | |
119 | } | |
120 | ||
121 | unit_type = (versions & 0xf000) >> 12; | |
122 | hardware_version = versions & 0x000f; | |
123 | feature_channels = fpga_features & 0x007f; | |
124 | feature_expansion = fpga_features & (1<<15); | |
125 | ||
126 | switch (unit_type) { | |
127 | case UNITTYPE_CCD_SWITCH: | |
128 | printf("CCD-Switch"); | |
129 | break; | |
130 | ||
131 | default: | |
132 | printf("UnitType %d(not supported)", unit_type); | |
133 | break; | |
134 | } | |
135 | ||
136 | switch (hardware_version) { | |
137 | case HWVER_100: | |
138 | printf(" HW-Ver 1.00\n"); | |
139 | break; | |
140 | ||
141 | case HWVER_110: | |
142 | printf(" HW-Ver 1.10\n"); | |
143 | break; | |
144 | ||
145 | default: | |
146 | printf(" HW-Ver %d(not supported)\n", | |
147 | hardware_version); | |
148 | break; | |
149 | } | |
150 | ||
151 | printf(" FPGA V %d.%02d, features:", | |
152 | fpga_version / 100, fpga_version % 100); | |
153 | ||
154 | printf(" %d channel(s)", feature_channels); | |
155 | ||
156 | printf(", expansion %ssupported\n", feature_expansion ? "" : "un"); | |
157 | } | |
158 | ||
159 | int checkboard(void) | |
160 | { | |
161 | char *s = getenv("serial#"); | |
162 | ||
163 | printf("Board: CATCenter Io64\n"); | |
164 | ||
165 | if (s != NULL) { | |
166 | puts(", serial# "); | |
167 | puts(s); | |
168 | } | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | int configure_gbit_phy(char *bus, unsigned char addr) | |
174 | { | |
175 | unsigned short value; | |
176 | ||
177 | /* select page 0 */ | |
178 | if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0000)) | |
179 | goto err_out; | |
180 | /* switch to powerdown */ | |
181 | if (miiphy_read(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1, | |
182 | &value)) | |
183 | goto err_out; | |
184 | if (miiphy_write(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1, | |
185 | value | 0x0004)) | |
186 | goto err_out; | |
187 | /* select page 2 */ | |
188 | if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0002)) | |
189 | goto err_out; | |
190 | /* disable SGMII autonegotiation */ | |
191 | if (miiphy_write(bus, addr, PHYREG_PG2_MAC_SPECIFIC_CONTROL, 48)) | |
192 | goto err_out; | |
193 | /* select page 0 */ | |
194 | if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0000)) | |
195 | goto err_out; | |
196 | /* switch from powerdown to normal operation */ | |
197 | if (miiphy_read(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1, | |
198 | &value)) | |
199 | goto err_out; | |
200 | if (miiphy_write(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1, | |
201 | value & ~0x0004)) | |
202 | goto err_out; | |
203 | /* reset phy so settings take effect */ | |
204 | if (miiphy_write(bus, addr, PHYREG_CONTROL, 0x9140)) | |
205 | goto err_out; | |
206 | ||
207 | return 0; | |
208 | ||
209 | err_out: | |
210 | printf("Error writing to the PHY addr=%02x\n", addr); | |
211 | return -1; | |
212 | } | |
213 | ||
214 | int verify_gbit_phy(char *bus, unsigned char addr) | |
215 | { | |
216 | unsigned short value; | |
217 | ||
218 | /* select page 2 */ | |
219 | if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0002)) | |
220 | goto err_out; | |
221 | /* verify SGMII link status */ | |
222 | if (miiphy_read(bus, addr, PHYREG_PG2_MAC_SPECIFIC_STATUS_1, &value)) | |
223 | goto err_out; | |
224 | if (!(value & (1 << 10))) | |
225 | return -2; | |
226 | ||
227 | return 0; | |
228 | ||
229 | err_out: | |
230 | printf("Error writing to the PHY addr=%02x\n", addr); | |
231 | return -1; | |
232 | } | |
233 | ||
234 | int last_stage_init(void) | |
235 | { | |
236 | unsigned int k; | |
237 | unsigned int fpga; | |
255ef4d9 DE |
238 | int failed = 0; |
239 | char str_phys[] = "Setup PHYs -"; | |
240 | char str_serdes[] = "Start SERDES blocks"; | |
241 | char str_channels[] = "Start FPGA channels"; | |
242 | char str_locks[] = "Verify SERDES locks"; | |
06b17412 | 243 | char str_hicb[] = "Verify HICB status"; |
255ef4d9 DE |
244 | char str_status[] = "Verify PHY status -"; |
245 | char slash[] = "\\|/-\\|/-"; | |
246 | ||
247 | print_fpga_info(0); | |
248 | print_fpga_info(1); | |
249 | ||
250 | /* setup Gbit PHYs */ | |
251 | puts("TRANS: "); | |
252 | puts(str_phys); | |
5a49f174 JH |
253 | int retval; |
254 | struct mii_dev *mdiodev = mdio_alloc(); | |
255 | if (!mdiodev) | |
256 | return -ENOMEM; | |
257 | strncpy(mdiodev->name, CONFIG_SYS_GBIT_MII_BUSNAME, MDIO_NAME_LEN); | |
258 | mdiodev->read = bb_miiphy_read; | |
259 | mdiodev->write = bb_miiphy_write; | |
260 | ||
261 | retval = mdio_register(mdiodev); | |
262 | if (retval < 0) | |
263 | return retval; | |
255ef4d9 DE |
264 | |
265 | for (k = 0; k < 32; ++k) { | |
266 | configure_gbit_phy(CONFIG_SYS_GBIT_MII_BUSNAME, k); | |
267 | putc('\b'); | |
268 | putc(slash[k % 8]); | |
269 | } | |
270 | ||
875e0bc6 | 271 | mdiodev = mdio_alloc(); |
5a49f174 JH |
272 | if (!mdiodev) |
273 | return -ENOMEM; | |
274 | strncpy(mdiodev->name, CONFIG_SYS_GBIT_MII1_BUSNAME, MDIO_NAME_LEN); | |
275 | mdiodev->read = bb_miiphy_read; | |
276 | mdiodev->write = bb_miiphy_write; | |
277 | ||
278 | retval = mdio_register(mdiodev); | |
279 | if (retval < 0) | |
280 | return retval; | |
255ef4d9 DE |
281 | |
282 | for (k = 0; k < 32; ++k) { | |
283 | configure_gbit_phy(CONFIG_SYS_GBIT_MII1_BUSNAME, k); | |
284 | putc('\b'); | |
285 | putc(slash[k % 8]); | |
286 | } | |
287 | blank_string(strlen(str_phys)); | |
288 | ||
289 | /* take fpga serdes blocks out of reset */ | |
290 | puts(str_serdes); | |
291 | udelay(500000); | |
aba27acf DE |
292 | FPGA_SET_REG(0, quad_serdes_reset, 0); |
293 | FPGA_SET_REG(1, quad_serdes_reset, 0); | |
255ef4d9 DE |
294 | blank_string(strlen(str_serdes)); |
295 | ||
296 | /* take channels out of reset */ | |
297 | puts(str_channels); | |
298 | udelay(500000); | |
299 | for (fpga = 0; fpga < 2; ++fpga) { | |
255ef4d9 | 300 | for (k = 0; k < 32; ++k) |
aba27acf | 301 | FPGA_SET_REG(fpga, ch[k].config_int, 0); |
255ef4d9 DE |
302 | } |
303 | blank_string(strlen(str_channels)); | |
304 | ||
305 | /* verify channels serdes lock */ | |
306 | puts(str_locks); | |
307 | udelay(500000); | |
308 | for (fpga = 0; fpga < 2; ++fpga) { | |
255ef4d9 | 309 | for (k = 0; k < 32; ++k) { |
aba27acf | 310 | u16 status; |
2e436467 | 311 | FPGA_GET_REG(fpga, ch[k].status_int, &status); |
255ef4d9 DE |
312 | if (!(status & (1 << 4))) { |
313 | failed = 1; | |
314 | printf("fpga %d channel %d: no serdes lock\n", | |
315 | fpga, k); | |
316 | } | |
317 | /* reset events */ | |
aba27acf | 318 | FPGA_SET_REG(fpga, ch[k].status_int, 0); |
255ef4d9 DE |
319 | } |
320 | } | |
321 | blank_string(strlen(str_locks)); | |
322 | ||
06b17412 DE |
323 | /* verify hicb_status */ |
324 | puts(str_hicb); | |
325 | for (fpga = 0; fpga < 2; ++fpga) { | |
06b17412 | 326 | for (k = 0; k < 32; ++k) { |
aba27acf | 327 | u16 status; |
2e436467 | 328 | FPGA_GET_REG(fpga, hicb_ch[k].status_int, &status); |
06b17412 DE |
329 | if (status) |
330 | printf("fpga %d hicb %d: hicb status %04x\n", | |
331 | fpga, k, status); | |
332 | /* reset events */ | |
aba27acf | 333 | FPGA_SET_REG(fpga, hicb_ch[k].status_int, 0); |
06b17412 DE |
334 | } |
335 | } | |
336 | blank_string(strlen(str_hicb)); | |
337 | ||
255ef4d9 DE |
338 | /* verify phy status */ |
339 | puts(str_status); | |
340 | for (k = 0; k < 32; ++k) { | |
341 | if (verify_gbit_phy(CONFIG_SYS_GBIT_MII_BUSNAME, k)) { | |
342 | printf("verify baseboard phy %d failed\n", k); | |
343 | failed = 1; | |
344 | } | |
345 | putc('\b'); | |
346 | putc(slash[k % 8]); | |
347 | } | |
348 | for (k = 0; k < 32; ++k) { | |
349 | if (verify_gbit_phy(CONFIG_SYS_GBIT_MII1_BUSNAME, k)) { | |
350 | printf("verify extensionboard phy %d failed\n", k); | |
351 | failed = 1; | |
352 | } | |
353 | putc('\b'); | |
354 | putc(slash[k % 8]); | |
355 | } | |
356 | blank_string(strlen(str_status)); | |
357 | ||
358 | printf("Starting 64 channels %s\n", failed ? "failed" : "ok"); | |
359 | ||
360 | return 0; | |
361 | } | |
362 | ||
363 | void gd405ex_init(void) | |
364 | { | |
365 | unsigned int k; | |
366 | ||
367 | if (i2c_probe(0x22)) { /* i2c_probe returns 0 on success */ | |
368 | for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) | |
923a662f | 369 | gd->arch.fpga_state[k] |= FPGA_STATE_PLATFORM; |
255ef4d9 DE |
370 | } else { |
371 | pca9698_direction_output(0x22, 39, 1); | |
372 | } | |
373 | } | |
374 | ||
375 | void gd405ex_set_fpga_reset(unsigned state) | |
376 | { | |
377 | int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM; | |
378 | ||
379 | if (legacy) { | |
380 | if (state) { | |
381 | out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_RESET); | |
382 | out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_RESET); | |
383 | } else { | |
384 | out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_BOOT); | |
385 | out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_BOOT); | |
386 | } | |
387 | } else { | |
388 | pca9698_set_value(0x22, 39, state ? 0 : 1); | |
389 | } | |
390 | } | |
391 | ||
392 | void gd405ex_setup_hw(void) | |
393 | { | |
394 | gpio_write_bit(CONFIG_SYS_GPIO_STARTUP_FINISHED_N, 0); | |
395 | gpio_write_bit(CONFIG_SYS_GPIO_STARTUP_FINISHED, 1); | |
396 | } | |
397 | ||
398 | int gd405ex_get_fpga_done(unsigned fpga) | |
399 | { | |
400 | int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM; | |
401 | ||
402 | if (legacy) | |
403 | return in_le16((void *)LATCH3_BASE) | |
404 | & CONFIG_SYS_FPGA_DONE(fpga); | |
405 | else | |
406 | return pca9698_get_value(0x22, fpga ? 9 : 8); | |
407 | } |