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