| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright (C) 2020 Marvell International Ltd. |
| * |
| * FDT Helper functions similar to those provided to U-Boot. |
| * If compiled for U-Boot, just provide wrappers to the equivalent U-Boot |
| * functions. |
| */ |
| |
| #ifndef __CVMX_HELPER_FDT_H__ |
| #define __CVMX_HELPER_FDT_H__ |
| |
| #include <fdt_support.h> |
| #include <fdtdec.h> |
| #include <time.h> |
| #include <asm/global_data.h> |
| #include <linux/libfdt.h> |
| |
| #include <mach/cvmx-helper-sfp.h> |
| |
| enum cvmx_i2c_bus_type { |
| CVMX_I2C_BUS_OCTEON, |
| CVMX_I2C_MUX_PCA9540, |
| CVMX_I2C_MUX_PCA9542, |
| CVMX_I2C_MUX_PCA9543, |
| CVMX_I2C_MUX_PCA9544, |
| CVMX_I2C_MUX_PCA9545, |
| CVMX_I2C_MUX_PCA9546, |
| CVMX_I2C_MUX_PCA9547, |
| CVMX_I2C_MUX_PCA9548, |
| CVMX_I2C_MUX_OTHER |
| }; |
| |
| struct cvmx_sfp_mod_info; /** Defined in cvmx-helper-sfp.h */ |
| struct cvmx_phy_info; /** Defined in cvmx-helper-board.h */ |
| |
| /** |
| * This data structure holds information about various I2C muxes and switches |
| * that may be between a device and the Octeon chip. |
| */ |
| struct cvmx_fdt_i2c_bus_info { |
| /** Parent I2C bus, NULL if root */ |
| struct cvmx_fdt_i2c_bus_info *parent; |
| /** Child I2C bus or NULL if last entry in the chain */ |
| struct cvmx_fdt_i2c_bus_info *child; |
| /** Offset in device tree */ |
| int of_offset; |
| /** Type of i2c bus or mux */ |
| enum cvmx_i2c_bus_type type; |
| /** I2C address of mux */ |
| u8 i2c_addr; |
| /** Mux channel number */ |
| u8 channel; |
| /** For muxes, the bit(s) to set to enable them */ |
| u8 enable_bit; |
| /** True if mux, false if switch */ |
| bool is_mux; |
| }; |
| |
| /** |
| * Data structure containing information about SFP/QSFP slots |
| */ |
| struct cvmx_fdt_sfp_info { |
| /** Used for a linked list of slots */ |
| struct cvmx_fdt_sfp_info *next, *prev; |
| /** Used when multiple SFP ports share the same IPD port */ |
| struct cvmx_fdt_sfp_info *next_iface_sfp; |
| /** Name from device tree of slot */ |
| const char *name; |
| /** I2C bus for slot EEPROM */ |
| struct cvmx_fdt_i2c_bus_info *i2c_bus; |
| /** Data from SFP or QSFP EEPROM */ |
| struct cvmx_sfp_mod_info sfp_info; |
| /** Data structure with PHY information */ |
| struct cvmx_phy_info *phy_info; |
| /** IPD port(s) slot is connected to */ |
| int ipd_port[4]; |
| /** Offset in device tree of slot */ |
| int of_offset; |
| /** EEPROM address of SFP module (usually 0x50) */ |
| u8 i2c_eeprom_addr; |
| /** Diagnostic address of SFP module (usually 0x51) */ |
| u8 i2c_diag_addr; |
| /** True if QSFP module */ |
| bool is_qsfp; |
| /** True if EEPROM data is valid */ |
| bool valid; |
| /** SFP tx_disable GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *tx_disable; |
| /** SFP mod_abs/QSFP mod_prs GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *mod_abs; |
| /** SFP tx_error GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *tx_error; |
| /** SFP rx_los GPIO discriptor */ |
| struct cvmx_fdt_gpio_info *rx_los; |
| /** QSFP select GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *select; |
| /** QSFP reset GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *reset; |
| /** QSFP interrupt GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *interrupt; |
| /** QSFP lp_mode GPIO descriptor */ |
| struct cvmx_fdt_gpio_info *lp_mode; |
| /** Last mod_abs value */ |
| int last_mod_abs; |
| /** Last rx_los value */ |
| int last_rx_los; |
| /** Function to call to check mod_abs */ |
| int (*check_mod_abs)(struct cvmx_fdt_sfp_info *sfp_info, void *data); |
| /** User-defined data to pass to check_mod_abs */ |
| void *mod_abs_data; |
| /** Function to call when mod_abs changes */ |
| int (*mod_abs_changed)(struct cvmx_fdt_sfp_info *sfp_info, int val, void *data); |
| /** User-defined data to pass to mod_abs_changed */ |
| void *mod_abs_changed_data; |
| /** Function to call when rx_los changes */ |
| int (*rx_los_changed)(struct cvmx_fdt_sfp_info *sfp_info, int val, void *data); |
| /** User-defined data to pass to rx_los_changed */ |
| void *rx_los_changed_data; |
| /** True if we're connected to a Microsemi VSC7224 reclocking chip */ |
| bool is_vsc7224; |
| /** Data structure for first vsc7224 channel we're attached to */ |
| struct cvmx_vsc7224_chan *vsc7224_chan; |
| /** True if we're connected to a Avago AVSP5410 phy */ |
| bool is_avsp5410; |
| /** Data structure for avsp5410 phy we're attached to */ |
| struct cvmx_avsp5410 *avsp5410; |
| /** xinterface we're on */ |
| int xiface; |
| /** port index */ |
| int index; |
| }; |
| |
| /** |
| * Look up a phandle and follow it to its node then return the offset of that |
| * node. |
| * |
| * @param[in] fdt_addr pointer to FDT blob |
| * @param node node to read phandle from |
| * @param[in] prop_name name of property to find |
| * @param[in,out] lenp Number of phandles, input max number |
| * @param[out] nodes Array of phandle nodes |
| * |
| * @return -ve error code on error or 0 for success |
| */ |
| int cvmx_fdt_lookup_phandles(const void *fdt_addr, int node, const char *prop_name, int *lenp, |
| int *nodes); |
| |
| /** |
| * Helper to return the address property |
| * |
| * @param[in] fdt_addr pointer to FDT blob |
| * @param node node to read address from |
| * @param prop_name property name to read |
| * |
| * @return address of property or FDT_ADDR_T_NONE if not found |
| */ |
| static inline fdt_addr_t cvmx_fdt_get_addr(const void *fdt_addr, int node, const char *prop_name) |
| { |
| return fdtdec_get_addr(fdt_addr, node, prop_name); |
| } |
| |
| /** |
| * Helper function to return an integer property |
| * |
| * @param[in] fdt_addr pointer to FDT blob |
| * @param node node to read integer from |
| * @param[in] prop_name property name to read |
| * @param default_val default value to return if property doesn't exist |
| * |
| * @return integer value of property or default_val if it doesn't exist. |
| */ |
| static inline int cvmx_fdt_get_int(const void *fdt_addr, int node, const char *prop_name, |
| int default_val) |
| { |
| return fdtdec_get_int(fdt_addr, node, prop_name, default_val); |
| } |
| |
| static inline bool cvmx_fdt_get_bool(const void *fdt_addr, int node, const char *prop_name) |
| { |
| return fdtdec_get_bool(fdt_addr, node, prop_name); |
| } |
| |
| static inline u64 cvmx_fdt_get_uint64(const void *fdt_addr, int node, const char *prop_name, |
| u64 default_val) |
| { |
| return fdtdec_get_uint64(fdt_addr, node, prop_name, default_val); |
| } |
| |
| /** |
| * Look up a phandle and follow it to its node then return the offset of that |
| * node. |
| * |
| * @param[in] fdt_addr pointer to FDT blob |
| * @param node node to read phandle from |
| * @param[in] prop_name name of property to find |
| * |
| * @return node offset if found, -ve error code on error |
| */ |
| static inline int cvmx_fdt_lookup_phandle(const void *fdt_addr, int node, const char *prop_name) |
| { |
| return fdtdec_lookup_phandle(fdt_addr, node, prop_name); |
| } |
| |
| /** |
| * Translate an address from the device tree into a CPU physical address by |
| * walking up the device tree and applying bus mappings along the way. |
| * |
| * This uses #size-cells and #address-cells. |
| * |
| * @param[in] fdt_addr Address of flat device tree |
| * @param node node to start translating from |
| * @param[in] in_addr Address to translate |
| * NOTE: in_addr must be in the native ENDIAN |
| * format. |
| * |
| * @return Translated address or FDT_ADDR_T_NONE if address cannot be |
| * translated. |
| */ |
| static inline u64 cvmx_fdt_translate_address(const void *fdt_addr, int node, const u32 *in_addr) |
| { |
| return fdt_translate_address((void *)fdt_addr, node, in_addr); |
| } |
| |
| /** |
| * Compare compatibile strings in the flat device tree. |
| * |
| * @param[in] s1 First string to compare |
| * @param[in] sw Second string to compare |
| * |
| * @return 0 if no match |
| * 1 if only the part number matches and not the manufacturer |
| * 2 if both the part number and manufacturer match |
| */ |
| int cvmx_fdt_compat_match(const char *s1, const char *s2); |
| |
| /** |
| * Returns whether a list of strings contains the specified string |
| * |
| * @param[in] slist String list |
| * @param llen string list total length |
| * @param[in] str string to search for |
| * |
| * @return 1 if string list contains string, 0 if it does not. |
| */ |
| int cvmx_fdt_compat_list_contains(const char *slist, int llen, const char *str); |
| |
| /** |
| * Check if a node is compatible with the specified compat string |
| * |
| * @param[in] fdt_addr FDT address |
| * @param node node offset to check |
| * @param[in] compat compatible string to check |
| * |
| * @return 0 if compatible, 1 if not compatible, error if negative |
| */ |
| int cvmx_fdt_node_check_compatible(const void *fdt_addr, int node, const char *compat); |
| |
| /** |
| * @INTERNAL |
| * Compares a string to a compatible field. |
| * |
| * @param[in] compat compatible string |
| * @param[in] str string to check |
| * |
| * @return 0 if not compatible, 1 if manufacturer compatible, 2 if |
| * part is compatible, 3 if both part and manufacturer are |
| * compatible. |
| */ |
| int __cvmx_fdt_compat_match(const char *compat, const char *str); |
| |
| /** |
| * Given a phandle to a GPIO device return the type of GPIO device it is. |
| * |
| * @param[in] fdt_addr Address of flat device tree |
| * @param phandle phandle to GPIO |
| * @param[out] size Number of pins (optional, may be NULL) |
| * |
| * @return Type of GPIO device or PIN_ERROR if error |
| */ |
| enum cvmx_gpio_type cvmx_fdt_get_gpio_type(const void *fdt_addr, int phandle, int *size); |
| |
| /** |
| * Given a phandle to a GPIO node output the i2c bus and address |
| * |
| * @param[in] fdt_addr Address of FDT |
| * @param phandle phandle of GPIO device |
| * @param[out] bus TWSI bus number with node in bits 1-3, can be |
| * NULL for none. |
| * @param[out] addr TWSI address number, can be NULL for none |
| * |
| * @return 0 for success, error otherwise |
| */ |
| int cvmx_fdt_get_twsi_gpio_bus_addr(const void *fdt_addr, int phandle, int *bus, int *addr); |
| |
| /** |
| * Given a FDT node return the CPU node number |
| * |
| * @param[in] fdt_addr Address of FDT |
| * @param node FDT node number |
| * |
| * @return CPU node number or error if negative |
| */ |
| int cvmx_fdt_get_cpu_node(const void *fdt_addr, int node); |
| |
| /** |
| * Get the total size of the flat device tree |
| * |
| * @param[in] fdt_addr Address of FDT |
| * |
| * @return Size of flat device tree in bytes or -1 if error. |
| */ |
| int cvmx_fdt_get_fdt_size(const void *fdt_addr); |
| |
| /** |
| * Returns if a node is compatible with one of the items in the string list |
| * |
| * @param[in] fdt_addr Pointer to flat device tree |
| * @param node Node offset to check |
| * @param[in] strlist Array of FDT device compatibility strings, |
| * must end with NULL or empty string. |
| * |
| * @return 0 if at least one item matches, 1 if no matches |
| */ |
| int cvmx_fdt_node_check_compatible_list(const void *fdt_addr, int node, const char *const *strlist); |
| |
| /** |
| * Given a FDT node, return the next compatible node. |
| * |
| * @param[in] fdt_addr Pointer to flat device tree |
| * @param start_offset Starting node offset or -1 to find the first |
| * @param strlist Array of FDT device compatibility strings, must |
| * end with NULL or empty string. |
| * |
| * @return next matching node or -1 if no more matches. |
| */ |
| int cvmx_fdt_node_offset_by_compatible_list(const void *fdt_addr, int startoffset, |
| const char *const *strlist); |
| |
| /** |
| * Given the parent offset of an i2c device build up a list describing the bus |
| * which can contain i2c muxes and switches. |
| * |
| * @param[in] fdt_addr address of device tree |
| * @param of_offset Offset of the parent node of a GPIO device in |
| * the device tree. |
| * |
| * @return pointer to list of i2c devices starting from the root which |
| * can include i2c muxes and switches or NULL if error. Note that |
| * all entries are allocated on the heap. |
| * |
| * @see cvmx_fdt_free_i2c_bus() |
| */ |
| struct cvmx_fdt_i2c_bus_info *cvmx_fdt_get_i2c_bus(const void *fdt_addr, int of_offset); |
| |
| /** |
| * Return the Octeon bus number for a bus descriptor |
| * |
| * @param[in] bus bus descriptor |
| * |
| * @return Octeon twsi bus number or -1 on error |
| */ |
| int cvmx_fdt_i2c_get_root_bus(const struct cvmx_fdt_i2c_bus_info *bus); |
| |
| /** |
| * Frees all entries for an i2c bus descriptor |
| * |
| * @param bus bus to free |
| * |
| * @return 0 |
| */ |
| int cvmx_fdt_free_i2c_bus(struct cvmx_fdt_i2c_bus_info *bus); |
| |
| /** |
| * Given the bus to a device, enable it. |
| * |
| * @param[in] bus i2c bus descriptor to enable or disable |
| * @param enable set to true to enable, false to disable |
| * |
| * @return 0 for success or -1 for invalid bus |
| * |
| * This enables the entire bus including muxes and switches in the path. |
| */ |
| int cvmx_fdt_enable_i2c_bus(const struct cvmx_fdt_i2c_bus_info *bus, bool enable); |
| |
| /** |
| * Return a GPIO handle given a GPIO phandle of the form <&gpio pin flags> |
| * |
| * @param[in] fdt_addr Address of flat device tree |
| * @param of_offset node offset for property |
| * @param prop_name name of property |
| * |
| * @return pointer to GPIO handle or NULL if error |
| */ |
| struct cvmx_fdt_gpio_info *cvmx_fdt_gpio_get_info_phandle(const void *fdt_addr, int of_offset, |
| const char *prop_name); |
| |
| /** |
| * Sets a GPIO pin given the GPIO descriptor |
| * |
| * @param pin GPIO pin descriptor |
| * @param value value to set it to, 0 or 1 |
| * |
| * @return 0 on success, -1 on error. |
| * |
| * NOTE: If the CVMX_GPIO_ACTIVE_LOW flag is set then the output value will be |
| * inverted. |
| */ |
| int cvmx_fdt_gpio_set(struct cvmx_fdt_gpio_info *pin, int value); |
| |
| /** |
| * Given a GPIO pin descriptor, input the value of that pin |
| * |
| * @param pin GPIO pin descriptor |
| * |
| * @return 0 if low, 1 if high, -1 on error. Note that the input will be |
| * inverted if the CVMX_GPIO_ACTIVE_LOW flag bit is set. |
| */ |
| int cvmx_fdt_gpio_get(struct cvmx_fdt_gpio_info *pin); |
| |
| /** |
| * Assigns an IPD port to a SFP slot |
| * |
| * @param sfp Handle to SFP data structure |
| * @param ipd_port Port to assign it to |
| * |
| * @return 0 for success, -1 on error |
| */ |
| int cvmx_sfp_set_ipd_port(struct cvmx_fdt_sfp_info *sfp, int ipd_port); |
| |
| /** |
| * Get the IPD port of a SFP slot |
| * |
| * @param[in] sfp Handle to SFP data structure |
| * |
| * @return IPD port number for SFP slot |
| */ |
| static inline int cvmx_sfp_get_ipd_port(const struct cvmx_fdt_sfp_info *sfp) |
| { |
| return sfp->ipd_port[0]; |
| } |
| |
| /** |
| * Get the IPD ports for a QSFP port |
| * |
| * @param[in] sfp Handle to SFP data structure |
| * @param[out] ipd_ports IPD ports for each lane, if running as 40G then |
| * only ipd_ports[0] is valid and the others will |
| * be set to -1. |
| */ |
| static inline void cvmx_qsfp_get_ipd_ports(const struct cvmx_fdt_sfp_info *sfp, int ipd_ports[4]) |
| { |
| int i; |
| |
| for (i = 0; i < 4; i++) |
| ipd_ports[i] = sfp->ipd_port[i]; |
| } |
| |
| /** |
| * Attaches a PHY to a SFP or QSFP. |
| * |
| * @param sfp sfp to attach PHY to |
| * @param phy_info phy descriptor to attach or NULL to detach |
| */ |
| void cvmx_sfp_attach_phy(struct cvmx_fdt_sfp_info *sfp, struct cvmx_phy_info *phy_info); |
| |
| /** |
| * Returns a phy descriptor for a SFP slot |
| * |
| * @param[in] sfp SFP to get phy info from |
| * |
| * @return phy descriptor or NULL if none. |
| */ |
| static inline struct cvmx_phy_info *cvmx_sfp_get_phy_info(const struct cvmx_fdt_sfp_info *sfp) |
| { |
| return sfp->phy_info; |
| } |
| |
| /** |
| * @INTERNAL |
| * Parses all instances of the Vitesse VSC7224 reclocking chip |
| * |
| * @param[in] fdt_addr Address of flat device tree |
| * |
| * @return 0 for success, error otherwise |
| */ |
| int __cvmx_fdt_parse_vsc7224(const void *fdt_addr); |
| |
| /** |
| * @INTERNAL |
| * Parses all instances of the Avago AVSP5410 gearbox phy |
| * |
| * @param[in] fdt_addr Address of flat device tree |
| * |
| * @return 0 for success, error otherwise |
| */ |
| int __cvmx_fdt_parse_avsp5410(const void *fdt_addr); |
| |
| /** |
| * Parse SFP information from device tree |
| * |
| * @param[in] fdt_addr Address of flat device tree |
| * |
| * @return pointer to sfp info or NULL if error |
| */ |
| struct cvmx_fdt_sfp_info *cvmx_helper_fdt_parse_sfp_info(const void *fdt_addr, int of_offset); |
| |
| /** |
| * @INTERNAL |
| * Parses either a CS4343 phy or a slice of the phy from the device tree |
| * @param[in] fdt_addr Address of FDT |
| * @param of_offset offset of slice or phy in device tree |
| * @param phy_info phy_info data structure to fill in |
| * |
| * @return 0 for success, -1 on error |
| */ |
| int cvmx_fdt_parse_cs4343(const void *fdt_addr, int of_offset, struct cvmx_phy_info *phy_info); |
| |
| /** |
| * Given an i2c bus and device address, write an 8 bit value |
| * |
| * @param bus i2c bus number |
| * @param addr i2c device address (7 bits) |
| * @param val 8-bit value to write |
| * |
| * This is just an abstraction to ease support in both U-Boot and SE. |
| */ |
| void cvmx_fdt_i2c_reg_write(int bus, int addr, u8 val); |
| |
| /** |
| * Read an 8-bit value from an i2c bus and device address |
| * |
| * @param bus i2c bus number |
| * @param addr i2c device address (7 bits) |
| * |
| * @return 8-bit value or error if negative |
| */ |
| int cvmx_fdt_i2c_reg_read(int bus, int addr); |
| |
| /** |
| * Write an 8-bit value to a register indexed i2c device |
| * |
| * @param bus i2c bus number to write to |
| * @param addr i2c device address (7 bits) |
| * @param reg i2c 8-bit register address |
| * @param val 8-bit value to write |
| * |
| * @return 0 for success, otherwise error |
| */ |
| int cvmx_fdt_i2c_write8(int bus, int addr, int reg, u8 val); |
| |
| /** |
| * Read an 8-bit value from a register indexed i2c device |
| * |
| * @param bus i2c bus number to write to |
| * @param addr i2c device address (7 bits) |
| * @param reg i2c 8-bit register address |
| * |
| * @return value or error if negative |
| */ |
| int cvmx_fdt_i2c_read8(int bus, int addr, int reg); |
| |
| int cvmx_sfp_vsc7224_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp_info, |
| int val, void *data); |
| int cvmx_sfp_avsp5410_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp_info, |
| int val, void *data); |
| |
| #endif /* CVMX_HELPER_FDT_H__ */ |