1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Copyright (C) 2020 Marvell International Ltd.
4 *
5 * FDT Helper functions similar to those provided to U-Boot.
6 * If compiled for U-Boot, just provide wrappers to the equivalent U-Boot
7 * functions.
8 */
9
10 #ifndef __CVMX_HELPER_FDT_H__
11 #define __CVMX_HELPER_FDT_H__
12
13 #include <fdt_support.h>
14 #include <fdtdec.h>
15 #include <time.h>
16 #include <asm/global_data.h>
17 #include <asm-generic/gpio.h>
18 #include <dm/device.h>
19 #include <linux/libfdt.h>
20
21 #include <mach/cvmx-helper-sfp.h>
22
23 /* todo: this is deprecated and some of it can be removed at some time */
24 enum cvmx_i2c_bus_type {
25 CVMX_I2C_BUS_OCTEON,
26 CVMX_I2C_MUX_PCA9540,
27 CVMX_I2C_MUX_PCA9542,
28 CVMX_I2C_MUX_PCA9543,
29 CVMX_I2C_MUX_PCA9544,
30 CVMX_I2C_MUX_PCA9545,
31 CVMX_I2C_MUX_PCA9546,
32 CVMX_I2C_MUX_PCA9547,
33 CVMX_I2C_MUX_PCA9548,
34 CVMX_I2C_MUX_OTHER
35 };
36
37 struct cvmx_sfp_mod_info; /** Defined in cvmx-helper-sfp.h */
38 struct cvmx_phy_info; /** Defined in cvmx-helper-board.h */
39
40 /**
41 * This data structure holds information about various I2C muxes and switches
42 * that may be between a device and the Octeon chip.
43 */
44 struct cvmx_fdt_i2c_bus_info {
45 /** Parent I2C bus, NULL if root */
46 struct cvmx_fdt_i2c_bus_info *parent;
47 /** Child I2C bus or NULL if last entry in the chain */
48 struct cvmx_fdt_i2c_bus_info *child;
49 /** Offset in device tree */
50 int of_offset;
51 /** Type of i2c bus or mux */
52 enum cvmx_i2c_bus_type type;
53 /** I2C address of mux */
54 u8 i2c_addr;
55 /** Mux channel number */
56 u8 channel;
57 /** For muxes, the bit(s) to set to enable them */
58 u8 enable_bit;
59 /** True if mux, false if switch */
60 bool is_mux;
61
62 struct udevice *i2c_bus;
63 };
64
65 /**
66 * Data structure containing information about SFP/QSFP slots
67 */
68 struct cvmx_fdt_sfp_info {
69 /** Used for a linked list of slots */
70 struct cvmx_fdt_sfp_info *next, *prev;
71 /** Used when multiple SFP ports share the same IPD port */
72 struct cvmx_fdt_sfp_info *next_iface_sfp;
73 /** Name from device tree of slot */
74 const char *name;
75 /** I2C bus for slot EEPROM */
76 struct cvmx_fdt_i2c_bus_info *i2c_bus;
77 /** Data from SFP or QSFP EEPROM */
78 struct cvmx_sfp_mod_info sfp_info;
79 /** Data structure with PHY information */
80 struct cvmx_phy_info *phy_info;
81 /** IPD port(s) slot is connected to */
82 int ipd_port[4];
83 /** Offset in device tree of slot */
84 int of_offset;
85 /** EEPROM address of SFP module (usually 0x50) */
86 u8 i2c_eeprom_addr;
87 /** Diagnostic address of SFP module (usually 0x51) */
88 u8 i2c_diag_addr;
89 /** True if QSFP module */
90 bool is_qsfp;
91 /** True if EEPROM data is valid */
92 bool valid;
93
94 /** SFP tx_disable GPIO descriptor */
95 struct gpio_desc tx_disable;
96 /** SFP mod_abs/QSFP mod_prs GPIO descriptor */
97 struct gpio_desc mod_abs;
98 /** SFP tx_error GPIO descriptor */
99 struct gpio_desc tx_error;
100 /** SFP rx_los GPIO discriptor */
101 struct gpio_desc rx_los;
102 /** QSFP select GPIO descriptor */
103 struct gpio_desc select;
104 /** QSFP reset GPIO descriptor */
105 struct gpio_desc reset;
106 /** QSFP interrupt GPIO descriptor */
107 struct gpio_desc interrupt;
108 /** QSFP lp_mode GPIO descriptor */
109 struct gpio_desc lp_mode;
110
111 /** Last mod_abs value */
112 int last_mod_abs;
113 /** Last rx_los value */
114 int last_rx_los;
115 /** Function to call to check mod_abs */
116 int (*check_mod_abs)(struct cvmx_fdt_sfp_info *sfp_info, void *data);
117 /** User-defined data to pass to check_mod_abs */
118 void *mod_abs_data;
119 /** Function to call when mod_abs changes */
120 int (*mod_abs_changed)(struct cvmx_fdt_sfp_info *sfp_info, int val, void *data);
121 /** User-defined data to pass to mod_abs_changed */
122 void *mod_abs_changed_data;
123 /** Function to call when rx_los changes */
124 int (*rx_los_changed)(struct cvmx_fdt_sfp_info *sfp_info, int val, void *data);
125 /** User-defined data to pass to rx_los_changed */
126 void *rx_los_changed_data;
127 /** True if we're connected to a Microsemi VSC7224 reclocking chip */
128 bool is_vsc7224;
129 /** Data structure for first vsc7224 channel we're attached to */
130 struct cvmx_vsc7224_chan *vsc7224_chan;
131 /** True if we're connected to a Avago AVSP5410 phy */
132 bool is_avsp5410;
133 /** Data structure for avsp5410 phy we're attached to */
134 struct cvmx_avsp5410 *avsp5410;
135 /** xinterface we're on */
136 int xiface;
137 /** port index */
138 int index;
139 };
140
141 /**
142 * Look up a phandle and follow it to its node then return the offset of that
143 * node.
144 *
145 * @param[in] fdt_addr pointer to FDT blob
146 * @param node node to read phandle from
147 * @param[in] prop_name name of property to find
148 * @param[in,out] lenp Number of phandles, input max number
149 * @param[out] nodes Array of phandle nodes
150 *
151 * Return: -ve error code on error or 0 for success
152 */
153 int cvmx_fdt_lookup_phandles(const void *fdt_addr, int node, const char *prop_name, int *lenp,
154 int *nodes);
155
156 int cvmx_ofnode_lookup_phandles(ofnode node, const char *prop_name,
157 int *lenp, ofnode *nodes);
158
159 /**
160 * Helper to return the address property
161 *
162 * @param[in] fdt_addr pointer to FDT blob
163 * @param node node to read address from
164 * @param prop_name property name to read
165 *
166 * Return: address of property or FDT_ADDR_T_NONE if not found
167 */
cvmx_fdt_get_addr(const void * fdt_addr,int node,const char * prop_name)168 static inline fdt_addr_t cvmx_fdt_get_addr(const void *fdt_addr, int node, const char *prop_name)
169 {
170 return fdtdec_get_addr(fdt_addr, node, prop_name);
171 }
172
173 /**
174 * Helper function to return an integer property
175 *
176 * @param[in] fdt_addr pointer to FDT blob
177 * @param node node to read integer from
178 * @param[in] prop_name property name to read
179 * @param default_val default value to return if property doesn't exist
180 *
181 * Return: integer value of property or default_val if it doesn't exist.
182 */
cvmx_fdt_get_int(const void * fdt_addr,int node,const char * prop_name,int default_val)183 static inline int cvmx_fdt_get_int(const void *fdt_addr, int node, const char *prop_name,
184 int default_val)
185 {
186 return fdtdec_get_int(fdt_addr, node, prop_name, default_val);
187 }
188
cvmx_fdt_get_bool(const void * fdt_addr,int node,const char * prop_name)189 static inline bool cvmx_fdt_get_bool(const void *fdt_addr, int node, const char *prop_name)
190 {
191 return fdtdec_get_bool(fdt_addr, node, prop_name);
192 }
193
cvmx_fdt_get_uint64(const void * fdt_addr,int node,const char * prop_name,u64 default_val)194 static inline u64 cvmx_fdt_get_uint64(const void *fdt_addr, int node, const char *prop_name,
195 u64 default_val)
196 {
197 return fdtdec_get_uint64(fdt_addr, node, prop_name, default_val);
198 }
199
200 /**
201 * Look up a phandle and follow it to its node then return the offset of that
202 * node.
203 *
204 * @param[in] fdt_addr pointer to FDT blob
205 * @param node node to read phandle from
206 * @param[in] prop_name name of property to find
207 *
208 * Return: node offset if found, -ve error code on error
209 */
cvmx_fdt_lookup_phandle(const void * fdt_addr,int node,const char * prop_name)210 static inline int cvmx_fdt_lookup_phandle(const void *fdt_addr, int node, const char *prop_name)
211 {
212 return fdtdec_lookup_phandle(fdt_addr, node, prop_name);
213 }
214
215 /**
216 * Translate an address from the device tree into a CPU physical address by
217 * walking up the device tree and applying bus mappings along the way.
218 *
219 * This uses #size-cells and #address-cells.
220 *
221 * @param[in] fdt_addr Address of flat device tree
222 * @param node node to start translating from
223 * @param[in] in_addr Address to translate
224 * NOTE: in_addr must be in the native ENDIAN
225 * format.
226 *
227 * Return: Translated address or FDT_ADDR_T_NONE if address cannot be
228 * translated.
229 */
cvmx_fdt_translate_address(const void * fdt_addr,int node,const u32 * in_addr)230 static inline u64 cvmx_fdt_translate_address(const void *fdt_addr, int node, const u32 *in_addr)
231 {
232 return fdt_translate_address((void *)fdt_addr, node, in_addr);
233 }
234
235 /**
236 * Compare compatibile strings in the flat device tree.
237 *
238 * @param[in] s1 First string to compare
239 * @param[in] sw Second string to compare
240 *
241 * Return: 0 if no match
242 * 1 if only the part number matches and not the manufacturer
243 * 2 if both the part number and manufacturer match
244 */
245 int cvmx_fdt_compat_match(const char *s1, const char *s2);
246
247 /**
248 * Returns whether a list of strings contains the specified string
249 *
250 * @param[in] slist String list
251 * @param llen string list total length
252 * @param[in] str string to search for
253 *
254 * Return: 1 if string list contains string, 0 if it does not.
255 */
256 int cvmx_fdt_compat_list_contains(const char *slist, int llen, const char *str);
257
258 /**
259 * Check if a node is compatible with the specified compat string
260 *
261 * @param[in] fdt_addr FDT address
262 * @param node node offset to check
263 * @param[in] compat compatible string to check
264 *
265 * Return: 0 if compatible, 1 if not compatible, error if negative
266 */
267 int cvmx_fdt_node_check_compatible(const void *fdt_addr, int node, const char *compat);
268
269 /**
270 * @INTERNAL
271 * Compares a string to a compatible field.
272 *
273 * @param[in] compat compatible string
274 * @param[in] str string to check
275 *
276 * Return: 0 if not compatible, 1 if manufacturer compatible, 2 if
277 * part is compatible, 3 if both part and manufacturer are
278 * compatible.
279 */
280 int __cvmx_fdt_compat_match(const char *compat, const char *str);
281
282 /**
283 * Given a phandle to a GPIO device return the type of GPIO device it is.
284 *
285 * @param[in] fdt_addr Address of flat device tree
286 * @param phandle phandle to GPIO
287 * @param[out] size Number of pins (optional, may be NULL)
288 *
289 * Return: Type of GPIO device or PIN_ERROR if error
290 */
291 enum cvmx_gpio_type cvmx_fdt_get_gpio_type(const void *fdt_addr, int phandle, int *size);
292
293 /**
294 * Given a phandle to a GPIO node output the i2c bus and address
295 *
296 * @param[in] fdt_addr Address of FDT
297 * @param phandle phandle of GPIO device
298 * @param[out] bus TWSI bus number with node in bits 1-3, can be
299 * NULL for none.
300 * @param[out] addr TWSI address number, can be NULL for none
301 *
302 * Return: 0 for success, error otherwise
303 */
304 int cvmx_fdt_get_twsi_gpio_bus_addr(const void *fdt_addr, int phandle, int *bus, int *addr);
305
306 /**
307 * Given a FDT node return the CPU node number
308 *
309 * @param[in] fdt_addr Address of FDT
310 * @param node FDT node number
311 *
312 * Return: CPU node number or error if negative
313 */
314 int cvmx_fdt_get_cpu_node(const void *fdt_addr, int node);
315
316 /**
317 * Get the total size of the flat device tree
318 *
319 * @param[in] fdt_addr Address of FDT
320 *
321 * Return: Size of flat device tree in bytes or -1 if error.
322 */
323 int cvmx_fdt_get_fdt_size(const void *fdt_addr);
324
325 /**
326 * Returns if a node is compatible with one of the items in the string list
327 *
328 * @param[in] fdt_addr Pointer to flat device tree
329 * @param node Node offset to check
330 * @param[in] strlist Array of FDT device compatibility strings,
331 * must end with NULL or empty string.
332 *
333 * Return: 0 if at least one item matches, 1 if no matches
334 */
335 int cvmx_fdt_node_check_compatible_list(const void *fdt_addr, int node, const char *const *strlist);
336
337 /**
338 * Given a FDT node, return the next compatible node.
339 *
340 * @param[in] fdt_addr Pointer to flat device tree
341 * @param start_offset Starting node offset or -1 to find the first
342 * @param strlist Array of FDT device compatibility strings, must
343 * end with NULL or empty string.
344 *
345 * Return: next matching node or -1 if no more matches.
346 */
347 int cvmx_fdt_node_offset_by_compatible_list(const void *fdt_addr, int startoffset,
348 const char *const *strlist);
349
350 /**
351 * Given the parent offset of an i2c device build up a list describing the bus
352 * which can contain i2c muxes and switches.
353 *
354 * @param[in] node ofnode of the parent node of a GPIO device in
355 * the device tree.
356 *
357 * Return: pointer to list of i2c devices starting from the root which
358 * can include i2c muxes and switches or NULL if error. Note that
359 * all entries are allocated on the heap.
360 *
361 * @see cvmx_fdt_free_i2c_bus()
362 */
363 struct cvmx_fdt_i2c_bus_info *cvmx_ofnode_get_i2c_bus(ofnode node);
364
365 /**
366 * Return the Octeon bus number for a bus descriptor
367 *
368 * @param[in] bus bus descriptor
369 *
370 * Return: Octeon twsi bus number or -1 on error
371 */
372 int cvmx_fdt_i2c_get_root_bus(const struct cvmx_fdt_i2c_bus_info *bus);
373
374 /**
375 * Frees all entries for an i2c bus descriptor
376 *
377 * @param bus bus to free
378 *
379 * Return: 0
380 */
381 int cvmx_fdt_free_i2c_bus(struct cvmx_fdt_i2c_bus_info *bus);
382
383 /**
384 * Given the bus to a device, enable it.
385 *
386 * @param[in] bus i2c bus descriptor to enable or disable
387 * @param enable set to true to enable, false to disable
388 *
389 * Return: 0 for success or -1 for invalid bus
390 *
391 * This enables the entire bus including muxes and switches in the path.
392 */
393 int cvmx_fdt_enable_i2c_bus(const struct cvmx_fdt_i2c_bus_info *bus, bool enable);
394
395 /**
396 * Return a GPIO handle given a GPIO phandle of the form <&gpio pin flags>
397 *
398 * @param[in] fdt_addr Address of flat device tree
399 * @param of_offset node offset for property
400 * @param prop_name name of property
401 *
402 * Return: pointer to GPIO handle or NULL if error
403 */
404 struct cvmx_fdt_gpio_info *cvmx_fdt_gpio_get_info_phandle(const void *fdt_addr, int of_offset,
405 const char *prop_name);
406
407 /**
408 * Sets a GPIO pin given the GPIO descriptor
409 *
410 * @param pin GPIO pin descriptor
411 * @param value value to set it to, 0 or 1
412 *
413 * Return: 0 on success, -1 on error.
414 *
415 * NOTE: If the CVMX_GPIO_ACTIVE_LOW flag is set then the output value will be
416 * inverted.
417 */
418 int cvmx_fdt_gpio_set(struct cvmx_fdt_gpio_info *pin, int value);
419
420 /**
421 * Given a GPIO pin descriptor, input the value of that pin
422 *
423 * @param pin GPIO pin descriptor
424 *
425 * Return: 0 if low, 1 if high, -1 on error. Note that the input will be
426 * inverted if the CVMX_GPIO_ACTIVE_LOW flag bit is set.
427 */
428 int cvmx_fdt_gpio_get(struct cvmx_fdt_gpio_info *pin);
429
430 /**
431 * Assigns an IPD port to a SFP slot
432 *
433 * @param sfp Handle to SFP data structure
434 * @param ipd_port Port to assign it to
435 *
436 * Return: 0 for success, -1 on error
437 */
438 int cvmx_sfp_set_ipd_port(struct cvmx_fdt_sfp_info *sfp, int ipd_port);
439
440 /**
441 * Get the IPD port of a SFP slot
442 *
443 * @param[in] sfp Handle to SFP data structure
444 *
445 * Return: IPD port number for SFP slot
446 */
cvmx_sfp_get_ipd_port(const struct cvmx_fdt_sfp_info * sfp)447 static inline int cvmx_sfp_get_ipd_port(const struct cvmx_fdt_sfp_info *sfp)
448 {
449 return sfp->ipd_port[0];
450 }
451
452 /**
453 * Get the IPD ports for a QSFP port
454 *
455 * @param[in] sfp Handle to SFP data structure
456 * @param[out] ipd_ports IPD ports for each lane, if running as 40G then
457 * only ipd_ports[0] is valid and the others will
458 * be set to -1.
459 */
cvmx_qsfp_get_ipd_ports(const struct cvmx_fdt_sfp_info * sfp,int ipd_ports[4])460 static inline void cvmx_qsfp_get_ipd_ports(const struct cvmx_fdt_sfp_info *sfp, int ipd_ports[4])
461 {
462 int i;
463
464 for (i = 0; i < 4; i++)
465 ipd_ports[i] = sfp->ipd_port[i];
466 }
467
468 /**
469 * Attaches a PHY to a SFP or QSFP.
470 *
471 * @param sfp sfp to attach PHY to
472 * @param phy_info phy descriptor to attach or NULL to detach
473 */
474 void cvmx_sfp_attach_phy(struct cvmx_fdt_sfp_info *sfp, struct cvmx_phy_info *phy_info);
475
476 /**
477 * Returns a phy descriptor for a SFP slot
478 *
479 * @param[in] sfp SFP to get phy info from
480 *
481 * Return: phy descriptor or NULL if none.
482 */
cvmx_sfp_get_phy_info(const struct cvmx_fdt_sfp_info * sfp)483 static inline struct cvmx_phy_info *cvmx_sfp_get_phy_info(const struct cvmx_fdt_sfp_info *sfp)
484 {
485 return sfp->phy_info;
486 }
487
488 /**
489 * @INTERNAL
490 * Parses all instances of the Vitesse VSC7224 reclocking chip
491 *
492 * @param[in] fdt_addr Address of flat device tree
493 *
494 * Return: 0 for success, error otherwise
495 */
496 int __cvmx_fdt_parse_vsc7224(const void *fdt_addr);
497
498 /**
499 * @INTERNAL
500 * Parses all instances of the Avago AVSP5410 gearbox phy
501 *
502 * @param[in] fdt_addr Address of flat device tree
503 *
504 * Return: 0 for success, error otherwise
505 */
506 int __cvmx_fdt_parse_avsp5410(const void *fdt_addr);
507
508 /**
509 * @INTERNAL
510 * Parses either a CS4343 phy or a slice of the phy from the device tree
511 * @param[in] fdt_addr Address of FDT
512 * @param of_offset offset of slice or phy in device tree
513 * @param phy_info phy_info data structure to fill in
514 *
515 * Return: 0 for success, -1 on error
516 */
517 int cvmx_fdt_parse_cs4343(const void *fdt_addr, int of_offset, struct cvmx_phy_info *phy_info);
518
519 /**
520 * Given an i2c bus and device address, write an 8 bit value
521 *
522 * @param bus i2c bus number
523 * @param addr i2c device address (7 bits)
524 * @param val 8-bit value to write
525 *
526 * This is just an abstraction to ease support in both U-Boot and SE.
527 */
528 void cvmx_fdt_i2c_reg_write(int bus, int addr, u8 val);
529
530 /**
531 * Read an 8-bit value from an i2c bus and device address
532 *
533 * @param bus i2c bus number
534 * @param addr i2c device address (7 bits)
535 *
536 * Return: 8-bit value or error if negative
537 */
538 int cvmx_fdt_i2c_reg_read(int bus, int addr);
539
540 /**
541 * Write an 8-bit value to a register indexed i2c device
542 *
543 * @param bus i2c bus number to write to
544 * @param addr i2c device address (7 bits)
545 * @param reg i2c 8-bit register address
546 * @param val 8-bit value to write
547 *
548 * Return: 0 for success, otherwise error
549 */
550 int cvmx_fdt_i2c_write8(int bus, int addr, int reg, u8 val);
551
552 /**
553 * Read an 8-bit value from a register indexed i2c device
554 *
555 * @param bus i2c bus number to write to
556 * @param addr i2c device address (7 bits)
557 * @param reg i2c 8-bit register address
558 *
559 * Return: value or error if negative
560 */
561 int cvmx_fdt_i2c_read8(int bus, int addr, int reg);
562
563 int cvmx_sfp_vsc7224_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp_info,
564 int val, void *data);
565 int cvmx_sfp_avsp5410_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp_info,
566 int val, void *data);
567
568 #endif /* CVMX_HELPER_FDT_H__ */
569