obj-$(CONFIG_LS102XA_STREAM_ID) += ls102xa_stream_id.o
obj-$(CONFIG_EMC2305) += emc2305.o
+obj-$(CONFIG_QSFP_EEPROM) += qsfp_eeprom.o
# deal with common files for P-series corenet based devices
obj-$(CONFIG_TARGET_P2041RDB) += p_corenet/
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2021 NXP
+ */
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <linux/ctype.h>
+
+#define DEV_ID_QSFP 0x0c
+#define DEV_ID_QSFP_PLUS 0x0d
+
+static struct __attribute__ ((__packed__)) qsfp_eeprom_map {
+ struct __attribute__ ((__packed__)) qsfp_low_mem {
+ /* field byte address */
+ u8 identifier; /* 0 */
+ u16 status; /* 1-2 */
+ u8 reserved[124]; /* 3-126 */
+ u8 page_select; /* 127 */
+ } base;
+
+ struct __attribute__ ((__packed__)) qsfp_page00_mem {
+ /* field byte address */
+ u8 identifier; /* 128 */
+ u8 ext_identifier; /* 129 */
+ u8 connector; /* 130 */
+ u8 compat[8]; /* 131-138 */
+ u8 reserved[3]; /* 139-142 */
+ u8 length_fiber[4];
+ u8 length_copper; /* 146 */
+ u8 tech; /* 147 */
+ u8 vendor_name[16]; /* 148-163 */
+ u8 reserved2; /* 164 */
+ u8 oui[3]; /* 165-167 */
+ u8 pn[16]; /* 168-183 */
+ u8 rev[2]; /* 184-185 */
+ u8 reserved3[10]; /* 186-195 */
+ u8 serial[16]; /* 196-211 */
+ u8 date[8]; /* 212-219 */
+ u8 reserved4[35]; /* 220-255 */
+ } page0;
+} qsfp;
+
+unsigned char get_qsfp_compat0(void)
+{
+ int ret;
+ char vendor[20] = {0};
+ char serial[20] = {0};
+ char pname[20] = {0};
+ char mfgdt[20] = {0};
+#ifdef CONFIG_DM_I2C
+ struct udevice *dev;
+#endif
+
+ memset(&qsfp, 0, sizeof(qsfp));
+#ifndef CONFIG_DM_I2C
+ ret = i2c_read(I2C_SFP_EEPROM_ADDR,
+ 0,
+ I2C_SFP_EEPROM_ADDR_LEN,
+ (void *)&qsfp,
+ sizeof(qsfp));
+#else
+ ret = i2c_get_chip_for_busnum(0, I2C_SFP_EEPROM_ADDR, 1, &dev);
+ if (!ret)
+ ret = dm_i2c_read(dev, 0, (void *)&qsfp, sizeof(qsfp));
+#endif
+
+ if (ret != 0) {
+ debug("\nQSFP: no module detected\n");
+ return 0;
+ }
+ /* check if QSFP type */
+ if (qsfp.base.identifier != DEV_ID_QSFP_PLUS) {
+ debug("\nQSFP: unrecognized module\n");
+ return 0;
+ }
+
+ /* copy fields and trim the whitespaces and dump on screen */
+ snprintf(vendor, sizeof(vendor), "%.16s", qsfp.page0.vendor_name);
+ snprintf(serial, sizeof(serial), "%.16s", qsfp.page0.serial);
+ snprintf(pname, sizeof(pname), "%.16s", qsfp.page0.pn);
+ snprintf(mfgdt, sizeof(mfgdt), "%.2s/%.2s/%.2s",
+ &qsfp.page0.date[0], &qsfp.page0.date[2], &qsfp.page0.date[4]);
+
+ printf("QSFP: detected %s %s s/n: %s mfgdt: %s\n",
+ strim(vendor), strim(pname), strim(serial), strim(mfgdt));
+
+ /* return ethernet compatibility code*/
+ return qsfp.page0.compat[0];
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019-2021 NXP
+ */
+
+#ifndef __QSFP_EEPROM_H_
+#define __QSFP_EEPROM_H_
+/*
+ * QSFP eeprom reader external API interface.
+ */
+
+/* return the ethernet compatibility field 0 */
+unsigned char get_qsfp_compat0(void);
+#endif /* __QSFP_EEPROM_H_ */
config SYS_CONFIG_NAME
default "lx2160ardb"
+config QSFP_EEPROM
+ bool "Support for reading QSFP+ transceiver eeprom"
+ default y if PHY_CORTINA
+ help
+ This option enables the functionality for reading
+ QSFP+ cable eeprom. It can be used when PHYs are
+ requiring different initialization based on cable
+ type.
+
source "board/freescale/common/Kconfig"
endif
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2018, 2020 NXP
+ * Copyright 2018-2021 NXP
*
*/
#include <fsl-mc/fsl_mc.h>
#include <fsl-mc/ldpaa_wriop.h>
#include "lx2160a.h"
+#include "../common/qsfp_eeprom.h"
DECLARE_GLOBAL_DATA_PTR;
+#if defined(CONFIG_QSFP_EEPROM) && defined(CONFIG_PHY_CORTINA)
+#define CS4223_CONFIG_ENV "cs4223_autoconfig"
+#define CS4223_CONFIG_CR4 "copper"
+#define CS4223_CONFIG_SR4 "optical"
+
+enum qsfp_compat_codes {
+ QSFP_COMPAT_XLPPI = 0x01,
+ QSFP_COMPAT_LR4 = 0x02,
+ QSFP_COMPAT_SR4 = 0x04,
+ QSFP_COMPAT_CR4 = 0x08,
+};
+#endif /* CONFIG_QSFP_EEPROM && CONFIG_PHY_CORTINA */
+
static bool get_inphi_phy_id(struct mii_dev *bus, int addr, int devad)
{
int phy_reg;
struct mii_dev *dev;
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
u32 srds_s1;
+#if defined(CONFIG_QSFP_EEPROM) && defined(CONFIG_PHY_CORTINA)
+ u8 qsfp_compat_code;
+#endif
srds_s1 = in_le32(&gur->rcwsr[28]) &
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK;
}
next:
+#if defined(CONFIG_QSFP_EEPROM) && defined(CONFIG_PHY_CORTINA)
+ /* read qsfp+ eeprom & update environment for cs4223 init */
+ select_i2c_ch_pca9547(I2C_MUX_CH_SEC);
+ select_i2c_ch_pca9547_sec(I2C_MUX_CH_QSFP);
+ qsfp_compat_code = get_qsfp_compat0();
+ switch (qsfp_compat_code) {
+ case QSFP_COMPAT_CR4:
+ env_set(CS4223_CONFIG_ENV, CS4223_CONFIG_CR4);
+ break;
+ case QSFP_COMPAT_XLPPI:
+ case QSFP_COMPAT_SR4:
+ env_set(CS4223_CONFIG_ENV, CS4223_CONFIG_SR4);
+ break;
+ default:
+ /* do nothing if detection fails or not supported*/
+ break;
+ }
+ select_i2c_ch_pca9547(I2C_MUX_CH_DEFAULT);
+#endif /* CONFIG_QSFP_EEPROM & CONFIG_PHY_CORTINA */
+
cpu_eth_init(bis);
#endif /* CONFIG_FSL_MC_ENET */
return 0;
}
+int select_i2c_ch_pca9547_sec(u8 ch)
+{
+ int ret;
+
+#ifndef CONFIG_DM_I2C
+ ret = i2c_write(I2C_MUX_PCA_ADDR_SEC, 0, 1, &ch, 1);
+#else
+ struct udevice *dev;
+
+ ret = i2c_get_chip_for_busnum(0, I2C_MUX_PCA_ADDR_SEC, 1, &dev);
+ if (!ret)
+ ret = dm_i2c_write(dev, 0, &ch, 1);
+#endif
+ if (ret) {
+ puts("PCA: failed to select proper channel\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static void uart_get_clock(void)
{
serial0.clock = get_serial_clock();
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2018-2020 NXP
+ * Copyright 2018-2021 NXP
*/
#ifndef __LX2_COMMON_H
/* I2C bus multiplexer */
#define I2C_MUX_PCA_ADDR_PRI 0x77 /* Primary Mux*/
+#define I2C_MUX_PCA_ADDR_SEC 0x75 /* Secondary Mux*/
#define I2C_MUX_CH_DEFAULT 0x8
+#define I2C_MUX_CH_SEC 0xF
+
+/* QSFP+/SFP+ I2C MUX related */
+#define I2C_MUX_CH_QSFP 0x8
+#define I2C_MUX_CH_SFP1 0xC
+#define I2C_MUX_CH_SFP2 0xD
/* RTC */
#define RTC
#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 5
+/* QSFP/SFP module EEPROMs */
+#define I2C_SFP_EEPROM_ADDR 0x50
+#define I2C_SFP_EEPROM_ADDR_LEN 1
+
/* Qixis */
#define CONFIG_FSL_QIXIS
#define CONFIG_QIXIS_I2C_ACCESS
#ifndef __ASSEMBLY__
unsigned long get_board_sys_clk(void);
unsigned long get_board_ddr_clk(void);
+int select_i2c_ch_pca9547(unsigned char ch);
+int select_i2c_ch_pca9547_sec(unsigned char ch);
#endif
#define CONFIG_SYS_CLK_FREQ get_board_sys_clk()