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 */ 24enum 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 37struct cvmx_sfp_mod_info; /** Defined in cvmx-helper-sfp.h */ 38struct 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 */ 44struct 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 */ 68struct 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 */ 153int cvmx_fdt_lookup_phandles(const void *fdt_addr, int node, const char *prop_name, int *lenp, 154 int *nodes); 155 156int 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 */ 168static 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 */ 183static 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 189static 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 194static 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 */ 210static 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 */ 230static 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 */ 245int 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 */ 256int 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 */ 267int 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 */ 280int __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 */ 291enum 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 */ 304int 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 */ 314int 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 */ 323int 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 */ 335int 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 */ 347int 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 */ 363struct 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 */ 372int 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 */ 381int 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 */ 393int 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 */ 404struct 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 */ 418int 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 */ 428int 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 */ 438int 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 */ 447static 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 */ 460static 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 */ 474void 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 */ 483static 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 */ 496int __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 */ 506int __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 */ 517int 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 */ 528void 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 */ 538int 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 */ 550int 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 */ 561int cvmx_fdt_i2c_read8(int bus, int addr, int reg); 562 563int cvmx_sfp_vsc7224_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp_info, 564 int val, void *data); 565int 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