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