1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2020 Marvell International Ltd.
4  *
5  * Helper functions to abstract SFP and QSFP connectors
6  */
7 
8 #ifndef __CVMX_HELPER_SFP_H__
9 #define __CVMX_HELPER_SFP_H__
10 
11 /**
12  * Maximum size for the SFP EEPROM.  Currently only 96 bytes are used.
13  */
14 #define CVMX_SFP_MAX_EEPROM_SIZE 0x100
15 
16 /**
17  * Default address of sfp EEPROM
18  */
19 #define CVMX_SFP_DEFAULT_I2C_ADDR 0x50
20 
21 /**
22  * Default address of SFP diagnostics chip
23  */
24 #define CVMX_SFP_DEFAULT_DIAG_I2C_ADDR 0x51
25 
26 struct cvmx_fdt_sfp_info;
27 struct cvmx_fdt_gpio_info;
28 /**
29  * Connector type for module, usually we only see SFP and QSFPP
30  */
31 enum cvmx_phy_sfp_conn_type {
32 	CVMX_SFP_CONN_GBIC = 0x01,	 /** GBIC */
33 	CVMX_SFP_CONN_SFP = 0x03,	 /** SFP/SFP+/SFP28 */
34 	CVMX_SFP_CONN_QSFP = 0x0C,	 /** 1G QSFP (obsolete) */
35 	CVMX_SFP_CONN_QSFPP = 0x0D,	 /** QSFP+ or later */
36 	CVMX_SFP_CONN_QSFP28 = 0x11,	 /** QSFP28 (100Gbps) */
37 	CVMX_SFP_CONN_MICRO_QSFP = 0x17, /** Micro QSFP */
38 	CVMX_SFP_CONN_QSFP_DD = 0x18,	 /** QSFP-DD Double Density 8X */
39 	CVMX_SFP_CONN_SFP_DD = 0x1A,	 /** SFP-DD Double Density 2X */
40 };
41 
42 /**
43  * module type plugged into a SFP/SFP+/QSFP+ port
44  */
45 enum cvmx_phy_sfp_mod_type {
46 	CVMX_SFP_MOD_UNKNOWN = 0, /** Unknown or unspecified */
47 	/** Fiber optic module (LC connector) */
48 	CVMX_SFP_MOD_OPTICAL_LC = 0x7,
49 	/** Multiple optical */
50 	CVMX_SFP_MOD_MULTIPLE_OPTICAL = 0x9,
51 	/** Fiber optic module (pigtail, no connector) */
52 	CVMX_SFP_MOD_OPTICAL_PIGTAIL = 0xB,
53 	CVMX_SFP_MOD_COPPER_PIGTAIL = 0x21, /** copper module */
54 	CVMX_SFP_MOD_RJ45 = 0x22,	    /** RJ45 (i.e. 10GBase-T) */
55 	/** No separable connector (SFP28/copper) */
56 	CVMX_SFP_MOD_NO_SEP_CONN = 0x23,
57 	/** MXC 2X16 */
58 	CVMX_SFP_MOD_MXC_2X16 = 0x24,
59 	/** CS optical connector */
60 	CVMX_SFP_MOD_CS_OPTICAL = 0x25,
61 	/** Mini CS optical connector */
62 	CVMX_SFP_MOD_MINI_CS_OPTICAL = 0x26,
63 	/** Unknown/other module type */
64 	CVMX_SFP_MOD_OTHER
65 };
66 
67 /** Peak rate supported by SFP cable */
68 enum cvmx_phy_sfp_rate {
69 	CVMX_SFP_RATE_UNKNOWN, /** Unknown rate */
70 	CVMX_SFP_RATE_1G,      /** 1Gbps */
71 	CVMX_SFP_RATE_10G,     /** 10Gbps */
72 	CVMX_SFP_RATE_25G,     /** 25Gbps */
73 	CVMX_SFP_RATE_40G,     /** 40Gbps */
74 	CVMX_SFP_RATE_100G     /** 100Gbps */
75 };
76 
77 /**
78  * Cable compliance specification
79  * See table 4-4 from SFF-8024 for the extended specification compliance codes
80  */
81 enum cvmx_phy_sfp_cable_ext_compliance {
82 	CVMX_SFP_CABLE_UNSPEC = 0,
83 	CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_HIGH_BER = 0x01, /** Active optical cable */
84 	CVMX_SFP_CABLE_100G_SR4_25G_SR = 0x2,
85 	CVMX_SFP_CABLE_100G_LR4_25G_LR = 0x3,
86 	CVMX_SFP_CABLE_100G_ER4_25G_ER = 0x4,
87 	CVMX_SFP_CABLE_100G_SR10 = 0x5,
88 	CVMX_SFP_CABLE_100G_CWDM4_MSA = 0x6,
89 	CVMX_SFP_CABLE_100G_PSM4 = 0x7,
90 	CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_HIGH_BER = 0x8,
91 	CVMX_SFP_CABLE_100G_CWDM4 = 0x9,
92 	CVMX_SFP_CABLE_100G_CR4_25G_CR_CA_L = 0xB,
93 	CVMX_SFP_CABLE_25G_CR_CA_S = 0xC,
94 	CVMX_SFP_CABLE_25G_CR_CA_N = 0xD,
95 	CVMX_SFP_CABLE_40G_ER4 = 0x10,
96 	CVMX_SFP_CABLE_4X10G_SR = 0x11,
97 	CVMX_SFP_CABLE_40G_PSM4 = 0x12,
98 	CVMX_SFP_CABLE_G959_1_P1I1_2D1 = 0x13,
99 	CVMX_SFP_CABLE_G959_1_P1S1_2D2 = 0x14,
100 	CVMX_SFP_CABLE_G959_1_P1L1_2D2 = 0x15,
101 	CVMX_SFP_CABLE_10GBASE_T = 0x16,
102 	CVMX_SFP_CABLE_100G_CLR4 = 0x17,
103 	CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_LOW_BER = 0x18,
104 	CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_LOW_BER = 0x19,
105 	CVMX_SFP_CABLE_100G_2_LAMBDA_DWDM = 0x1a,
106 	CVMX_SFP_CABLE_100G_1550NM_WDM = 0x1b,
107 	CVMX_SFP_CABLE_10GBASE_T_SR = 0x1c,
108 	CVMX_SFP_CABLE_5GBASE_T = 0x1d,
109 	CVMX_SFP_CABLE_2_5GBASE_T = 0x1e,
110 	CVMX_SFP_CABLE_40G_SWDM4 = 0x1f,
111 	CVMX_SFP_CABLE_100G_SWDM4 = 0x20,
112 	CVMX_SFP_CABLE_100G_PAM4_BIDI = 0x21,
113 	CVMX_SFP_CABLE_100G_4WDM_10_FEC_HOST = 0x22,
114 	CVMX_SFP_CABLE_100G_4WDM_20_FEC_HOST = 0x23,
115 	CVMX_SFP_CABLE_100G_4WDM_40_FEC_HOST = 0x24,
116 	CVMX_SFP_CABLE_100GBASE_DR_CAUI4_NO_FEC = 0x25,
117 	CVMX_SFP_CABLE_100G_FR_CAUI4_NO_FEC = 0x26,
118 	CVMX_SFP_CABLE_100G_LR_CAUI4_NO_FEC = 0x27,
119 	CVMX_SFP_CABLE_ACTIVE_COPPER_50_100_200GAUI_LOW_BER = 0x30,
120 	CVMX_SFP_CABLE_ACTIVE_OPTICAL_50_100_200GAUI_LOW_BER = 0x31,
121 	CVMX_SFP_CABLE_ACTIVE_COPPER_50_100_200GAUI_HI_BER = 0x32,
122 	CVMX_SFP_CABLE_ACTIVE_OPTICAL_50_100_200GAUI_HI_BER = 0x33,
123 	CVMX_SFP_CABLE_50_100_200G_CR = 0x40,
124 	CVMX_SFP_CABLE_50_100_200G_SR = 0x41,
125 	CVMX_SFP_CABLE_50GBASE_FR_200GBASE_DR4 = 0x42,
126 	CVMX_SFP_CABLE_200GBASE_FR4 = 0x43,
127 	CVMX_SFP_CABLE_200G_1550NM_PSM4 = 0x44,
128 	CVMX_SFP_CABLE_50GBASE_LR = 0x45,
129 	CVMX_SFP_CABLE_200GBASE_LR4 = 0x46,
130 	CVMX_SFP_CABLE_64GFC_EA = 0x50,
131 	CVMX_SFP_CABLE_64GFC_SW = 0x51,
132 	CVMX_SFP_CABLE_64GFC_LW = 0x52,
133 	CVMX_SFP_CABLE_128GFC_EA = 0x53,
134 	CVMX_SFP_CABLE_128GFC_SW = 0x54,
135 	CVMX_SFP_CABLE_128GFC_LW = 0x55,
136 
137 };
138 
139 /** Optical modes module is compliant with */
140 enum cvmx_phy_sfp_10g_eth_compliance {
141 	CVMX_SFP_CABLE_10GBASE_ER = 0x80,  /** 10G ER */
142 	CVMX_SFP_CABLE_10GBASE_LRM = 0x40, /** 10G LRM */
143 	CVMX_SFP_CABLE_10GBASE_LR = 0x20,  /** 10G LR */
144 	CVMX_SFP_CABLE_10GBASE_SR = 0x10   /** 10G SR */
145 };
146 
147 /** Diagnostic ASIC compatibility */
148 enum cvmx_phy_sfp_sff_8472_diag_rev {
149 	CVMX_SFP_SFF_8472_NO_DIAG = 0x00,
150 	CVMX_SFP_SFF_8472_REV_9_3 = 0x01,
151 	CVMX_SFP_SFF_8472_REV_9_5 = 0x02,
152 	CVMX_SFP_SFF_8472_REV_10_2 = 0x03,
153 	CVMX_SFP_SFF_8472_REV_10_4 = 0x04,
154 	CVMX_SFP_SFF_8472_REV_11_0 = 0x05,
155 	CVMX_SFP_SFF_8472_REV_11_3 = 0x06,
156 	CVMX_SFP_SFF_8472_REV_11_4 = 0x07,
157 	CVMX_SFP_SFF_8472_REV_12_0 = 0x08,
158 	CVMX_SFP_SFF_8472_REV_UNALLOCATED = 0xff
159 };
160 
161 /**
162  * Data structure describing the current SFP or QSFP EEPROM
163  */
164 struct cvmx_sfp_mod_info {
165 	enum cvmx_phy_sfp_conn_type conn_type; /** Connector type */
166 	enum cvmx_phy_sfp_mod_type mod_type;   /** Module type */
167 	enum cvmx_phy_sfp_rate rate;	       /** Rate of module */
168 	/** 10G Ethernet Compliance codes (logical OR) */
169 	enum cvmx_phy_sfp_10g_eth_compliance eth_comp;
170 	/** Extended Cable compliance */
171 	enum cvmx_phy_sfp_cable_ext_compliance cable_comp;
172 	u8 vendor_name[17]; /** Module vendor name */
173 	u8 vendor_oui[3];   /** vendor OUI */
174 	u8 vendor_pn[17];   /** Vendor part number */
175 	u8 vendor_rev[5];   /** Vendor revision */
176 	u8 vendor_sn[17];   /** Vendor serial number */
177 	u8 date_code[9];    /** Date code */
178 	bool valid;	    /** True if module is valid */
179 	bool active_cable;  /** False for passive copper */
180 	bool copper_cable;  /** True if cable is copper */
181 	/** True if module is limiting (i.e. not passive copper) */
182 	bool limiting;
183 	/** Maximum length of copper cable in meters */
184 	int max_copper_cable_len;
185 	/** Max single mode cable length in meters */
186 	int max_single_mode_cable_length;
187 	/** Max 50um OM2 cable length */
188 	int max_50um_om2_cable_length;
189 	/** Max 62.5um OM1 cable length */
190 	int max_62_5um_om1_cable_length;
191 	/** Max 50um OM4 cable length */
192 	int max_50um_om4_cable_length;
193 	/** Max 50um OM3 cable length */
194 	int max_50um_om3_cable_length;
195 	/** Minimum bitrate in Mbps */
196 	int bitrate_min;
197 	/** Maximum bitrate in Mbps */
198 	int bitrate_max;
199 	/**
200 	 * Set to true if forward error correction is required,
201 	 * for example, a 25GBase-CR CA-S cable.
202 	 *
203 	 * FEC should only be disabled at 25G with CA-N cables.  FEC is required
204 	 * with 5M and longer cables.
205 	 */
206 	bool fec_required;
207 	/** True if RX output is linear */
208 	bool linear_rx_output;
209 	/** Power level, can be 1, 2 or 3 */
210 	int power_level;
211 	/** False if conventional cooling is used, true for active cooling */
212 	bool cooled_laser;
213 	/** True if internal retimer or clock and data recovery circuit */
214 	bool internal_cdr;
215 	/** True if LoS is implemented */
216 	bool los_implemented;
217 	/** True if LoS is inverted from the standard */
218 	bool los_inverted;
219 	/** True if TX_FAULT is implemented */
220 	bool tx_fault_implemented;
221 	/** True if TX_DISABLE is implemented */
222 	bool tx_disable_implemented;
223 	/** True if RATE_SELECT is implemented */
224 	bool rate_select_implemented;
225 	/** True if tuneable transmitter technology is used */
226 	bool tuneable_transmitter;
227 	/** True if receiver decision threshold is implemented */
228 	bool rx_decision_threshold_implemented;
229 	/** True if diagnostic monitoring present */
230 	bool diag_monitoring;
231 	/** True if diagnostic address 0x7f is used for selecting the page */
232 	bool diag_paging;
233 	/** Diagnostic feature revision */
234 	enum cvmx_phy_sfp_sff_8472_diag_rev diag_rev;
235 	/** True if an address change sequence is required for diagnostics */
236 	bool diag_addr_change_required;
237 	/** True if RX power is averaged, false if OMA */
238 	bool diag_rx_power_averaged;
239 	/** True if diagnostics are externally calibrated */
240 	bool diag_externally_calibrated;
241 	/** True if diagnostics are internally calibrated */
242 	bool diag_internally_calibrated;
243 	/** True of soft rate select control implemented per SFF-8431 */
244 	bool diag_soft_rate_select_control;
245 	/** True if application select control implemented per SFF-8079 */
246 	bool diag_app_select_control;
247 	/** True if soft RATE_SELECT control and moonitoring implemented */
248 	bool diag_soft_rate_select_implemented;
249 	/** True if soft RX_LOS monitoring implemented */
250 	bool diag_soft_rx_los_implemented;
251 	/** True if soft TX_FAULT monitoring implemented */
252 	bool diag_soft_tx_fault_implemented;
253 	/** True if soft TX_DISABLE control and monitoring implemented */
254 	bool diag_soft_tx_disable_implemented;
255 	/** True if alarm/warning flags implemented */
256 	bool diag_alarm_warning_flags_implemented;
257 };
258 
259 /**
260  * Reads the SFP EEPROM using the i2c bus
261  *
262  * @param[out]	buffer		Buffer to store SFP EEPROM data in
263  *				The buffer should be SFP_MAX_EEPROM_SIZE bytes.
264  * @param	i2c_bus		i2c bus number to read from for SFP port
265  * @param	i2c_addr	i2c address to use, 0 for default
266  *
267  * @return	-1 if invalid bus or i2c read error, 0 for success
268  */
269 int cvmx_phy_sfp_read_i2c_eeprom(u8 *buffer, int i2c_bus, int i2c_addr);
270 
271 /**
272  * Reads the SFP/SFP+/QSFP EEPROM and outputs the type of module or cable
273  * plugged in
274  *
275  * @param[out]	sfp_info	Info about SFP module
276  * @param[in]	buffer		SFP EEPROM buffer to parse
277  *
278  * @return	0 on success, -1 if error reading EEPROM or if EEPROM corrupt
279  */
280 int cvmx_phy_sfp_parse_eeprom(struct cvmx_sfp_mod_info *sfp_info, const u8 *buffer);
281 
282 /**
283  * Prints out information about a SFP/QSFP device
284  *
285  * @param[in]	sfp_info	data structure to print
286  */
287 void cvmx_phy_sfp_print_info(const struct cvmx_sfp_mod_info *sfp_info);
288 
289 /**
290  * Reads and parses SFP/QSFP EEPROM
291  *
292  * @param	sfp	sfp handle to read
293  *
294  * @return	0 for success, -1 on error.
295  */
296 int cvmx_sfp_read_i2c_eeprom(struct cvmx_fdt_sfp_info *sfp);
297 
298 /**
299  * Returns the information about a SFP/QSFP device
300  *
301  * @param       sfp             sfp handle
302  *
303  * @return      sfp_info        Pointer sfp mod info data structure
304  */
305 const struct cvmx_sfp_mod_info *cvmx_phy_get_sfp_mod_info(const struct cvmx_fdt_sfp_info *sfp);
306 
307 /**
308  * Function called to check and return the status of the mod_abs pin or
309  * mod_pres pin for QSFPs.
310  *
311  * @param	sfp	Handle to SFP information.
312  * @param	data	User-defined data passed to the function
313  *
314  * @return	0 if absent, 1 if present, -1 on error
315  */
316 int cvmx_sfp_check_mod_abs(struct cvmx_fdt_sfp_info *sfp, void *data);
317 
318 /**
319  * Registers a function to be called to check mod_abs/mod_pres for a SFP/QSFP
320  * slot.
321  *
322  * @param	sfp		Handle to SFP data structure
323  * @param	check_mod_abs	Function to be called or NULL to remove
324  * @param	mod_abs_data	User-defined data to be passed to check_mod_abs
325  *
326  * @return	0 for success
327  */
328 int cvmx_sfp_register_check_mod_abs(struct cvmx_fdt_sfp_info *sfp,
329 				    int (*check_mod_abs)(struct cvmx_fdt_sfp_info *sfp, void *data),
330 				    void *mod_abs_data);
331 
332 /**
333  * Registers a function to be called whenever the mod_abs/mod_pres signal
334  * changes.
335  *
336  * @param	sfp		Handle to SFP data structure
337  * @param	mod_abs_changed	Function called whenever mod_abs is changed
338  *				or NULL to remove.
339  * @param	mod_abs_changed_data	User-defined data passed to
340  *					mod_abs_changed
341  *
342  * @return	0 for success
343  */
344 int cvmx_sfp_register_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp,
345 				      int (*mod_abs_changed)(struct cvmx_fdt_sfp_info *sfp, int val,
346 							     void *data),
347 				      void *mod_abs_changed_data);
348 
349 /**
350  * Function called to check and return the status of the tx_fault pin
351  *
352  * @param	sfp	Handle to SFP information.
353  * @param	data	User-defined data passed to the function
354  *
355  * @return	0 if signal present, 1 if signal absent, -1 on error
356  */
357 int cvmx_sfp_check_tx_fault(struct cvmx_fdt_sfp_info *sfp, void *data);
358 
359 /**
360  * Function called to check and return the status of the rx_los pin
361  *
362  * @param	sfp	Handle to SFP information.
363  * @param	data	User-defined data passed to the function
364  *
365  * @return	0 if signal present, 1 if signal absent, -1 on error
366  */
367 int cvmx_sfp_check_rx_los(struct cvmx_fdt_sfp_info *sfp, void *data);
368 
369 /**
370  * Registers a function to be called whenever rx_los changes
371  *
372  * @param	sfp		Handle to SFP data structure
373  * @param	rx_los_changed	Function to be called when rx_los changes
374  *				or NULL to remove the function
375  * @param	rx_los_changed_data	User-defined data passed to
376  *					rx_los_changed
377  *
378  * @return	0 for success
379  */
380 int cvmx_sfp_register_rx_los_changed(struct cvmx_fdt_sfp_info *sfp,
381 				     int (*rx_los_changed)(struct cvmx_fdt_sfp_info *sfp, int val,
382 							   void *data),
383 				     void *rx_los_changed_data);
384 
385 /**
386  * Parses the device tree for SFP and QSFP slots
387  *
388  * @param	fdt_addr	Address of flat device-tree
389  *
390  * @return	0 for success, -1 on error
391  */
392 int cvmx_sfp_parse_device_tree(const void *fdt_addr);
393 
394 /**
395  * Given an IPD port number find the corresponding SFP or QSFP slot
396  *
397  * @param	ipd_port	IPD port number to search for
398  *
399  * @return	pointer to SFP data structure or NULL if not found
400  */
401 struct cvmx_fdt_sfp_info *cvmx_sfp_find_slot_by_port(int ipd_port);
402 
403 /**
404  * Given a fdt node offset find the corresponding SFP or QSFP slot
405  *
406  * @param	of_offset	flat device tree node offset
407  *
408  * @return	pointer to SFP data structure or NULL if not found
409  */
410 struct cvmx_fdt_sfp_info *cvmx_sfp_find_slot_by_fdt_node(int of_offset);
411 
412 /**
413  * Reads the EEPROMs of all SFP modules.
414  *
415  * @return 0 for success
416  */
417 int cvmx_sfp_read_all_modules(void);
418 
419 /**
420  * Validates if the module is correct for the specified port
421  *
422  * @param[in]	sfp	SFP port to check
423  * @param	mode	interface mode
424  *
425  * @return	true if module is valid, false if invalid
426  * NOTE: This will also toggle the error LED, if present
427  */
428 bool cvmx_sfp_validate_module(struct cvmx_fdt_sfp_info *sfp, int mode);
429 
430 /**
431  * Prints information about the SFP module
432  *
433  * @param[in]	sfp	sfp data structure
434  */
435 void cvmx_sfp_print_info(const struct cvmx_fdt_sfp_info *sfp);
436 
437 #endif /* __CVMX_HELPER_SFP_H__ */
438