From 21bd0f668671104fd28a3127893a53459ed0bf1f Mon Sep 17 00:00:00 2001 From: jumao Date: Thu, 11 Dec 2025 11:59:28 -0500 Subject: [PATCH 1/3] [h6-128] Add H6-128 support --- debian/control | 6 + debian/rules | 2 +- ...sonic-platform-nokia-ixr7220h6-128.install | 5 + ...onic-platform-nokia-ixr7220h6-128.postinst | 11 + ixr7220h6-128/modules/Makefile | 12 + ixr7220h6-128/modules/eeprom_fru.c | 536 +++++++++++ ixr7220h6-128/modules/embd_ctrl.c | 196 ++++ ixr7220h6-128/modules/h6_fan_cpld.c | 606 ++++++++++++ ixr7220h6-128/modules/h6_i2c_oc.c | 312 ++++++ ixr7220h6-128/modules/i2c-ocores.c | 885 ++++++++++++++++++ ixr7220h6-128/modules/pmbus_psu.c | 563 +++++++++++ ixr7220h6-128/modules/port_cpld0.c | 637 +++++++++++++ ixr7220h6-128/modules/port_cpld1.c | 730 +++++++++++++++ ixr7220h6-128/modules/port_cpld2.c | 562 +++++++++++ ixr7220h6-128/modules/sys_cpld.c | 421 +++++++++ ixr7220h6-128/modules/sys_fpga.c | 243 +++++ ixr7220h6-128/modules/sys_mux.c | 238 +++++ ixr7220h6-128/scripts/h6_128_platform_init.sh | 151 +++ .../service/h6_128_platform_init.service | 12 + ixr7220h6-128/setup.py | 21 + ixr7220h6-128/sonic_platform/__init__.py | 2 + ixr7220h6-128/sonic_platform/chassis.py | 402 ++++++++ ixr7220h6-128/sonic_platform/component.py | 277 ++++++ ixr7220h6-128/sonic_platform/eeprom.py | 220 +++++ ixr7220h6-128/sonic_platform/fan.py | 262 ++++++ ixr7220h6-128/sonic_platform/fan_drawer.py | 208 ++++ ixr7220h6-128/sonic_platform/platform.py | 19 + ixr7220h6-128/sonic_platform/psu.py | 305 ++++++ ixr7220h6-128/sonic_platform/sfp.py | 225 +++++ ixr7220h6-128/sonic_platform/sfp_event.py | 146 +++ ixr7220h6-128/sonic_platform/sysfs.py | 48 + ixr7220h6-128/sonic_platform/test/README | 1 + .../sonic_platform/test/test-chassis.py | 62 ++ .../sonic_platform/test/test-component.py | 19 + .../sonic_platform/test/test-eeprom.py | 24 + .../sonic_platform/test/test-fan-drawer.py | 29 + ixr7220h6-128/sonic_platform/test/test-fan.py | 34 + ixr7220h6-128/sonic_platform/test/test-psu.py | 44 + ixr7220h6-128/sonic_platform/test/test-sfp.py | 54 ++ .../sonic_platform/test/test-thermal.py | 49 + .../sonic_platform/test/test-watchdog.py | 19 + ixr7220h6-128/sonic_platform/thermal.py | 264 ++++++ .../sonic_platform/thermal_actions.py | 199 ++++ .../sonic_platform/thermal_conditions.py | 70 ++ ixr7220h6-128/sonic_platform/thermal_infos.py | 236 +++++ .../sonic_platform/thermal_manager.py | 58 ++ ixr7220h6-128/sonic_platform/watchdog.py | 175 ++++ 47 files changed, 9599 insertions(+), 1 deletion(-) create mode 100644 debian/sonic-platform-nokia-ixr7220h6-128.install create mode 100644 debian/sonic-platform-nokia-ixr7220h6-128.postinst create mode 100755 ixr7220h6-128/modules/Makefile create mode 100644 ixr7220h6-128/modules/eeprom_fru.c create mode 100644 ixr7220h6-128/modules/embd_ctrl.c create mode 100644 ixr7220h6-128/modules/h6_fan_cpld.c create mode 100644 ixr7220h6-128/modules/h6_i2c_oc.c create mode 100644 ixr7220h6-128/modules/i2c-ocores.c create mode 100644 ixr7220h6-128/modules/pmbus_psu.c create mode 100644 ixr7220h6-128/modules/port_cpld0.c create mode 100644 ixr7220h6-128/modules/port_cpld1.c create mode 100644 ixr7220h6-128/modules/port_cpld2.c create mode 100644 ixr7220h6-128/modules/sys_cpld.c create mode 100644 ixr7220h6-128/modules/sys_fpga.c create mode 100644 ixr7220h6-128/modules/sys_mux.c create mode 100755 ixr7220h6-128/scripts/h6_128_platform_init.sh create mode 100755 ixr7220h6-128/service/h6_128_platform_init.service create mode 100755 ixr7220h6-128/setup.py create mode 100755 ixr7220h6-128/sonic_platform/__init__.py create mode 100755 ixr7220h6-128/sonic_platform/chassis.py create mode 100755 ixr7220h6-128/sonic_platform/component.py create mode 100755 ixr7220h6-128/sonic_platform/eeprom.py create mode 100755 ixr7220h6-128/sonic_platform/fan.py create mode 100755 ixr7220h6-128/sonic_platform/fan_drawer.py create mode 100755 ixr7220h6-128/sonic_platform/platform.py create mode 100755 ixr7220h6-128/sonic_platform/psu.py create mode 100755 ixr7220h6-128/sonic_platform/sfp.py create mode 100755 ixr7220h6-128/sonic_platform/sfp_event.py create mode 100755 ixr7220h6-128/sonic_platform/sysfs.py create mode 100755 ixr7220h6-128/sonic_platform/test/README create mode 100755 ixr7220h6-128/sonic_platform/test/test-chassis.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-component.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-eeprom.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-fan-drawer.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-fan.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-psu.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-sfp.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-thermal.py create mode 100755 ixr7220h6-128/sonic_platform/test/test-watchdog.py create mode 100755 ixr7220h6-128/sonic_platform/thermal.py create mode 100755 ixr7220h6-128/sonic_platform/thermal_actions.py create mode 100755 ixr7220h6-128/sonic_platform/thermal_conditions.py create mode 100755 ixr7220h6-128/sonic_platform/thermal_infos.py create mode 100755 ixr7220h6-128/sonic_platform/thermal_manager.py create mode 100755 ixr7220h6-128/sonic_platform/watchdog.py diff --git a/debian/control b/debian/control index b4bd552..1a4a57f 100755 --- a/debian/control +++ b/debian/control @@ -63,3 +63,9 @@ Package: sonic-platform-nokia-ixr7220h6-64 Architecture: amd64 Depends: ${misc:Depends} Description: kernel modules for platform devices such as osfp, fan, led, sfp + +Package: sonic-platform-nokia-ixr7220h6-128 +Architecture: amd64 +Depends: ${misc:Depends} +Description: kernel modules for platform devices such as osfp, fan, led, sfp + diff --git a/debian/rules b/debian/rules index 37d2661..367be75 100755 --- a/debian/rules +++ b/debian/rules @@ -20,7 +20,7 @@ KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR := $(shell pwd) MODULE_DIRS := chassis ixr7220h3 ixr7220h4-32d ixr7220h5-32d ixr7220h5-64d ixr7220h4-64d \ - ixr7220h5-64o ixr7250x1b ixr7250x3b ixr7250x4 ixr7220d4 ixr7220h6-64 + ixr7220h5-64o ixr7250x1b ixr7250x3b ixr7250x4 ixr7220d4 ixr7220h6-64 ixr7220h6-128 BRIDGE_DRIVER_TARGETS := ixr7250x1b ixr7250x3b ixr7250x4 MODULE_DIR := modules UTILS_DIR := utils diff --git a/debian/sonic-platform-nokia-ixr7220h6-128.install b/debian/sonic-platform-nokia-ixr7220h6-128.install new file mode 100644 index 0000000..72baf88 --- /dev/null +++ b/debian/sonic-platform-nokia-ixr7220h6-128.install @@ -0,0 +1,5 @@ +ixr7220h6-128/scripts/h6_128_platform_init.sh usr/local/bin +#ixr7220h6-128/scripts/ports_notify.py usr/local/bin +ixr7220h6-128/service/h6_128_platform_init.service etc/systemd/system +#ixr7220h6-128/service/ports_notify.service etc/systemd/system/ +ixr7220h6-128/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-nokia_ixr7220_h6_128-r0 diff --git a/debian/sonic-platform-nokia-ixr7220h6-128.postinst b/debian/sonic-platform-nokia-ixr7220h6-128.postinst new file mode 100644 index 0000000..2cead83 --- /dev/null +++ b/debian/sonic-platform-nokia-ixr7220h6-128.postinst @@ -0,0 +1,11 @@ +#!/bin/sh +# postinst script for sonic-platform-nokia-IXR7220-H6-128 +# +# see: dh_installdeb(1) + +chmod a+x /usr/local/bin/h6_128_platform_init.sh +systemctl enable h6_128_platform_init.service +systemctl start h6_128_platform_init.service +# chmod a+x /usr/local/bin/ports_notify.py +# systemctl enable ports_notify.service +# systemctl start --no-block ports_notify.service diff --git a/ixr7220h6-128/modules/Makefile b/ixr7220h6-128/modules/Makefile new file mode 100755 index 0000000..327463c --- /dev/null +++ b/ixr7220h6-128/modules/Makefile @@ -0,0 +1,12 @@ +obj-m += i2c-ocores.o +obj-m += h6_i2c_oc.o +obj-m += sys_mux.o +obj-m += sys_cpld.o +obj-m += port_cpld0.o +obj-m += port_cpld1.o +obj-m += port_cpld2.o +obj-m += eeprom_fru.o +obj-m += h6_fan_cpld.o +obj-m += sys_fpga.o +obj-m += embd_ctrl.o +obj-m += pmbus_psu.o diff --git a/ixr7220h6-128/modules/eeprom_fru.c b/ixr7220h6-128/modules/eeprom_fru.c new file mode 100644 index 0000000..853a60e --- /dev/null +++ b/ixr7220h6-128/modules/eeprom_fru.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * eeprom_fru.c - NOKIA EEPROM FRU Sysfs driver + * + * + * Copyright (C) 2025 Nokia Corporation. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * see + */ + +#include +#include +#include +#include + +#define EEPROM_NAME "eeprom_fru" +#define FIELD_LEN_MAX 255 +static unsigned int debug = 0; +module_param_named(debug, debug, uint, 0); +MODULE_PARM_DESC(debug, "Debug enable(default to 0)"); + +static unsigned int read_eeprom_max_len = 0xb8; +module_param_named(read_eeprom_max_len, read_eeprom_max_len, uint, 0); +MODULE_PARM_DESC(read_eeprom_max_len, "read_eeprom_max_len(default to 0xb8)"); + +#define FRU_END_OF_FIELDS 0xc1 +#define BUF2STR_MAXIMUM_OUTPUT_SIZE (3*1024 + 1) +struct fru_header { + u8 version; + union { + struct { + u8 internal; + u8 chassis; + u8 board; + u8 product; + u8 multi; + } offset; + u8 offsets[5]; + }; + u8 pad; + u8 checksum; +}; + +struct at24_data { + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + struct i2c_client *client; + char part_number[FIELD_LEN_MAX + 1]; + char product_version[FIELD_LEN_MAX + 1]; + char serial_number[FIELD_LEN_MAX + 1]; + char mfg_name[FIELD_LEN_MAX+1]; + char product_name[FIELD_LEN_MAX + 1]; + char clei_code[FIELD_LEN_MAX + 1]; + char deviation[FIELD_LEN_MAX + 1]; + char customer_sn[FIELD_LEN_MAX + 1]; + char fru_ver[FIELD_LEN_MAX + 1]; + char mfg_date[FIELD_LEN_MAX + 1]; +}; + +u8 fru_calc_checksum(void *area, size_t len); +int fru_checksum_is_valid(void *area, size_t len); +const char * buf2str_extended(const u8 *buf, int len, const char *sep); +const char * buf2str(const u8 *buf, int len); +char * get_fru_area_str(struct device *dev, u8 * data, u32 * offset); +int decode_eeprom(struct i2c_client *client); + +u8 fru_calc_checksum(void *area, size_t len) +{ + u8 checksum = 0; + u8 * data = area; + size_t i; + + for (i = 0; i < len - 1; i++) + checksum += data[i]; + + return -checksum; +} + +int fru_checksum_is_valid(void *area, size_t len) +{ + u8 * data = area; + /* Checksum is valid when the stored checksum equals calculated */ + return data[len - 1] == fru_calc_checksum(area, len); +} + +const char * buf2str_extended(const u8 *buf, int len, const char *sep) +{ + static char str[BUF2STR_MAXIMUM_OUTPUT_SIZE] = {0}; + char *cur; + int i; + int sz; + int left; + int sep_len; + + if (!buf) { + snprintf(str, sizeof(str), ""); + return (const char *)str; + } + cur = str; + left = sizeof(str); + if (sep) { + sep_len = strlen(sep); + } else { + sep_len = 0; + } + for (i = 0; i < len; i++) { + /* may return more than 2, depending on locale */ + sz = snprintf(cur, left, "%2.2x", buf[i]); + if (sz >= left) { + /* buffer overflow, truncate */ + break; + } + cur += sz; + left -= sz; + /* do not write separator after last byte */ + if (sep && i != (len - 1)) { + if (sep_len >= left) { + break; + } + strncpy(cur, sep, left - sz); + cur += sep_len; + left -= sep_len; + } + } + *cur = '\0'; + + return (const char *)str; +} + +const char * buf2str(const u8 *buf, int len) +{ + return buf2str_extended(buf, len, NULL); +} + +char * get_fru_area_str(struct device *dev, u8 * data, u32 * offset) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + char * str = NULL; + int len, off, size, i, j, k, typecode, char_idx; + union { + u32 bits; + char chars[4]; + } u; + + size = 0; + off = *offset; + + if(data[off] == FRU_END_OF_FIELDS) + return NULL; + /* bits 6:7 contain format */ + typecode = ((data[off] & 0xC0) >> 6); + + /* bits 0:5 contain length */ + len = data[off++]; + len &= 0x3f; + if(debug) { + dev_info(dev, "data[0x%x] = %x, typecode:0x%x len:%d, ", off, data[off], typecode, len); + } + + switch (typecode) { + case 0: /* 00b: binary/unspecified */ + case 1: /* 01b: BCD plus */ + /* hex dump or BCD -> 2x length */ + size = (len * 2); + break; + case 2: /* 10b: 6-bit ASCII */ + /* 4 chars per group of 1-3 bytes, round up to 4 bytes boundary */ + size = (len / 3 + 1) * 4; + break; + case 3: /* 11b: 8-bit ASCII */ + /* no length adjustment */ + size = len; + break; + } + + if (size < 1) { + *offset = off; + return NULL; + } + str = devm_kzalloc(dev, size+1, GFP_KERNEL); + if (!str) + return NULL; + + if (size == 0) { + str[0] = '\0'; + *offset = off; + return str; + } + + switch (typecode) { + case 0: /* Binary */ + strncpy(str, buf2str(&data[off], len), size); + break; + + case 1: /* BCD plus */ + for (k = 0; k < size; k++) + str[k] = bcd_plus[((data[off + k / 2] >> ((k % 2) ? 0 : 4)) & 0x0f)]; + str[k] = '\0'; + break; + + case 2: /* 6-bit ASCII */ + for (i = j = 0; i < len; i += 3) { + u.bits = 0; + k = ((len - i) < 3 ? (len - i) : 3); + + memcpy((void *)&u.bits, &data[off+i], k); + char_idx = 0; + for (k=0; k<4; k++) { + str[j++] = ((u.chars[char_idx] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + str[j] = '\0'; + break; + + case 3: + memcpy(str, &data[off], size); + str[size] = '\0'; + break; + } + + off += len; + *offset = off; + + return str; +} + +static int decode_fru_product_info_area(struct i2c_client *client, u8 * raw_data, u32 offset) +{ + char * fru_area; + u8 * fru_data; + u32 fru_len, i; + u8 * tmp = raw_data + offset; + struct device *dev = &client->dev; + struct at24_data *at24 = i2c_get_clientdata(client); + fru_len = 0; + + /* read enough to check length field */ + fru_len = 8 * tmp[1]; + + if (fru_len == 0) { + return -EINVAL; + } + fru_data = devm_kzalloc(dev, fru_len, GFP_KERNEL); + + if (!fru_data) + return -ENOMEM; + + memcpy(fru_data, raw_data+offset, fru_len); + + struct fru_product_info_area_field { + char name[64]; + char * p; + }; + + const struct fru_product_info_area_field fru_fields[] = { + {"Product Area Format Version", NULL}, + {"Product Area Length", NULL}, + {"Language Code", NULL}, + {"Manufacturer Name", at24->mfg_name}, + {"Product Name", at24->product_name}, + {"Product Part/Model Number", at24->part_number}, + {"Product Version", at24->product_version}, + {"Product Serial Number", at24->serial_number}, + {"Asset Tag", NULL}, + {"FRU File ID", NULL}, + {"CLEI Code", at24->clei_code}, + {"Deviation", at24->deviation}, + {"Customer SN", at24->customer_sn}, + {"FRU Version", at24->fru_ver}, + {"Manufacture Date", at24->mfg_date} + }; + + /* Check area checksum */ + if(debug && !fru_checksum_is_valid(fru_data, fru_len)) { + dev_warn(dev, "Invalid eeprom checksum.\n"); + return -EINVAL; + } + + i = 3; + int j = 0; + for(; j < ARRAY_SIZE(fru_fields); j++) + { + if(j < 3) { + if(debug) { + dev_info(dev, "%s: %x\n", fru_fields[j].name, fru_data[j]); + } + continue; + } + fru_area = get_fru_area_str(dev, fru_data, &i); + if(fru_area && fru_fields[j].p) { + if (strlen(fru_area) > 0) { + if(debug) { + dev_info(dev, "%s: %s\n", fru_fields[j].name, fru_area); + } + int len = strlen(fru_area); + if( len > FIELD_LEN_MAX) { + len = FIELD_LEN_MAX; + } + strncpy(fru_fields[j].p, fru_area, len); + } + } + } + return 0; +} + +int decode_eeprom(struct i2c_client *client) +{ + u8 * raw_data = kzalloc(read_eeprom_max_len, GFP_KERNEL); + if (!raw_data) { + return -ENOMEM; + } + + for (int i = 0; i < read_eeprom_max_len / 2; i++) { + u16 data = i2c_smbus_read_word_data(client, i * 2); + raw_data[i * 2] = data & 0xff; + raw_data[i * 2 + 1] = (data >> 8) & 0xff; + } + + struct fru_header header; + memset(&header, 0, sizeof(struct fru_header)); + + if(debug) { + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, raw_data + 8, read_eeprom_max_len - 8, true); + } + + /* According to IPMI Platform Management FRU Information Storage Definition v1.0 */ + memcpy(&header, raw_data, 8); + if (header.version != 1) { + struct device *dev = &client->dev; + dev_err(dev, "Unknown FRU header version 0x%02x", header.version); + } + /* + * Only process Product Info Area + */ + if ((header.offset.product*8) >= sizeof(struct fru_header)) + decode_fru_product_info_area(client, raw_data, header.offset.product*8); + + kfree(raw_data); + return 0; +} + +static ssize_t trigger_read_eeprom(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + if(!strncmp(buf,"1", count-1)) { + struct at24_data *data = dev_get_drvdata(dev); + decode_eeprom(data->client); + } + return count; +} + +static ssize_t show_part_number(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->part_number); +} + +static ssize_t show_serial_number(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->serial_number); +} + +static ssize_t show_product_version(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->product_version); +} + +static ssize_t show_mfg_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->mfg_name); +} + +static ssize_t show_product_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->product_name); +} + +static ssize_t show_clei_code(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->clei_code); +} + +static ssize_t show_deviation(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->deviation); +} + +static ssize_t show_customer_sn(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->customer_sn); +} + +static ssize_t show_fru_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->fru_ver); +} + +static ssize_t show_mfg_date(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->mfg_date); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(read_eeprom, S_IWUSR, NULL, trigger_read_eeprom, 0); +static SENSOR_DEVICE_ATTR(part_number, S_IRUGO, show_part_number, NULL, 0); +static SENSOR_DEVICE_ATTR(serial_number, S_IRUGO, show_serial_number, NULL, 0); +static SENSOR_DEVICE_ATTR(product_version, S_IRUGO, show_product_version, NULL, 0); +static SENSOR_DEVICE_ATTR(mfg_name, S_IRUGO, show_mfg_name, NULL, 0); +static SENSOR_DEVICE_ATTR(product_name, S_IRUGO, show_product_name, NULL, 0); +static SENSOR_DEVICE_ATTR(clei_code, S_IRUGO, show_clei_code, NULL, 0); +static SENSOR_DEVICE_ATTR(deviation, S_IRUGO, show_deviation, NULL, 0); +static SENSOR_DEVICE_ATTR(customer_sn, S_IRUGO, show_customer_sn, NULL, 0); +static SENSOR_DEVICE_ATTR(fru_ver, S_IRUGO, show_fru_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(mfg_date, S_IRUGO, show_mfg_date, NULL, 0); + +static struct attribute *eeprom_attributes[] = { + &sensor_dev_attr_read_eeprom.dev_attr.attr, + &sensor_dev_attr_part_number.dev_attr.attr, + &sensor_dev_attr_serial_number.dev_attr.attr, + &sensor_dev_attr_product_version.dev_attr.attr, + &sensor_dev_attr_mfg_name.dev_attr.attr, + &sensor_dev_attr_product_name.dev_attr.attr, + &sensor_dev_attr_clei_code.dev_attr.attr, + &sensor_dev_attr_deviation.dev_attr.attr, + &sensor_dev_attr_customer_sn.dev_attr.attr, + &sensor_dev_attr_fru_ver.dev_attr.attr, + &sensor_dev_attr_mfg_date.dev_attr.attr, + NULL +}; + +static const struct attribute_group eeprom_group = { + .attrs = eeprom_attributes, +}; + +static int eeprom_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct at24_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)) { + dev_info(&client->dev, "i2c_check_functionality failed!\n"); + status = -EIO; + return status; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + return status; + } + + mutex_init(&data->lock); + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "eeprom chip found\n"); + /* Create sysfs entries */ + status = sysfs_create_group(&client->dev.kobj, &eeprom_group); + if (status) { + dev_err(dev, "Cannot create sysfs\n"); + kfree(data); + return status; + } + data->client = client; + decode_eeprom(client); + return status; +} + +static void eeprom_remove(struct i2c_client *client) +{ + struct at24_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &eeprom_group); + kfree(data); + return; +} + +static const struct i2c_device_id eeprom_id[] = { + { EEPROM_NAME, 0 }, + { EEPROM_NAME, 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, eeprom_id); + +/* Address scanned */ +static const unsigned short normal_i2c[] = { 0x50, 0x51, I2C_CLIENT_END }; + +/* This is the driver that will be inserted */ +static struct i2c_driver eeprom_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = EEPROM_NAME, + }, + .probe = eeprom_probe, + .remove = eeprom_remove, + .id_table = eeprom_id, + .address_list = normal_i2c, +}; + +static int __init eeprom_init(void) +{ + return i2c_add_driver(&eeprom_driver); +} + +static void __exit eeprom_exit(void) +{ + i2c_del_driver(&eeprom_driver); +} + +MODULE_DESCRIPTION("NOKIA EEPROM FRU Sysfs driver"); +MODULE_AUTHOR("Nokia"); +MODULE_LICENSE("GPL"); + +module_init(eeprom_init); +module_exit(eeprom_exit); diff --git a/ixr7220h6-128/modules/embd_ctrl.c b/ixr7220h6-128/modules/embd_ctrl.c new file mode 100644 index 0000000..8a6a588 --- /dev/null +++ b/ixr7220h6-128/modules/embd_ctrl.c @@ -0,0 +1,196 @@ +// * Embedded Controller driver for Nokia Router +// * +// * Copyright (C) 2025 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "embd_ctrl" + +// REGISTERS ADDRESS MAP +#define CPU_TEMP_REG 0x10 +#define MEM0_TEMP_REG 0x12 +#define MEM1_TEMP_REG 0x13 + +static const unsigned short ec_address_list[] = {0x21, I2C_CLIENT_END}; + +struct ec_data { + struct i2c_client *client; + struct mutex update_lock; +}; + +static int ec_i2c_read(struct ec_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_warn(&client->dev, "EC READ WARN: reg(0x%02x) err %d\n", reg, val); + } + + return val; +} + +#ifdef EC_WRITE +static void ec_i2c_write(struct ec_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_warn(&client->dev, "EC WRITE WARN: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} +#endif + +static ssize_t show_cpu_temperature(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct ec_data *data = dev_get_drvdata(dev); + u8 val = 0; + val = ec_i2c_read(data, CPU_TEMP_REG); + return sprintf(buf, "%d\n", (s8)val * 1000); +} + +static ssize_t show_mem0_temperature(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct ec_data *data = dev_get_drvdata(dev); + u8 val = 0; + val = ec_i2c_read(data, MEM0_TEMP_REG); + return sprintf(buf, "%d\n", (s8)val * 1000); +} + +static ssize_t show_mem1_temperature(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct ec_data *data = dev_get_drvdata(dev); + u8 val = 0; + val = ec_i2c_read(data, MEM1_TEMP_REG); + return sprintf(buf, "%d\n", (s8)val * 1000); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(cpu_temperature, S_IRUGO, show_cpu_temperature, NULL, 0); +static SENSOR_DEVICE_ATTR(mem0_temperature, S_IRUGO, show_mem0_temperature, NULL, 0); +static SENSOR_DEVICE_ATTR(mem1_temperature, S_IRUGO, show_mem1_temperature, NULL, 0); + +static struct attribute *embd_ctrl_attributes[] = { + &sensor_dev_attr_cpu_temperature.dev_attr.attr, + &sensor_dev_attr_mem0_temperature.dev_attr.attr, + &sensor_dev_attr_mem1_temperature.dev_attr.attr, + NULL +}; + +static const struct attribute_group embd_ctrl_group = { + .attrs = embd_ctrl_attributes, +}; + +static int embd_ctrl_probe(struct i2c_client *client) +{ + int status = 0; + struct ec_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&client->dev, "EC PROBE WARN: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia embeded controller chip found.\n"); + data = kzalloc(sizeof(struct ec_data), GFP_KERNEL); + + if (!data) { + dev_warn(&client->dev, "EC PROBE WARN: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &embd_ctrl_group); + if (status) { + dev_warn(&client->dev, "EC INIT WARN: Cannot create sysfs\n"); + goto exit; + } + + return 0; + +exit: + return status; +} + +static void embd_ctrl_remove(struct i2c_client *client) +{ + struct ec_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &embd_ctrl_group); + kfree(data); +} + +static const struct of_device_id embd_ctrl_of_ids[] = { + { + .compatible = "Nokia,embd_ctrl", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, embd_ctrl_of_ids); + +static const struct i2c_device_id embd_ctrl_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, embd_ctrl_ids); + +static struct i2c_driver embd_ctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(embd_ctrl_of_ids), + }, + .probe = embd_ctrl_probe, + .remove = embd_ctrl_remove, + .id_table = embd_ctrl_ids, + .address_list = ec_address_list, +}; + +static int __init embd_ctrl_init(void) +{ + return i2c_add_driver(&embd_ctrl_driver); +} + +static void __exit embd_ctrl_exit(void) +{ + i2c_del_driver(&embd_ctrl_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA Embedded Controller driver"); +MODULE_LICENSE("GPL"); + +module_init(embd_ctrl_init); +module_exit(embd_ctrl_exit); diff --git a/ixr7220h6-128/modules/h6_fan_cpld.c b/ixr7220h6-128/modules/h6_fan_cpld.c new file mode 100644 index 0000000..289d48a --- /dev/null +++ b/ixr7220h6-128/modules/h6_fan_cpld.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * A hwmon driver for the Accton h6 fan + * + * Copyright (C) 2025 Accton Technology Corporation. + * Roger Ho + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "h6_fan" + +#define I2C_RW_RETRY_COUNT (10) +#define I2C_RW_RETRY_INTERVAL (60) /* ms */ + +static struct h6_fan_data *h6_fan_update_device(struct device + *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_fan_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t reg_read(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t reg_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x00, /* fan pcb information */ + 0x01, /* fan cpld major version */ + 0x02, /* fan cpld minor version */ + 0x08, /* fan 0-3 present status */ + 0x0e, /* fan 0-3 led */ + 0x10, /* front fan 0 pwm */ + 0x11, /* rear fan 0 pwm */ + 0x12, /* front fan 1 pwm */ + 0x13, /* rear fan 1 pwm */ + 0x14, /* front fan 2 pwm */ + 0x15, /* rear fan 2 pwm */ + 0x16, /* front fan 3 pwm */ + 0x17, /* rear fan 3 pwm */ + 0x20, /* front fan 0 speed(rpm) */ + 0x21, /* rear fan 0 speed(rpm) */ + 0x22, /* front fan 1 speed(rpm) */ + 0x23, /* rear fan 1 speed(rpm) */ + 0x24, /* front fan 2 speed(rpm) */ + 0x25, /* rear fan 2 speed(rpm) */ + 0x26, /* front fan 3 speed(rpm) */ + 0x27, /* rear fan 3 speed(rpm) */ +}; + +/* Each client has this additional data */ +struct h6_fan_data { + struct i2c_client *client; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ + u8 reg_addr; +}; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID, +}; + +enum sysfs_fan_attributes { + FAN_PCB_REG, + FAN_MAJOR_VERSION_REG, + FAN_MINOR_VERSION_REG, + FAN_PRESENT_REG, + FAN_LED_REG, + FAN1_FRONT_PWM_REG, + FAN1_REAR_PWM_REG, + FAN2_FRONT_PWM_REG, + FAN2_REAR_PWM_REG, + FAN3_FRONT_PWM_REG, + FAN3_REAR_PWM_REG, + FAN4_FRONT_PWM_REG, + FAN4_REAR_PWM_REG, + FAN1_FRONT_SPEED_RPM_REG, + FAN1_REAR_SPEED_RPM_REG, + FAN2_FRONT_SPEED_RPM_REG, + FAN2_REAR_SPEED_RPM_REG, + FAN3_REAR_SPEED_RPM_REG, + FAN3_FRONT_SPEED_RPM_REG, + FAN4_FRONT_SPEED_RPM_REG, + FAN4_REAR_SPEED_RPM_REG, + + FAN1_RPM, + FAN2_RPM, + FAN3_RPM, + FAN4_RPM, + FAN5_RPM, + FAN6_RPM, + FAN7_RPM, + FAN8_RPM, + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, + FAN1_PWM, + FAN2_PWM, + FAN3_PWM, + FAN4_PWM, + FAN5_PWM, + FAN6_PWM, + FAN7_PWM, + FAN8_PWM, + FAN1_LED, + FAN2_LED, + FAN3_LED, + FAN4_LED, + FAN_FW_VERSION, + FAN_PCB_VERSION, + FAN_ACCESS +}; + +enum fan_led_light_mode { + FAN_LED_MODE_OFF, + FAN_LED_MODE_RED = 10, + FAN_LED_MODE_GREEN = 16, + FAN_LED_MODE_UNKNOWN = 99 +}; + + +/* Define attributes + */ +#define DECLARE_FAN_SENSOR_DEVICE_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, \ + FAN##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(fan##index##_pwm, S_IWUSR | S_IRUGO, fan_show_value, \ + set_duty_cycle, FAN##index##_PWM); \ + static SENSOR_DEVICE_ATTR(fan##index2##_pwm, S_IWUSR | S_IRUGO, fan_show_value, \ + set_duty_cycle, FAN##index2##_PWM); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, \ + FAN##index##_RPM); \ + static SENSOR_DEVICE_ATTR(fan##index2##_input, S_IRUGO, fan_show_value, NULL, \ + FAN##index2##_RPM); \ + static SENSOR_DEVICE_ATTR(fan##index##_led, S_IRUGO, fan_show_value, NULL,\ + FAN##index##_LED); \ + +#define DECLARE_FAN_ATTR(index, index2) \ + &sensor_dev_attr_fan##index##_present.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_pwm.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_pwm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_led.dev_attr.attr + +#define DECLARE_FAN_FW_VERSION_SENSOR_DEV_ATTR() \ + static SENSOR_DEVICE_ATTR(version, S_IRUGO, fan_show_value, NULL, FAN_FW_VERSION) + +#define DECLARE_FAN_FW_VERSION_ATTR() &sensor_dev_attr_version.dev_attr.attr + +#define DECLARE_FAN_PCB_VERSION_SENSOR_DEV_ATTR() \ + static SENSOR_DEVICE_ATTR(pcb_version, S_IRUGO, fan_show_value, NULL, FAN_PCB_VERSION) + +#define DECLARE_FAN_PCB_VERSION_ATTR() &sensor_dev_attr_pcb_version.dev_attr.attr + +#define DECLARE_FAN_ACCESS_SENSOR_DEV_ATTR() \ + static SENSOR_DEVICE_ATTR(access, S_IWUSR | S_IRUGO, reg_read, reg_write, FAN_ACCESS) + +#define DECLARE_FAN_ACCESS_ATTR() &sensor_dev_attr_access.dev_attr.attr + +DECLARE_FAN_SENSOR_DEVICE_ATTR(1, 5); +DECLARE_FAN_SENSOR_DEVICE_ATTR(2, 6); +DECLARE_FAN_SENSOR_DEVICE_ATTR(3, 7); +DECLARE_FAN_SENSOR_DEVICE_ATTR(4, 8); +DECLARE_FAN_FW_VERSION_SENSOR_DEV_ATTR(); +DECLARE_FAN_PCB_VERSION_SENSOR_DEV_ATTR(); +DECLARE_FAN_ACCESS_SENSOR_DEV_ATTR(); + +static struct attribute *h6_fan_attributes[] = { + /* fan related attributes */ + DECLARE_FAN_ATTR(1, 5), + DECLARE_FAN_ATTR(2, 6), + DECLARE_FAN_ATTR(3, 7), + DECLARE_FAN_ATTR(4, 8), + DECLARE_FAN_FW_VERSION_ATTR(), + DECLARE_FAN_PCB_VERSION_ATTR(), + DECLARE_FAN_ACCESS_ATTR(), + NULL +}; + +#define FAN_DUTY_CYCLE_REG_MASK 0xF +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 150 + +static int h6_fan_read_value(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int h6_fan_write_value(struct i2c_client *client, u8 reg, + u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32) reg_val *FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + return !((reg_val >> id) & 0x1); +} + +static u8 reg_val_to_color(u8 reg_val, enum fan_id id) +{ + u8 green_mask = (1 << (7 - (id * 2))); + u8 red_mask = (1 << (6 - (id * 2))); + + if (!(reg_val & green_mask)) + return FAN_LED_MODE_GREEN; + else if (!(reg_val & red_mask)) + return FAN_LED_MODE_RED; + else + return FAN_LED_MODE_OFF; +} + +static u8 reg_val_to_led(u8 reg_val, enum fan_id id) +{ + return (reg_val >> (id * 2)) & 0x3; +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct h6_fan_data *data = dev_get_drvdata(dev); + u8 reg_val, idx; + + error = kstrtoint(buf, 10, &value); + if (error) { + return error; + } + + if (value < 0 || value > FAN_MAX_DUTY_CYCLE) { + return -EINVAL; + } + + switch (attr->index) { + case FAN1_PWM ... FAN8_PWM: + reg_val = (value * 100) / 666; + idx = (attr->index - FAN1_PWM); + + mutex_lock(&data->update_lock); + /* Front FAN */ + h6_fan_write_value(data->client, + fan_reg[FAN1_FRONT_PWM_REG + idx], + reg_val); + /* force update register */ + data->valid = 0; + mutex_unlock(&data->update_lock); + break; + default: + break; + } + + return count; +} + +static ssize_t set_fan_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct h6_fan_data *data = dev_get_drvdata(dev); + u8 green_mask, red_mask; + u8 reg_val; + + error = kstrtoint(buf, 10, &value); + if (error) { + return error; + } + + if (value < 0) { + return -EINVAL; + } + else if (value != FAN_LED_MODE_GREEN && + value != FAN_LED_MODE_RED && + value != FAN_LED_MODE_OFF) { + return -EINVAL; + } + + switch (attr->index) { + case FAN1_LED ... FAN4_LED: + green_mask = (1 << (7 - ((attr->index - FAN1_LED) * 2))); + red_mask = (1 << (6 - ((attr->index - FAN1_LED) * 2))); + reg_val = h6_fan_read_value(data->client, fan_reg[FAN_LED_REG]); + switch (value) { + case FAN_LED_MODE_RED: + reg_val |= green_mask; + reg_val &= ~(red_mask); + break; + case FAN_LED_MODE_GREEN: + reg_val |= red_mask; + reg_val &= ~(green_mask); + break; + case FAN_LED_MODE_OFF: + reg_val |= (green_mask); + reg_val |= (red_mask); + break; + default: + break; + } + mutex_lock(&data->update_lock); + h6_fan_write_value(data->client, fan_reg[FAN_LED_REG], + reg_val); + /* force update register */ + data->valid = 0; + mutex_unlock(&data->update_lock); + break; + default: + break; + } + + return count; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct h6_fan_data *data = h6_fan_update_device(dev); + ssize_t ret = 0; + u8 idx, reg_val; + + if (!data->valid) { + return ret; + } + + switch (attr->index) { + case FAN_PCB_VERSION: + ret = sprintf(buf, "0x%02x\n", data->reg_val[FAN_PCB_REG]); + break; + case FAN_FW_VERSION: + ret = sprintf(buf, "%d.%d\n", + data->reg_val[FAN_MAJOR_VERSION_REG], + data->reg_val[FAN_MINOR_VERSION_REG]); + break; + case FAN1_PWM ... FAN8_PWM: + reg_val = data->reg_val[FAN1_FRONT_PWM_REG + + (attr->index - FAN1_PWM)] & 0x0F; + ret = sprintf(buf, "%u\n", (reg_val * 667) / 100); + break; + case FAN1_RPM ... FAN8_RPM: + idx = FAN1_FRONT_SPEED_RPM_REG + (attr->index - FAN1_RPM); + ret = sprintf(buf, "%u\n", + reg_val_to_speed_rpm(data->reg_val[idx])); + break; + case FAN1_PRESENT ... FAN4_PRESENT: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG], + attr->index - FAN1_PRESENT)); + break; + case FAN1_LED ... FAN4_LED: + ret = sprintf(buf, "%d\n", + reg_val_to_led(data->reg_val[FAN_LED_REG], + attr->index - FAN1_LED)); + break; + default: + break; + } + + return ret; +} + +static ssize_t reg_read(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct h6_fan_data *data = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + u8 reg_val; + + reg_val = h6_fan_read_value(data->client, data->reg_addr); + ret = sprintf(buf, "0x%02x\n", reg_val); + + return ret; +} + +static ssize_t reg_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct h6_fan_data *data = dev_get_drvdata(dev); + int args; + char *opt, tmp[32] = { 0 }; + char *tmp_p; + size_t copy_size; + u8 input[2] = { 0 }; + + copy_size = (count < sizeof(tmp)) ? count : sizeof(tmp) - 1; +#ifdef __STDC_LIB_EXT1__ + memcpy_s(tmp, copy_size, buf, copy_size); +#else + memcpy(tmp, buf, copy_size); +#endif + tmp[copy_size] = '\0'; + + args = 0; + tmp_p = tmp; + while (args < 2 && (opt = strsep(&tmp_p, " ")) != NULL) { + if (kstrtou8(opt, 16, &input[args]) == 0) { + args++; + } + } + + switch (args) { + case 2: + /* Write value to register */ + mutex_lock(&data->update_lock); + h6_fan_write_value(data->client, input[0], input[1]); + data->valid = 0; + mutex_unlock(&data->update_lock); + break; + case 1: + /* Read value from register */ + data->reg_addr = input[0]; + break; + default: + return -EINVAL; + } + + return count; +} + +static const struct attribute_group h6_fan_group = { + .attrs = h6_fan_attributes, +}; + +__ATTRIBUTE_GROUPS(h6_fan); + +static struct h6_fan_data *h6_fan_update_device(struct device + *dev) +{ + struct h6_fan_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(dev, "Starting h6_fan update\n"); + data->valid = 0; + + /* Update fan data */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + int status = h6_fan_read_value(data->client, fan_reg[i]); + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(dev, "reg %d, err %d\n", fan_reg[i], + status); + return data; + } else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static int h6_fan_probe(struct i2c_client *client) +{ + struct h6_fan_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct h6_fan_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->client = client; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + data->hwmon_dev = + hwmon_device_register_with_groups(&client->dev, client->name, data, + h6_fan_groups); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_free; + } + + dev_info(&client->dev, "%s: fan '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + + exit_free: + kfree(data); + exit: + return status; +} + +static void h6_fan_remove(struct i2c_client *client) +{ + struct h6_fan_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + kfree(data); + +} + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { 0x33, I2C_CLIENT_END }; + +static const struct i2c_device_id h6_fan_id[] = { + {"h6_fan", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, h6_fan_id); + +static struct i2c_driver h6_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = h6_fan_probe, + .remove = h6_fan_remove, + .id_table = h6_fan_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(h6_fan_driver); + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("FAN Driver"); +MODULE_LICENSE("GPL"); diff --git a/ixr7220h6-128/modules/h6_i2c_oc.c b/ixr7220h6-128/modules/h6_i2c_oc.c new file mode 100644 index 0000000..6e78663 --- /dev/null +++ b/ixr7220h6-128/modules/h6_i2c_oc.c @@ -0,0 +1,312 @@ +// Driver for Nokia-7220-IXR-H6-128 Router +/* + * Copyright (C) 2025 Accton Technology Corporation. + * Copyright (C) 2025 Nokia Corporation. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * see + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT_NUM (128 + 2) /*128 OSFPs + 2 SFP28s*/ + +/* + * PCIE BAR0 address + */ +#define BAR0_NUM 0 +#define BAR1_NUM 1 +#define BAR2_NUM 2 +#define REGION_LEN 0xFF +#define FPGA_PCI_VENDOR_ID 0x10ee +#define FPGA_PCI_DEVICE_ID 0x7021 + +/* CPLD 1 */ +#define CPLD1_PCIE_START_OFFSET 0x2000 + +/* CPLD 2 */ +#define CPLD2_PCIE_START_OFFSET 0x3000 + +static uint param_i2c_khz = 400; +module_param(param_i2c_khz, uint, S_IRUGO); +MODULE_PARM_DESC(param_i2c_khz, "Target clock speed of i2c bus, in KHz."); + +static struct pci_dev *g_pcidev = NULL; + +static const uint adapt_offset[PORT_NUM]= { + 0x2100,// MESS_TOP_L_CPLD I2C Master OSFP Port1 + 0x2120,// MESS_TOP_L_CPLD I2C Master OSFP Port2 + 0x2100,// PORTCPLD0 I2C Master OSFP Port3 + 0x2120,// PORTCPLD0 I2C Master OSFP Port4 + 0x2140,// PORTCPLD0 I2C Master OSFP Port5 + 0x2160,// PORTCPLD0 I2C Master OSFP Port6 + 0x2100,// MESS_BOT_L_CPLD I2C Master OSFP Port7 + 0x2120,// MESS_BOT_L_CPLD I2C Master OSFP Port8 + 0x2140,// MESS_TOP_L_CPLD I2C Master OSFP Port9 + 0x2160,// MESS_TOP_L_CPLD I2C Master OSFP Port10 + 0x2180,// PORTCPLD0 I2C Master OSFP Port11 + 0x21A0,// PORTCPLD0 I2C Master OSFP Port12 + 0x21C0,// PORTCPLD0 I2C Master OSFP Port13 + 0x21E0,// PORTCPLD0 I2C Master OSFP Port14 + 0x2140,// MESS_BOT_L_CPLD I2C Master OSFP Port15 + 0x2160,// MESS_BOT_L_CPLD I2C Master OSFP Port16 + 0x2180,// MESS_TOP_L_CPLD I2C Master OSFP Port17 + 0x21A0,// MESS_TOP_L_CPLD I2C Master OSFP Port18 + 0x2200,// PORTCPLD0 I2C Master OSFP Port19 + 0x2220,// PORTCPLD0 I2C Master OSFP Port20 + 0x2240,// PORTCPLD0 I2C Master OSFP Port21 + 0x2260,// PORTCPLD0 I2C Master OSFP Port22 + 0x2180,// MESS_BOT_L_CPLD I2C Master OSFP Port23 + 0x21A0,// MESS_BOT_L_CPLD I2C Master OSFP Port24 + 0x21C0,// MESS_TOP_L_CPLD I2C Master OSFP Port25 + 0x21E0,// MESS_TOP_L_CPLD I2C Master OSFP Port26 + 0x2280,// PORTCPLD0 I2C Master OSFP Port27 + 0x22A0,// PORTCPLD0 I2C Master OSFP Port28 + 0x22C0,// PORTCPLD0 I2C Master OSFP Port29 + 0x22E0,// PORTCPLD0 I2C Master OSFP Port30 + 0x21C0,// MESS_BOT_L_CPLD I2C Master OSFP Port31 + 0x21E0,// MESS_BOT_L_CPLD I2C Master OSFP Port32 +////////////////////////////////////////////////////// + 0x2200,// MESS_TOP_L_CPLD I2C Master OSFP Port33 + 0x2220,// MESS_TOP_L_CPLD I2C Master OSFP Port34 + 0x2300,// PORTCPLD0 I2C Master OSFP Port35 + 0x2320,// PORTCPLD0 I2C Master OSFP Port36 + 0x2340,// PORTCPLD0 I2C Master OSFP Port37 + 0x2360,// PORTCPLD0 I2C Master OSFP Port38 + 0x2200,// MESS_BOT_L_CPLD I2C Master OSFP Port39 + 0x2220,// MESS_BOT_L_CPLD I2C Master OSFP Port40 + 0x2240,// MESS_TOP_L_CPLD I2C Master OSFP Port41 + 0x2260,// MESS_TOP_L_CPLD I2C Master OSFP Port42 + 0x2380,// PORTCPLD0 I2C Master OSFP Port43 + 0x23A0,// PORTCPLD0 I2C Master OSFP Port44 + 0x23C0,// PORTCPLD0 I2C Master OSFP Port45 + 0x23E0,// PORTCPLD0 I2C Master OSFP Port46 + 0x2240,// MESS_BOT_L_CPLD I2C Master OSFP Port47 + 0x2260,// MESS_BOT_L_CPLD I2C Master OSFP Port48 + 0x2280,// MESS_TOP_L_CPLD I2C Master OSFP Port49 + 0x22A0,// MESS_TOP_L_CPLD I2C Master OSFP Port50 + 0x2400,// PORTCPLD0 I2C Master OSFP Port51 + 0x2420,// PORTCPLD0 I2C Master OSFP Port52 + 0x2440,// PORTCPLD0 I2C Master OSFP Port53 + 0x2460,// PORTCPLD0 I2C Master OSFP Port54 + 0x2280,// MESS_BOT_L_CPLD I2C Master OSFP Port55 + 0x22A0,// MESS_BOT_L_CPLD I2C Master OSFP Port56 + 0x22C0,// MESS_TOP_L_CPLD I2C Master OSFP Port57 + 0x22E0,// MESS_TOP_L_CPLD I2C Master OSFP Port58 + 0x2480,// PORTCPLD0 I2C Master OSFP Port59 + 0x24A0,// PORTCPLD0 I2C Master OSFP Port60 + 0x24C0,// PORTCPLD0 I2C Master OSFP Port61 + 0x24E0,// PORTCPLD0 I2C Master OSFP Port62 + 0x22C0,// MESS_BOT_L_CPLD I2C Master OSFP Port63 + 0x22E0,// MESS_BOT_L_CPLD I2C Master OSFP Port64 +////////////////////////////////////////////////////// + 0x2100,// MESS_TOP_R_CPLD I2C Master OSFP Port65 + 0x2120,// MESS_TOP_R_CPLD I2C Master OSFP Port66 + 0x2100,// PORTCPLD1 I2C Master OSFP Port67 + 0x2120,// PORTCPLD1 I2C Master OSFP Port68 + 0x2140,// PORTCPLD1 I2C Master OSFP Port69 + 0x2160,// PORTCPLD1 I2C Master OSFP Port70 + 0x2100,// MESS_BOT_R_CPLD I2C Master OSFP Port71 + 0x2120,// MESS_BOT_R_CPLD I2C Master OSFP Port72 + 0x2140,// MESS_TOP_R_CPLD I2C Master OSFP Port73 + 0x2160,// MESS_TOP_R_CPLD I2C Master OSFP Port74 + 0x2180,// PORTCPLD1 I2C Master OSFP Port75 + 0x21A0,// PORTCPLD1 I2C Master OSFP Port76 + 0x21C0,// PORTCPLD1 I2C Master OSFP Port77 + 0x21E0,// PORTCPLD1 I2C Master OSFP Port78 + 0x2140,// MESS_BOT_R_CPLD I2C Master OSFP Port79 + 0x2160,// MESS_BOT_R_CPLD I2C Master OSFP Port80 + 0x2180,// MESS_TOP_R_CPLD I2C Master OSFP Port81 + 0x21A0,// MESS_TOP_R_CPLD I2C Master OSFP Port82 + 0x2200,// PORTCPLD1 I2C Master OSFP Port83 + 0x2220,// PORTCPLD1 I2C Master OSFP Port84 + 0x2240,// PORTCPLD1 I2C Master OSFP Port85 + 0x2260,// PORTCPLD1 I2C Master OSFP Port86 + 0x2180,// MESS_BOT_R_CPLD I2C Master OSFP Port87 + 0x21A0,// MESS_BOT_R_CPLD I2C Master OSFP Port88 + 0x21C0,// MESS_TOP_R_CPLD I2C Master OSFP Port89 + 0x21E0,// MESS_TOP_R_CPLD I2C Master OSFP Port90 + 0x2280,// PORTCPLD1 I2C Master OSFP Port91 + 0x22A0,// PORTCPLD1 I2C Master OSFP Port92 + 0x22C0,// PORTCPLD1 I2C Master OSFP Port93 + 0x22E0,// PORTCPLD1 I2C Master OSFP Port94 + 0x21C0,// MESS_BOT_R_CPLD I2C Master OSFP Port95 + 0x21E0,// MESS_BOT_R_CPLD I2C Master OSFP Port96 +////////////////////////////////////////////////////// + 0x2200,// MESS_TOP_R_CPLD I2C Master OSFP Port97 + 0x2220,// MESS_TOP_R_CPLD I2C Master OSFP Port98 + 0x2300,// PORTCPLD1 I2C Master OSFP Port99 + 0x2320,// PORTCPLD1 I2C Master OSFP Port100 + 0x2340,// PORTCPLD1 I2C Master OSFP Port101 + 0x2360,// PORTCPLD1 I2C Master OSFP Port102 + 0x2200,// MESS_BOT_R_CPLD I2C Master OSFP Port103 + 0x2220,// MESS_BOT_R_CPLD I2C Master OSFP Port104 + 0x2240,// MESS_TOP_R_CPLD I2C Master OSFP Port105 + 0x2260,// MESS_TOP_R_CPLD I2C Master OSFP Port106 + 0x2380,// PORTCPLD1 I2C Master OSFP Port107 + 0x23A0,// PORTCPLD1 I2C Master OSFP Port108 + 0x23C0,// PORTCPLD1 I2C Master OSFP Port109 + 0x23E0,// PORTCPLD1 I2C Master OSFP Port110 + 0x2240,// MESS_BOT_R_CPLD I2C Master OSFP Port111 + 0x2260,// MESS_BOT_R_CPLD I2C Master OSFP Port112 + 0x2280,// MESS_TOP_R_CPLD I2C Master OSFP Port113 + 0x22A0,// MESS_TOP_R_CPLD I2C Master OSFP Port114 + 0x2400,// PORTCPLD1 I2C Master OSFP Port115 + 0x2420,// PORTCPLD1 I2C Master OSFP Port116 + 0x2440,// PORTCPLD1 I2C Master OSFP Port117 + 0x2460,// PORTCPLD1 I2C Master OSFP Port118 + 0x2280,// MESS_BOT_R_CPLD I2C Master OSFP Port119 + 0x22A0,// MESS_BOT_R_CPLD I2C Master OSFP Port120 + 0x22C0,// MESS_TOP_R_CPLD I2C Master OSFP Port121 + 0x22E0,// MESS_TOP_R_CPLD I2C Master OSFP Port122 + 0x2480,// PORTCPLD1 I2C Master OSFP Port123 + 0x24A0,// PORTCPLD1 I2C Master OSFP Port124 + 0x24C0,// PORTCPLD1 I2C Master OSFP Port125 + 0x24E0,// PORTCPLD1 I2C Master OSFP Port126 + 0x22C0,// MESS_BOT_R_CPLD I2C Master OSFP Port127 + 0x22E0,// MESS_BOT_R_CPLD I2C Master OSFP Port128 + 0x2500,// MESS_BOT_R_CPLD I2C Master SFP Port1 + 0x2520,// MESS_BOT_R_CPLD I2C Master SFP Port2 +}; + +static struct ocores_i2c_platform_data i2c_data = { + .reg_shift = 2, + .clock_khz = 25000, + .bus_khz = 400, + .devices = NULL, //trcv_nvm, + .num_devices = 1 //ARRAY_SIZE(trcv_nvm) +}; + +static void ftdi_release_platform_dev(struct device *dev) +{ + dev->parent = NULL; +} + +static struct platform_device myi2c[PORT_NUM] = {{0}}; +static int __init h6_ocore_i2c_init(void) +{ + int i, err = 0; + static const char *devname = "ocores-i2c"; + static struct resource ocores_resources[PORT_NUM] = {0}; + struct pci_dev *pcidev; + int status = 0; + unsigned long bar_base; + struct resource *res; + struct platform_device *p = NULL; + + pcidev = pci_get_device(FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID, NULL); + if (!pcidev) { + pr_err("Cannot found PCI device(%x:%x)\n", + FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID); + return -ENODEV; + } + + g_pcidev = pcidev; + + err = pci_enable_device(pcidev); + if (err != 0) { + pr_err("Cannot enable PCI device(%x:%x)\n", + FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID); + status = -ENODEV; + goto exit_pci_put; + } + /* enable PCI bus-mastering */ + pci_set_master(pcidev); + + status = pci_enable_msi(pcidev); + if (status < 0) { + pr_err("Failed to allocate IRQ vectors: %d\n", status); + goto exit_pci_disable; + } + + i2c_data.bus_khz = clamp_val(param_i2c_khz, 50, 400); + for(i = 0; i < PORT_NUM; i++) { + p = &myi2c[i]; + p->name = devname; + p->id = i; + p->dev.platform_data = &i2c_data; + p->dev.release = ftdi_release_platform_dev; + res = &ocores_resources[i]; + switch (i) + { + case 0 ... 129: + bar_base = pci_resource_start(pcidev, BAR0_NUM); + break; + default: + break; + } + res->start = bar_base + adapt_offset[i]; + res->end = res->start + 0x20 - 1; + res->name = NULL; + res->flags =IORESOURCE_MEM; + res->desc = IORES_DESC_NONE; + p->num_resources = 1; + p->resource = res; + err = platform_device_register(p); + if (err) + goto unload; + } + + return 0; + +unload: + { + int j; + pr_err("[ERROR]rc:%d, unload %u register devices\n", err, i); + for(j = 0; j < i; j++) { + platform_device_unregister(&myi2c[j]); + } + } + pci_disable_msi(pcidev); + +exit_pci_disable: + pci_disable_device(pcidev); + +exit_pci_put: + pci_dev_put(pcidev); + g_pcidev = NULL; + + return status ? status : err; +} + +static void __exit h6_ocore_i2c_exit(void) +{ + int i; + for(i = PORT_NUM ; i > 0; i--) { + platform_device_unregister(&myi2c[i-1]); + } + if (g_pcidev) { + pci_disable_msi(g_pcidev); + pci_disable_device(g_pcidev); + pci_dev_put(g_pcidev); + g_pcidev = NULL; + } +} + +module_init(h6_ocore_i2c_init); +module_exit(h6_ocore_i2c_exit); + +MODULE_AUTHOR("Roy Lee "); +MODULE_DESCRIPTION("h6 ocore_i2c platform device driver"); +MODULE_LICENSE("GPL"); diff --git a/ixr7220h6-128/modules/i2c-ocores.c b/ixr7220h6-128/modules/i2c-ocores.c new file mode 100644 index 0000000..d45b262 --- /dev/null +++ b/ixr7220h6-128/modules/i2c-ocores.c @@ -0,0 +1,885 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (https://opencores.org/project/i2c/overview) + * + * Peter Korsgaard + * + * Support for the GRLIB port of the controller by + * Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum _print_level {PL_ERR, PL_WARN, PL_INFO, PL_DEBUG}; + +static uint param_verbose = PL_WARN; +module_param(param_verbose, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(param_verbose, "Print more information for debugging. It can be 0,1 2, or 3."); + +static uint param_timeout = 1; +module_param(param_timeout, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(param_timeout, "for debugging. 1 ms should be enough"); + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + void __iomem *base; + int iobase; + u32 reg_shift; + u32 reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + spinlock_t process_lock; + struct clk *clk; + int ip_clock_khz; + int bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); +}; + +/* registers */ +#define OCI2C_PRELOW 0 +#define OCI2C_PREHIGH 1 +#define OCI2C_CONTROL 2 +#define OCI2C_DATA 3 +#define OCI2C_CMD 4 /* write only */ +#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ + +#define OCI2C_CTRL_IEN 0x40 +#define OCI2C_CTRL_EN 0x80 + +#define OCI2C_CMD_START 0x91 +#define OCI2C_CMD_STOP 0x41 +#define OCI2C_CMD_READ 0x21 +#define OCI2C_CMD_WRITE 0x11 +#define OCI2C_CMD_READ_ACK 0x21 +#define OCI2C_CMD_READ_NACK 0x29 +#define OCI2C_CMD_IACK 0x01 + +#define OCI2C_STAT_IF 0x01 +#define OCI2C_STAT_TIP 0x02 +#define OCI2C_STAT_ARBLOST 0x20 +#define OCI2C_STAT_BUSY 0x40 +#define OCI2C_STAT_NACK 0x80 + +#define STATE_DONE 0 +#define STATE_START 1 +#define STATE_WRITE 2 +#define STATE_READ 3 +#define STATE_ERROR 4 + +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 +#define TYPE_SIFIVE_REV0 2 + +#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */ + +#define DEBUG(args...) \ + debug_print(__func__, __LINE__, PL_DEBUG, args) +#define INFO(args...) \ + debug_print(__func__, __LINE__, PL_INFO, args) +#define _WARN(args...) \ + debug_print(__func__, __LINE__, PL_WARN, args) +#define ERR(args...) \ + debug_print(__func__, __LINE__, PL_ERR, args) +/*-----------------------------------------------------------------------*/ +static void debug_print(const char *func, int line, u32 level, + const char *fmt, ...) +{ + va_list args; + char buf[256]; + if (param_verbose >= level) { + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + pr_info("[%d]%s#%d: %s\n", level, func, line, buf); + } +} + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + outb(value, i2c->iobase + reg); +} + +static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) +{ + return inb(i2c->iobase + reg); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + i2c->setreg(i2c, reg, value); + DEBUG("Write 0x%02x to 0x%02x\n", value, reg); +} + +static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + u8 value; + value = i2c->getreg(i2c, reg); + + DEBUG("Read 0x%02x from 0x%02x\n", value, reg); + return value; +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + unsigned long flags; + + /* + * If we spin here is because we are in timeout, so we are going + * to be in STATE_ERROR. See ocores_process_timeout() + */ + spin_lock_irqsave(&i2c->process_lock, flags); + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + /*_WARN("I2C %s arbitration lost", i2c->adap.name);*/ + dev_warn(i2c->adap.dev.parent, "arbitration lost, stat:%02x", stat); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + i2c->state = STATE_ERROR; + /*DEBUG("I2C %s, no ACK from slave 0x%02x", i2c->adap.name, msg->addr);*/ + dev_warn(i2c->adap.dev.parent, "no ACK from slave 0x%02x", msg->addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = i2c_8bit_addr_from_msg(msg); + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + goto out; + } + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } + +out: + spin_unlock_irqrestore(&i2c->process_lock, flags); + +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat = oc_getreg(i2c, OCI2C_STATUS); + + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) { + if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY)) + return IRQ_NONE; + } else if (!(stat & OCI2C_STAT_IF)) { + return IRQ_NONE; + } + ocores_process(i2c, stat); + + return IRQ_HANDLED; +} + +/** + * Process timeout event + * @i2c: ocores I2C device instance + */ +static void ocores_process_timeout(struct ocores_i2c *i2c) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c->process_lock, flags); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +/** + * Wait until something change in a given register + * @i2c: ocores I2C device instance + * @reg: register to query + * @mask: bitmask to apply on register value + * @val: expected result + * @timeout: timeout in jiffies + * + * Timeout is necessary to avoid to stay here forever when the chip + * does not answer correctly. + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_wait(struct ocores_i2c *i2c, + int reg, u8 mask, u8 val, + const unsigned long timeout) +{ + unsigned long j; + + j = jiffies + timeout; + while (1) { + u8 status = oc_getreg(i2c, reg); + + if ((status & mask) == val) + break; + + if (time_after(jiffies, j)) + return -ETIMEDOUT; + } + return 0; +} + +/** + * Wait until is possible to process some data + * @i2c: ocores I2C device instance + * + * Used when the device is in polling mode (interrupts disabled). + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_poll_wait(struct ocores_i2c *i2c) +{ + u8 mask; + int err; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* transfer is over */ + mask = OCI2C_STAT_BUSY; + } else { + /* on going transfer */ + mask = OCI2C_STAT_TIP; + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + */ + udelay((8 * 1000) / i2c->bus_clock_khz); + } + + /* + * once we are here we expect to get the expected result immediately + * so if after 1ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(param_timeout)); + if (err) + dev_warn(i2c->adap.dev.parent, + "%s: STATUS timeout, bit 0x%x did not clear in %u ms\n", + __func__, mask, param_timeout); + return err; +} + +/** + * It handles an IRQ-less transfer + * @i2c: ocores I2C device instance + * + * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same + * (only that IRQ are not produced). This means that we can re-use entirely + * ocores_isr(), we just add our polling code around it. + * + * It can run in atomic context + */ +static void ocores_process_polling(struct ocores_i2c *i2c) +{ + while (1) { + irqreturn_t ret; + int err; + + err = ocores_poll_wait(i2c); + if (err) { + i2c->state = STATE_ERROR; + break; /* timeout */ + } + + ret = ocores_isr(-1, i2c); + if (ret == IRQ_NONE) + break; /* all messages have been transferred */ + else { + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) + if (i2c->state == STATE_DONE) + break; + } + } +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret; + u8 ctrl; + + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + if (polling) + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); + else + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + if (polling) { + ocores_process_polling(i2c); + } else { + ret = wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ); + if (ret == 0) { + ocores_process_timeout(i2c); + return -ETIMEDOUT; + } + } + + return (i2c->state == STATE_DONE) ? num : -EIO; +} + +static int ocores_xfer_polling(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); +} + +static int ocores_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, false); +} + +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) +{ + int prescale; + int diff; + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + dev_err(dev, + "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + + return 0; +} + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .master_xfer_atomic = ocores_xfer_polling, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "i2c-ocores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + { + .compatible = "sifive,fu540-c000-i2c", + .data = (void *)TYPE_SIFIVE_REV0, + }, + { + .compatible = "sifive,i2c0", + .data = (void *)TYPE_SIFIVE_REV0, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +#ifdef CONFIG_OF +/* + * Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers have their offsets decreased accordingly. + */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + u32 val; + u32 clock_frequency; + bool clock_frequency_present; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } + } + + clock_frequency_present = !of_property_read_u32(np, "clock-frequency", + &clock_frequency); + i2c->bus_clock_khz = 100; + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(i2c->clk)) { + int ret = clk_prepare_enable(i2c->clk); + + DEBUG("Write %d KHz => %dKHz", i2c->ip_clock_khz, i2c->clk); + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + + if (i2c->ip_clock_khz == 0) { + if (of_property_read_u32(np, "opencores,ip-clock-frequency", + &val)) { + if (!clock_frequency_present) { + dev_err(&pdev->dev, + "Missing required parameter 'opencores,ip-clock-frequency'\n"); + clk_disable_unprepare(i2c->clk); + return -ENODEV; + } + i2c->ip_clock_khz = clock_frequency / 1000; + dev_warn(&pdev->dev, + "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); + } else { + i2c->ip_clock_khz = val / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + } + + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + + return 0; +} +#else +#define ocores_i2c_of_probe(pdev, i2c) -ENODEV +#endif + +static void __iomem *ocores_devm_ioremap(struct device *dev, struct resource *res) +{ + resource_size_t size; + void __iomem *dest_ptr; + + BUG_ON(!dev); + + if (!res || resource_type(res) != IORESOURCE_MEM) { + dev_err(dev, "invalid resource\n"); + return IOMEM_ERR_PTR(-EINVAL); + } + + size = resource_size(res); + dest_ptr = devm_ioremap(dev, res->start, size); + if (!dest_ptr) { + dev_err(dev, "ioremap failed for resource %pR\n", res); + dest_ptr = IOMEM_ERR_PTR(-ENOMEM); + } + + return dest_ptr; +} + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + struct ocores_i2c_platform_data *pdata; + const struct of_device_id *match; + struct resource *res; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + spin_lock_init(&i2c->process_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + i2c->base = ocores_devm_ioremap(&pdev->dev, res); + dev_info(&pdev->dev, "Resouce start:0x%llx, end:0x%llx", res->start, res->end); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + } else { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EINVAL; + i2c->iobase = res->start; + if (!devm_request_region(&pdev->dev, res->start, + resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Can't get I/O resource.\n"); + return -EBUSY; + } + i2c->setreg = oc_setreg_io_8; + i2c->getreg = oc_getreg_io_8; + } + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; + i2c->ip_clock_khz = pdata->clock_khz; + INFO("Write %d KHz, ioWidth:%d, shift:%d", i2c->ip_clock_khz, pdata->reg_io_width ,pdata->reg_shift); + if (pdata->bus_khz) + i2c->bus_clock_khz = pdata->bus_khz; + else + i2c->bus_clock_khz = 100; + } else { + INFO("No specific config"); + ret = ocores_i2c_of_probe(pdev, i2c); + if (ret) + return ret; + } + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->setreg || !i2c->getreg) { + bool be = pdata ? pdata->big_endian : + of_device_is_big_endian(pdev->dev.of_node); + + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case 4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto err_clk; + } + } + + init_waitqueue_head(&i2c->wait); + + // irq == -ENXIO + ocores_algorithm.master_xfer = ocores_xfer_polling; + + /* + * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for + * FU540-C000 SoC in polling mode. + */ + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_SIFIVE_REV0) + i2c->flags |= OCORES_FLAG_BROKEN_IRQ; + + DEBUG("Write ocores_init"); + ret = ocores_init(&pdev->dev, i2c); + if (ret) { + ERR("Fail init device id %u", pdev->id); + goto err_clk; + } + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + DEBUG("pdev:%p dev:%p = %p", pdev, &pdev->dev, i2c->adap.dev.parent); + i2c->adap.dev.of_node = pdev->dev.of_node; + DEBUG("Config adap:%s", i2c->adap.name); + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) { + ERR("Fail to add adap:%s", i2c->adap.name); + goto err_clk; + } + + return 0; + +err_clk: + DEBUG("err_ret:%d", ret); + clk_disable_unprepare(i2c->clk); + return ret; +} + +static void ocores_i2c_remove(struct platform_device *pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* disable i2c logic */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + +} + +#ifdef CONFIG_PM_SLEEP +static int ocores_i2c_suspend(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + return 0; +} + +static int ocores_i2c_resume(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + + if (!IS_ERR(i2c->clk)) { + unsigned long rate; + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; + } + return ocores_init(dev, i2c); +} + +static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); +#define OCORES_I2C_PM (&ocores_i2c_pm) +#else +#define OCORES_I2C_PM NULL +#endif + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "ocores-i2c", + .of_match_table = ocores_i2c_match, + .pm = OCORES_I2C_PM, + }, +}; + +static int __init ocores_i2c_as1813_init(void) +{ + int err; + + err = platform_driver_register(&ocores_i2c_driver); + if (err < 0) { + ERR("Failed to register ocores_i2c_driver"); + return err; + } + return 0; +} +static void __exit ocores_i2c_as1813_exit(void) +{ + platform_driver_unregister(&ocores_i2c_driver); + +} + +module_init(ocores_i2c_as1813_init); +module_exit(ocores_i2c_as1813_exit); + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); \ No newline at end of file diff --git a/ixr7220h6-128/modules/pmbus_psu.c b/ixr7220h6-128/modules/pmbus_psu.c new file mode 100644 index 0000000..5f4d92e --- /dev/null +++ b/ixr7220h6-128/modules/pmbus_psu.c @@ -0,0 +1,563 @@ +// Driver for delta PSU +// +// Copyright (C) 2025 Delta Network Technology Corporation +// Copyright (C) 2025 Nokia Corporation. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PSU parameter */ +#define PSU_REG_OPERATION (0x01) +#define PSU_REG_RW_VOUT_MODE (0x20) +#define PSU_REG_STATUS (0x79) +#define PSU_REG_RO_FAN_STATUS (0x81) +#define PSU_REG_RO_FAN_SPEED (0x90) +#define PSU_REG_RO_VIN (0x88) +#define PSU_REG_RO_VOUT (0x8b) +#define PSU_REG_RO_IIN (0x89) +#define PSU_REG_RO_IOUT (0x8c) +#define PSU_REG_RO_POUT (0x96) +#define PSU_REG_RO_PIN (0x97) +#define PSU_REG_RO_TEMP1 (0x8d) +#define PSU_REG_RO_TEMP2 (0x8e) +#define PSU_REG_RO_TEMP3 (0x8f) +#define PSU_REG_RO_MFR_MODEL (0x9a) +#define PSU_REG_RO_MFR_SERIAL (0x9e) +#define PSU_REG_FW_REV (0xd9) +#define PSU_REG_LED (0xe2) +#define PSU_MFR_MODELNAME_LENGTH (16) +#define PSU_MFR_SERIALNUM_LENGTH (20) +#define PSU_DRIVER_NAME "pmbus_psu" + +/* fan in PSU */ +#define PSU_FAN_NUMBER (1) +#define PSU_FAN1_FAULT_BIT (7) + +/* thermal in PSU */ +#define PSU_THERMAL_NUMBER (3) + +/* Address scanned */ +static const unsigned short normal_i2c[] = { 0x58, 0x59, 0x5a, 0x5b, I2C_CLIENT_END }; + +/* This is additional data */ +struct psu_data +{ + struct mutex update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + /* Registers value */ + u8 vout_mode; + u16 v_in; + u16 v_out; + u16 i_in; + u16 i_out; + u16 p_in; + u16 p_out; + u16 temp_input[PSU_THERMAL_NUMBER]; + u8 fan_fault; + u16 fan_speed[PSU_FAN_NUMBER]; +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask); +static int calculate_return_value(int value); +static ssize_t for_vin(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_iin(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_iout(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_pin(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_pout(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp1(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp2(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp3(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_speed(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static int psu_read_byte(struct i2c_client *client, u8 reg); +static int psu_read_word(struct i2c_client *client, u8 reg); +static int psu_read_block(struct i2c_client *client, u8 command, u8 *data); +static struct psu_data *psu_update_device(struct device *dev, u8 reg); +static ssize_t for_serial(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_model(struct device *dev, struct device_attribute *dev_attr, char *buf); + +enum psu_sysfs_attributes +{ + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_FAN1_FAULT, + PSU_FAN1_DUTY_CYCLE, + PSU_FAN1_SPEED, + PSU_MFR_MODEL, + PSU_MFR_SERIAL, +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static int calculate_return_value(int value) +{ + int multiplier = 1000; + int exponent = 0, mantissa = 0; + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + + return (exponent >= 0) ? (mantissa << exponent) * multiplier : (mantissa * multiplier) / (1 << -exponent); + +} + +static ssize_t for_vin(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_VIN); + + return sprintf(buf, "%d\n", calculate_return_value(data->v_in)); +} + +static ssize_t for_iin(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_IIN); + + + return sprintf(buf, "%d\n", calculate_return_value(data->i_in)); +} + +static ssize_t for_iout(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_IOUT); + + return sprintf(buf, "%d\n", calculate_return_value(data->i_out)); +} + +static ssize_t for_pin(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_PIN); + + return sprintf(buf, "%d\n", calculate_return_value(data->p_in)); +} + +static ssize_t for_pout(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_POUT); + + return sprintf(buf, "%d\n", calculate_return_value(data->p_out)); +} + +static ssize_t for_temp1(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_TEMP1); + + return sprintf(buf, "%d\n", calculate_return_value(data->temp_input[0])); +} + +static ssize_t for_temp2(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_TEMP2); + + return sprintf(buf, "%d\n", calculate_return_value(data->temp_input[1])); +} + +static ssize_t for_temp3(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_TEMP3); + + return sprintf(buf, "%d\n", calculate_return_value(data->temp_input[2])); +} + +static ssize_t for_fan_speed(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_FAN_SPEED); + + return sprintf(buf, "%d\n", calculate_return_value(data->fan_speed[0])/1000); +} + +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RW_VOUT_MODE); + int exponent = 0, mantissa = 0; + int multiplier = 1000; + + data = psu_update_device(dev, PSU_REG_RO_VOUT); + mdelay(30); + exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + mantissa = data->v_out; + + return (exponent > 0) ? sprintf(buf, "%d\n", \ + mantissa * (1 << exponent)) : \ + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_FAN_STATUS); + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? PSU_FAN1_FAULT_BIT : (PSU_FAN1_FAULT_BIT - (attr->index - PSU_FAN1_FAULT)); + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_model(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 mfr_model[PSU_MFR_MODELNAME_LENGTH+1]; + int status; + + status = psu_read_block(client, PSU_REG_RO_MFR_MODEL, mfr_model); + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", PSU_REG_RO_MFR_MODEL, status); + mfr_model[1] = '\0'; + } + else + { + mfr_model[ARRAY_SIZE(mfr_model) - 1] = '\0'; + } + + return sprintf(buf, "%s\n", mfr_model); +} + +static ssize_t for_serial(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 mfr_serial[PSU_MFR_SERIALNUM_LENGTH+1]; + int status; + + status = psu_read_block(client, PSU_REG_RO_MFR_SERIAL, mfr_serial); + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", PSU_REG_RO_MFR_SERIAL, status); + mfr_serial[1] = '\0'; + } + else + { + mfr_serial[ARRAY_SIZE(mfr_serial) - 1] = '\0'; + } + + return sprintf(buf, "%s\n", mfr_serial); +} + +static int psu_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int psu_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int psu_write_byte_pec(struct i2c_client *client, u8 reg, \ + u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags |= I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, reg, + I2C_SMBUS_BYTE_DATA, &data); +} + +static int psu_read_block(struct i2c_client *client, u8 command, u8 *data) +{ + int result = i2c_smbus_read_block_data(client, command, data); + if (unlikely(result < 0)) + goto abort; + + result = 0; +abort: + return result; +} + +struct reg_data_byte +{ + u8 reg; + u8 *value; +}; + +struct reg_data_word +{ + u8 reg; + u16 *value; +}; + +static struct psu_data *psu_update_device(struct device *dev, u8 reg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated)) + { + int i, status; + + struct reg_data_byte regs_byte[] = { + {PSU_REG_RW_VOUT_MODE, &data->vout_mode}, + {PSU_REG_RO_FAN_STATUS, &data->fan_fault} + }; + + struct reg_data_word regs_word[] = { + {PSU_REG_RO_VIN, &data->v_in}, + {PSU_REG_RO_VOUT, &data->v_out}, + {PSU_REG_RO_IIN, &data->i_in}, + {PSU_REG_RO_IOUT, &data->i_out}, + {PSU_REG_RO_POUT, &data->p_out}, + {PSU_REG_RO_PIN, &data->p_in}, + {PSU_REG_RO_TEMP1, &(data->temp_input[0])}, + {PSU_REG_RO_TEMP2, &(data->temp_input[1])}, + {PSU_REG_RO_TEMP3, &(data->temp_input[2])}, + {PSU_REG_RO_FAN_SPEED, &(data->fan_speed[0])}, + }; + + //dev_info(&client->dev, "start data update\n"); + + /* one milliseconds from now */ + data->last_updated = jiffies + HZ / 1000; + + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) + { + if (reg != regs_byte[i].reg) + continue; + + status = psu_read_byte(client, regs_byte[i].reg); + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + } + else + { + *(regs_byte[i].value) = status; + } + break; + } + + for (i = 0; i < ARRAY_SIZE(regs_word); i++) + { + if (reg != regs_word[i].reg) + continue; + + status = psu_read_word(client, regs_word[i].reg); + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", regs_word[i].reg, status); + *(regs_word[i].value) = 0; + } + else + { + *(regs_word[i].value) = status; + } + break; + } + + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static ssize_t show_psu_rst(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 val; + + val = psu_read_byte(client, PSU_REG_OPERATION); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_psu_rst(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + const char *str_in = "Reset\n"; + int res = 0; + + if (strcmp(buf, str_in) == 0) { + dev_warn(&client->dev, "Reg(0x%02x) written to cycle this PSU\n", PSU_REG_OPERATION); + res = psu_write_byte_pec(client, PSU_REG_OPERATION, 0x60); + if (res < 0) { + dev_warn(&client->dev, "%s WRITE ERROR: reg(0x%02x) err %d\n", PSU_DRIVER_NAME, PSU_REG_OPERATION, res); + } + } + else + return -EINVAL; + + return count; +} + +static ssize_t show_psu_ioc(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int val; + + val = psu_read_word(client, PSU_REG_STATUS); + + return sprintf(buf, "%d\n", (val>>4) & 0x1 ? 1:0); +} + +static ssize_t show_psu_rev(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int status; + u8 rev[4]; + + status = psu_read_block(client, PSU_REG_FW_REV, rev); + + return sprintf(buf, "0x%02x 0x%02x 0x%02x\n", rev[2], rev[1], rev[0]); +} + +static ssize_t show_psu_led(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 val; + + val = psu_read_byte(client, PSU_REG_LED); + + return sprintf(buf, "%d\n", val); +} + +/* sysfs attributes */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, for_vin, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, for_vout_data, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, for_iin, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, for_iout, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, for_pin, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, for_pout, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, for_temp1, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, for_temp2, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, for_temp3, NULL, PSU_TEMP3_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, for_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, for_fan_speed, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, for_model, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, for_serial, NULL, PSU_MFR_SERIAL); +static SENSOR_DEVICE_ATTR(psu_rst, S_IRUGO | S_IWUSR, show_psu_rst, set_psu_rst, 0); +static SENSOR_DEVICE_ATTR(psu_ioc, S_IRUGO, show_psu_ioc, NULL, 0); +static SENSOR_DEVICE_ATTR(psu_rev, S_IRUGO, show_psu_rev, NULL, 0); +static SENSOR_DEVICE_ATTR(psu_led, S_IRUGO, show_psu_led, NULL, 0); + +static struct attribute *psu_attributes[] = { + &sensor_dev_attr_psu_v_in.dev_attr.attr, + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_in.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_in.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_mfr_model.dev_attr.attr, + &sensor_dev_attr_psu_mfr_serial.dev_attr.attr, + &sensor_dev_attr_psu_rst.dev_attr.attr, + &sensor_dev_attr_psu_ioc.dev_attr.attr, + &sensor_dev_attr_psu_rev.dev_attr.attr, + &sensor_dev_attr_psu_led.dev_attr.attr, + NULL +}; + +static const struct attribute_group psu_group = { + .attrs = psu_attributes, +}; + +static int psu_probe(struct i2c_client *client) +{ + struct psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)) + { + dev_info(&client->dev, "i2c_check_functionality failed!!!\n"); + status = -EIO; + return status; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + { + status = -ENOMEM; + return status; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "%s found\n", PSU_DRIVER_NAME); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &psu_group); + if (status) + { + dev_info(&client->dev, "sysfs_create_group failed!!!\n"); + kfree(data); + return status; + } + + return 0; +} + +static void psu_remove(struct i2c_client *client) +{ + struct psu_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &psu_group); + kfree(data); + + return; +} + +static const struct i2c_device_id psu_id[] = { + { PSU_DRIVER_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, psu_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver psu_driver = { + .driver = { + .name = PSU_DRIVER_NAME, + }, + .probe = psu_probe, + .remove = psu_remove, + .id_table = psu_id, + .address_list = normal_i2c, +}; + +static int __init pmbus_psu_init(void) +{ + return i2c_add_driver(&psu_driver); +} + +static void __exit pmbus_psu_exit(void) +{ + i2c_del_driver(&psu_driver); +} + +MODULE_AUTHOR("DNI SW5"); +MODULE_DESCRIPTION("DNI PSU Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.3"); + +module_init(pmbus_psu_init); +module_exit(pmbus_psu_exit); diff --git a/ixr7220h6-128/modules/port_cpld0.c b/ixr7220h6-128/modules/port_cpld0.c new file mode 100644 index 0000000..a0e4682 --- /dev/null +++ b/ixr7220h6-128/modules/port_cpld0.c @@ -0,0 +1,637 @@ +// * CPLD driver for Nokia-7220-IXR-H6-128 Router +// * +// * Copyright (C) 2026 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "port_cpld0" + +// REGISTERS ADDRESS MAP +#define VER_MAJOR_REG 0x00 +#define VER_MINOR_REG 0x01 +#define SCRATCH_REG 0x04 +#define PORT_LPMODE_REG0 0x70 +#define PORT_RST_REG0 0x78 +#define PORT_MODPRS_REG0 0x88 +#define PORT_PWGOOD_REG0 0x90 + +static const unsigned short cpld_address_list[] = {0x74, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_warn(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_warn(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static void dump_reg(struct cpld_data *data) +{ + struct i2c_client *client = data->client; + u8 val0 = 0; + u8 val1 = 0; + u8 val2 = 0; + u8 val3 = 0; + + val0 = cpld_i2c_read(data, PORT_RST_REG0); + val1 = cpld_i2c_read(data, PORT_RST_REG0 + 1); + val2 = cpld_i2c_read(data, PORT_RST_REG0 + 2); + val3 = cpld_i2c_read(data, PORT_RST_REG0 + 3); + dev_info(&client->dev, "[PORT_CPLD0]PORT_RESET_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, PORT_LPMODE_REG0); + val1 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 1); + val2 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 2); + val3 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 3); + dev_info(&client->dev, "[PORT_CPLD0]PORT_LPMODE_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, PORT_MODPRS_REG0); + val1 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 1); + val2 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 2); + val3 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 3); + dev_info(&client->dev, "[PORT_CPLD0]PORT_MODPRES_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + +} + +static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 reg_major = 0; + u8 reg_minor = 0; + + reg_major = cpld_i2c_read(data, VER_MAJOR_REG); + reg_minor = cpld_i2c_read(data, VER_MINOR_REG); + + return sprintf(buf, "%d.%d\n", reg_major, reg_minor); +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_port_lpmode(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_LPMODE_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_lpmode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_LPMODE_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_LPMODE_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +static ssize_t show_port_rst(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_RST_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_rst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_RST_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_RST_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +static ssize_t show_port_prs(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_MODPRS_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_MODPRS_REG0 + sda->index); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_port_pwgood(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_PWGOOD_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); + +static SENSOR_DEVICE_ATTR(port_1_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 0); +static SENSOR_DEVICE_ATTR(port_2_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 1); +static SENSOR_DEVICE_ATTR(port_3_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 2); +static SENSOR_DEVICE_ATTR(port_4_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 3); +static SENSOR_DEVICE_ATTR(port_5_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 4); +static SENSOR_DEVICE_ATTR(port_6_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 5); +static SENSOR_DEVICE_ATTR(port_7_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 6); +static SENSOR_DEVICE_ATTR(port_8_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 7); +static SENSOR_DEVICE_ATTR(port_9_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 8); +static SENSOR_DEVICE_ATTR(port_10_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 9); +static SENSOR_DEVICE_ATTR(port_11_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 10); +static SENSOR_DEVICE_ATTR(port_12_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 11); +static SENSOR_DEVICE_ATTR(port_13_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 12); +static SENSOR_DEVICE_ATTR(port_14_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 13); +static SENSOR_DEVICE_ATTR(port_15_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 14); +static SENSOR_DEVICE_ATTR(port_16_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 15); +static SENSOR_DEVICE_ATTR(port_17_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 16); +static SENSOR_DEVICE_ATTR(port_18_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 17); +static SENSOR_DEVICE_ATTR(port_19_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 18); +static SENSOR_DEVICE_ATTR(port_20_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 19); +static SENSOR_DEVICE_ATTR(port_21_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 20); +static SENSOR_DEVICE_ATTR(port_22_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 21); +static SENSOR_DEVICE_ATTR(port_23_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 22); +static SENSOR_DEVICE_ATTR(port_24_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 23); +static SENSOR_DEVICE_ATTR(port_25_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 24); +static SENSOR_DEVICE_ATTR(port_26_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 25); +static SENSOR_DEVICE_ATTR(port_27_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 26); +static SENSOR_DEVICE_ATTR(port_28_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 27); +static SENSOR_DEVICE_ATTR(port_29_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 28); +static SENSOR_DEVICE_ATTR(port_30_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 29); +static SENSOR_DEVICE_ATTR(port_31_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 30); +static SENSOR_DEVICE_ATTR(port_32_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 31); + +static SENSOR_DEVICE_ATTR(port_1_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 0); +static SENSOR_DEVICE_ATTR(port_2_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 1); +static SENSOR_DEVICE_ATTR(port_3_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 2); +static SENSOR_DEVICE_ATTR(port_4_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 3); +static SENSOR_DEVICE_ATTR(port_5_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 4); +static SENSOR_DEVICE_ATTR(port_6_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 5); +static SENSOR_DEVICE_ATTR(port_7_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 6); +static SENSOR_DEVICE_ATTR(port_8_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 7); +static SENSOR_DEVICE_ATTR(port_9_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 8); +static SENSOR_DEVICE_ATTR(port_10_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 9); +static SENSOR_DEVICE_ATTR(port_11_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 10); +static SENSOR_DEVICE_ATTR(port_12_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 11); +static SENSOR_DEVICE_ATTR(port_13_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 12); +static SENSOR_DEVICE_ATTR(port_14_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 13); +static SENSOR_DEVICE_ATTR(port_15_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 14); +static SENSOR_DEVICE_ATTR(port_16_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 15); +static SENSOR_DEVICE_ATTR(port_17_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 16); +static SENSOR_DEVICE_ATTR(port_18_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 17); +static SENSOR_DEVICE_ATTR(port_19_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 18); +static SENSOR_DEVICE_ATTR(port_20_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 19); +static SENSOR_DEVICE_ATTR(port_21_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 20); +static SENSOR_DEVICE_ATTR(port_22_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 21); +static SENSOR_DEVICE_ATTR(port_23_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 22); +static SENSOR_DEVICE_ATTR(port_24_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 23); +static SENSOR_DEVICE_ATTR(port_25_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 24); +static SENSOR_DEVICE_ATTR(port_26_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 25); +static SENSOR_DEVICE_ATTR(port_27_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 26); +static SENSOR_DEVICE_ATTR(port_28_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 27); +static SENSOR_DEVICE_ATTR(port_29_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 28); +static SENSOR_DEVICE_ATTR(port_30_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 29); +static SENSOR_DEVICE_ATTR(port_31_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 30); +static SENSOR_DEVICE_ATTR(port_32_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 31); + +static SENSOR_DEVICE_ATTR(port_1_prs, S_IRUGO, show_port_prs, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_prs, S_IRUGO, show_port_prs, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_prs, S_IRUGO, show_port_prs, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_prs, S_IRUGO, show_port_prs, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_prs, S_IRUGO, show_port_prs, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_prs, S_IRUGO, show_port_prs, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_prs, S_IRUGO, show_port_prs, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_prs, S_IRUGO, show_port_prs, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_prs, S_IRUGO, show_port_prs, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_prs, S_IRUGO, show_port_prs, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_prs, S_IRUGO, show_port_prs, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_prs, S_IRUGO, show_port_prs, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_prs, S_IRUGO, show_port_prs, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_prs, S_IRUGO, show_port_prs, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_prs, S_IRUGO, show_port_prs, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_prs, S_IRUGO, show_port_prs, NULL, 15); +static SENSOR_DEVICE_ATTR(port_17_prs, S_IRUGO, show_port_prs, NULL, 16); +static SENSOR_DEVICE_ATTR(port_18_prs, S_IRUGO, show_port_prs, NULL, 17); +static SENSOR_DEVICE_ATTR(port_19_prs, S_IRUGO, show_port_prs, NULL, 18); +static SENSOR_DEVICE_ATTR(port_20_prs, S_IRUGO, show_port_prs, NULL, 19); +static SENSOR_DEVICE_ATTR(port_21_prs, S_IRUGO, show_port_prs, NULL, 20); +static SENSOR_DEVICE_ATTR(port_22_prs, S_IRUGO, show_port_prs, NULL, 21); +static SENSOR_DEVICE_ATTR(port_23_prs, S_IRUGO, show_port_prs, NULL, 22); +static SENSOR_DEVICE_ATTR(port_24_prs, S_IRUGO, show_port_prs, NULL, 23); +static SENSOR_DEVICE_ATTR(port_25_prs, S_IRUGO, show_port_prs, NULL, 24); +static SENSOR_DEVICE_ATTR(port_26_prs, S_IRUGO, show_port_prs, NULL, 25); +static SENSOR_DEVICE_ATTR(port_27_prs, S_IRUGO, show_port_prs, NULL, 26); +static SENSOR_DEVICE_ATTR(port_28_prs, S_IRUGO, show_port_prs, NULL, 27); +static SENSOR_DEVICE_ATTR(port_29_prs, S_IRUGO, show_port_prs, NULL, 28); +static SENSOR_DEVICE_ATTR(port_30_prs, S_IRUGO, show_port_prs, NULL, 29); +static SENSOR_DEVICE_ATTR(port_31_prs, S_IRUGO, show_port_prs, NULL, 30); +static SENSOR_DEVICE_ATTR(port_32_prs, S_IRUGO, show_port_prs, NULL, 31); + +static SENSOR_DEVICE_ATTR(modprs_reg1, S_IRUGO, show_modprs_reg, NULL, 0); +static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 1); +static SENSOR_DEVICE_ATTR(modprs_reg3, S_IRUGO, show_modprs_reg, NULL, 2); +static SENSOR_DEVICE_ATTR(modprs_reg4, S_IRUGO, show_modprs_reg, NULL, 3); + +static SENSOR_DEVICE_ATTR(port_1_pwgood, S_IRUGO, show_port_pwgood, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_pwgood, S_IRUGO, show_port_pwgood, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_pwgood, S_IRUGO, show_port_pwgood, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_pwgood, S_IRUGO, show_port_pwgood, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_pwgood, S_IRUGO, show_port_pwgood, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_pwgood, S_IRUGO, show_port_pwgood, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_pwgood, S_IRUGO, show_port_pwgood, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_pwgood, S_IRUGO, show_port_pwgood, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_pwgood, S_IRUGO, show_port_pwgood, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_pwgood, S_IRUGO, show_port_pwgood, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_pwgood, S_IRUGO, show_port_pwgood, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_pwgood, S_IRUGO, show_port_pwgood, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_pwgood, S_IRUGO, show_port_pwgood, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_pwgood, S_IRUGO, show_port_pwgood, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_pwgood, S_IRUGO, show_port_pwgood, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_pwgood, S_IRUGO, show_port_pwgood, NULL, 15); +static SENSOR_DEVICE_ATTR(port_17_pwgood, S_IRUGO, show_port_pwgood, NULL, 16); +static SENSOR_DEVICE_ATTR(port_18_pwgood, S_IRUGO, show_port_pwgood, NULL, 17); +static SENSOR_DEVICE_ATTR(port_19_pwgood, S_IRUGO, show_port_pwgood, NULL, 18); +static SENSOR_DEVICE_ATTR(port_20_pwgood, S_IRUGO, show_port_pwgood, NULL, 19); +static SENSOR_DEVICE_ATTR(port_21_pwgood, S_IRUGO, show_port_pwgood, NULL, 20); +static SENSOR_DEVICE_ATTR(port_22_pwgood, S_IRUGO, show_port_pwgood, NULL, 21); +static SENSOR_DEVICE_ATTR(port_23_pwgood, S_IRUGO, show_port_pwgood, NULL, 22); +static SENSOR_DEVICE_ATTR(port_24_pwgood, S_IRUGO, show_port_pwgood, NULL, 23); +static SENSOR_DEVICE_ATTR(port_25_pwgood, S_IRUGO, show_port_pwgood, NULL, 24); +static SENSOR_DEVICE_ATTR(port_26_pwgood, S_IRUGO, show_port_pwgood, NULL, 25); +static SENSOR_DEVICE_ATTR(port_27_pwgood, S_IRUGO, show_port_pwgood, NULL, 26); +static SENSOR_DEVICE_ATTR(port_28_pwgood, S_IRUGO, show_port_pwgood, NULL, 27); +static SENSOR_DEVICE_ATTR(port_29_pwgood, S_IRUGO, show_port_pwgood, NULL, 28); +static SENSOR_DEVICE_ATTR(port_30_pwgood, S_IRUGO, show_port_pwgood, NULL, 29); +static SENSOR_DEVICE_ATTR(port_31_pwgood, S_IRUGO, show_port_pwgood, NULL, 30); +static SENSOR_DEVICE_ATTR(port_32_pwgood, S_IRUGO, show_port_pwgood, NULL, 31); + +static struct attribute *port_cpld0_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_scratch.dev_attr.attr, + + &sensor_dev_attr_port_1_lpmod.dev_attr.attr, + &sensor_dev_attr_port_2_lpmod.dev_attr.attr, + &sensor_dev_attr_port_3_lpmod.dev_attr.attr, + &sensor_dev_attr_port_4_lpmod.dev_attr.attr, + &sensor_dev_attr_port_5_lpmod.dev_attr.attr, + &sensor_dev_attr_port_6_lpmod.dev_attr.attr, + &sensor_dev_attr_port_7_lpmod.dev_attr.attr, + &sensor_dev_attr_port_8_lpmod.dev_attr.attr, + &sensor_dev_attr_port_9_lpmod.dev_attr.attr, + &sensor_dev_attr_port_10_lpmod.dev_attr.attr, + &sensor_dev_attr_port_11_lpmod.dev_attr.attr, + &sensor_dev_attr_port_12_lpmod.dev_attr.attr, + &sensor_dev_attr_port_13_lpmod.dev_attr.attr, + &sensor_dev_attr_port_14_lpmod.dev_attr.attr, + &sensor_dev_attr_port_15_lpmod.dev_attr.attr, + &sensor_dev_attr_port_16_lpmod.dev_attr.attr, + &sensor_dev_attr_port_17_lpmod.dev_attr.attr, + &sensor_dev_attr_port_18_lpmod.dev_attr.attr, + &sensor_dev_attr_port_19_lpmod.dev_attr.attr, + &sensor_dev_attr_port_20_lpmod.dev_attr.attr, + &sensor_dev_attr_port_21_lpmod.dev_attr.attr, + &sensor_dev_attr_port_22_lpmod.dev_attr.attr, + &sensor_dev_attr_port_23_lpmod.dev_attr.attr, + &sensor_dev_attr_port_24_lpmod.dev_attr.attr, + &sensor_dev_attr_port_25_lpmod.dev_attr.attr, + &sensor_dev_attr_port_26_lpmod.dev_attr.attr, + &sensor_dev_attr_port_27_lpmod.dev_attr.attr, + &sensor_dev_attr_port_28_lpmod.dev_attr.attr, + &sensor_dev_attr_port_29_lpmod.dev_attr.attr, + &sensor_dev_attr_port_30_lpmod.dev_attr.attr, + &sensor_dev_attr_port_31_lpmod.dev_attr.attr, + &sensor_dev_attr_port_32_lpmod.dev_attr.attr, + + &sensor_dev_attr_port_1_rst.dev_attr.attr, + &sensor_dev_attr_port_2_rst.dev_attr.attr, + &sensor_dev_attr_port_3_rst.dev_attr.attr, + &sensor_dev_attr_port_4_rst.dev_attr.attr, + &sensor_dev_attr_port_5_rst.dev_attr.attr, + &sensor_dev_attr_port_6_rst.dev_attr.attr, + &sensor_dev_attr_port_7_rst.dev_attr.attr, + &sensor_dev_attr_port_8_rst.dev_attr.attr, + &sensor_dev_attr_port_9_rst.dev_attr.attr, + &sensor_dev_attr_port_10_rst.dev_attr.attr, + &sensor_dev_attr_port_11_rst.dev_attr.attr, + &sensor_dev_attr_port_12_rst.dev_attr.attr, + &sensor_dev_attr_port_13_rst.dev_attr.attr, + &sensor_dev_attr_port_14_rst.dev_attr.attr, + &sensor_dev_attr_port_15_rst.dev_attr.attr, + &sensor_dev_attr_port_16_rst.dev_attr.attr, + &sensor_dev_attr_port_17_rst.dev_attr.attr, + &sensor_dev_attr_port_18_rst.dev_attr.attr, + &sensor_dev_attr_port_19_rst.dev_attr.attr, + &sensor_dev_attr_port_20_rst.dev_attr.attr, + &sensor_dev_attr_port_21_rst.dev_attr.attr, + &sensor_dev_attr_port_22_rst.dev_attr.attr, + &sensor_dev_attr_port_23_rst.dev_attr.attr, + &sensor_dev_attr_port_24_rst.dev_attr.attr, + &sensor_dev_attr_port_25_rst.dev_attr.attr, + &sensor_dev_attr_port_26_rst.dev_attr.attr, + &sensor_dev_attr_port_27_rst.dev_attr.attr, + &sensor_dev_attr_port_28_rst.dev_attr.attr, + &sensor_dev_attr_port_29_rst.dev_attr.attr, + &sensor_dev_attr_port_30_rst.dev_attr.attr, + &sensor_dev_attr_port_31_rst.dev_attr.attr, + &sensor_dev_attr_port_32_rst.dev_attr.attr, + + &sensor_dev_attr_port_1_prs.dev_attr.attr, + &sensor_dev_attr_port_2_prs.dev_attr.attr, + &sensor_dev_attr_port_3_prs.dev_attr.attr, + &sensor_dev_attr_port_4_prs.dev_attr.attr, + &sensor_dev_attr_port_5_prs.dev_attr.attr, + &sensor_dev_attr_port_6_prs.dev_attr.attr, + &sensor_dev_attr_port_7_prs.dev_attr.attr, + &sensor_dev_attr_port_8_prs.dev_attr.attr, + &sensor_dev_attr_port_9_prs.dev_attr.attr, + &sensor_dev_attr_port_10_prs.dev_attr.attr, + &sensor_dev_attr_port_11_prs.dev_attr.attr, + &sensor_dev_attr_port_12_prs.dev_attr.attr, + &sensor_dev_attr_port_13_prs.dev_attr.attr, + &sensor_dev_attr_port_14_prs.dev_attr.attr, + &sensor_dev_attr_port_15_prs.dev_attr.attr, + &sensor_dev_attr_port_16_prs.dev_attr.attr, + &sensor_dev_attr_port_17_prs.dev_attr.attr, + &sensor_dev_attr_port_18_prs.dev_attr.attr, + &sensor_dev_attr_port_19_prs.dev_attr.attr, + &sensor_dev_attr_port_20_prs.dev_attr.attr, + &sensor_dev_attr_port_21_prs.dev_attr.attr, + &sensor_dev_attr_port_22_prs.dev_attr.attr, + &sensor_dev_attr_port_23_prs.dev_attr.attr, + &sensor_dev_attr_port_24_prs.dev_attr.attr, + &sensor_dev_attr_port_25_prs.dev_attr.attr, + &sensor_dev_attr_port_26_prs.dev_attr.attr, + &sensor_dev_attr_port_27_prs.dev_attr.attr, + &sensor_dev_attr_port_28_prs.dev_attr.attr, + &sensor_dev_attr_port_29_prs.dev_attr.attr, + &sensor_dev_attr_port_30_prs.dev_attr.attr, + &sensor_dev_attr_port_31_prs.dev_attr.attr, + &sensor_dev_attr_port_32_prs.dev_attr.attr, + + &sensor_dev_attr_modprs_reg1.dev_attr.attr, + &sensor_dev_attr_modprs_reg2.dev_attr.attr, + &sensor_dev_attr_modprs_reg3.dev_attr.attr, + &sensor_dev_attr_modprs_reg4.dev_attr.attr, + + &sensor_dev_attr_port_1_pwgood.dev_attr.attr, + &sensor_dev_attr_port_2_pwgood.dev_attr.attr, + &sensor_dev_attr_port_3_pwgood.dev_attr.attr, + &sensor_dev_attr_port_4_pwgood.dev_attr.attr, + &sensor_dev_attr_port_5_pwgood.dev_attr.attr, + &sensor_dev_attr_port_6_pwgood.dev_attr.attr, + &sensor_dev_attr_port_7_pwgood.dev_attr.attr, + &sensor_dev_attr_port_8_pwgood.dev_attr.attr, + &sensor_dev_attr_port_9_pwgood.dev_attr.attr, + &sensor_dev_attr_port_10_pwgood.dev_attr.attr, + &sensor_dev_attr_port_11_pwgood.dev_attr.attr, + &sensor_dev_attr_port_12_pwgood.dev_attr.attr, + &sensor_dev_attr_port_13_pwgood.dev_attr.attr, + &sensor_dev_attr_port_14_pwgood.dev_attr.attr, + &sensor_dev_attr_port_15_pwgood.dev_attr.attr, + &sensor_dev_attr_port_16_pwgood.dev_attr.attr, + &sensor_dev_attr_port_17_pwgood.dev_attr.attr, + &sensor_dev_attr_port_18_pwgood.dev_attr.attr, + &sensor_dev_attr_port_19_pwgood.dev_attr.attr, + &sensor_dev_attr_port_20_pwgood.dev_attr.attr, + &sensor_dev_attr_port_21_pwgood.dev_attr.attr, + &sensor_dev_attr_port_22_pwgood.dev_attr.attr, + &sensor_dev_attr_port_23_pwgood.dev_attr.attr, + &sensor_dev_attr_port_24_pwgood.dev_attr.attr, + &sensor_dev_attr_port_25_pwgood.dev_attr.attr, + &sensor_dev_attr_port_26_pwgood.dev_attr.attr, + &sensor_dev_attr_port_27_pwgood.dev_attr.attr, + &sensor_dev_attr_port_28_pwgood.dev_attr.attr, + &sensor_dev_attr_port_29_pwgood.dev_attr.attr, + &sensor_dev_attr_port_30_pwgood.dev_attr.attr, + &sensor_dev_attr_port_31_pwgood.dev_attr.attr, + &sensor_dev_attr_port_32_pwgood.dev_attr.attr, + + NULL +}; + +static const struct attribute_group port_cpld0_group = { + .attrs = port_cpld0_attributes, +}; + +static int port_cpld0_probe(struct i2c_client *client) +{ + int status; + struct cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia PORT_CPLD0 chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &port_cpld0_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + dump_reg(data); + dev_info(&client->dev, "[PORT_CPLD0]Reseting PORTs ...\n"); + cpld_i2c_write(data, PORT_LPMODE_REG0, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+1, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+2, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+3, 0x0); + cpld_i2c_write(data, PORT_RST_REG0, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+1, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+2, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+3, 0x0); + msleep(500); + cpld_i2c_write(data, PORT_RST_REG0, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+1, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+2, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+3, 0xFF); + dev_info(&client->dev, "[PORT_CPLD0]PORTs reset done.\n"); + dump_reg(data); + + return 0; + +exit: + return status; +} + +static void port_cpld0_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &port_cpld0_group); + kfree(data); +} + +static const struct of_device_id port_cpld0_of_ids[] = { + { + .compatible = "port_cpld0", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, port_cpld0_of_ids); + +static const struct i2c_device_id port_cpld0_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, port_cpld0_ids); + +static struct i2c_driver port_cpld0_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(port_cpld0_of_ids), + }, + .probe = port_cpld0_probe, + .remove = port_cpld0_remove, + .id_table = port_cpld0_ids, + .address_list = cpld_address_list, +}; + +static int __init port_cpld0_init(void) +{ + return i2c_add_driver(&port_cpld0_driver); +} + +static void __exit port_cpld0_exit(void) +{ + i2c_del_driver(&port_cpld0_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA H6-128 PORT_CPLD0 driver"); +MODULE_LICENSE("GPL"); + +module_init(port_cpld0_init); +module_exit(port_cpld0_exit); diff --git a/ixr7220h6-128/modules/port_cpld1.c b/ixr7220h6-128/modules/port_cpld1.c new file mode 100644 index 0000000..f9dbe5d --- /dev/null +++ b/ixr7220h6-128/modules/port_cpld1.c @@ -0,0 +1,730 @@ +// * CPLD driver for Nokia-7220-IXR-H6-128 Router +// * +// * Copyright (C) 2026 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "port_cpld1" + +// REGISTERS ADDRESS MAP +#define VER_MAJOR_REG 0x00 +#define VER_MINOR_REG 0x01 +//#define SFP_CTRL_REG 0x03 +#define SCRATCH_REG 0x04 +//#define SFP_MISC_REG 0x05 +#define SFP_TXFAULT_REG 0x10 +#define SFP_TXDIS_REG 0x18 +#define SFP_RXLOSS_REG 0x20 +#define SFP_MODPRS_REG 0x28 +#define PORT_LPMODE_REG0 0x70 +#define PORT_RST_REG0 0x78 +#define PORT_MODPRS_REG0 0x88 +#define PORT_PWGOOD_REG0 0x90 + +static const unsigned short cpld_address_list[] = {0x75, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_warn(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_warn(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static void dump_reg(struct cpld_data *data) +{ + struct i2c_client *client = data->client; + u8 val0 = 0; + u8 val1 = 0; + u8 val2 = 0; + u8 val3 = 0; + + val0 = cpld_i2c_read(data, PORT_RST_REG0); + val1 = cpld_i2c_read(data, PORT_RST_REG0 + 1); + val2 = cpld_i2c_read(data, PORT_RST_REG0 + 2); + val3 = cpld_i2c_read(data, PORT_RST_REG0 + 3); + dev_info(&client->dev, "[PORT_CPLD1]PORT_RESET_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, PORT_LPMODE_REG0); + val1 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 1); + val2 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 2); + val3 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 3); + dev_info(&client->dev, "[PORT_CPLD1]PORT_LPMODE_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, PORT_MODPRS_REG0); + val1 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 1); + val2 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 2); + val3 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 3); + dev_info(&client->dev, "[PORT_CPLD1]PORT_MODPRES_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + +} + +static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 reg_major = 0; + u8 reg_minor = 0; + + reg_major = cpld_i2c_read(data, VER_MAJOR_REG); + reg_minor = cpld_i2c_read(data, VER_MINOR_REG); + + return sprintf(buf, "%d.%d\n", reg_major, reg_minor); +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_sfp_tx_fault(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, SFP_TXFAULT_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_sfp_tx_en(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, SFP_TXDIS_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_sfp_tx_en(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, SFP_TXDIS_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, SFP_TXDIS_REG, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_sfp_rx_los(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, SFP_RXLOSS_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_sfp_prs(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, SFP_MODPRS_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_port_lpmode(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_LPMODE_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_lpmode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_LPMODE_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_LPMODE_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +static ssize_t show_port_rst(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_RST_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_rst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_RST_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_RST_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +static ssize_t show_port_prs(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_MODPRS_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_MODPRS_REG0 + sda->index); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_port_pwgood(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_PWGOOD_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); + +static SENSOR_DEVICE_ATTR(port_33_tx_fault, S_IRUGO, show_sfp_tx_fault, NULL, 0); +static SENSOR_DEVICE_ATTR(port_34_tx_fault, S_IRUGO, show_sfp_tx_fault, NULL, 1); +static SENSOR_DEVICE_ATTR(port_33_tx_en, S_IRUGO | S_IWUSR, show_sfp_tx_en, set_sfp_tx_en, 0); +static SENSOR_DEVICE_ATTR(port_34_tx_en, S_IRUGO | S_IWUSR, show_sfp_tx_en, set_sfp_tx_en, 1); +static SENSOR_DEVICE_ATTR(port_33_rx_los, S_IRUGO, show_sfp_rx_los, NULL, 0); +static SENSOR_DEVICE_ATTR(port_34_rx_los, S_IRUGO, show_sfp_rx_los, NULL, 1); +static SENSOR_DEVICE_ATTR(port_33_prs, S_IRUGO, show_sfp_prs, NULL, 0); +static SENSOR_DEVICE_ATTR(port_34_prs, S_IRUGO, show_sfp_prs, NULL, 1); + +static SENSOR_DEVICE_ATTR(port_1_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 0); +static SENSOR_DEVICE_ATTR(port_2_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 1); +static SENSOR_DEVICE_ATTR(port_3_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 2); +static SENSOR_DEVICE_ATTR(port_4_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 3); +static SENSOR_DEVICE_ATTR(port_5_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 4); +static SENSOR_DEVICE_ATTR(port_6_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 5); +static SENSOR_DEVICE_ATTR(port_7_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 6); +static SENSOR_DEVICE_ATTR(port_8_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 7); +static SENSOR_DEVICE_ATTR(port_9_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 8); +static SENSOR_DEVICE_ATTR(port_10_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 9); +static SENSOR_DEVICE_ATTR(port_11_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 10); +static SENSOR_DEVICE_ATTR(port_12_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 11); +static SENSOR_DEVICE_ATTR(port_13_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 12); +static SENSOR_DEVICE_ATTR(port_14_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 13); +static SENSOR_DEVICE_ATTR(port_15_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 14); +static SENSOR_DEVICE_ATTR(port_16_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 15); +static SENSOR_DEVICE_ATTR(port_17_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 16); +static SENSOR_DEVICE_ATTR(port_18_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 17); +static SENSOR_DEVICE_ATTR(port_19_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 18); +static SENSOR_DEVICE_ATTR(port_20_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 19); +static SENSOR_DEVICE_ATTR(port_21_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 20); +static SENSOR_DEVICE_ATTR(port_22_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 21); +static SENSOR_DEVICE_ATTR(port_23_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 22); +static SENSOR_DEVICE_ATTR(port_24_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 23); +static SENSOR_DEVICE_ATTR(port_25_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 24); +static SENSOR_DEVICE_ATTR(port_26_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 25); +static SENSOR_DEVICE_ATTR(port_27_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 26); +static SENSOR_DEVICE_ATTR(port_28_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 27); +static SENSOR_DEVICE_ATTR(port_29_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 28); +static SENSOR_DEVICE_ATTR(port_30_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 29); +static SENSOR_DEVICE_ATTR(port_31_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 30); +static SENSOR_DEVICE_ATTR(port_32_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 31); + +static SENSOR_DEVICE_ATTR(port_1_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 0); +static SENSOR_DEVICE_ATTR(port_2_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 1); +static SENSOR_DEVICE_ATTR(port_3_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 2); +static SENSOR_DEVICE_ATTR(port_4_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 3); +static SENSOR_DEVICE_ATTR(port_5_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 4); +static SENSOR_DEVICE_ATTR(port_6_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 5); +static SENSOR_DEVICE_ATTR(port_7_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 6); +static SENSOR_DEVICE_ATTR(port_8_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 7); +static SENSOR_DEVICE_ATTR(port_9_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 8); +static SENSOR_DEVICE_ATTR(port_10_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 9); +static SENSOR_DEVICE_ATTR(port_11_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 10); +static SENSOR_DEVICE_ATTR(port_12_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 11); +static SENSOR_DEVICE_ATTR(port_13_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 12); +static SENSOR_DEVICE_ATTR(port_14_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 13); +static SENSOR_DEVICE_ATTR(port_15_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 14); +static SENSOR_DEVICE_ATTR(port_16_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 15); +static SENSOR_DEVICE_ATTR(port_17_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 16); +static SENSOR_DEVICE_ATTR(port_18_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 17); +static SENSOR_DEVICE_ATTR(port_19_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 18); +static SENSOR_DEVICE_ATTR(port_20_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 19); +static SENSOR_DEVICE_ATTR(port_21_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 20); +static SENSOR_DEVICE_ATTR(port_22_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 21); +static SENSOR_DEVICE_ATTR(port_23_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 22); +static SENSOR_DEVICE_ATTR(port_24_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 23); +static SENSOR_DEVICE_ATTR(port_25_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 24); +static SENSOR_DEVICE_ATTR(port_26_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 25); +static SENSOR_DEVICE_ATTR(port_27_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 26); +static SENSOR_DEVICE_ATTR(port_28_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 27); +static SENSOR_DEVICE_ATTR(port_29_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 28); +static SENSOR_DEVICE_ATTR(port_30_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 29); +static SENSOR_DEVICE_ATTR(port_31_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 30); +static SENSOR_DEVICE_ATTR(port_32_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 31); + +static SENSOR_DEVICE_ATTR(port_1_prs, S_IRUGO, show_port_prs, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_prs, S_IRUGO, show_port_prs, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_prs, S_IRUGO, show_port_prs, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_prs, S_IRUGO, show_port_prs, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_prs, S_IRUGO, show_port_prs, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_prs, S_IRUGO, show_port_prs, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_prs, S_IRUGO, show_port_prs, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_prs, S_IRUGO, show_port_prs, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_prs, S_IRUGO, show_port_prs, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_prs, S_IRUGO, show_port_prs, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_prs, S_IRUGO, show_port_prs, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_prs, S_IRUGO, show_port_prs, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_prs, S_IRUGO, show_port_prs, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_prs, S_IRUGO, show_port_prs, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_prs, S_IRUGO, show_port_prs, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_prs, S_IRUGO, show_port_prs, NULL, 15); +static SENSOR_DEVICE_ATTR(port_17_prs, S_IRUGO, show_port_prs, NULL, 16); +static SENSOR_DEVICE_ATTR(port_18_prs, S_IRUGO, show_port_prs, NULL, 17); +static SENSOR_DEVICE_ATTR(port_19_prs, S_IRUGO, show_port_prs, NULL, 18); +static SENSOR_DEVICE_ATTR(port_20_prs, S_IRUGO, show_port_prs, NULL, 19); +static SENSOR_DEVICE_ATTR(port_21_prs, S_IRUGO, show_port_prs, NULL, 20); +static SENSOR_DEVICE_ATTR(port_22_prs, S_IRUGO, show_port_prs, NULL, 21); +static SENSOR_DEVICE_ATTR(port_23_prs, S_IRUGO, show_port_prs, NULL, 22); +static SENSOR_DEVICE_ATTR(port_24_prs, S_IRUGO, show_port_prs, NULL, 23); +static SENSOR_DEVICE_ATTR(port_25_prs, S_IRUGO, show_port_prs, NULL, 24); +static SENSOR_DEVICE_ATTR(port_26_prs, S_IRUGO, show_port_prs, NULL, 25); +static SENSOR_DEVICE_ATTR(port_27_prs, S_IRUGO, show_port_prs, NULL, 26); +static SENSOR_DEVICE_ATTR(port_28_prs, S_IRUGO, show_port_prs, NULL, 27); +static SENSOR_DEVICE_ATTR(port_29_prs, S_IRUGO, show_port_prs, NULL, 28); +static SENSOR_DEVICE_ATTR(port_30_prs, S_IRUGO, show_port_prs, NULL, 29); +static SENSOR_DEVICE_ATTR(port_31_prs, S_IRUGO, show_port_prs, NULL, 30); +static SENSOR_DEVICE_ATTR(port_32_prs, S_IRUGO, show_port_prs, NULL, 31); + +static SENSOR_DEVICE_ATTR(modprs_reg1, S_IRUGO, show_modprs_reg, NULL, 0); +static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 1); +static SENSOR_DEVICE_ATTR(modprs_reg3, S_IRUGO, show_modprs_reg, NULL, 2); +static SENSOR_DEVICE_ATTR(modprs_reg4, S_IRUGO, show_modprs_reg, NULL, 3); + +static SENSOR_DEVICE_ATTR(port_1_pwgood, S_IRUGO, show_port_pwgood, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_pwgood, S_IRUGO, show_port_pwgood, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_pwgood, S_IRUGO, show_port_pwgood, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_pwgood, S_IRUGO, show_port_pwgood, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_pwgood, S_IRUGO, show_port_pwgood, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_pwgood, S_IRUGO, show_port_pwgood, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_pwgood, S_IRUGO, show_port_pwgood, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_pwgood, S_IRUGO, show_port_pwgood, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_pwgood, S_IRUGO, show_port_pwgood, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_pwgood, S_IRUGO, show_port_pwgood, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_pwgood, S_IRUGO, show_port_pwgood, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_pwgood, S_IRUGO, show_port_pwgood, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_pwgood, S_IRUGO, show_port_pwgood, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_pwgood, S_IRUGO, show_port_pwgood, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_pwgood, S_IRUGO, show_port_pwgood, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_pwgood, S_IRUGO, show_port_pwgood, NULL, 15); +static SENSOR_DEVICE_ATTR(port_17_pwgood, S_IRUGO, show_port_pwgood, NULL, 16); +static SENSOR_DEVICE_ATTR(port_18_pwgood, S_IRUGO, show_port_pwgood, NULL, 17); +static SENSOR_DEVICE_ATTR(port_19_pwgood, S_IRUGO, show_port_pwgood, NULL, 18); +static SENSOR_DEVICE_ATTR(port_20_pwgood, S_IRUGO, show_port_pwgood, NULL, 19); +static SENSOR_DEVICE_ATTR(port_21_pwgood, S_IRUGO, show_port_pwgood, NULL, 20); +static SENSOR_DEVICE_ATTR(port_22_pwgood, S_IRUGO, show_port_pwgood, NULL, 21); +static SENSOR_DEVICE_ATTR(port_23_pwgood, S_IRUGO, show_port_pwgood, NULL, 22); +static SENSOR_DEVICE_ATTR(port_24_pwgood, S_IRUGO, show_port_pwgood, NULL, 23); +static SENSOR_DEVICE_ATTR(port_25_pwgood, S_IRUGO, show_port_pwgood, NULL, 24); +static SENSOR_DEVICE_ATTR(port_26_pwgood, S_IRUGO, show_port_pwgood, NULL, 25); +static SENSOR_DEVICE_ATTR(port_27_pwgood, S_IRUGO, show_port_pwgood, NULL, 26); +static SENSOR_DEVICE_ATTR(port_28_pwgood, S_IRUGO, show_port_pwgood, NULL, 27); +static SENSOR_DEVICE_ATTR(port_29_pwgood, S_IRUGO, show_port_pwgood, NULL, 28); +static SENSOR_DEVICE_ATTR(port_30_pwgood, S_IRUGO, show_port_pwgood, NULL, 29); +static SENSOR_DEVICE_ATTR(port_31_pwgood, S_IRUGO, show_port_pwgood, NULL, 30); +static SENSOR_DEVICE_ATTR(port_32_pwgood, S_IRUGO, show_port_pwgood, NULL, 31); + +static struct attribute *port_cpld1_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_scratch.dev_attr.attr, + + &sensor_dev_attr_port_33_tx_fault.dev_attr.attr, + &sensor_dev_attr_port_34_tx_fault.dev_attr.attr, + &sensor_dev_attr_port_33_tx_en.dev_attr.attr, + &sensor_dev_attr_port_34_tx_en.dev_attr.attr, + &sensor_dev_attr_port_33_rx_los.dev_attr.attr, + &sensor_dev_attr_port_34_rx_los.dev_attr.attr, + &sensor_dev_attr_port_33_prs.dev_attr.attr, + &sensor_dev_attr_port_34_prs.dev_attr.attr, + + &sensor_dev_attr_port_1_lpmod.dev_attr.attr, + &sensor_dev_attr_port_2_lpmod.dev_attr.attr, + &sensor_dev_attr_port_3_lpmod.dev_attr.attr, + &sensor_dev_attr_port_4_lpmod.dev_attr.attr, + &sensor_dev_attr_port_5_lpmod.dev_attr.attr, + &sensor_dev_attr_port_6_lpmod.dev_attr.attr, + &sensor_dev_attr_port_7_lpmod.dev_attr.attr, + &sensor_dev_attr_port_8_lpmod.dev_attr.attr, + &sensor_dev_attr_port_9_lpmod.dev_attr.attr, + &sensor_dev_attr_port_10_lpmod.dev_attr.attr, + &sensor_dev_attr_port_11_lpmod.dev_attr.attr, + &sensor_dev_attr_port_12_lpmod.dev_attr.attr, + &sensor_dev_attr_port_13_lpmod.dev_attr.attr, + &sensor_dev_attr_port_14_lpmod.dev_attr.attr, + &sensor_dev_attr_port_15_lpmod.dev_attr.attr, + &sensor_dev_attr_port_16_lpmod.dev_attr.attr, + &sensor_dev_attr_port_17_lpmod.dev_attr.attr, + &sensor_dev_attr_port_18_lpmod.dev_attr.attr, + &sensor_dev_attr_port_19_lpmod.dev_attr.attr, + &sensor_dev_attr_port_20_lpmod.dev_attr.attr, + &sensor_dev_attr_port_21_lpmod.dev_attr.attr, + &sensor_dev_attr_port_22_lpmod.dev_attr.attr, + &sensor_dev_attr_port_23_lpmod.dev_attr.attr, + &sensor_dev_attr_port_24_lpmod.dev_attr.attr, + &sensor_dev_attr_port_25_lpmod.dev_attr.attr, + &sensor_dev_attr_port_26_lpmod.dev_attr.attr, + &sensor_dev_attr_port_27_lpmod.dev_attr.attr, + &sensor_dev_attr_port_28_lpmod.dev_attr.attr, + &sensor_dev_attr_port_29_lpmod.dev_attr.attr, + &sensor_dev_attr_port_30_lpmod.dev_attr.attr, + &sensor_dev_attr_port_31_lpmod.dev_attr.attr, + &sensor_dev_attr_port_32_lpmod.dev_attr.attr, + + &sensor_dev_attr_port_1_rst.dev_attr.attr, + &sensor_dev_attr_port_2_rst.dev_attr.attr, + &sensor_dev_attr_port_3_rst.dev_attr.attr, + &sensor_dev_attr_port_4_rst.dev_attr.attr, + &sensor_dev_attr_port_5_rst.dev_attr.attr, + &sensor_dev_attr_port_6_rst.dev_attr.attr, + &sensor_dev_attr_port_7_rst.dev_attr.attr, + &sensor_dev_attr_port_8_rst.dev_attr.attr, + &sensor_dev_attr_port_9_rst.dev_attr.attr, + &sensor_dev_attr_port_10_rst.dev_attr.attr, + &sensor_dev_attr_port_11_rst.dev_attr.attr, + &sensor_dev_attr_port_12_rst.dev_attr.attr, + &sensor_dev_attr_port_13_rst.dev_attr.attr, + &sensor_dev_attr_port_14_rst.dev_attr.attr, + &sensor_dev_attr_port_15_rst.dev_attr.attr, + &sensor_dev_attr_port_16_rst.dev_attr.attr, + &sensor_dev_attr_port_17_rst.dev_attr.attr, + &sensor_dev_attr_port_18_rst.dev_attr.attr, + &sensor_dev_attr_port_19_rst.dev_attr.attr, + &sensor_dev_attr_port_20_rst.dev_attr.attr, + &sensor_dev_attr_port_21_rst.dev_attr.attr, + &sensor_dev_attr_port_22_rst.dev_attr.attr, + &sensor_dev_attr_port_23_rst.dev_attr.attr, + &sensor_dev_attr_port_24_rst.dev_attr.attr, + &sensor_dev_attr_port_25_rst.dev_attr.attr, + &sensor_dev_attr_port_26_rst.dev_attr.attr, + &sensor_dev_attr_port_27_rst.dev_attr.attr, + &sensor_dev_attr_port_28_rst.dev_attr.attr, + &sensor_dev_attr_port_29_rst.dev_attr.attr, + &sensor_dev_attr_port_30_rst.dev_attr.attr, + &sensor_dev_attr_port_31_rst.dev_attr.attr, + &sensor_dev_attr_port_32_rst.dev_attr.attr, + + &sensor_dev_attr_port_1_prs.dev_attr.attr, + &sensor_dev_attr_port_2_prs.dev_attr.attr, + &sensor_dev_attr_port_3_prs.dev_attr.attr, + &sensor_dev_attr_port_4_prs.dev_attr.attr, + &sensor_dev_attr_port_5_prs.dev_attr.attr, + &sensor_dev_attr_port_6_prs.dev_attr.attr, + &sensor_dev_attr_port_7_prs.dev_attr.attr, + &sensor_dev_attr_port_8_prs.dev_attr.attr, + &sensor_dev_attr_port_9_prs.dev_attr.attr, + &sensor_dev_attr_port_10_prs.dev_attr.attr, + &sensor_dev_attr_port_11_prs.dev_attr.attr, + &sensor_dev_attr_port_12_prs.dev_attr.attr, + &sensor_dev_attr_port_13_prs.dev_attr.attr, + &sensor_dev_attr_port_14_prs.dev_attr.attr, + &sensor_dev_attr_port_15_prs.dev_attr.attr, + &sensor_dev_attr_port_16_prs.dev_attr.attr, + &sensor_dev_attr_port_17_prs.dev_attr.attr, + &sensor_dev_attr_port_18_prs.dev_attr.attr, + &sensor_dev_attr_port_19_prs.dev_attr.attr, + &sensor_dev_attr_port_20_prs.dev_attr.attr, + &sensor_dev_attr_port_21_prs.dev_attr.attr, + &sensor_dev_attr_port_22_prs.dev_attr.attr, + &sensor_dev_attr_port_23_prs.dev_attr.attr, + &sensor_dev_attr_port_24_prs.dev_attr.attr, + &sensor_dev_attr_port_25_prs.dev_attr.attr, + &sensor_dev_attr_port_26_prs.dev_attr.attr, + &sensor_dev_attr_port_27_prs.dev_attr.attr, + &sensor_dev_attr_port_28_prs.dev_attr.attr, + &sensor_dev_attr_port_29_prs.dev_attr.attr, + &sensor_dev_attr_port_30_prs.dev_attr.attr, + &sensor_dev_attr_port_31_prs.dev_attr.attr, + &sensor_dev_attr_port_32_prs.dev_attr.attr, + + &sensor_dev_attr_modprs_reg1.dev_attr.attr, + &sensor_dev_attr_modprs_reg2.dev_attr.attr, + &sensor_dev_attr_modprs_reg3.dev_attr.attr, + &sensor_dev_attr_modprs_reg4.dev_attr.attr, + + &sensor_dev_attr_port_1_pwgood.dev_attr.attr, + &sensor_dev_attr_port_2_pwgood.dev_attr.attr, + &sensor_dev_attr_port_3_pwgood.dev_attr.attr, + &sensor_dev_attr_port_4_pwgood.dev_attr.attr, + &sensor_dev_attr_port_5_pwgood.dev_attr.attr, + &sensor_dev_attr_port_6_pwgood.dev_attr.attr, + &sensor_dev_attr_port_7_pwgood.dev_attr.attr, + &sensor_dev_attr_port_8_pwgood.dev_attr.attr, + &sensor_dev_attr_port_9_pwgood.dev_attr.attr, + &sensor_dev_attr_port_10_pwgood.dev_attr.attr, + &sensor_dev_attr_port_11_pwgood.dev_attr.attr, + &sensor_dev_attr_port_12_pwgood.dev_attr.attr, + &sensor_dev_attr_port_13_pwgood.dev_attr.attr, + &sensor_dev_attr_port_14_pwgood.dev_attr.attr, + &sensor_dev_attr_port_15_pwgood.dev_attr.attr, + &sensor_dev_attr_port_16_pwgood.dev_attr.attr, + &sensor_dev_attr_port_17_pwgood.dev_attr.attr, + &sensor_dev_attr_port_18_pwgood.dev_attr.attr, + &sensor_dev_attr_port_19_pwgood.dev_attr.attr, + &sensor_dev_attr_port_20_pwgood.dev_attr.attr, + &sensor_dev_attr_port_21_pwgood.dev_attr.attr, + &sensor_dev_attr_port_22_pwgood.dev_attr.attr, + &sensor_dev_attr_port_23_pwgood.dev_attr.attr, + &sensor_dev_attr_port_24_pwgood.dev_attr.attr, + &sensor_dev_attr_port_25_pwgood.dev_attr.attr, + &sensor_dev_attr_port_26_pwgood.dev_attr.attr, + &sensor_dev_attr_port_27_pwgood.dev_attr.attr, + &sensor_dev_attr_port_28_pwgood.dev_attr.attr, + &sensor_dev_attr_port_29_pwgood.dev_attr.attr, + &sensor_dev_attr_port_30_pwgood.dev_attr.attr, + &sensor_dev_attr_port_31_pwgood.dev_attr.attr, + &sensor_dev_attr_port_32_pwgood.dev_attr.attr, + + NULL +}; + +static const struct attribute_group port_cpld1_group = { + .attrs = port_cpld1_attributes, +}; + +static int port_cpld1_probe(struct i2c_client *client) +{ + int status; + struct cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia PORT_CPLD1 chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &port_cpld1_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + dump_reg(data); + dev_info(&client->dev, "[PORT_CPLD1]Reseting PORTs ...\n"); + cpld_i2c_write(data, PORT_LPMODE_REG0, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+1, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+2, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+3, 0x0); + cpld_i2c_write(data, PORT_RST_REG0, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+1, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+2, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+3, 0x0); + msleep(500); + cpld_i2c_write(data, PORT_RST_REG0, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+1, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+2, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+3, 0xFF); + dev_info(&client->dev, "[PORT_CPLD1]PORTs reset done.\n"); + dump_reg(data); + + return 0; + +exit: + return status; +} + +static void port_cpld1_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &port_cpld1_group); + kfree(data); +} + +static const struct of_device_id port_cpld1_of_ids[] = { + { + .compatible = "port_cpld1", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, port_cpld1_of_ids); + +static const struct i2c_device_id port_cpld1_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, port_cpld1_ids); + +static struct i2c_driver port_cpld1_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(port_cpld1_of_ids), + }, + .probe = port_cpld1_probe, + .remove = port_cpld1_remove, + .id_table = port_cpld1_ids, + .address_list = cpld_address_list, +}; + +static int __init port_cpld1_init(void) +{ + return i2c_add_driver(&port_cpld1_driver); +} + +static void __exit port_cpld1_exit(void) +{ + i2c_del_driver(&port_cpld1_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA H6-128 PORT_CPLD1 driver"); +MODULE_LICENSE("GPL"); + +module_init(port_cpld1_init); +module_exit(port_cpld1_exit); diff --git a/ixr7220h6-128/modules/port_cpld2.c b/ixr7220h6-128/modules/port_cpld2.c new file mode 100644 index 0000000..557989a --- /dev/null +++ b/ixr7220h6-128/modules/port_cpld2.c @@ -0,0 +1,562 @@ +// * CPLD driver for Nokia-7220-IXR-H6-128 Router +// * +// * Copyright (C) 2026 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "port_cpld2" + +// REGISTERS ADDRESS MAP +#define VER_MAJOR_REG 0x00 +#define VER_MINOR_REG 0x01 +#define SCRATCH_REG 0x04 +#define PORT_LPMODE_REG0 0x70 +#define PORT_ENABLE_REG0 0x72 +#define PORT_RST_REG0 0x78 +#define PORT_MODPRS_REG0 0x88 +#define PORT_PWGOOD_REG0 0x90 + +static const unsigned short cpld_address_list[] = {0x73, 0x76, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_warn(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_warn(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static void dump_reg(struct cpld_data *data) +{ + struct i2c_client *client = data->client; + u8 val0 = 0; + u8 val1 = 0; + + val0 = cpld_i2c_read(data, PORT_RST_REG0); + val1 = cpld_i2c_read(data, PORT_RST_REG0 + 1); + dev_info(&client->dev, "[PORT_CPLD2]PORT_RESET_REG: 0x%02x, 0x%02x\n", val0, val1); + + val0 = cpld_i2c_read(data, PORT_LPMODE_REG0); + val1 = cpld_i2c_read(data, PORT_LPMODE_REG0 + 1); + dev_info(&client->dev, "[PORT_CPLD2]PORT_LPMODE_REG: 0x%02x, 0x%02x\n", val0, val1); + + val0 = cpld_i2c_read(data, PORT_MODPRS_REG0); + val1 = cpld_i2c_read(data, PORT_MODPRS_REG0 + 1); + dev_info(&client->dev, "[PORT_CPLD2]PORT_MODPRES_REG: 0x%02x, 0x%02x\n", val0, val1); + +} + +static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 reg_major = 0; + u8 reg_minor = 0; + + reg_major = cpld_i2c_read(data, VER_MAJOR_REG); + reg_minor = cpld_i2c_read(data, VER_MINOR_REG); + + return sprintf(buf, "%d.%d\n", reg_major, reg_minor); +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_port_lpmode(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_LPMODE_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_lpmode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_LPMODE_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_LPMODE_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +static ssize_t show_port_rst(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_RST_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_rst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_RST_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_RST_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +static ssize_t show_port_prs(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_MODPRS_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_MODPRS_REG0 + sda->index); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_port_pwgood(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_PWGOOD_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t show_port_en(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); + + return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); +} + +static ssize_t set_port_en(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_ENABLE_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); + +static SENSOR_DEVICE_ATTR(port_1_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 0); +static SENSOR_DEVICE_ATTR(port_2_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 1); +static SENSOR_DEVICE_ATTR(port_3_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 2); +static SENSOR_DEVICE_ATTR(port_4_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 3); +static SENSOR_DEVICE_ATTR(port_5_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 4); +static SENSOR_DEVICE_ATTR(port_6_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 5); +static SENSOR_DEVICE_ATTR(port_7_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 6); +static SENSOR_DEVICE_ATTR(port_8_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 7); +static SENSOR_DEVICE_ATTR(port_9_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 8); +static SENSOR_DEVICE_ATTR(port_10_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 9); +static SENSOR_DEVICE_ATTR(port_11_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 10); +static SENSOR_DEVICE_ATTR(port_12_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 11); +static SENSOR_DEVICE_ATTR(port_13_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 12); +static SENSOR_DEVICE_ATTR(port_14_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 13); +static SENSOR_DEVICE_ATTR(port_15_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 14); +static SENSOR_DEVICE_ATTR(port_16_lpmod, S_IRUGO | S_IWUSR, show_port_lpmode, set_port_lpmode, 15); + +static SENSOR_DEVICE_ATTR(port_1_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 0); +static SENSOR_DEVICE_ATTR(port_2_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 1); +static SENSOR_DEVICE_ATTR(port_3_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 2); +static SENSOR_DEVICE_ATTR(port_4_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 3); +static SENSOR_DEVICE_ATTR(port_5_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 4); +static SENSOR_DEVICE_ATTR(port_6_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 5); +static SENSOR_DEVICE_ATTR(port_7_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 6); +static SENSOR_DEVICE_ATTR(port_8_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 7); +static SENSOR_DEVICE_ATTR(port_9_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 8); +static SENSOR_DEVICE_ATTR(port_10_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 9); +static SENSOR_DEVICE_ATTR(port_11_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 10); +static SENSOR_DEVICE_ATTR(port_12_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 11); +static SENSOR_DEVICE_ATTR(port_13_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 12); +static SENSOR_DEVICE_ATTR(port_14_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 13); +static SENSOR_DEVICE_ATTR(port_15_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 14); +static SENSOR_DEVICE_ATTR(port_16_rst, S_IRUGO | S_IWUSR, show_port_rst, set_port_rst, 15); + +static SENSOR_DEVICE_ATTR(port_1_prs, S_IRUGO, show_port_prs, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_prs, S_IRUGO, show_port_prs, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_prs, S_IRUGO, show_port_prs, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_prs, S_IRUGO, show_port_prs, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_prs, S_IRUGO, show_port_prs, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_prs, S_IRUGO, show_port_prs, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_prs, S_IRUGO, show_port_prs, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_prs, S_IRUGO, show_port_prs, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_prs, S_IRUGO, show_port_prs, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_prs, S_IRUGO, show_port_prs, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_prs, S_IRUGO, show_port_prs, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_prs, S_IRUGO, show_port_prs, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_prs, S_IRUGO, show_port_prs, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_prs, S_IRUGO, show_port_prs, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_prs, S_IRUGO, show_port_prs, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_prs, S_IRUGO, show_port_prs, NULL, 15); + +static SENSOR_DEVICE_ATTR(modprs_reg1, S_IRUGO, show_modprs_reg, NULL, 0); +static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 1); + +static SENSOR_DEVICE_ATTR(port_1_pwgood, S_IRUGO, show_port_pwgood, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_pwgood, S_IRUGO, show_port_pwgood, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_pwgood, S_IRUGO, show_port_pwgood, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_pwgood, S_IRUGO, show_port_pwgood, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_pwgood, S_IRUGO, show_port_pwgood, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_pwgood, S_IRUGO, show_port_pwgood, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_pwgood, S_IRUGO, show_port_pwgood, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_pwgood, S_IRUGO, show_port_pwgood, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_pwgood, S_IRUGO, show_port_pwgood, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_pwgood, S_IRUGO, show_port_pwgood, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_pwgood, S_IRUGO, show_port_pwgood, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_pwgood, S_IRUGO, show_port_pwgood, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_pwgood, S_IRUGO, show_port_pwgood, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_pwgood, S_IRUGO, show_port_pwgood, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_pwgood, S_IRUGO, show_port_pwgood, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_pwgood, S_IRUGO, show_port_pwgood, NULL, 15); + +static SENSOR_DEVICE_ATTR(port_1_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 0); +static SENSOR_DEVICE_ATTR(port_2_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 1); +static SENSOR_DEVICE_ATTR(port_3_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 2); +static SENSOR_DEVICE_ATTR(port_4_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 3); +static SENSOR_DEVICE_ATTR(port_5_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 4); +static SENSOR_DEVICE_ATTR(port_6_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 5); +static SENSOR_DEVICE_ATTR(port_7_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 6); +static SENSOR_DEVICE_ATTR(port_8_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 7); +static SENSOR_DEVICE_ATTR(port_9_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 8); +static SENSOR_DEVICE_ATTR(port_10_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 9); +static SENSOR_DEVICE_ATTR(port_11_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 10); +static SENSOR_DEVICE_ATTR(port_12_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 11); +static SENSOR_DEVICE_ATTR(port_13_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 12); +static SENSOR_DEVICE_ATTR(port_14_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 13); +static SENSOR_DEVICE_ATTR(port_15_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 14); +static SENSOR_DEVICE_ATTR(port_16_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 15); + +static struct attribute *port_cpld2_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_scratch.dev_attr.attr, + + &sensor_dev_attr_port_1_lpmod.dev_attr.attr, + &sensor_dev_attr_port_2_lpmod.dev_attr.attr, + &sensor_dev_attr_port_3_lpmod.dev_attr.attr, + &sensor_dev_attr_port_4_lpmod.dev_attr.attr, + &sensor_dev_attr_port_5_lpmod.dev_attr.attr, + &sensor_dev_attr_port_6_lpmod.dev_attr.attr, + &sensor_dev_attr_port_7_lpmod.dev_attr.attr, + &sensor_dev_attr_port_8_lpmod.dev_attr.attr, + &sensor_dev_attr_port_9_lpmod.dev_attr.attr, + &sensor_dev_attr_port_10_lpmod.dev_attr.attr, + &sensor_dev_attr_port_11_lpmod.dev_attr.attr, + &sensor_dev_attr_port_12_lpmod.dev_attr.attr, + &sensor_dev_attr_port_13_lpmod.dev_attr.attr, + &sensor_dev_attr_port_14_lpmod.dev_attr.attr, + &sensor_dev_attr_port_15_lpmod.dev_attr.attr, + &sensor_dev_attr_port_16_lpmod.dev_attr.attr, + + &sensor_dev_attr_port_1_rst.dev_attr.attr, + &sensor_dev_attr_port_2_rst.dev_attr.attr, + &sensor_dev_attr_port_3_rst.dev_attr.attr, + &sensor_dev_attr_port_4_rst.dev_attr.attr, + &sensor_dev_attr_port_5_rst.dev_attr.attr, + &sensor_dev_attr_port_6_rst.dev_attr.attr, + &sensor_dev_attr_port_7_rst.dev_attr.attr, + &sensor_dev_attr_port_8_rst.dev_attr.attr, + &sensor_dev_attr_port_9_rst.dev_attr.attr, + &sensor_dev_attr_port_10_rst.dev_attr.attr, + &sensor_dev_attr_port_11_rst.dev_attr.attr, + &sensor_dev_attr_port_12_rst.dev_attr.attr, + &sensor_dev_attr_port_13_rst.dev_attr.attr, + &sensor_dev_attr_port_14_rst.dev_attr.attr, + &sensor_dev_attr_port_15_rst.dev_attr.attr, + &sensor_dev_attr_port_16_rst.dev_attr.attr, + + &sensor_dev_attr_port_1_prs.dev_attr.attr, + &sensor_dev_attr_port_2_prs.dev_attr.attr, + &sensor_dev_attr_port_3_prs.dev_attr.attr, + &sensor_dev_attr_port_4_prs.dev_attr.attr, + &sensor_dev_attr_port_5_prs.dev_attr.attr, + &sensor_dev_attr_port_6_prs.dev_attr.attr, + &sensor_dev_attr_port_7_prs.dev_attr.attr, + &sensor_dev_attr_port_8_prs.dev_attr.attr, + &sensor_dev_attr_port_9_prs.dev_attr.attr, + &sensor_dev_attr_port_10_prs.dev_attr.attr, + &sensor_dev_attr_port_11_prs.dev_attr.attr, + &sensor_dev_attr_port_12_prs.dev_attr.attr, + &sensor_dev_attr_port_13_prs.dev_attr.attr, + &sensor_dev_attr_port_14_prs.dev_attr.attr, + &sensor_dev_attr_port_15_prs.dev_attr.attr, + &sensor_dev_attr_port_16_prs.dev_attr.attr, + + &sensor_dev_attr_modprs_reg1.dev_attr.attr, + &sensor_dev_attr_modprs_reg2.dev_attr.attr, + + &sensor_dev_attr_port_1_pwgood.dev_attr.attr, + &sensor_dev_attr_port_2_pwgood.dev_attr.attr, + &sensor_dev_attr_port_3_pwgood.dev_attr.attr, + &sensor_dev_attr_port_4_pwgood.dev_attr.attr, + &sensor_dev_attr_port_5_pwgood.dev_attr.attr, + &sensor_dev_attr_port_6_pwgood.dev_attr.attr, + &sensor_dev_attr_port_7_pwgood.dev_attr.attr, + &sensor_dev_attr_port_8_pwgood.dev_attr.attr, + &sensor_dev_attr_port_9_pwgood.dev_attr.attr, + &sensor_dev_attr_port_10_pwgood.dev_attr.attr, + &sensor_dev_attr_port_11_pwgood.dev_attr.attr, + &sensor_dev_attr_port_12_pwgood.dev_attr.attr, + &sensor_dev_attr_port_13_pwgood.dev_attr.attr, + &sensor_dev_attr_port_14_pwgood.dev_attr.attr, + &sensor_dev_attr_port_15_pwgood.dev_attr.attr, + &sensor_dev_attr_port_16_pwgood.dev_attr.attr, + + &sensor_dev_attr_port_1_en.dev_attr.attr, + &sensor_dev_attr_port_2_en.dev_attr.attr, + &sensor_dev_attr_port_3_en.dev_attr.attr, + &sensor_dev_attr_port_4_en.dev_attr.attr, + &sensor_dev_attr_port_5_en.dev_attr.attr, + &sensor_dev_attr_port_6_en.dev_attr.attr, + &sensor_dev_attr_port_7_en.dev_attr.attr, + &sensor_dev_attr_port_8_en.dev_attr.attr, + &sensor_dev_attr_port_9_en.dev_attr.attr, + &sensor_dev_attr_port_10_en.dev_attr.attr, + &sensor_dev_attr_port_11_en.dev_attr.attr, + &sensor_dev_attr_port_12_en.dev_attr.attr, + &sensor_dev_attr_port_13_en.dev_attr.attr, + &sensor_dev_attr_port_14_en.dev_attr.attr, + &sensor_dev_attr_port_15_en.dev_attr.attr, + &sensor_dev_attr_port_16_en.dev_attr.attr, + + NULL +}; + +static const struct attribute_group port_cpld2_group = { + .attrs = port_cpld2_attributes, +}; + +static int port_cpld2_probe(struct i2c_client *client) +{ + int status; + struct cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia PORT_CPLD2 chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &port_cpld2_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + dump_reg(data); + dev_info(&client->dev, "[PORT_CPLD2]Reseting PORTs ...\n"); + cpld_i2c_write(data, PORT_LPMODE_REG0, 0x0); + cpld_i2c_write(data, PORT_LPMODE_REG0+1, 0x0); + cpld_i2c_write(data, PORT_RST_REG0, 0x0); + cpld_i2c_write(data, PORT_RST_REG0+1, 0x0); + msleep(500); + cpld_i2c_write(data, PORT_RST_REG0, 0xFF); + cpld_i2c_write(data, PORT_RST_REG0+1, 0xFF); + dev_info(&client->dev, "[PORT_CPLD2]PORTs reset done.\n"); + dump_reg(data); + + return 0; + +exit: + return status; +} + +static void port_cpld2_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &port_cpld2_group); + kfree(data); +} + +static const struct of_device_id port_cpld2_of_ids[] = { + { + .compatible = "port_cpld2", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, port_cpld2_of_ids); + +static const struct i2c_device_id port_cpld2_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, port_cpld2_ids); + +static struct i2c_driver port_cpld2_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(port_cpld2_of_ids), + }, + .probe = port_cpld2_probe, + .remove = port_cpld2_remove, + .id_table = port_cpld2_ids, + .address_list = cpld_address_list, +}; + +static int __init port_cpld2_init(void) +{ + return i2c_add_driver(&port_cpld2_driver); +} + +static void __exit port_cpld2_exit(void) +{ + i2c_del_driver(&port_cpld2_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA H6-128 PORT_CPLD2 driver"); +MODULE_LICENSE("GPL"); + +module_init(port_cpld2_init); +module_exit(port_cpld2_exit); diff --git a/ixr7220h6-128/modules/sys_cpld.c b/ixr7220h6-128/modules/sys_cpld.c new file mode 100644 index 0000000..22b188d --- /dev/null +++ b/ixr7220h6-128/modules/sys_cpld.c @@ -0,0 +1,421 @@ +// * CPLD driver for Nokia-7220-IXR-H6-128 Router +// * +// * Copyright (C) 2026 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sys_cpld" + +// REGISTERS ADDRESS MAP +#define VER_MAJOR_REG 0x00 +#define VER_MINOR_REG 0x01 +#define SCRATCH_REG 0x04 +#define PSU_GOOD_REG 0x0B +#define PSU_PRES_REG 0x0C +#define RST_GROUP1_REG 0x11 +#define OSFP_EFUSE_REG0 0x70 +#define SYS_LED_REG0 0x80 +#define SYS_LED_REG1 0x81 + +// REG BIT FIELD POSITION or MASK + +static const unsigned short cpld_address_list[] = {0x61, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; + int osfp_efuse; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_warn(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_warn(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 reg_major = 0; + u8 reg_minor = 0; + + reg_major = cpld_i2c_read(data, VER_MAJOR_REG); + reg_minor = cpld_i2c_read(data, VER_MINOR_REG); + + return sprintf(buf, "%d.%d\n", reg_major, reg_minor); +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_psu_ok(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PSU_GOOD_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_psu_pres(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PSU_PRES_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_led0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + u8 mask = 0xF; + + val = cpld_i2c_read(data, SYS_LED_REG0); + if (sda->index == 0) mask = 0xF; + else mask = 0x3; + return sprintf(buf, "0x%x\n", (val>>sda->index) & mask); +} + +static ssize_t set_led0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 reg_mask = 0xFF; + u8 mask = 0xF; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (sda->index == 0) mask = 0xF; + else mask = 0x3; + if (usr_val > mask) { + return -EINVAL; + } + reg_mask = (~(mask << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, SYS_LED_REG0); + reg_val = reg_val & reg_mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, SYS_LED_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_led1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + u8 mask = 0xF; + + val = cpld_i2c_read(data, SYS_LED_REG1); + if (sda->index == 0) mask = 0xF; + else mask = 0x3; + return sprintf(buf, "0x%x\n", (val>>sda->index) & mask); +} + +static ssize_t set_led1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 reg_mask = 0xFF; + u8 mask = 0xF; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (sda->index == 0) mask = 0xF; + else mask = 0x3; + if (usr_val > mask) { + return -EINVAL; + } + reg_mask = (~(mask << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, SYS_LED_REG1); + reg_val = reg_val & reg_mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, SYS_LED_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_rst1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, RST_GROUP1_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_rst1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, RST_GROUP1_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, RST_GROUP1_REG, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_osfp_efuse(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", (data->osfp_efuse) ? "Enabled":"Disabled"); +} + +static ssize_t set_osfp_efuse(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + int i; + const char *str_en = "Enable\n"; + const char *str_dis = "Disable\n"; + + if (strcmp(buf, str_en) == 0) { + for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0xFF); + data->osfp_efuse = 1; + } + else if (strcmp(buf, str_dis) == 0) { + for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0x0); + data->osfp_efuse = 0; + } + else + return -EINVAL; + + return count; +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); + +static SENSOR_DEVICE_ATTR(psu1_ok, S_IRUGO, show_psu_ok, NULL, 0); +static SENSOR_DEVICE_ATTR(psu2_ok, S_IRUGO, show_psu_ok, NULL, 1); +static SENSOR_DEVICE_ATTR(psu3_ok, S_IRUGO, show_psu_ok, NULL, 2); +static SENSOR_DEVICE_ATTR(psu4_ok, S_IRUGO, show_psu_ok, NULL, 3); +static SENSOR_DEVICE_ATTR(psu1_pres, S_IRUGO, show_psu_pres, NULL, 4); +static SENSOR_DEVICE_ATTR(psu2_pres, S_IRUGO, show_psu_pres, NULL, 5); +static SENSOR_DEVICE_ATTR(psu3_pres, S_IRUGO, show_psu_pres, NULL, 6); +static SENSOR_DEVICE_ATTR(psu4_pres, S_IRUGO, show_psu_pres, NULL, 7); + +static SENSOR_DEVICE_ATTR(led_sys, S_IRUGO | S_IWUSR, show_led0, set_led0, 0); +static SENSOR_DEVICE_ATTR(led_psu, S_IRUGO, show_led0, NULL, 4); +static SENSOR_DEVICE_ATTR(led_loc, S_IRUGO | S_IWUSR, show_led1, set_led1, 0); +static SENSOR_DEVICE_ATTR(led_fan, S_IRUGO | S_IWUSR, show_led1, set_led1, 4); + +static SENSOR_DEVICE_ATTR(mac_pcie_rst, S_IRUGO | S_IWUSR, show_rst1, set_rst1, 3); +static SENSOR_DEVICE_ATTR(osfp_efuse, S_IRUGO | S_IWUSR, show_osfp_efuse, set_osfp_efuse, 0); + +static struct attribute *sys_cpld_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_scratch.dev_attr.attr, + + &sensor_dev_attr_psu1_ok.dev_attr.attr, + &sensor_dev_attr_psu2_ok.dev_attr.attr, + &sensor_dev_attr_psu3_ok.dev_attr.attr, + &sensor_dev_attr_psu4_ok.dev_attr.attr, + &sensor_dev_attr_psu1_pres.dev_attr.attr, + &sensor_dev_attr_psu2_pres.dev_attr.attr, + &sensor_dev_attr_psu3_pres.dev_attr.attr, + &sensor_dev_attr_psu4_pres.dev_attr.attr, + + &sensor_dev_attr_led_sys.dev_attr.attr, + &sensor_dev_attr_led_psu.dev_attr.attr, + &sensor_dev_attr_led_loc.dev_attr.attr, + &sensor_dev_attr_led_fan.dev_attr.attr, + + &sensor_dev_attr_mac_pcie_rst.dev_attr.attr, + &sensor_dev_attr_osfp_efuse.dev_attr.attr, + + NULL +}; + +static const struct attribute_group sys_cpld_group = { + .attrs = sys_cpld_attributes, +}; + +static int sys_cpld_probe(struct i2c_client *client) +{ + int status; + struct cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia SYS_CPLD chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &sys_cpld_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + int i; + for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0xFF); + data->osfp_efuse = 1; + + return 0; + +exit: + return status; +} + +static void sys_cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &sys_cpld_group); + kfree(data); +} + +static const struct of_device_id sys_cpld_of_ids[] = { + { + .compatible = "nokia,sys_cpld", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sys_cpld_of_ids); + +static const struct i2c_device_id sys_cpld_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sys_cpld_ids); + +static struct i2c_driver sys_cpld_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(sys_cpld_of_ids), + }, + .probe = sys_cpld_probe, + .remove = sys_cpld_remove, + .id_table = sys_cpld_ids, + .address_list = cpld_address_list, +}; + +static int __init sys_cpld_init(void) +{ + return i2c_add_driver(&sys_cpld_driver); +} + +static void __exit sys_cpld_exit(void) +{ + i2c_del_driver(&sys_cpld_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA H6-128 SYS_CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(sys_cpld_init); +module_exit(sys_cpld_exit); diff --git a/ixr7220h6-128/modules/sys_fpga.c b/ixr7220h6-128/modules/sys_fpga.c new file mode 100644 index 0000000..686ff33 --- /dev/null +++ b/ixr7220h6-128/modules/sys_fpga.c @@ -0,0 +1,243 @@ +// * CPLD driver for Nokia-7220-IXR-H6-128 Router +// * +// * Copyright (C) 2026 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sys_fpga" + +// REGISTERS ADDRESS MAP +#define HW_BOARD_VER_REG 0x00 +#define VER_MAJOR_REG 0x01 +#define VER_MINOR_REG 0x02 +#define BMC_TIMING_FCM_PSU_PRESENT_REG 0x07 +#define SSD_PRESENT_REG 0x08 +#define PSU_POWERGOOD_REG 0x51 + +// REG BIT FIELD POSITION or MASK + +static const unsigned short cpld_address_list[] = {0x60, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; + int reset_cause; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_warn(&client->dev, "SYS_FPGA READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_warn(&client->dev, "SYS_FPGA WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static ssize_t show_hw_board_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + val = cpld_i2c_read(data, HW_BOARD_VER_REG); + return sprintf(buf, "0x%x\n", val); +} + +static ssize_t show_fpga_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 reg_major = 0; + u8 reg_minor = 0; + + reg_major = cpld_i2c_read(data, VER_MAJOR_REG); + reg_minor = cpld_i2c_read(data, VER_MINOR_REG); + + return sprintf(buf, "%d.%d\n", reg_major, reg_minor); +} + +static ssize_t show_bmc_timing_fcm_psu_present(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, BMC_TIMING_FCM_PSU_PRESENT_REG); + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_psu_ok(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, PSU_POWERGOOD_REG); + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_ssd_present(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, SSD_PRESENT_REG); + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(hw_board_version, S_IRUGO, show_hw_board_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(fpga_version, S_IRUGO, show_fpga_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(psu1_ok, S_IRUGO, show_psu_ok, NULL, 0); +static SENSOR_DEVICE_ATTR(psu2_ok, S_IRUGO, show_psu_ok, NULL, 1); +static SENSOR_DEVICE_ATTR(psu3_ok, S_IRUGO, show_psu_ok, NULL, 2); +static SENSOR_DEVICE_ATTR(psu4_ok, S_IRUGO, show_psu_ok, NULL, 3); +static SENSOR_DEVICE_ATTR(psu1_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 3); +static SENSOR_DEVICE_ATTR(psu2_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 2); +static SENSOR_DEVICE_ATTR(psu3_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 1); +static SENSOR_DEVICE_ATTR(psu4_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 0); +static SENSOR_DEVICE_ATTR(ssd1_pres, S_IRUGO, show_ssd_present, NULL, 1); +static SENSOR_DEVICE_ATTR(ssd2_pres, S_IRUGO, show_ssd_present, NULL, 0); + +static struct attribute *sys_fpga_attributes[] = { + &sensor_dev_attr_hw_board_version.dev_attr.attr, + &sensor_dev_attr_fpga_version.dev_attr.attr, + &sensor_dev_attr_psu1_ok.dev_attr.attr, + &sensor_dev_attr_psu2_ok.dev_attr.attr, + &sensor_dev_attr_psu3_ok.dev_attr.attr, + &sensor_dev_attr_psu4_ok.dev_attr.attr, + &sensor_dev_attr_psu1_pres.dev_attr.attr, + &sensor_dev_attr_psu2_pres.dev_attr.attr, + &sensor_dev_attr_psu3_pres.dev_attr.attr, + &sensor_dev_attr_psu4_pres.dev_attr.attr, + &sensor_dev_attr_ssd1_pres.dev_attr.attr, + &sensor_dev_attr_ssd2_pres.dev_attr.attr, + NULL +}; + +static const struct attribute_group sys_fpga_group = { + .attrs = sys_fpga_attributes, +}; + +static int sys_fpga_probe(struct i2c_client *client) +{ + int status; + struct cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia SYS_FPGA chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &sys_fpga_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + return 0; + +exit: + return status; +} + +static void sys_fpga_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &sys_fpga_group); + kfree(data); +} + +static const struct of_device_id sys_fpga_of_ids[] = { + { + .compatible = "nokia,sys_fpga", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sys_fpga_of_ids); + +static const struct i2c_device_id sys_fpga_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sys_fpga_ids); + +static struct i2c_driver sys_fpga_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(sys_fpga_of_ids), + }, + .probe = sys_fpga_probe, + .remove = sys_fpga_remove, + .id_table = sys_fpga_ids, + .address_list = cpld_address_list, +}; + +static int __init sys_fpga_init(void) +{ + return i2c_add_driver(&sys_fpga_driver); +} + +static void __exit sys_fpga_exit(void) +{ + i2c_del_driver(&sys_fpga_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA H6-128 SYS_FPGA driver"); +MODULE_LICENSE("GPL"); + +module_init(sys_fpga_init); +module_exit(sys_fpga_exit); diff --git a/ixr7220h6-128/modules/sys_mux.c b/ixr7220h6-128/modules/sys_mux.c new file mode 100644 index 0000000..ad0884e --- /dev/null +++ b/ixr7220h6-128/modules/sys_mux.c @@ -0,0 +1,238 @@ +/* NOKIA I2C-bus multiplexer driver + * Copyright (C) 2025 Nokia Corporation. + * This module supports the FPGA & CPLD that hold the channel select + * mechanism for other i2c slave devices + * + * + * Based on: + * sys_mux.c Brandon Chuang + * Copyright (C) 2025 + # + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "sys_mux" + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +#define SYS_MUX_NCHANS 16 +#define SYS_MUX_SELECT_REG 0x0 +#define SYS_MUX_DESELECT_VAL 0x0 + +enum mux_type { + mux_fpga, + mux_sys_cpld, + mux_fcm, + mux_mezz +}; + +struct chip_desc { + u8 nchans; + u8 select_reg; + u8 deselect_val; + enum muxtype { + is_mux = 0, + isswi + } muxtype; +}; + +struct sys_mux_data { + enum mux_type type; + struct mutex update_lock; + struct i2c_client *client; +}; + +static const struct chip_desc chips[] = { + [mux_fpga] = { + .nchans = 14, + .select_reg = SYS_MUX_SELECT_REG, + .deselect_val = SYS_MUX_DESELECT_VAL, + .muxtype = is_mux + }, + [mux_sys_cpld] = { + .nchans = 15, + .select_reg = SYS_MUX_SELECT_REG, + .deselect_val = SYS_MUX_DESELECT_VAL, + .muxtype = is_mux + }, + [mux_fcm] = { + .nchans = 6, + .select_reg = SYS_MUX_SELECT_REG, + .deselect_val = SYS_MUX_DESELECT_VAL, + .muxtype = isswi + }, + [mux_mezz] = { + .nchans = 3, + .select_reg = SYS_MUX_SELECT_REG, + .deselect_val = SYS_MUX_DESELECT_VAL, + .muxtype = is_mux + } +}; + +static const struct i2c_device_id sys_mux_id[] = { + {"mux_fpga", mux_fpga}, + {"mux_sys_cpld", mux_sys_cpld}, + {"mux_fcm", mux_fcm}, + {"mux_mezz", mux_mezz}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sys_mux_id); + +static const struct of_device_id sys_mux_of_match[] = { + {.compatible = "mux_fpga",.data = &chips[mux_fpga]}, + {.compatible = "mux_sys_cpld",.data = &chips[mux_sys_cpld]}, + {.compatible = "mux_fcm",.data = &chips[mux_fcm]}, + {.compatible = "mux_mezz",.data = &chips[mux_mezz]}, + {} +}; + +MODULE_DEVICE_TABLE(of, sys_mux_of_match); + +/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() + for this as they will try to lock adapter a second time */ +static int sys_mux_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 reg, u8 val) +{ + union i2c_smbus_data data; + + data.byte = val; + return __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, + &data); +} + +static int sys_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct sys_mux_data *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret = 0; + mutex_lock(&data->update_lock); + switch (data->type) { + case mux_fpga: + case mux_sys_cpld: + case mux_mezz: + ret = sys_mux_write(muxc->parent, client, + chips[data->type].select_reg, + chan + 1); + break; + case mux_fcm: + ret = sys_mux_write(muxc->parent, client, + chips[data->type].select_reg, + 1 << chan); + break; + default: + break; + } + + mutex_unlock(&data->update_lock); + return ret; +} + +static int sys_mux_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct sys_mux_data *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret = 0; + + mutex_lock(&data->update_lock); + ret = sys_mux_write(muxc->parent, client, + chips[data->type].select_reg, + chips[data->type].deselect_val); + mutex_unlock(&data->update_lock); + return ret; +} + +static void sys_mux_cleanup(struct i2c_mux_core *muxc) +{ + i2c_mux_del_adapters(muxc); +} + +static int sys_mux_probe(struct i2c_client *client) +{ + const struct i2c_device_id *id = i2c_client_get_device_id(client); + struct i2c_adapter *adap = client->adapter; + struct device *dev = &client->dev; + struct sys_mux_data *data; + struct i2c_mux_core *muxc; + int ret = -ENODEV; + int i = 0; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + return -ENODEV; + + muxc = i2c_mux_alloc(adap, dev, SYS_MUX_NCHANS, sizeof(*data), 0, + sys_mux_select_chan, + sys_mux_deselect_mux); + if (!muxc) + return -ENOMEM; + + data = i2c_mux_priv(muxc); + mutex_init(&data->update_lock); + data->type = id->driver_data; + data->client = client; + i2c_set_clientdata(client, muxc); + + /* Now create an adapter for each channel */ + for (i = 0; i < chips[data->type].nchans; i++) { + ret = i2c_mux_add_adapter(muxc, 0, i); + if (ret) + goto exit_mux; + } + + return 0; + + exit_mux: + sys_mux_cleanup(muxc); + return ret; +} + +static void sys_mux_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + sys_mux_cleanup(muxc); +} + +static struct i2c_driver sys_mux_driver = { + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = sys_mux_of_match, + }, + .probe = sys_mux_probe, + .remove = sys_mux_remove, + .id_table = sys_mux_id, +}; + +module_i2c_driver(sys_mux_driver); +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA I2C-bus multiplexer driver"); +MODULE_LICENSE("GPL"); + diff --git a/ixr7220h6-128/scripts/h6_128_platform_init.sh b/ixr7220h6-128/scripts/h6_128_platform_init.sh new file mode 100755 index 0000000..d3649a3 --- /dev/null +++ b/ixr7220h6-128/scripts/h6_128_platform_init.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +# Load required kernel-mode drivers + +load_kernel_drivers() { + echo "Loading Kernel Drivers" + depmod -a + rmmod amd-xgbe + rmmod igb + rmmod i2c-piix4 + rmmod i2c_designware_platform + modprobe igb + modprobe amd-xgbe + modprobe i2c_designware_platform + + modprobe i2c-i801 + modprobe i2c-dev + modprobe i2c-mux + modprobe i2c-smbus + modprobe i2c-ismt + modprobe i2c-ocores + modprobe h6_i2c_oc +} + +h6-128_profile() +{ + MAC_ADDR=$(ip link show eth0 | grep ether | awk '{print $2}') + sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" /usr/share/sonic/device/x86_64-nokia_ixr7220_h6_128-r0/Nokia-IXR7220-H6-128/profile.ini + echo "Nokia-IXR7220-H6-128: Updated switch mac address ${MAC_ADDR}" +} + +file_exists() { + # Wait 10 seconds max till file exists + for((i=0; i<10; i++)); + do + if [ -f $1 ]; then + return 1 + fi + sleep 1 + done + return 0 +} + +load_kernel_drivers + +sleep 1 +i2cset -y 1 0x60 0xf 0x1 +sleep 1 +i2cset -y 1 0x77 0x0 0x03 +sleep 2 +i2cset -y 1 0x71 0xc 0x3f +sleep 1 + +echo sys_fpga 0x60 > /sys/bus/i2c/devices/i2c-1/new_device + +echo mux_fpga 0x77 > /sys/bus/i2c/devices/i2c-1/new_device +sleep 1 +echo mux_sys_cpld 0x72 > /sys/bus/i2c/devices/i2c-134/new_device + +echo mux_fcm 0x75 > /sys/bus/i2c/devices/i2c-144/new_device +echo mux_fcm 0x76 > /sys/bus/i2c/devices/i2c-145/new_device +sleep 1 +echo mux_mezz 0x75 > /sys/bus/i2c/devices/i2c-150/new_device +echo mux_mezz 0x75 > /sys/bus/i2c/devices/i2c-151/new_device +echo mux_mezz 0x75 > /sys/bus/i2c/devices/i2c-152/new_device +echo mux_mezz 0x75 > /sys/bus/i2c/devices/i2c-153/new_device + +echo port_cpld0 0x74 > /sys/bus/i2c/devices/i2c-148/new_device +echo port_cpld1 0x75 > /sys/bus/i2c/devices/i2c-149/new_device +echo port_cpld2 0x73 > /sys/bus/i2c/devices/i2c-150/new_device +echo port_cpld2 0x73 > /sys/bus/i2c/devices/i2c-151/new_device +echo port_cpld2 0x76 > /sys/bus/i2c/devices/i2c-152/new_device +echo port_cpld2 0x76 > /sys/bus/i2c/devices/i2c-153/new_device + +echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-173/new_device +echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-176/new_device +echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-179/new_device +echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-182/new_device + +echo 24c04 0x56 > /sys/bus/i2c/devices/i2c-158/new_device + +echo h6_fan 0x32 > /sys/bus/i2c/devices/i2c-144/new_device +echo h6_fan 0x33 > /sys/bus/i2c/devices/i2c-145/new_device + +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-163/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-164/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-165/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-166/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-169/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-170/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-171/new_device +echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-172/new_device + +for i in {0..3}; do + pres="/sys/bus/i2c/devices/1-0060/psu$((i+1))_pres" + bus_path="/sys/bus/i2c/devices/i2c-$((136+i))/new_device" + pmbus_addr=$((0x58 + i)) + eeprom_addr=$((0x50 + i)) + + if [ "$(cat "$pres")" = "0" ]; then + echo "pmbus_psu $(printf '0x%X' $pmbus_addr)" > "$bus_path" + echo "eeprom_fru $(printf '0x%X' $eeprom_addr)" > "$bus_path" + fi +done + +echo embd_ctrl 0x21 > /sys/bus/i2c/devices/i2c-0/new_device +echo jc42 0x18 > /sys/bus/i2c/devices/i2c-0/new_device +echo lm75 0x48 > /sys/bus/i2c/devices/i2c-143/new_device +echo lm75 0x48 > /sys/bus/i2c/devices/i2c-154/new_device +echo lm75 0x49 > /sys/bus/i2c/devices/i2c-154/new_device +echo lm75 0x4A > /sys/bus/i2c/devices/i2c-154/new_device +echo lm75 0x4B > /sys/bus/i2c/devices/i2c-154/new_device +echo lm75 0x4C > /sys/bus/i2c/devices/i2c-154/new_device +echo lm75 0x4D > /sys/bus/i2c/devices/i2c-154/new_device + +echo tmp75 0x4D > /sys/bus/i2c/devices/i2c-161/new_device +echo tmp75 0x4E > /sys/bus/i2c/devices/i2c-162/new_device +echo tmp75 0x4D > /sys/bus/i2c/devices/i2c-167/new_device +echo tmp75 0x4E > /sys/bus/i2c/devices/i2c-168/new_device + +echo lm75 0x48 > /sys/bus/i2c/devices/i2c-174/new_device +echo lm75 0x48 > /sys/bus/i2c/devices/i2c-177/new_device +echo lm75 0x48 > /sys/bus/i2c/devices/i2c-180/new_device +echo lm75 0x48 > /sys/bus/i2c/devices/i2c-183/new_device + +file_exists /sys/bus/i2c/devices/158-0056/eeprom +status=$? +if [ "$status" == "1" ]; then + chmod 644 /sys/bus/i2c/devices/158-0056/eeprom +else + echo "SYSEEPROM file not found" +fi + +for index in {2..129}; do + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-${index}/new_device +done +echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-130/new_device +echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-131/new_device + +exit + +for ch in {1..8}; do + echo 60 > /sys/bus/i2c/devices/144-0032/hwmon/hwmon*/fan${ch}_pwm + echo 60 > /sys/bus/i2c/devices/145-0033/hwmon/hwmon*/fan${ch}_pwm +done + +h6-128_profile + +exit + + diff --git a/ixr7220h6-128/service/h6_128_platform_init.service b/ixr7220h6-128/service/h6_128_platform_init.service new file mode 100755 index 0000000..0154996 --- /dev/null +++ b/ixr7220h6-128/service/h6_128_platform_init.service @@ -0,0 +1,12 @@ +[Unit] +Description=Nokia-IXR7220-H6-128 Platform Service +After=sysinit.target +Before=pmon.service determine-reboot-cause.service + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/h6_128_platform_init.sh +StandardOutput=tty + +[Install] +WantedBy=multi-user.target diff --git a/ixr7220h6-128/setup.py b/ixr7220h6-128/setup.py new file mode 100755 index 0000000..8f329c2 --- /dev/null +++ b/ixr7220h6-128/setup.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='sonic_platform', + version='1.0', + description='Module to initialize Nokia IXR7220-H6-128 platforms', + + packages=[ + 'sonic_platform', + 'sonic_platform.test' + ], + + package_dir={ + 'sonic_platform': 'sonic_platform' + } +) diff --git a/ixr7220h6-128/sonic_platform/__init__.py b/ixr7220h6-128/sonic_platform/__init__.py new file mode 100755 index 0000000..290d8cd --- /dev/null +++ b/ixr7220h6-128/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform"] +from sonic_platform import * diff --git a/ixr7220h6-128/sonic_platform/chassis.py b/ixr7220h6-128/sonic_platform/chassis.py new file mode 100755 index 0000000..9364727 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/chassis.py @@ -0,0 +1,402 @@ +""" + Module contains an implementation of SONiC Platform Base API and + provides the platform information +""" + +try: + import os + import sys + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.eeprom import Eeprom + from sonic_platform.fan import Fan + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file + from .fan_drawer import RealDrawer + from sonic_platform.psu import Psu + from sonic_platform.thermal import Thermal + from sonic_platform.component import Component + from sonic_platform.sfp_event import SfpEvent + from sonic_py_common import logger +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +# Port numbers for SFP List Initialization +PORT_START = 1 +PORT_NUM = 128 +PORT_END = 130 +PORT_I2C_START = 2 +MAX_SELECT_DELAY = 10 + +# Device counts +FAN_DRAWERS = 8 +FANS_PER_DRAWER = 2 +PSU_NUM = 4 +THERMAL_NUM = 21 +COMPONENT_NUM = 7 + +CPLD_DIR = "/sys/bus/i2c/devices/73-0061/" +SYSFPGA_DIR = "/sys/bus/i2c/devices/1-0060/" +BUS_IDX = [1,2,9,10,17,18,25,26,33,34,41,42,49,50,57,58,65,66,73,74,81,82,89,90,97,98,105,106,113,114,121,122, + 3,4,11,12,19,20,27,28,35,36,43,44,51,52,59,60,67,68,75,76,83,84,91,92,99,100,107,108,115,116,123,124, + 5,6,13,14,21,22,29,30,37,38,45,46,53,54,61,62,69,70,77,78,85,86,93,94,101,102,109,110,117,118,125,126, + 7,8,15,16,23,24,31,32,39,40,47,48,55,56,63,64,71,72,79,80,87,88,95,96,103,104,111,112,119,120,127,128,129,130] + +SYSLOG_IDENTIFIER = "chassis" +sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) +sonic_logger.set_min_log_priority_info() + +class Chassis(ChassisBase): + """ + Nokia platform-specific Chassis class + customized for the 7220 H6-128 platform. + """ + def __init__(self): + ChassisBase.__init__(self) + self.system_led_supported_color = ['green', 'blue', 'green_blink', + 'amber', 'off'] + + # Verify optoe driver OSFP eeprom devices were enumerated and exist + # then create the sfp nodes + eeprom_path = "/sys/bus/i2c/devices/{}-0050/eeprom" + for index in range(PORT_START, PORT_START + PORT_END): + port_i2c_map = PORT_I2C_START + BUS_IDX[index-1] - 1 + port_eeprom_path = eeprom_path.format(port_i2c_map) + if not os.path.exists(port_eeprom_path): + sonic_logger.log_info(f"path {port_eeprom_path} didnt exist") + if index <= PORT_NUM: + sfp_node = Sfp(index, 'OSFP', port_eeprom_path, port_i2c_map) + elif index > PORT_NUM and index <= PORT_END: + sfp_node = Sfp(index, 'SFP56', port_eeprom_path, port_i2c_map) + self._sfp_list.append(sfp_node) + + self.sfp_event_initialized = False + + # Instantiate system eeprom object + self._eeprom = Eeprom(False, 0, False, 0) + + self._watchdog = None + self.sfp_event = None + self.max_select_event_returned = None + + # Construct lists fans, power supplies, thermals & components + for i in range(THERMAL_NUM): + thermal = Thermal(i, self._sfp_list) + self._thermal_list.append(thermal) + + drawer_num = FAN_DRAWERS + fan_num_per_drawer = FANS_PER_DRAWER + drawer_ctor = RealDrawer + for drawer_index in range(drawer_num): + drawer = drawer_ctor(drawer_index) + self._fan_drawer_list.append(drawer) + for fan_index in range(fan_num_per_drawer): + fan = Fan(fan_index, drawer_index) + drawer._fan_list.append(fan) + self._fan_list.append(fan) + + for i in range(PSU_NUM): + psu = Psu(i) + self._psu_list.append(psu) + + # for i in range(COMPONENT_NUM): + # component = Component(i) + # self._component_list.append(component) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of physical SFP ports in a + chassis starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write(f"SFP index {index} out of range (1-{len(self._sfp_list)})\n") + return sfp + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + """ + # Initialize SFP event first + if not self.sfp_event_initialized: + self.sfp_event = SfpEvent() + self.sfp_event.initialize() + self.max_select_event_returned = PORT_END + self.sfp_event_initialized = True + + wait_for_ever = timeout == 0 + port_dict = {} + if wait_for_ever: + # xrcvd will call this monitor loop in the "SYSTEM_READY" state + # sonic_logger.log_info(" wait_for_ever get_change_event %d" % timeout) + timeout = MAX_SELECT_DELAY + while True: + status = self.sfp_event.check_sfp_status(port_dict, timeout) + if port_dict: + break + else: + # At boot up and in "INIT" state call from xrcvd will have timeout + # value return true without change after timeout and will + # transition to "SYSTEM_READY" + status = self.sfp_event.check_sfp_status(port_dict, timeout) + + if status: + return True, {'sfp': port_dict} + return True, {'sfp': {}} + + def get_num_psus(self): + """ + Retrieves the num of the psus + Returns: + int: The num of the psus + """ + return PSU_NUM + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.base_mac_addr() + + def get_service_tag(self): + """ + Retrieves the Service Tag of the chassis + Returns: + string: Service Tag of chassis + """ + return self._eeprom.service_tag_str() + + def get_revision(self): + """ + Retrieves the hardware revision of the chassis + + Returns: + string: Revision value of chassis + """ + return str(0) + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the + chassis + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their + corresponding values. + """ + return self._eeprom.system_eeprom_info() + + def get_thermal_manager(self): + """ + Get thermal manager + + Returns: + ThermalManager + """ + from .thermal_manager import ThermalManager + return ThermalManager + + def initizalize_system_led(self): + """ + Initizalize system led + + Returns: + bool: True if it is successful. + """ + return True + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + result = read_sysfs_file(SYSFPGA_DIR + "reset_cause") + + if (int(result, 16) & 0x10) >> 4 == 1: + return (self.REBOOT_CAUSE_WATCHDOG, "CPU_WD") + + if (int(result, 16) & 0x01) == 1: + return (self.REBOOT_CAUSE_WATCHDOG, "EC_WD") + + if (int(result, 16) & 0x02) >> 1 == 1: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "CPU Over Heat") + + if (int(result, 16) & 0x08) >> 3 == 1: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Power Cycle") + + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + + def get_watchdog(self): + """ + Retrieves hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + + Note: + We overload this method to ensure that watchdog is only initialized + when it is referenced. Currently, only one daemon can open the + watchdog. To initialize watchdog in the constructor causes multiple + daemon try opening watchdog when loading and constructing a chassis + object and fail. By doing so we can eliminate that risk. + """ + try: + if self._watchdog is None: + from sonic_platform.watchdog import WatchdogImplBase + watchdog_device_path = "/dev/watchdog0" + self._watchdog = WatchdogImplBase(watchdog_device_path) + except ImportError as e: + sonic_logger.log_warning(f"Fail to load watchdog {repr(e)}") + + return self._watchdog + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent + cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', + then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if + cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def set_status_led(self, color): + """ + Sets the state of the system LED + + Args: + color: A string representing the color with which to set the + system LED + + Returns: + bool: True if system LED state is set successfully, False if not + """ + color_to_value = { + 'blue': '0x3', + 'green': '0x5', + 'amber': '0x6', + 'off': '0x7', + 'green_blink': '0xf' + } + + if color not in self.system_led_supported_color: + return False + + value = color_to_value.get(color) + if value is None: + return False + + write_sysfs_file(CPLD_DIR + 'led_sys', value) + return True + + def get_status_led(self): + """ + Gets the state of the system LED + + Returns: + A string, one of the valid LED color strings which could be vendor + specified. + """ + result = read_sysfs_file(CPLD_DIR + 'led_sys') + val = int(result, 16) + if (val & 0x8) == 0x8: + return self.system_led_supported_color[2] + if val == 0x3: + return self.system_led_supported_color[1] + if val == 0x5: + return self.system_led_supported_color[0] + if val == 0x6: + return self.system_led_supported_color[3] + if val == 0x7: + return self.system_led_supported_color[4] + return 'N/A' diff --git a/ixr7220h6-128/sonic_platform/component.py b/ixr7220h6-128/sonic_platform/component.py new file mode 100755 index 0000000..17fca2e --- /dev/null +++ b/ixr7220h6-128/sonic_platform/component.py @@ -0,0 +1,277 @@ +""" + NOKIA IXR7220 H6-128 + + Module contains an implementation of SONiC Platform Base API and + provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in + the platform +""" + +try: + import os + import subprocess + import ntpath + import time + import glob + from sonic_platform_base.component_base import ComponentBase + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +SYSFS_DIR = ["/sys/class/dmi/id/", + "/sys/bus/i2c/devices/1-0060/", + "/sys/bus/i2c/devices/73-0061/", + "/sys/bus/i2c/devices/89-0064/", + "/sys/bus/i2c/devices/90-0065/", + "/sys/bus/i2c/devices/79-0033/hwmon/hwmon*/", + "/sys/bus/i2c/devices/80-0033/hwmon/hwmon*/"] + +class Component(ComponentBase): + """Nokia platform-specific Component class""" + + CHASSIS_COMPONENTS = [ + ["BIOS", "Basic Input/Output System"], + ["SYS_FPGA", "Used for managing CPU board"], + ["SYS_CPLD", "Used for managing BCM chip, PSUs and LEDs"], + ["PORT_CPLD0", "Used for managing PORT 1-16, 33-48, SFP28"], + ["PORT_CPLD1", "Used for managing PORT 17-32, 49-64"], + ["FCM0_CPLD", "Used for managing upper fan drawers"], + ["FCM1_CPLD", "Used for managing lower fan drawers"] ] + DEV_NAME = [" ", " ", "MAIN_CPLD", "MAIN_CPLD", "MAIN_CPLD", "FAN0_CPLD", "FAN1_CPLD"] + TFR_NAME = [" ", " ", "h6_128_sys_cpld_tfr.vme", "h6_128_port_cpld0_tfr.vme", + "h6_128_port_cpld1_tfr.vme", "h6_128_fan_cpld_tfr.vme", "h6_128_fan_cpld_tfr.vme"] + + BIOS_UPDATE_COMMAND = ['./afulnx_128', '', '/B', '/P', '/N', '/K'] + FPGA_CHECK_COMMAND = ['./fpga_spi_flash.sh', '-rid'] + FPGA_UPDATE_COMMAND = ['./fpga_spi_flash.sh', '-upd', '', '-all'] + CPLD_UPDATE_COMMAND = ['./cpldupd', '-u', '', ''] + + def __init__(self, component_index): + self.index = component_index + self.name = self.CHASSIS_COMPONENTS[self.index][0] + self.description = self.CHASSIS_COMPONENTS[self.index][1] + if self.name == "FCM0_CPLD" or self.name == "FCM1_CPLD": + hwmon_dir = glob.glob(SYSFS_DIR[self.index]) + self.sysfs_dir = hwmon_dir[0] + else: + self.sysfs_dir = SYSFS_DIR[self.index] + self.dev_name = self.DEV_NAME[self.index] + self.tfr_name = self.TFR_NAME[self.index] + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + except OSError: + result = None + + return result + + def _get_cpld_version(self): + if self.name == "BIOS": + return read_sysfs_file(self.sysfs_dir + "bios_version") + else: + return read_sysfs_file(self.sysfs_dir + "version") + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.name + + def get_model(self): + """ + Retrieves the part number of the component + Returns: + string: Part number of component + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the component + Returns: + string: Serial number of component + """ + return 'NA' + + def get_presence(self): + """ + Retrieves the presence of the component + Returns: + bool: True if present, False if not + """ + return True + + def get_status(self): + """ + Retrieves the operational status of the component + Returns: + bool: True if component is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether component is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.description + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + return self._get_cpld_version() + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + image_name = ntpath.basename(image_path) + + # check whether the image file exists + os.chdir("/tmp") + if not os.path.isfile(image_name): + print(f"ERROR: the image {image_name} doesn't exist in /tmp") + return False + + if self.name == "BIOS": + # check whether the BIOS upgrade tool exists + if not os.path.isfile('/tmp/afulnx_128'): + print("ERROR: the BIOS upgrade tool /tmp/afulnx_128 doesn't exist ") + return False + self.BIOS_UPDATE_COMMAND[1] = image_name + try: + subprocess.run(self.BIOS_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade BIOS: rc={e.returncode}") + return False + print("\nBIOS update has ended\n") + + elif self.name == "SYS_FPGA": + # check whether the fpga upgrade tool exists + if not os.path.isfile('/tmp/fpga_spi_flash.sh'): + print("ERROR: the fpga upgrade tool /tmp/fpga_spi_flash.sh doesn't exist ") + return False + if not os.path.isfile('/tmp/fpga_upd2'): + print("ERROR: the fpga upgrade tool /tmp/fpga_upd2 doesn't exist ") + return False + try: + result = subprocess.check_output(self.FPGA_CHECK_COMMAND) + result = subprocess.check_output(self.FPGA_CHECK_COMMAND) + text = result.decode('utf-8') + print(text) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to check SYS_FPGA RDID: rc={e.returncode}") + last = text.splitlines() + if last[-1].strip() != "RDID: c2 20 18": + print("FPGA RDID check failed!") + return False + self.FPGA_UPDATE_COMMAND[2] = image_name + try: + subprocess.run(self.FPGA_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade SYS_FPGA: rc={e.returncode}") + return False + print("\nSYS_FPGA firmware update has ended\n") + print("!!!The system will power cycle in 10 sec!!!") + time.sleep(7) + self._power_cycle() + + else: + # check whether the cpld upgrade tool exists + if not os.path.isfile('/tmp/cpldupd'): + print("ERROR: the cpld upgrade tool /tmp/cpldupd doesn't exist ") + return False + val = [" ", " ", "0x4", "0x2", "0x1", "0x10", "0x8"] + write_sysfs_file("/sys/bus/i2c/devices/1-0060/hitless", val[self.index]) + self.CPLD_UPDATE_COMMAND[2] = self.dev_name + self.CPLD_UPDATE_COMMAND[3] = image_name + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade {self.name}: rc={e.returncode}") + return False + self.CPLD_UPDATE_COMMAND[3] = self.tfr_name + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade {self.name}: rc={e.returncode}") + return False + write_sysfs_file("/sys/bus/i2c/devices/1-0060/hitless", "0x0") + print(f"\n{self.name} firmware update has ended\n") + + return True + + def update_firmware(self, image_path): + """ + Updates firmware of the component + + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + + Args: + image_path: A string, path to firmware image + + Raises: + RuntimeError: update failed + """ + return False + + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + + Note: the firmware version will be read from image + + Args: + image_path: A string, path to firmware image + + Returns: + A string containing the available firmware version of the component + """ + return "N/A" + + def _power_cycle(self): + os.system('sync') + os.system('sync') + time.sleep(3) + for i in range(4): + file_path = f"/sys/bus/i2c/devices/{i+94}-00{hex(0x58+i)[2:]}/psu_rst" + if os.path.exists(file_path): + write_sysfs_file(file_path, "Reset\n") \ No newline at end of file diff --git a/ixr7220h6-128/sonic_platform/eeprom.py b/ixr7220h6-128/sonic_platform/eeprom.py new file mode 100755 index 0000000..069fe58 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/eeprom.py @@ -0,0 +1,220 @@ +""" + Nokia IXR7220 H6-128 + + Module contains platform specific implementation of SONiC Platform + Base API and provides the EEPROMs' information. + + The different EEPROMs available are as follows: + - System EEPROM : Contains Serial number, Service tag, Base MA + address, etc. in ONIE TlvInfo EEPROM format. +""" + +try: + import os + from sonic_platform_base.sonic_eeprom.eeprom_tlvinfo import TlvInfoDecoder + from sonic_py_common import logger +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +I2C_FAN_EEPROM = ["163-0050", "164-0050", + "165-0050", "166-0050", + "169-0050", "170-0050", + "171-0050", "172-0050"] + +sonic_logger = logger.Logger('eeprom') + +class Eeprom(TlvInfoDecoder): + """Nokia platform-specific EEPROM class""" + + I2C_DIR = "/sys/bus/i2c/devices/" + def __init__(self, is_psu, psu_index, is_fan, drawer_index): + self.is_psu_eeprom = is_psu + self.is_fan_eeprom = is_fan + self.is_sys_eeprom = not (is_psu | is_fan) + self.service_tag = 'NA' + self.part_number = 'NA' + + if self.is_sys_eeprom: + self.start_offset = 0 + self.eeprom_path = self.I2C_DIR + "158-0056/eeprom" + # System EEPROM is in ONIE TlvInfo EEPROM format + super(Eeprom, self).__init__(self.eeprom_path, self.start_offset, '', True) + self.base_mac = '' + self.serial_number = '' + self.part_number = '' + self.model_str = '' + self.service_tag = '' + self.manuf_date = 'NA' + elif self.is_fan_eeprom: + self.start_offset = 0 + self.eeprom_path = self.I2C_DIR + f"{I2C_FAN_EEPROM[drawer_index]}/eeprom" + # Fan EEPROM is in ONIE TlvInfo EEPROM format + super(Eeprom, self).__init__(self.eeprom_path, self.start_offset, '', True) + self.serial_number = '' + self.part_number = '' + self.model_str = '' + self.service_tag = '' + self.manuf_date = '' + self.base_mac = 'N/A' + else: + self.serial_number = 'N/A' + self.part_number = 'N/A' + self.model_str = 'N/A' + self.service_tag = 'N/A' + self.manuf_date = 'N/A' + + def _load_system_eeprom(self): + """ + Reads the system EEPROM and retrieves the values corresponding + to the codes defined as per ONIE TlvInfo EEPROM format and fills + them in a dictionary. + """ + try: + # Read System EEPROM as per ONIE TlvInfo EEPROM format. + self.eeprom_data = self.read_eeprom() + except Exception as e: + sonic_logger.log_warning("Unable to read system eeprom") + self.base_mac = 'NA' + self.serial_number = 'NA' + self.part_number = 'NA' + self.model_str = 'NA' + self.service_tag = 'NA' + self.manuf_date = 'NA' + self.eeprom_tlv_dict = dict() + else: + eeprom = self.eeprom_data + self.eeprom_tlv_dict = dict() + + if not self.is_valid_tlvinfo_header(eeprom): + sonic_logger.log_warning("Invalid system eeprom TLV header") + self.base_mac = 'NA' + self.serial_number = 'NA' + self.part_number = 'NA' + self.model_str = 'NA' + self.service_tag = 'NA' + self.manuf_date = 'NA' + return + + total_length = (eeprom[9] << 8) | eeprom[10] + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length + + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break + + tlv = eeprom[tlv_index:tlv_index + 2 + + eeprom[tlv_index + 1]] + code = "0x%02X" % (tlv[0]) + + name, value = self.decoder(None, tlv) + + self.eeprom_tlv_dict[code] = value + if eeprom[tlv_index] == self._TLV_CODE_CRC_32: + break + + tlv_index += eeprom[tlv_index+1] + 2 + + self.base_mac = self.eeprom_tlv_dict.get( + "0x%X" % (self._TLV_CODE_MAC_BASE), 'NA') + self.serial_number = self.eeprom_tlv_dict.get( + "0x%X" % (self._TLV_CODE_SERIAL_NUMBER), 'NA') + self.part_number = self.eeprom_tlv_dict.get( + "0x%X" % (self._TLV_CODE_PART_NUMBER), 'NA') + self.model_str = self.eeprom_tlv_dict.get( + "0x%X" % (self._TLV_CODE_PRODUCT_NAME), 'NA') + self.service_tag = self.eeprom_tlv_dict.get( + "0x%X" % (self._TLV_CODE_SERVICE_TAG), 'NA') + self.manuf_date = self.eeprom_tlv_dict.get( + "0x%X" % (self._TLV_CODE_MANUF_DATE), 'NA') + + + def _get_eeprom_field(self, field_name): + """ + For a field name specified in the EEPROM format, returns the + presence of the field and the value for the same. + """ + field_start = 0 + for field in self.format: + field_end = field_start + field[2] + if field[0] == field_name: + return (True, self.eeprom_data[field_start:field_end]) + field_start = field_end + + return (False, None) + + def serial_number_str(self): + """ + Returns the serial number. + """ + if not self.serial_number: + self._load_system_eeprom() + + return self.serial_number + + def part_number_str(self): + """ + Returns the part number. + """ + if not self.part_number: + self._load_system_eeprom() + + return self.part_number + + def airflow_fan_type(self): + """ + Returns the airflow fan type. + """ + if self.is_psu_eeprom: + return int(self.psu_type.encode('hex'), 16) + if self.is_fan_eeprom: + return int(self.fan_type.encode('hex'), 16) + return None + + # System EEPROM specific methods + def base_mac_addr(self): + """ + Returns the base MAC address found in the system EEPROM. + """ + if not self.base_mac: + self._load_system_eeprom() + + return self.base_mac + + def modelstr(self): + """ + Returns the Model name. + """ + if not self.model_str: + self._load_system_eeprom() + + return self.model_str + + def service_tag_str(self): + """ + Returns the servicetag number. + """ + if not self.service_tag: + self._load_system_eeprom() + + return self.service_tag + + def manuf_date_str(self): + """ + Returns the servicetag number. + """ + if not self.manuf_date: + self._load_system_eeprom() + + return self.manuf_date + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + if not self.eeprom_tlv_dict: + self._load_system_eeprom() + + return self.eeprom_tlv_dict diff --git a/ixr7220h6-128/sonic_platform/fan.py b/ixr7220h6-128/sonic_platform/fan.py new file mode 100755 index 0000000..364db68 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/fan.py @@ -0,0 +1,262 @@ +""" + Nokia IXR7220 H6-128 + + Module contains an implementation of SONiC Platform Base API and + provides the Fans' information which are available in the platform +""" + +try: + import glob + from sonic_platform_base.fan_base import FanBase + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file + from sonic_py_common import logger +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_DRAWER = 2 +MAX_FAN_F_SPEED = 20500 +MAX_FAN_R_SPEED = 21800 +FAN_TOLERANCE = 50 +WORKING_FAN_SPEED = 2000 + +HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" +I2C_DEV_LIST = ["144-0032", "145-0033"] + +FAN_INDEX_IN_DRAWER = [(1, 2), + (1, 2), + (3, 4), + (3, 4), + (5, 6), + (5, 6), + (7, 8), + (7, 8)] + +sonic_logger = logger.Logger('fan') + +class Fan(FanBase): + """Nokia platform-specific Fan class""" + + def __init__(self, fan_index, drawer_index, psu_fan=False, dependency=None): + self.is_psu_fan = psu_fan + i2c_dev = I2C_DEV_LIST[drawer_index%2] + hwmon_path = glob.glob(HWMON_DIR.format(i2c_dev)) + self.fan_led_color = ['off', 'green', 'amber', 'green_blink'] + + if not self.is_psu_fan: + # Fan is 1-based in Nokia platforms + self.index = drawer_index * FANS_PER_DRAWER + fan_index + 1 + fan_index_dir = FAN_INDEX_IN_DRAWER[drawer_index][fan_index] + self.set_fan_speed_reg = hwmon_path[0] + f"fan{fan_index_dir}_pwm" + self.get_fan_speed_reg = hwmon_path[0] + f"fan{fan_index_dir}_input" + self.get_fan_presence_reg = hwmon_path[0] + f"fan{(drawer_index//2)+1}_present" + self.fan_led_reg = hwmon_path[0] + f"fan{(drawer_index//2)+1}_led" + + if fan_index == 0: + self.max_fan_speed = MAX_FAN_F_SPEED + else: + self.max_fan_speed = MAX_FAN_R_SPEED + + else: + # this is a PSU Fan + self.index = fan_index + self.dependency = dependency + + def get_name(self): + """ + Retrieves the name of the Fan + + Returns: + string: The name of the Fan + """ + if not self.is_psu_fan: + return f"Fan{self.index}" + else: + return f"PSU{self.index}_Fan" + + def get_presence(self): + """ + Retrieves the presence of the Fan Unit + + Returns: + bool: True if Fan is present, False if not + """ + result = read_sysfs_file(self.get_fan_presence_reg) + if result == '1': # present + return True + + return False + + def get_model(self): + """ + Retrieves the model number of the Fan + + Returns: + string: Model number of Fan. Use part number for this. + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the Fan + + Returns: + string: Serial number of Fan + """ + #if self.get_presence(): + # result = read_sysfs_file(self.eeprom_dir + "serial_number") + # return result.strip() + return 'N/A' + + def get_part_number(self): + """ + Retrieves the part number of the Fan + + Returns: + string: Part number of Fan + """ + #if self.get_presence(): + # result = read_sysfs_file(self.eeprom_dir + "part_number") + # return result.strip() + return 'N/A' + + def get_service_tag(self): + """ + Retrieves the service tag of the Fan + + Returns: + string: Service Tag of Fan + """ + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the Fan + + Returns: + bool: True if Fan is operating properly, False if not + """ + status = False + + fan_speed = read_sysfs_file(self.get_fan_speed_reg) + if (fan_speed != 'ERR'): + if (int(fan_speed) > WORKING_FAN_SPEED): + status = True + + return status + + def get_direction(self): + """ + Retrieves the fan airflow direction + Possible fan directions (relative to port-side of device) + Returns: + A string, either FAN_DIRECTION_INTAKE or + FAN_DIRECTION_EXHAUST depending on fan direction + """ + return self.FAN_DIRECTION_INTAKE + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device + Returns: + integer: The 1-based relative physical position in parent device + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_speed(self): + """ + Retrieves the speed of a Front FAN in the tray in revolutions per + minute defined by 1-based index + :param index: An integer, 1-based index of the FAN to query speed + :return: integer, denoting front FAN speed + """ + speed = 0 + + fan_speed = read_sysfs_file(self.get_fan_speed_reg) + if (fan_speed != 'ERR'): + speed_in_rpm = int(fan_speed) + else: + speed_in_rpm = 0 + + speed = round(100*speed_in_rpm/self.max_fan_speed) + + return min(speed, 100) + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed + which is considered tolerable + """ + return FAN_TOLERANCE + + def set_speed(self, speed): + """ + Set fan speed to expected value + Args: + speed: An integer, the percentage of full fan speed to set + fan to, in the range 0 (off) to 100 (full speed) + Returns: + bool: True if set success, False if fail. + """ + if self.is_psu_fan: + return False + + if speed in range(0, 101): + rv = write_sysfs_file(self.set_fan_speed_reg, str(speed)) + if (rv != 'ERR'): + return True + else: + return False + else: + return False + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + return False + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + if not self.get_presence(): + return 'N/A' + + result = read_sysfs_file(self.fan_led_reg) + val = int(result) + if val < len(self.fan_led_color): + return self.fan_led_color[val] + return 'N/A' + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 + (off) to 100 (full speed) + """ + + fan_duty = read_sysfs_file(self.set_fan_speed_reg) + if fan_duty != 'ERR': + return int(fan_duty) + return 0 diff --git a/ixr7220h6-128/sonic_platform/fan_drawer.py b/ixr7220h6-128/sonic_platform/fan_drawer.py new file mode 100755 index 0000000..e508186 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/fan_drawer.py @@ -0,0 +1,208 @@ +""" + Nokia IXR7220 H6-128 + + Module contains an implementation of SONiC Platform Base API and + provides the Fan Drawer status which is available in the platform +""" + +try: + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file + from sonic_platform.eeprom import Eeprom + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_py_common import logger + import os + import glob +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +FANS_PER_DRAWER = 2 +HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" +I2C_DEV_LIST = ["144-0032", "145-0033"] +EEPROM_ADDR = ['163', '169', '164', '170', + '165', '171', '166', '172'] +sonic_logger = logger.Logger('fan_drawer') + +class NokiaFanDrawer(FanDrawerBase): + """ + Nokia platform-specific NokiaFanDrawer class + """ + def __init__(self, index): + super().__init__() + self._index = index + 1 + self.fan_led_color = ['off', 'green', 'amber', 'green_blink'] + + self.fan_direction_intake = "intake" + i2c_dev = I2C_DEV_LIST[self._index%2] + hwmon_path = glob.glob(HWMON_DIR.format(i2c_dev)) + self.get_fan_presence_reg = hwmon_path[0] + f"fan{(index//2)+1}_present" + self.fan_led_reg = hwmon_path[0] + f"fan{(index//2)+1}_led" + self.eeprom_inited = False + self.eeprom_dir = f"/sys/bus/i2c/devices/{EEPROM_ADDR[index]}-0050" + self.new_eeprom_cmd = f"echo 24c64 0x50 > /sys/bus/i2c/devices/i2c-{EEPROM_ADDR[index]}/new_device" + self.del_eeprom_cmd = f"echo 0x50 > /sys/bus/i2c/devices/i2c-{EEPROM_ADDR[index]}/delete_device" + + def get_index(self): + """ + Retrieves the index of the Fan Drawer + Returns: + int: the Fan Drawer's index + """ + return self._index + + def get_presence(self): + """ + Retrieves the presence of the Fan Drawer + Returns: + bool: return True if the Fan Drawer is present + """ + result = read_sysfs_file(self.get_fan_presence_reg) + if result == '1': # present + if not self.eeprom_inited: + if not os.path.exists(self.eeprom_dir): + os.system(self.new_eeprom_cmd) + self.eeprom = Eeprom(False, 0, True, self._index-1) + self.eeprom_inited = True + return True + + if os.path.exists(self.eeprom_dir): + os.system(self.del_eeprom_cmd) + self.eeprom_inited = False + return False + + def get_model(self): + """ + Retrieves the model number of the Fan Drawer + Returns: + string: Part number of Fan Drawer + """ + if not self.get_presence(): + return 'N/A' + return self.eeprom.modelstr() + + def get_serial(self): + """ + Retrieves the serial number of the Fan Drawer + Returns: + string: Serial number of Fan + """ + if not self.get_presence(): + return 'N/A' + return self.eeprom.serial_number_str() + + def get_part_number(self): + """ + Retrieves the part number of the Fan Drawer + + Returns: + string: Part number of Fan + """ + if not self.get_presence(): + return 'N/A' + return self.eeprom.part_number_str() + + def get_service_tag(self): + """ + Retrieves the servicetag number of the Fan Drawer + + Returns: + string: servicetag number of Fan + """ + if not self.get_presence(): + return 'N/A' + return self.eeprom.service_tag_str() + + def get_manuf_date(self): + """ + Retrieves the servicetag number of the Fan Drawer + + Returns: + string: servicetag number of Fan + """ + if not self.get_presence(): + return 'N/A' + return self.eeprom.manuf_date_str() + + def get_status(self): + """ + Retrieves the operational status of the Fan Drawer + Returns: + bool: True if Fan is operating properly, False if not + """ + good_fan = 0 + if not self.get_presence(): + return False + for fan in self._fan_list: + if fan.get_status(): + good_fan = good_fan + 1 + + if good_fan == FANS_PER_DRAWER: + return True + return False + + def get_direction(self): + """ + Retrieves the direction of the Fan Drawer + Returns: + string: direction string + """ + return self.fan_direction_intake + + def set_status_led(self, color): + """ + Sets the state of the fan drawer status LED + + Args: + color: A string representing the color with which to set the + fan drawer status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + if not self.get_presence(): + return False + return False + + def get_status_led(self): + """ + Gets the state of the fan drawer LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings + """ + if not self.get_presence(): + return 'N/A' + + result = read_sysfs_file(self.fan_led_reg) + val = int(result) + if val < len(self.fan_led_color): + return self.fan_led_color[val] + return 'N/A' + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device + Returns: + integer: The 1-based relative physical position in parent device + """ + return self._index + +class RealDrawer(NokiaFanDrawer): + """ + For Nokia platforms with fan drawer(s) + """ + def __init__(self, index): + super(RealDrawer, self).__init__(index) + self._name = f'drawer{self._index}' + + def get_name(self): + """ + return module name + """ + return self._name diff --git a/ixr7220h6-128/sonic_platform/platform.py b/ixr7220h6-128/sonic_platform/platform.py new file mode 100755 index 0000000..6af8751 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/platform.py @@ -0,0 +1,19 @@ +""" + Module contains an implementation of SONiC Platform Base API and + provides the platform information +""" + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +class Platform(PlatformBase): + """ + Nokia platform-specific class + """ + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/ixr7220h6-128/sonic_platform/psu.py b/ixr7220h6-128/sonic_platform/psu.py new file mode 100755 index 0000000..2e3f501 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/psu.py @@ -0,0 +1,305 @@ +""" + Nokia IXR7220 H6-128 + + Module contains an implementation of SONiC Platform Base API and + provides the PSUs' information which are available in the platform +""" + +try: + from sonic_platform.sysfs import read_sysfs_file + from sonic_platform_base.psu_base import PsuBase + from sonic_py_common import logger + import os +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +PSU_NUM = 4 +REG_DIR = "/sys/bus/i2c/devices/1-0060/" +MAX_VOLTAGE = 264 +MIN_VOLTAGE = 180 +I2C_BUS = [136, 137, 138, 139] +PSU_ADDR = ["58", "59", "5a", "5b"] +EEPROM_ADDR = ['50', '51', '52', '53'] + +sonic_logger = logger.Logger('psu') +sonic_logger.set_min_log_priority_info() + +class Psu(PsuBase): + """Nokia platform-specific PSU class for 7220 H6-128 """ + def __init__(self, psu_index): + PsuBase.__init__(self) + self.psu_led_color = ['off', 'green', 'green_blink', 'amber', + 'amber_blink', 'green_blink_fast'] + # PSU is 1-based in Nokia platforms + self.index = psu_index + 1 + self.psu_dir = f"/sys/bus/i2c/devices/{I2C_BUS[psu_index]}-00{PSU_ADDR[psu_index]}/" + self.eeprom_dir = f"/sys/bus/i2c/devices/{I2C_BUS[psu_index]}-00{EEPROM_ADDR[psu_index]}/" + self.new_psu_cmd = f"echo dni_psu 0x{PSU_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/new_device" + self.new_eeprom_cmd = f"echo eeprom_fru 0x{EEPROM_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/new_device" + self.del_eeprom_cmd = f"echo 0x{EEPROM_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/delete_device" + + def _get_active_psus(self): + """ + Retrieves the operational status of the PSU and + calculates number of active PSU's + + Returns: + Integer: Number of active PSU's + """ + active_psus = 0 + for i in range(PSU_NUM): + result = read_sysfs_file(REG_DIR+f"psu{i+1}_ok") + if result == '1': + active_psus = active_psus + 1 + + return active_psus + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return f"PSU{self.index}" + + def get_presence(self): + """ + Retrieves the presence of the Power Supply Unit (PSU) + + Returns: + bool: True if PSU is present, False if not + """ + result = read_sysfs_file(REG_DIR + f"psu{self.index}_pres") + if result == '0': # present + if not os.path.exists(self.psu_dir): + os.system(self.new_psu_cmd) + if not os.path.exists(self.eeprom_dir): + os.system(self.new_eeprom_cmd) + return True + # not present + if os.path.exists(self.eeprom_dir): + os.system(self.del_eeprom_cmd) + return False + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + if self.get_presence(): + return read_sysfs_file(self.eeprom_dir+"product_name") + + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + if self.get_presence(): + return read_sysfs_file(self.eeprom_dir+"serial_number") + + return 'N/A' + + def get_revision(self): + """ + Retrieves the HW revision of the PSU + + Returns: + string: HW revision of PSU + """ + if self.get_presence(): + return read_sysfs_file(self.eeprom_dir+"product_version") + return 'N/A' + + def get_part_number(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + if self.get_presence(): + return read_sysfs_file(self.eeprom_dir+"part_number") + + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the PSU + + Returns: + bool: True if PSU is operating properly, False if not + """ + return '1' == read_sysfs_file(REG_DIR+f"psu{self.index}_ok") + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + if self.get_presence(): + result = read_sysfs_file(self.psu_dir+"psu_v_in") + psu_voltage = (float(result))/1000 + else: + psu_voltage = 0.0 + + return psu_voltage + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + if self.get_presence(): + result = read_sysfs_file(self.psu_dir+"psu_i_in") + psu_current = (float(result))/1000 + else: + psu_current = 0.0 + + return psu_current + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + if self.get_presence(): + result = read_sysfs_file(self.psu_dir+"psu_p_in") + psu_power = (float(result))/1000 + else: + psu_power = 0.0 + + return psu_power + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device + Returns: + integer: The 1-based relative physical position in parent device + """ + return self.index + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + return MAX_VOLTAGE + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + return MIN_VOLTAGE + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and + passed all its internal self-tests, False if not. + """ + return '1' == read_sysfs_file(REG_DIR+f"psu{self.index}_ok") + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + if not self.get_presence(): + return 'N/A' + + result = read_sysfs_file(self.psu_dir+"psu_led") + val = int(result) + if val < len(self.psu_led_color): + return self.psu_led_color[val] + return 'N/A' + + def set_status_led(self, _color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the + PSU status LED + Returns: + bool: True if status LED state is set successfully, False if + not + """ + return False + + def get_status_master_led(self): + """ + Gets the state of the front panel PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + result = read_sysfs_file(REG_DIR+"led_psu") + if result == '1': + return 'green' + else: + return 'amber' + + def set_status_master_led(self, _color): + """ + Sets the state of the front panel PSU status LED + + Returns: + bool: True if status LED state is set successfully, False if + not + """ + return False + + def get_mfg_date(self): + """ + Retrieves the manufacturing date in the PSU EEPROM + + Returns: + string: mfg_date of PSU + """ + if self.get_presence() and os.path.exists(self.eeprom_dir+"mfg_date"): + return read_sysfs_file(self.eeprom_dir+"mfg_date") + + return 'N/A' + + def get_fw_rev(self): + """ + Retrieves the firmware revision of the PSU + + Returns: + string: firmware revision of PSU + """ + if self.get_presence(): + return read_sysfs_file(self.psu_dir+"psu_rev") + + return 'N/A' diff --git a/ixr7220h6-128/sonic_platform/sfp.py b/ixr7220h6-128/sonic_platform/sfp.py new file mode 100755 index 0000000..c734132 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/sfp.py @@ -0,0 +1,225 @@ +""" + Name: sfp.py, version: 1.0 + + Description: Module contains the definitions of SFP related APIs + for Nokia IXR 7220 H6-128 platform. + + Copyright (c) 2026, Nokia + All rights reserved. +""" +try: + import time + import sys + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from sonic_py_common import logger, device_info + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +PORT_NUM = 128 + +SYSFS_DIR = "/sys/bus/i2c/devices/{}/" +PORTPLD_ADDR = ["152-0076", "153-0076", "148-0074", "149-0075", "150-0073", "151-0073"] +ADDR_IDX = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,3] +PORT_IDX = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, + 1,2,5,6,9,10,13,14,17,18,21,22,25,26,29,30,1,2,5,6,9,10,13,14,17,18,21,22,25,26,29,30, + 3,4,7,8,11,12,15,16,19,20,23,24,27,28,31,32,3,4,7,8,11,12,15,16,19,20,23,24,27,28,31,32, + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,33,34] + +SYSLOG_IDENTIFIER = "sfp" +sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) +sonic_logger.set_min_log_priority_info() + +class Sfp(SfpOptoeBase): + """ + Nokia IXR-7220 H6-128 Platform-specific Sfp refactor class + """ + instances = [] + + port_to_i2c_mapping = 0 + + def __init__(self, index, sfp_type, eeprom_path, port_i2c_map): + SfpOptoeBase.__init__(self) + + self.index = index + self.port_num = index + self.sfp_type = sfp_type + + self.eeprom_path = eeprom_path + self.port_to_i2c_mapping = port_i2c_map + if index <= PORT_NUM: + self.name = sfp_type + '_' + str(index) + self.port_name = sfp_type + '_' + str(index-1) + else: + self.name = sfp_type + '_' + str(index-PORT_NUM) + self.port_name = sfp_type + '_' + str(index-PORT_NUM-1) + self.port_to_eeprom_mapping = {} + self.port_to_eeprom_mapping[index] = eeprom_path + + self.pld_path = SYSFS_DIR.format(PORTPLD_ADDR[ADDR_IDX[self.index-1]]) + self.pld_port_idx = PORT_IDX[self.index-1] + + self._version_info = device_info.get_sonic_version_info() + + Sfp.instances.append(self) + + def get_eeprom_path(self): + """ + Retrieves the eeprom path + Returns: + string: eeprom path + """ + return self.eeprom_path + + def get_presence(self): + """ + Retrieves the presence + Returns: + bool: True if is present, False if not + """ + sfpstatus = read_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_prs") + + if sfpstatus == '0': + return True + + return False + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self.name + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent device or + -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def _get_error_code(self): + """ + Get error code of the SFP module + + Returns: + The error code + """ + return NotImplementedError + + def get_error_description(self): + """ + Get error description + + Args: + error_code: The error code returned by _get_error_code + + Returns: + The error description + """ + if not self.get_presence(): + error_description = self.SFP_STATUS_UNPLUGGED + else: + error_description = self.SFP_STATUS_OK + + return error_description + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + if self.index <= PORT_NUM: + result = read_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_rst") + if result == '0': + return True + return False + return False + + def get_status(self): + """ + Retrieves the operational status of the device + """ + status = False + reset = self.get_reset_status() + if self.get_presence(): + if not reset: + status = True + + return status + + def reset(self): + """ + Reset SFP. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + sys.stderr.write(f"Error: Port {self.index} not inserted, could not reset it.\n\n") + return False + sonic_logger.log_info(f"Reseting port #{self.index}.") + + result1 = 'ERR' + result2 = 'ERR' + result1 = write_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_lpmod", '0') + result2 = write_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_rst", '0') + time.sleep(0.5) + result2 = write_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_rst", '1') + + if result1 != 'ERR' and result2 != 'ERR': + return True + + return False + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + result = 'ERR' + + if self.index <= PORT_NUM: + if lpmode: + result = write_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_lpmod", '0') + else: + result = write_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_lpmod", '1') + + if result != 'ERR': + return True + + return False + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + result = 'ERR' + + if self.index <= PORT_NUM: + result = read_sysfs_file(self.pld_path+f"port_{self.pld_port_idx}_lpmod") + + if result == '0': + return True + + return False diff --git a/ixr7220h6-128/sonic_platform/sfp_event.py b/ixr7220h6-128/sonic_platform/sfp_event.py new file mode 100755 index 0000000..abf3e70 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/sfp_event.py @@ -0,0 +1,146 @@ +"""" + listen for the SFP change event and return to chassis. +""" + +try: + import time + from sonic_py_common import logger + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +# system level event/error +EVENT_ON_ALL_SFP = '-1' +SYSTEM_NOT_READY = 'system_not_ready' +SYSTEM_READY = 'system_become_ready' +SYSTEM_FAIL = 'system_fail' + +# SFP PORT numbers +PORT_START = 1 +PORT_END = 130 + +SYSFS_DIR = "/sys/bus/i2c/devices/{}/" +PORTPLD_ADDR = ["152-0076", "153-0076", "148-0074", "149-0075", "150-0073", "151-0073"] + +_BOOL_LOOKUP_LSB = [tuple((i >> s) & 1 for s in range(8)) for i in range(256)] +_BOOL_TABLE_A = [((i >> 0) & 1, (i >> 1) & 1, (i >> 4) & 1, (i >> 5) & 1) + for i in range(256)] +_BOOL_TABLE_B = [((i >> 2) & 1, (i >> 3) & 1, (i >> 6) & 1, (i >> 7) & 1) + for i in range(256)] + +SYSLOG_IDENTIFIER = "sfp_event" +sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) + +class SfpEvent: + ''' Listen to plugin/plugout cable events ''' + + def __init__(self): + self.handle = None + self.modprs_list = [] + + + def initialize(self): + # Get Transceiver status + time.sleep(5) + self.modprs_list = self._get_transceiver_status() + if self.modprs_list[PORT_END-2]: + write_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[3])+"port_33_tx_en", '0') + if self.modprs_list[PORT_END-1]: + write_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[3])+"port_34_tx_en", '0') + + def deinitialize(self): + if self.handle is None: + return + + def _get_transceiver_status(self): + lookup = _BOOL_LOOKUP_LSB + port_status = [] + reg_value = [] + + for i in range(6): + m = read_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[i]) + "modprs_reg1") + n = read_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[i]) + "modprs_reg2") + reg_value.extend([m,n]) + if i == 2 or i == 3: + m = read_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[i]) + "modprs_reg3") + n = read_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[i]) + "modprs_reg4") + reg_value.extend([m,n]) + + port_status.extend([bit for h in reg_value[:4] for bit in lookup[int(h, 16)]]) + port_status.extend(self._reorder(reg_value[4:12])) + port_status.extend([bit for h in reg_value[-4:] for bit in lookup[int(h, 16)]]) + + for i in range (33, 35): + status = read_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[3])+f"port_{i}_prs") + if status == '0': + port_status.append(0) + else: + port_status.append(1) + + return port_status + + def check_sfp_status(self, port_change, timeout): + """ + check_sfp_status called from get_change_event, this will return correct + status of all SFP ports if there is a change in any of them + """ + start_time = time.time() + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + return False, {} + end_time = start_time + timeout + + if start_time > end_time: + return False, {} # Time wrap or possibly incorrect timeout + + while (timeout >= 0): + # Check for OIR events and return updated port_change + port_status = self._get_transceiver_status() + if port_status != self.modprs_list: + for i in range(PORT_END): + if port_status[i] != self.modprs_list[i]: + if port_status[i] == 0: + port_change[i+1] = '1' + else: + port_change[i+1] = '0' + + if (i == PORT_END -2) or (i == PORT_END -1): + if port_status[i] == 0: + write_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[3])+f"port_{i-95}_tx_en", '0') + else: + write_sysfs_file(SYSFS_DIR.format(PORTPLD_ADDR[3])+f"port_{i-95}_tx_en", '1') + + # Update reg value + self.modprs_list = port_status + return True, port_change + + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, {} + return False, {} + + def _reorder(self, hex_list): + t_a = _BOOL_TABLE_A + t_b = _BOOL_TABLE_B + res = [] + ext = res.extend + data = [int(h, 16) for h in hex_list] + for i in range(0, len(data), 8): + chunk = data[i:i+8] + for byte in chunk: + ext(t_a[byte]) + for byte in chunk: + ext(t_b[byte]) + return res diff --git a/ixr7220h6-128/sonic_platform/sysfs.py b/ixr7220h6-128/sonic_platform/sysfs.py new file mode 100755 index 0000000..b8338be --- /dev/null +++ b/ixr7220h6-128/sonic_platform/sysfs.py @@ -0,0 +1,48 @@ +""" + Nokia IXR7220 sysfs functions + + Module contains an implementation of SONiC Platform Base API and + provides the PSUs' information which are available in the platform +""" + +def read_sysfs_file(sysfs_file): + """ + On successful read, returns the value read from given + reg_name and on failure returns ERR + """ + rv = 'ERR' + + try: + with open(sysfs_file, 'r', encoding='utf-8') as fd: + rv = fd.read() + fd.close() + except FileNotFoundError: + print(f"Error: {sysfs_file} doesn't exist.") + except PermissionError: + print(f"Error: Permission denied when reading file {sysfs_file}.") + except IOError: + print(f"IOError: An error occurred while reading file {sysfs_file}.") + if rv != 'ERR': + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + +def write_sysfs_file(sysfs_file, value): + """ + On successful write, the value read will be written on + reg_name and on failure returns ERR + """ + rv = 'ERR' + + try: + with open(sysfs_file, 'w', encoding='utf-8') as fd: + rv = fd.write(value) + fd.close() + except FileNotFoundError: + print(f"Error: {sysfs_file} doesn't exist.") + except PermissionError: + print(f"Error: Permission denied when writing file {sysfs_file}.") + except IOError: + print(f"IOError: An error occurred while writing file {sysfs_file}.") + + return rv diff --git a/ixr7220h6-128/sonic_platform/test/README b/ixr7220h6-128/sonic_platform/test/README new file mode 100755 index 0000000..3efc8fa --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/README @@ -0,0 +1 @@ +This directory contains unit tests of the Platform API 2.0 diff --git a/ixr7220h6-128/sonic_platform/test/test-chassis.py b/ixr7220h6-128/sonic_platform/test/test-chassis.py new file mode 100755 index 0000000..7d065dd --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-chassis.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +try: + import sonic_platform.platform + import sonic_platform.chassis + import unittest +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + + +class Test1(unittest.TestCase): + def test_1(self): + print("-----------------") + print("Chassis Unit Test") + print("-----------------") + + chassis = sonic_platform.platform.Platform().get_chassis() + print(" Chassis name: {}".format(chassis.get_name())) + + print(" Chassis presence: {}".format(chassis.get_presence())) + + print(" Chassis serial: {}".format(chassis.get_serial())) + + print(" Chassis revision: {}".format(chassis.get_revision())) + + print(" Chassis status: {}".format(chassis.get_status())) + + print(" Chassis base_mac: {}".format(chassis.get_base_mac())) + + print(" Chassis reboot cause: {}\n".format(chassis.get_reboot_cause())) + + print(" Chassis watchdog: {}".format(chassis.get_watchdog())) + + print(" Chassis num_components: {}".format(chassis.get_num_components())) + + print(" Chassis all_components: {}\n".format(chassis.get_all_components())) + + print(" Chassis num_modules: {}".format(chassis.get_num_modules())) + + print(" Chassis all_modules: {}\n".format(chassis.get_all_modules())) + + print(" Chassis num_fans: {}".format(chassis.get_num_fans())) + + print(" Chassis all_fans: {}\n".format(chassis.get_all_fans())) + + print(" Chassis num_psus: {}".format(chassis.get_num_psus())) + + print(" Chassis all_psus: {}\n".format(chassis.get_all_psus())) + + print(" Chassis num_thermals: {}".format(chassis.get_num_thermals())) + + print(" Chassis all_thermals: {}\n".format(chassis.get_all_thermals())) + + print(" Chassis num_sfps: {}".format(chassis.get_num_sfps())) + + print(" Chassis all_sfps: {}\n".format(chassis.get_all_sfps())) + + print(" Chassis eeprom: {}".format(chassis.get_eeprom())) + + +if __name__ == '__main__': + unittest.main() diff --git a/ixr7220h6-128/sonic_platform/test/test-component.py b/ixr7220h6-128/sonic_platform/test/test-component.py new file mode 100755 index 0000000..ee29512 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-component.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis + + +def main(): + print("---------------------------") + print("Chassis Component Unit Test") + print("---------------------------") + + chassis = Chassis() + + for component in chassis.get_all_components(): + print(" Name: {}".format(component.get_name())) + print(" Description: {}".format(component.get_description())) + print(" FW version: {}\n".format(component.get_firmware_version())) + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/test/test-eeprom.py b/ixr7220h6-128/sonic_platform/test/test-eeprom.py new file mode 100755 index 0000000..d6f214c --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-eeprom.py @@ -0,0 +1,24 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis + + +def main(): + print("------------------------") + print("Chassis eeprom Unit Test") + print("------------------------") + + chassis = Chassis() + + eeprom = chassis.get_eeprom() + + print(" Model: {}, Service Tag: {}".format(eeprom.modelstr(), + eeprom.service_tag_str())) + print(" Part#: {}, Serial#: {}".format(eeprom.part_number_str(), + eeprom.serial_number_str())) + print(" Base MAC: {}".format(eeprom.base_mac_addr())) + + + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/test/test-fan-drawer.py b/ixr7220h6-128/sonic_platform/test/test-fan-drawer.py new file mode 100755 index 0000000..20860e4 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-fan-drawer.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +import unittest +from sonic_platform.chassis import Chassis + +class Test1(unittest.TestCase): + def test_1(self): + print("---------------------------") + print("Chassis Fan Drawer Unit Test") + print("---------------------------") + + chassis = Chassis() + + for fan_drawer in chassis.get_all_fan_drawers(): + if not fan_drawer.get_presence(): + print(" Name: {} not present".format(fan_drawer.get_name())) + else: + print(" Name:", fan_drawer.get_name()) + print(" Presence: {}, Status: {}, LED: {}".format(fan_drawer.get_presence(), + fan_drawer.get_status(), + fan_drawer.get_status_led())) + print(" Serial#: {}".format(fan_drawer.get_serial())) + print(" Part#: {}".format(fan_drawer.get_part_number())) + print(" Direction: {}\n".format(fan_drawer.get_direction())) + print(" Replaceable: {}, Index: {}\n".format(fan_drawer.is_replaceable(), fan_drawer.get_position_in_parent())) + + + +if __name__ == '__main__': + unittest.main() diff --git a/ixr7220h6-128/sonic_platform/test/test-fan.py b/ixr7220h6-128/sonic_platform/test/test-fan.py new file mode 100755 index 0000000..ae647aa --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-fan.py @@ -0,0 +1,34 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis + +def main(): + print("---------------------") + print("Chassis Fan Unit Test") + print("---------------------") + + chassis = Chassis() + + for fandraw in chassis.get_all_fan_drawers(): + if not fandraw.get_presence(): + print("\n Name: {} not present".format(fandraw.get_name())) + else: + print(" Name:", fandraw.get_name()) + print(" Presence: {}, Status: {}, Direction: {}, LED: {}".format(fandraw.get_presence(), + fandraw.get_status(), + fandraw.fan_direction_intake, + fandraw.get_status_led())) + print(" Part_number: {}, Serial: {}".format(fandraw.get_part_number(), + fandraw.get_serial())) + print(" Service Tag: {}, mfg_date: {}, ".format(fandraw.get_service_tag(), + fandraw.get_manuf_date())) + for fan in fandraw.get_all_fans(): + fan_status = fan.get_status() + print(" {} Status: {}, Target Speed: {}%, Speed: {}%".format(fan.get_name(), + fan_status, + str(fan.get_target_speed()), + str(fan.get_speed()))) + return + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/test/test-psu.py b/ixr7220h6-128/sonic_platform/test/test-psu.py new file mode 100755 index 0000000..2db5878 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-psu.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis + + +def main(): + print("---------------------") + print("Chassis PSU Unit Test") + print("---------------------") + + chassis = Chassis() + + for psu in chassis.get_all_psus(): + if psu.index == 1: + print(" Active num:", psu._get_active_psus()) + print(" Master LED: {}\n".format(psu.get_status_master_led())) + + if not psu.get_presence(): + print(" Name: {} not present\n".format(psu.get_name())) + else: + print(" Name:", psu.get_name()) + print(" Presence: {}, Status: {}, LED: {}".format(psu.get_presence(), + psu.get_status(), + psu.get_status_led())) + print(" Model: {}, Serial#: {}, Part#: {}".format(psu.get_model(), + psu.get_serial(), + psu.get_part_number())) + print(" Mfg_date: {}, FW_Rev: {}".format(psu.get_mfg_date(), + psu.get_fw_rev())) + try: + current = psu.get_current() + except NotImplementedError: + current = "NA" + try: + power = psu.get_power() + except NotImplementedError: + power = "NA" + + print(" Voltage: {}, Current: {}, Power: {}\n".format(psu.get_voltage(), + current, + power)) + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/test/test-sfp.py b/ixr7220h6-128/sonic_platform/test/test-sfp.py new file mode 100755 index 0000000..f76c2e7 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-sfp.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +try: + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +def main(): + print("---------------------") + print("Chassis SFP Unit Test") + print("---------------------") + + chassis = Chassis() + + PORT_START = 1 + PORT_END = 66 + + for physical_port in range(PORT_START, PORT_START + PORT_END): + + print(" ") + print(" SFP transceiver tests PORT = ", physical_port) + name = chassis.get_sfp(physical_port).get_name() + print(" SFP transceiver tests NAME = ", name) + + presence = chassis.get_sfp(physical_port).get_presence() + print("TEST 1 - sfp presence [ True ] ", physical_port, presence) + + status = chassis.get_sfp(physical_port).get_reset_status() + print("TEST 2 - sfp reset status [ False ] ", physical_port, status) + + txdisable = chassis.get_sfp(physical_port).get_tx_disable() + print("TEST 3 - sfp tx_disable [ False ] ", physical_port, txdisable) + + rxlos = chassis.get_sfp(physical_port).get_rx_los() + print("TEST 4 - sfp status rxlos [ False ] ", physical_port, rxlos) + + txfault = chassis.get_sfp(physical_port).get_tx_fault() + print("TEST 5 - sfp status txfault [ False ] ", physical_port, txfault) + + lpmode = chassis.get_sfp(physical_port).get_lpmode() + print("TEST 6 - sfp enable lpmode [ False ] ", physical_port, lpmode) + + trans_info = chassis.get_sfp(physical_port).get_transceiver_info() + print("TEST 7 - sfp transceiver info for port:", physical_port, trans_info) + + dom_real_value = chassis.get_sfp(physical_port).get_transceiver_dom_real_value() + print("TEST 8 - sfp transceiver dom real value for port:", physical_port, dom_real_value) + + threshold = chassis.get_sfp(physical_port).get_transceiver_threshold_info() + print("TEST 9 - transceiver sfp threshold info for port:", physical_port, threshold) + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/test/test-thermal.py b/ixr7220h6-128/sonic_platform/test/test-thermal.py new file mode 100755 index 0000000..ce008de --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-thermal.py @@ -0,0 +1,49 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis + +def main(): + print("-------------------------") + print("Chassis Thermal Unit Test") + print("-------------------------") + + chassis = Chassis() + + for thermal in chassis.get_all_thermals(): + if not thermal.get_presence(): + print(" Name: {} not present".format(thermal.get_name())) + else: + print(" Name:", thermal.get_name()) + print(" Presence: {}, Status: {}".format(thermal.get_presence(), + thermal.get_status())) + print(" Model: {}, Serial#: {}".format(thermal.get_model(), + thermal.get_serial())) + print(" Temperature(C): {}".format(thermal.get_temperature())) + + try: + low_thresh = thermal.get_low_threshold() + except NotImplementedError: + low_thresh = "NA" + try: + high_thresh = thermal.get_high_threshold() + except NotImplementedError: + high_thresh = "NA" + + print(" Low Threshold(C): {}, High Threshold(C): {}".format(low_thresh, + high_thresh)) + + try: + crit_low_thresh = thermal.get_low_critical_threshold() + except NotImplementedError: + crit_low_thresh = "NA" + try: + crit_high_thresh = thermal.get_high_critical_threshold() + except NotImplementedError: + crit_high_thresh = "NA" + + print(" Crit Low Threshold(C): {}, Crit High Threshold(C): {}\n".format(crit_low_thresh, + crit_high_thresh)) + + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/test/test-watchdog.py b/ixr7220h6-128/sonic_platform/test/test-watchdog.py new file mode 100755 index 0000000..135c26f --- /dev/null +++ b/ixr7220h6-128/sonic_platform/test/test-watchdog.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis + + +def main(): + print("---------------------") + print("Chassis Watchdog Test") + print("---------------------") + + chassis = Chassis() + + watchdog = chassis.get_watchdog() + + print(" Armed: {}".format(watchdog.is_armed())) + print(" Time Left: {}".format(watchdog.get_remaining_time())) + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/sonic_platform/thermal.py b/ixr7220h6-128/sonic_platform/thermal.py new file mode 100755 index 0000000..e476e92 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/thermal.py @@ -0,0 +1,264 @@ +""" + Nokia IXR7220-H6-128 + Module contains an implementation of SONiC Platform Base API and + provides the Thermals' information which are available in the platform +""" + +try: + import glob + from sonic_platform_base.thermal_base import ThermalBase + from sonic_py_common import logger + from swsscommon.swsscommon import SonicV2Connector + from sonic_platform.sysfs import read_sysfs_file +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +sonic_logger = logger.Logger('thermal') + +THERMAL_NUM = 21 + +class Thermal(ThermalBase): + """Nokia platform-specific Thermal class""" + + HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" + I2C_DEV_LIST = ["0-0018", "143-0048", "154-004b", "154-004c", "154-004d", + "154-0049", "154-0048", "154-004a", "174-0048", "177-0048", + "180-0048", "183-0048", "167-004d","168-004e", "161-004d", + "162-004e", "0-0021", "0-0021"] + THERMAL_NAME = ["CPU Board", "Carrier Board", "MB Top U34", "MB Top U178", "MB Bottom U196", + "MB Bottom U183", "MB Top U3", "MB Top U15", "LDB Left", "LDB Right", + "UDB Left", "UDB Right", "Top FCM 1", "Top FCM 2", "Bottom FCM 1", + "Bottom FCM 2", "CPU", "DDR", "Max Port Temp.", "SSD", + "ASIC TH6"] + + THRESHHOLD = [65.0, 66.0, 68.0, 62.0, 75.0, + 105.0, 105.0, 105.0, 78.0, 65.0, + 66.0, 66.0, 95.0, 70.0, 85.0, + 85.0, 95.0, 70.0, 85.0,70.0, + 95.0] + CRITICAL_THRESHHOLD = [70.0, 70.0, 72.0, 67.0, 80.0, + 115.0, 115.0, 115.0, 80.0, 70.0, + 69.0, 69.0, 99.0, 80.0, 90.0, + 90.0, 99.0, 80.0, 90.0,80.0, + 100.0] + + def __init__(self, thermal_index, sfps): + ThermalBase.__init__(self) + self.index = thermal_index + 1 + self.is_fan_thermal = False + self.dependency = None + self._minimum = None + self._maximum = None + self.thermal_high_threshold_file = None + + self.thermal_high_crit_threshold_file = None + self.thermal_temperature_file = None + + if self.index == THERMAL_NUM - 1: #SSD + self.thermal_temperature_file = "/sys/class/hwmon/hwmon1/temp1_input" + elif self.index == THERMAL_NUM - 2: + self.sfps = sfps + elif self.index == THERMAL_NUM - 3: + self.thermal_temperature_file = "/sys/bus/i2c/devices/" + self.I2C_DEV_LIST[self.index - 1] + "/mem1_temperature" + elif self.index == THERMAL_NUM - 4: + self.thermal_temperature_file = "/sys/bus/i2c/devices/" + self.I2C_DEV_LIST[self.index - 1] + "/cpu_temperature" + elif self.index < THERMAL_NUM - 4: + self.device_path = glob.glob(self.HWMON_DIR.format(self.I2C_DEV_LIST[self.index - 1])) + if len(self.device_path) > 0: + self.thermal_temperature_file = self.device_path[0] + "temp1_input" + + def get_name(self): + """ + Retrieves the name of the thermal + + Returns: + string: The name of the thermal + """ + return self.THERMAL_NAME[self.index - 1] + + def get_presence(self): + """ + Retrieves the presence of the thermal + + Returns: + bool: True if thermal is present, False if not + """ + if self.dependency: + return self.dependency.get_presence() + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the Thermal + + Returns: + string: Model/part number of Thermal + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the Thermal + + Returns: + string: Serial number of Thermal + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the thermal + + Returns: + A boolean value, True if thermal is operating properly, + False if not + """ + if self.dependency: + return self.dependency.get_status() + return True + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + + Returns: + A float number of current temperature in Celsius up to + nearest thousandth of one degree Celsius, e.g. 30.125 + """ + thermal_temperature = 0.0 + if self.index == THERMAL_NUM: + db = SonicV2Connector() + db.connect(db.STATE_DB) + data_dict = db.get_all(db.STATE_DB, 'ASIC_TEMPERATURE_INFO') + if data_dict: + thermal_temperature = float(data_dict['maximum_temperature']) + elif self.index == THERMAL_NUM - 1: # SSD + temp = read_sysfs_file(self.thermal_temperature_file) + if temp != 'ERR': + thermal_temperature = float(temp) / 1000 + elif self.index == THERMAL_NUM - 2: + for sfp in self.sfps: + try: + if sfp.get_presence(): + temp = sfp.get_temperature() + else: + temp = None + except: + temp = None + if (temp is not None) and (temp > thermal_temperature): + thermal_temperature = temp + elif self.thermal_temperature_file is not None: + temp = read_sysfs_file(self.thermal_temperature_file) + if temp != 'ERR': + thermal_temperature = float(temp) / 1000 + + if self._minimum is None or self._minimum > thermal_temperature: + self._minimum = thermal_temperature + if self._maximum is None or self._maximum < thermal_temperature: + self._maximum = thermal_temperature + + return float(f"{thermal_temperature:.3f}") + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + + Returns: + A float number, the high threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + return self.THRESHHOLD[self.index-1] + + def set_high_threshold(self, _temperature): + """ + Sets the high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + # Thermal threshold values are pre-defined based on HW. + return False + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.index == THERMAL_NUM: + return 103.0 + return 80.0 + + def set_high_critical_threshold(self): + """ + Sets the high_critical threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + # Thermal threshold values are pre-defined based on HW. + return False + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + Returns: + A float number, the low threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return 0.0 + + def set_low_threshold(self, _temperature): + """ + Sets the low threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one + degree Celsius, e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if + not + """ + # Thermal threshold values are pre-defined based on HW. + return False + + def get_minimum_recorded(self): + """ + Retrieves minimum recorded temperature + """ + self.get_temperature() + return self._minimum + + def get_maximum_recorded(self): + """ + Retrieves maxmum recorded temperature + """ + self.get_temperature() + return self._maximum + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device + Returns: + integer: The 1-based relative physical position in parent device + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/ixr7220h6-128/sonic_platform/thermal_actions.py b/ixr7220h6-128/sonic_platform/thermal_actions.py new file mode 100755 index 0000000..e71359e --- /dev/null +++ b/ixr7220h6-128/sonic_platform/thermal_actions.py @@ -0,0 +1,199 @@ +try: + from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase + from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object + from sonic_py_common import logger +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +sonic_logger = logger.Logger('thermal_actions') + +class SetFanSpeedAction(ThermalPolicyActionBase): + """ + Base thermal action class to set speed for fans + """ + # JSON field definition + JSON_FIELD_SPEED = 'speed' + JSON_FIELD_DEFAULT_SPEED = 'default_speed' + JSON_FIELD_THRESHOLD1_SPEED = 'threshold1_speed' + JSON_FIELD_HIGHTEMP_SPEED = 'hightemp_speed' + + def __init__(self): + """ + Constructor of SetFanSpeedAction + """ + self.default_speed = 46 + self.threshold1_speed=73 + self.hightemp_speed = 100 + self.speed = self.default_speed + + def load_from_json(self, json_obj): + """ + Construct SetFanSpeedAction via JSON. JSON example: + { + "type": "fan.all.set_speed" + "speed": "100" + } + :param json_obj: A JSON object representing a SetFanSpeedAction action. + :return: + """ + if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj: + speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) + if speed < 0 or speed > 100: + raise ValueError('SetFanSpeedAction invalid speed value {} in JSON policy file, valid value should be [0, 100]'. + format(speed)) + self.speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) + else: + raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. + format(SetFanSpeedAction.JSON_FIELD_SPEED)) + + @classmethod + def set_all_fan_speed(cls, thermal_info_dict, speed): + from .thermal_infos import FanInfo + if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): + fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME] + for fan in fan_info_obj.get_presence_fans(): + fan.set_speed(int(speed)) + +@thermal_json_object('fan.all.set_speed') +class SetAllFanSpeedAction(SetFanSpeedAction): + """ + Action to set speed for all fans + """ + def execute(self, thermal_info_dict): + """ + Set speed for all fans + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + SetAllFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.speed) + +@thermal_json_object('thermal.temp_check_and_set_all_fan_speed') +class ThermalRecoverAction(SetFanSpeedAction): + """ + Action to check thermal sensor temperature change status and set speed for all fans + """ + def load_from_json(self, json_obj): + """ + Construct ThermalRecoverAction via JSON. JSON example: + { + "type": "thermal.temp_check_and_set_all_fan_speed" + "default_speed": "46", + "threshold1_speed": "73", + "hightemp_speed": "100" + } + :param json_obj: A JSON object representing a ThermalRecoverAction action. + :return: + """ + if SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED in json_obj: + default_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED]) + if default_speed < 0 or default_speed > 100: + raise ValueError('SetFanSpeedAction invalid default speed value {} in JSON policy file, valid value should be [0, 100]'. + format(default_speed)) + self.default_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED]) + else: + raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. + format(SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED)) + + if SetFanSpeedAction.JSON_FIELD_THRESHOLD1_SPEED in json_obj: + threshold1_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_THRESHOLD1_SPEED]) + if threshold1_speed < 0 or threshold1_speed > 100: + raise ValueError('SetFanSpeedAction invalid default speed value {} in JSON policy file, valid value should be [0, 100]'. + format(threshold1_speed)) + self.threshold1_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_THRESHOLD1_SPEED]) + else: + raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. + format(SetFanSpeedAction.JSON_FIELD_THRESHOLD1_SPEED)) + + if SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED in json_obj: + hightemp_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED]) + if hightemp_speed < 0 or hightemp_speed > 100: + raise ValueError('SetFanSpeedAction invalid hightemp speed value {} in JSON policy file, valid value should be [0, 100]'. + format(hightemp_speed)) + self.hightemp_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED]) + else: + raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. + format(SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED)) + + sonic_logger.log_warning("ThermalRecoverAction: default: {}, threshold1: {}, hightemp: {}".format(self.default_speed, self.threshold1_speed, self.hightemp_speed)) + + def execute(self, thermal_info_dict): + """ + Check check thermal sensor temperature change status and set speed for all fans + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + from .thermal_infos import ThermalInfo + if ThermalInfo.INFO_NAME in thermal_info_dict and \ + isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): + + thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] + if thermal_info_obj.is_set_fan_high_temp_speed(): + ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.hightemp_speed) + elif thermal_info_obj.is_set_fan_threshold_one_speed(): + ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.threshold1_speed) + elif thermal_info_obj.is_set_fan_default_speed(): + ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.default_speed) + +@thermal_json_object('switch.shutdown') +class SwitchPolicyAction(ThermalPolicyActionBase): + """ + Base class for thermal action. Once all thermal conditions in a thermal policy are matched, + all predefined thermal action will be executed. + """ + def execute(self, thermal_info_dict): + """ + Take action when thermal condition matches. For example, adjust speed of fan or shut + down the switch. + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + sonic_logger.log_warning("Alarm for temperature critical is detected, reboot Device") + +@thermal_json_object('thermal_control.control') +class ControlThermalAlgoAction(ThermalPolicyActionBase): + """ + Action to control the thermal control algorithm + """ + # JSON field definition + JSON_FIELD_STATUS = 'status' + + def __init__(self): + self.status = True + + def load_from_json(self, json_obj): + """ + Construct ControlThermalAlgoAction via JSON. JSON example: + { + "type": "thermal_control.control" + "status": "true" + } + :param json_obj: A JSON object representing a ControlThermalAlgoAction action. + :return: + """ + if ControlThermalAlgoAction.JSON_FIELD_STATUS in json_obj: + status_str = json_obj[ControlThermalAlgoAction.JSON_FIELD_STATUS].lower() + if status_str == 'true': + self.status = True + elif status_str == 'false': + self.status = False + else: + raise ValueError(f'Invalid {ControlThermalAlgoAction.JSON_FIELD_STATUS} field value, please specify true of false') + else: + raise ValueError('ControlThermalAlgoAction ' + f'missing mandatory field {ControlThermalAlgoAction.JSON_FIELD_STATUS} in JSON policy file') + + def execute(self, thermal_info_dict): + """ + Disable thermal control algorithm + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + from .thermal_infos import ChassisInfo + if ChassisInfo.INFO_NAME in thermal_info_dict: + chassis_info_obj = thermal_info_dict[ChassisInfo.INFO_NAME] + chassis = chassis_info_obj.get_chassis() + thermal_manager = chassis.get_thermal_manager() + if self.status: + thermal_manager.start_thermal_control_algorithm() + else: + thermal_manager.stop_thermal_control_algorithm() diff --git a/ixr7220h6-128/sonic_platform/thermal_conditions.py b/ixr7220h6-128/sonic_platform/thermal_conditions.py new file mode 100755 index 0000000..d19fd4f --- /dev/null +++ b/ixr7220h6-128/sonic_platform/thermal_conditions.py @@ -0,0 +1,70 @@ +try: + from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase + from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +class FanCondition(ThermalPolicyConditionBase): + def get_fan_info(self, thermal_info_dict): + from .thermal_infos import FanInfo + if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): + return thermal_info_dict[FanInfo.INFO_NAME] + return None + +@thermal_json_object('fan.any.absence') +class AnyFanAbsenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False + +@thermal_json_object('fan.all.absence') +class AllFanAbsenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False + +@thermal_json_object('fan.all.presence') +class AllFanPresenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False + +class ThermalCondition(ThermalPolicyConditionBase): + def get_thermal_info(self, thermal_info_dict): + from .thermal_infos import ThermalInfo + if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): + return thermal_info_dict[ThermalInfo.INFO_NAME] + return None + +@thermal_json_object('thermal.over.high_critical_threshold') +class ThermalOverHighCriticalCondition(ThermalCondition): + def is_match(self, thermal_info_dict): + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + return thermal_info_obj.is_over_high_critical_threshold() + return False + +class PsuCondition(ThermalPolicyConditionBase): + def get_psu_info(self, thermal_info_dict): + from .thermal_infos import PsuInfo + if PsuInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[PsuInfo.INFO_NAME], PsuInfo): + return thermal_info_dict[PsuInfo.INFO_NAME] + return None + +@thermal_json_object('psu.any.absence') +class AnyPsuAbsenceCondition(PsuCondition): + def is_match(self, thermal_info_dict): + psu_info_obj = self.get_psu_info(thermal_info_dict) + return len(psu_info_obj.get_absence_psus()) > 0 if psu_info_obj else False + +@thermal_json_object('psu.all.absence') +class AllPsuAbsenceCondition(PsuCondition): + def is_match(self, thermal_info_dict): + psu_info_obj = self.get_psu_info(thermal_info_dict) + return len(psu_info_obj.get_presence_psus()) == 0 if psu_info_obj else False + +@thermal_json_object('psu.all.presence') +class AllPsuPresenceCondition(PsuCondition): + def is_match(self, thermal_info_dict): + psu_info_obj = self.get_psu_info(thermal_info_dict) + return len(psu_info_obj.get_absence_psus()) == 0 if psu_info_obj else False diff --git a/ixr7220h6-128/sonic_platform/thermal_infos.py b/ixr7220h6-128/sonic_platform/thermal_infos.py new file mode 100755 index 0000000..5b60d3b --- /dev/null +++ b/ixr7220h6-128/sonic_platform/thermal_infos.py @@ -0,0 +1,236 @@ +try: + from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase + from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +logger = Logger() + +@thermal_json_object('fan_info') +class FanInfo(ThermalPolicyInfoBase): + """ + Fan information needed by thermal policy + """ + # Fan information name + INFO_NAME = 'fan_info' + + def __init__(self): + self._absence_fans = set() + self._presence_fans = set() + self._status_changed = False + + def collect(self, chassis): + """ + Collect absence and presence fans. + :param chassis: The chassis object + :return: + """ + self._status_changed = False + for fan in chassis.get_all_fans(): + if fan.get_presence() and fan not in self._presence_fans: + self._presence_fans.add(fan) + self._status_changed = True + if fan in self._absence_fans: + self._absence_fans.remove(fan) + elif not fan.get_presence() and fan not in self._absence_fans: + self._absence_fans.add(fan) + self._status_changed = True + if fan in self._presence_fans: + self._presence_fans.remove(fan) + + def get_absence_fans(self): + """ + Retrieves absence fans + :return: A set of absence fans + """ + return self._absence_fans + + def get_presence_fans(self): + """ + Retrieves presence fans + :return: A set of presence fans + """ + return self._presence_fans + + def is_status_changed(self): + """ + Retrieves if the status of fan information changed + :return: True if status changed else False + """ + return self._status_changed + +@thermal_json_object('thermal_info') +class ThermalInfo(ThermalPolicyInfoBase): + """ + Thermal information needed by thermal policy + """ + # Fan information name + INFO_NAME = 'thermal_info' + + def __init__(self): + self._old_threshold_level = -1 + self._current_threshold_level = 0 + self._num_fan_levels = 1 + self._level_up_threshold = [[55, 60, 65, 55, 65, 100, 100, 100, 75, 60, 55, 55, 85, 65, 65, 60, 80]] + + self._level_down_threshold = [[45, 36, 45, 45, 50, 68, 68, 68, 60, 36, 45, 45, 68, 40, 45, 35, 55]] + + def collect(self, chassis): + """ + Collect thermal sensor temperature change status + :param chassis: The chassis object + :return: + """ + self._temps = [] + self._over_high_critical_threshold = False + self._set_fan_default_speed = False + self._set_fan_threshold_one_speed = False + self._set_fan_high_temp_speed = False + + # Calculate average temp within the device + num_of_thermals = chassis.get_num_thermals() + for index in range(num_of_thermals): + self._temps.insert(index, chassis.get_thermal(index).get_temperature()) + + # Find current required threshold level + max_level =0 + min_level = [self._num_fan_levels for i in range(num_of_thermals)] + for index in range(num_of_thermals): + for level in range(self._num_fan_levels): + + if self._temps[index]>self._level_up_threshold[level][index]: + if max_levellevel: + min_level[index]=level + + max_of_min_level=max(min_level) + + #compare with running threshold level + if max_of_min_level > self._old_threshold_level: + max_of_min_level=self._old_threshold_level + + self._current_threshold_level = max(max_of_min_level,max_level) + + #set fan to max speed if one fan is down + for fan in chassis.get_all_fans(): + if not fan.get_status() : + self._current_threshold_level = 2 + + # Decide fan speed based on threshold level + if self._current_threshold_level != self._old_threshold_level: + if self._current_threshold_level == 0: + self._set_fan_default_speed = True + elif self._current_threshold_level == 1: + self._set_fan_threshold_one_speed = True + elif self._current_threshold_level == 2: + self._set_fan_high_temp_speed = True + + self._old_threshold_level=self._current_threshold_level + + def is_set_fan_default_speed(self): + """ + Retrieves if the temperature is warm up and over high threshold + :return: True if the temperature is warm up and over high threshold else False + """ + return self._set_fan_default_speed + + def is_set_fan_threshold_one_speed(self): + """ + Retrieves if the temperature is warm up and over high threshold + :return: True if the temperature is warm up and over high threshold else False + """ + return self._set_fan_threshold_one_speed + + def is_set_fan_high_temp_speed(self): + """ + Retrieves if the temperature is warm up and over high threshold + :return: True if the temperature is warm up and over high threshold else False + """ + return self._set_fan_high_temp_speed + + def is_over_high_critical_threshold(self): + """ + Retrieves if the temperature is over high critical threshold + :return: True if the temperature is over high critical threshold else False + """ + return self._over_high_critical_threshold + +@thermal_json_object('psu_info') +class PsuInfo(ThermalPolicyInfoBase): + """ + PSU information needed by thermal policy + """ + INFO_NAME = 'psu_info' + + def __init__(self): + self._absence_psus = set() + self._presence_psus = set() + self._status_changed = False + + def collect(self, chassis): + """ + Collect absence and presence PSUs. + :param chassis: The chassis object + :return: + """ + self._status_changed = False + for psu in chassis.get_all_psus(): + if psu.get_presence() and psu.get_powergood_status() and psu not in self._presence_psus: + self._presence_psus.add(psu) + self._status_changed = True + if psu in self._absence_psus: + self._absence_psus.remove(psu) + elif (not psu.get_presence() or not psu.get_powergood_status()) and psu not in self._absence_psus: + self._absence_psus.add(psu) + self._status_changed = True + if psu in self._presence_psus: + self._presence_psus.remove(psu) + + def get_absence_psus(self): + """ + Retrieves presence PSUs + :return: A set of absence PSUs + """ + return self._absence_psus + + def get_presence_psus(self): + """ + Retrieves presence PSUs + :return: A set of presence fans + """ + return self._presence_psus + + def is_status_changed(self): + """ + Retrieves if the status of PSU information changed + :return: True if status changed else False + """ + return self._status_changed + +@thermal_json_object('chassis_info') +class ChassisInfo(ThermalPolicyInfoBase): + """ + Chassis information needed by thermal policy + """ + INFO_NAME = 'chassis_info' + + def __init__(self): + self._chassis = None + + def collect(self, chassis): + """ + Collect platform chassis. + :param chassis: The chassis object + :return: + """ + self._chassis = chassis + + def get_chassis(self): + """ + Retrieves platform chassis object + :return: A platform chassis object. + """ + return self._chassis diff --git a/ixr7220h6-128/sonic_platform/thermal_manager.py b/ixr7220h6-128/sonic_platform/thermal_manager.py new file mode 100755 index 0000000..7d84fa9 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/thermal_manager.py @@ -0,0 +1,58 @@ +try: + from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase + from .thermal_actions import * + from .thermal_conditions import * + from .thermal_infos import * +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +THERMALD_INTERVAL = 10 + +class ThermalManager(ThermalManagerBase): + """Nokia platform-specific Thermal Manager class""" + THERMAL_ALGORITHM_CONTROL_PATH = '/var/run/hw-management/config/suspend' + + @classmethod + def get_interval(cls): + return THERMALD_INTERVAL + + @classmethod + def start_thermal_control_algorithm(cls): + """ + Start thermal control algorithm + + Returns: + bool: True if set success, False if fail. + """ + cls._control_thermal_control_algorithm(False) + + @classmethod + def stop_thermal_control_algorithm(cls): + """ + Stop thermal control algorithm + + Returns: + bool: True if set success, False if fail. + """ + cls._control_thermal_control_algorithm(True) + + @classmethod + def _control_thermal_control_algorithm(cls, suspend): + """ + Control thermal control algorithm + + Args: + suspend: Bool, indicate suspend the algorithm or not + + Returns: + bool: True if set success, False if fail. + """ + status = True + write_value = 1 if suspend else 0 + try: + with open(cls.THERMAL_ALGORITHM_CONTROL_PATH, 'w') as control_file: + control_file.write(str(write_value)) + except (ValueError, IOError): + status = False + + return status diff --git a/ixr7220h6-128/sonic_platform/watchdog.py b/ixr7220h6-128/sonic_platform/watchdog.py new file mode 100755 index 0000000..5bb2e00 --- /dev/null +++ b/ixr7220h6-128/sonic_platform/watchdog.py @@ -0,0 +1,175 @@ +""" + Module contains an implementation of SONiC Platform Base API and + provides access to hardware watchdog +""" +try: + import os + import fcntl + import array + from sonic_platform_base.watchdog_base import WatchdogBase + from sonic_platform.sysfs import read_sysfs_file +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +# ioctl constants +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_SIZE_INT = 0x00040000 +IO_READ_WRITE = 0xC0000000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +# Watchdog ioctl commands +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +# Watchdog status constants +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +# watchdog sysfs +WD_SYSFS_PATH = "/sys/class/watchdog/watchdog0/" + +WD_COMMON_ERROR = -1 + +class WatchdogImplBase(WatchdogBase): + """ + Base class that implements common logic for interacting + with watchdog using ioctl commands + """ + def __init__(self, wd_device_path): + """ + Open a watchdog handle + @param wd_device_path Path to watchdog device + """ + super().__init__() + + self.watchdog="" + self.watchdog_path = wd_device_path + self.wd_state_reg = WD_SYSFS_PATH+"state" + self.wd_timeout_reg = WD_SYSFS_PATH+"timeout" + self.wd_timeleft_reg = WD_SYSFS_PATH+"timeleft" + + self.timeout = self._gettimeout() + + def _disablewatchdog(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _enablewatchdog(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeout(self): + """ + Get watchdog timeout + @return watchdog timeout + """ + timeout=0 + timeout=read_sysfs_file(self.wd_timeout_reg) + + return timeout + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + def arm(self, seconds): + """ + Implements arm WatchdogBase API + """ + ret = WD_COMMON_ERROR + if (seconds < 0 or seconds > 340 ): + return ret + + if not self.watchdog: + self.watchdog = os.open(self.watchdog_path, os.O_WRONLY) + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.is_armed(): + self._keepalive() + else: + self._enablewatchdog() + ret = self.timeout + except IOError: + pass + + return ret + + def disarm(self): + """ + Implements disarm WatchdogBase API + + Returns: + A boolean, True if watchdog is disarmed successfully, False + if not + """ + if not self.watchdog: + self.watchdog = os.open(self.watchdog_path, os.O_WRONLY) + try: + self._disablewatchdog() + self.timeout = 0 + except IOError: + return False + + return True + + def is_armed(self): + """ + Implements is_armed WatchdogBase API + """ + status = False + + state = read_sysfs_file(self.wd_state_reg) + if state != 'inactive': + status = True + + return status + + def get_remaining_time(self): + """ + Implements get_remaining_time WatchdogBase API + """ + timeleft = WD_COMMON_ERROR + + if self.is_armed(): + timeleft=read_sysfs_file(self.wd_timeleft_reg) + + return int(timeleft) From 6f86df9856d315c62cb0c820bd1dca0c8d2c9f4e Mon Sep 17 00:00:00 2001 From: y7zhou Date: Thu, 22 Jan 2026 15:17:24 -0500 Subject: [PATCH 2/3] [H6-128] Update FPGA driver and thermal, add component module [H6-128]Update thermal algo. with 4 fan speed levels --- ...sonic-platform-nokia-ixr7220h6-128.install | 2 +- ...onic-platform-nokia-ixr7220h6-128.postinst | 2 +- ixr7220h6-128/modules/h6_fan_cpld.c | 2 +- ixr7220h6-128/modules/h6_i2c_oc.c | 4 +- ixr7220h6-128/modules/i2c-ocores.c | 256 +++++++++++++++++- ixr7220h6-128/modules/port_cpld0.c | 2 +- ixr7220h6-128/modules/port_cpld1.c | 2 +- ixr7220h6-128/modules/port_cpld2.c | 2 +- ixr7220h6-128/modules/sys_cpld.c | 135 ++------- ixr7220h6-128/modules/sys_fpga.c | 26 +- ixr7220h6-128/scripts/h6_128_platform_init.sh | 12 +- ixr7220h6-128/scripts/set_ps.py | 38 +++ ixr7220h6-128/sonic_platform/chassis.py | 16 +- ixr7220h6-128/sonic_platform/component.py | 83 +++--- ixr7220h6-128/sonic_platform/fan.py | 4 +- ixr7220h6-128/sonic_platform/thermal.py | 26 +- .../sonic_platform/thermal_actions.py | 54 +++- ixr7220h6-128/sonic_platform/thermal_infos.py | 23 +- 18 files changed, 476 insertions(+), 213 deletions(-) create mode 100644 ixr7220h6-128/scripts/set_ps.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/thermal_actions.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/thermal_infos.py diff --git a/debian/sonic-platform-nokia-ixr7220h6-128.install b/debian/sonic-platform-nokia-ixr7220h6-128.install index 72baf88..fcb1a6d 100644 --- a/debian/sonic-platform-nokia-ixr7220h6-128.install +++ b/debian/sonic-platform-nokia-ixr7220h6-128.install @@ -1,5 +1,5 @@ ixr7220h6-128/scripts/h6_128_platform_init.sh usr/local/bin -#ixr7220h6-128/scripts/ports_notify.py usr/local/bin +ixr7220h6-128/scripts/set_ps.py usr/local/bin ixr7220h6-128/service/h6_128_platform_init.service etc/systemd/system #ixr7220h6-128/service/ports_notify.service etc/systemd/system/ ixr7220h6-128/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-nokia_ixr7220_h6_128-r0 diff --git a/debian/sonic-platform-nokia-ixr7220h6-128.postinst b/debian/sonic-platform-nokia-ixr7220h6-128.postinst index 2cead83..f2b0921 100644 --- a/debian/sonic-platform-nokia-ixr7220h6-128.postinst +++ b/debian/sonic-platform-nokia-ixr7220h6-128.postinst @@ -6,6 +6,6 @@ chmod a+x /usr/local/bin/h6_128_platform_init.sh systemctl enable h6_128_platform_init.service systemctl start h6_128_platform_init.service -# chmod a+x /usr/local/bin/ports_notify.py +chmod a+x /usr/local/bin/set_ps.py # systemctl enable ports_notify.service # systemctl start --no-block ports_notify.service diff --git a/ixr7220h6-128/modules/h6_fan_cpld.c b/ixr7220h6-128/modules/h6_fan_cpld.c index 289d48a..a450116 100644 --- a/ixr7220h6-128/modules/h6_fan_cpld.c +++ b/ixr7220h6-128/modules/h6_fan_cpld.c @@ -397,7 +397,7 @@ static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, ret = sprintf(buf, "0x%02x\n", data->reg_val[FAN_PCB_REG]); break; case FAN_FW_VERSION: - ret = sprintf(buf, "%d.%d\n", + ret = sprintf(buf, "%02x.%02x\n", data->reg_val[FAN_MAJOR_VERSION_REG], data->reg_val[FAN_MINOR_VERSION_REG]); break; diff --git a/ixr7220h6-128/modules/h6_i2c_oc.c b/ixr7220h6-128/modules/h6_i2c_oc.c index 6e78663..15162cc 100644 --- a/ixr7220h6-128/modules/h6_i2c_oc.c +++ b/ixr7220h6-128/modules/h6_i2c_oc.c @@ -1,7 +1,7 @@ // Driver for Nokia-7220-IXR-H6-128 Router /* - * Copyright (C) 2025 Accton Technology Corporation. - * Copyright (C) 2025 Nokia Corporation. + * Copyright (C) 2026 Accton Technology Corporation. + * Copyright (C) 2026 Nokia Corporation. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/ixr7220h6-128/modules/i2c-ocores.c b/ixr7220h6-128/modules/i2c-ocores.c index d45b262..b4c7ddb 100644 --- a/ixr7220h6-128/modules/i2c-ocores.c +++ b/ixr7220h6-128/modules/i2c-ocores.c @@ -25,6 +25,9 @@ #include #include #include +#include + +#define OCORE_DRIVER_VERSION "2.0.0" enum _print_level {PL_ERR, PL_WARN, PL_INFO, PL_DEBUG}; @@ -36,6 +39,174 @@ static uint param_timeout = 1; module_param(param_timeout, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(param_timeout, "for debugging. 1 ms should be enough"); +// spi mux mapping table +// ex : arr_spi_mux [0] = port 1 = dev_id 0 = spi mux 0x04 +// ex : arr_spi_mux [2] = port 3 = dev_id 2 = spi mux 0x0 +static uint8_t arr_spi_mux[] = { + // left part 64 port + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, + + // right part 64 port + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + + // SFP + 0x01, 0x01 +}; + +#define PORT_NUM (128 + 2) /*128 OSFPs + 2 SFP28s*/ +static const uint arr_pcie_offset[PORT_NUM]= { + 0x2100,// MESS_TOP_L_CPLD I2C Master OSFP Port1 + 0x2120,// MESS_TOP_L_CPLD I2C Master OSFP Port2 + 0x2100,// PORTCPLD0 I2C Master OSFP Port3 + 0x2120,// PORTCPLD0 I2C Master OSFP Port4 + 0x2140,// PORTCPLD0 I2C Master OSFP Port5 + 0x2160,// PORTCPLD0 I2C Master OSFP Port6 + 0x2100,// MESS_BOT_L_CPLD I2C Master OSFP Port7 + 0x2120,// MESS_BOT_L_CPLD I2C Master OSFP Port8 + 0x2140,// MESS_TOP_L_CPLD I2C Master OSFP Port9 + 0x2160,// MESS_TOP_L_CPLD I2C Master OSFP Port10 + 0x2180,// PORTCPLD0 I2C Master OSFP Port11 + 0x21A0,// PORTCPLD0 I2C Master OSFP Port12 + 0x21C0,// PORTCPLD0 I2C Master OSFP Port13 + 0x21E0,// PORTCPLD0 I2C Master OSFP Port14 + 0x2140,// MESS_BOT_L_CPLD I2C Master OSFP Port15 + 0x2160,// MESS_BOT_L_CPLD I2C Master OSFP Port16 + 0x2180,// MESS_TOP_L_CPLD I2C Master OSFP Port17 + 0x21A0,// MESS_TOP_L_CPLD I2C Master OSFP Port18 + 0x2200,// PORTCPLD0 I2C Master OSFP Port19 + 0x2220,// PORTCPLD0 I2C Master OSFP Port20 + 0x2240,// PORTCPLD0 I2C Master OSFP Port21 + 0x2260,// PORTCPLD0 I2C Master OSFP Port22 + 0x2180,// MESS_BOT_L_CPLD I2C Master OSFP Port23 + 0x21A0,// MESS_BOT_L_CPLD I2C Master OSFP Port24 + 0x21C0,// MESS_TOP_L_CPLD I2C Master OSFP Port25 + 0x21E0,// MESS_TOP_L_CPLD I2C Master OSFP Port26 + 0x2280,// PORTCPLD0 I2C Master OSFP Port27 + 0x22A0,// PORTCPLD0 I2C Master OSFP Port28 + 0x22C0,// PORTCPLD0 I2C Master OSFP Port29 + 0x22E0,// PORTCPLD0 I2C Master OSFP Port30 + 0x21C0,// MESS_BOT_L_CPLD I2C Master OSFP Port31 + 0x21E0,// MESS_BOT_L_CPLD I2C Master OSFP Port32 +////////////////////////////////////////////////////// + 0x2200,// MESS_TOP_L_CPLD I2C Master OSFP Port33 + 0x2220,// MESS_TOP_L_CPLD I2C Master OSFP Port34 + 0x2300,// PORTCPLD0 I2C Master OSFP Port35 + 0x2320,// PORTCPLD0 I2C Master OSFP Port36 + 0x2340,// PORTCPLD0 I2C Master OSFP Port37 + 0x2360,// PORTCPLD0 I2C Master OSFP Port38 + 0x2200,// MESS_BOT_L_CPLD I2C Master OSFP Port39 + 0x2220,// MESS_BOT_L_CPLD I2C Master OSFP Port40 + 0x2240,// MESS_TOP_L_CPLD I2C Master OSFP Port41 + 0x2260,// MESS_TOP_L_CPLD I2C Master OSFP Port42 + 0x2380,// PORTCPLD0 I2C Master OSFP Port43 + 0x23A0,// PORTCPLD0 I2C Master OSFP Port44 + 0x23C0,// PORTCPLD0 I2C Master OSFP Port45 + 0x23E0,// PORTCPLD0 I2C Master OSFP Port46 + 0x2240,// MESS_BOT_L_CPLD I2C Master OSFP Port47 + 0x2260,// MESS_BOT_L_CPLD I2C Master OSFP Port48 + 0x2280,// MESS_TOP_L_CPLD I2C Master OSFP Port49 + 0x22A0,// MESS_TOP_L_CPLD I2C Master OSFP Port50 + 0x2400,// PORTCPLD0 I2C Master OSFP Port51 + 0x2420,// PORTCPLD0 I2C Master OSFP Port52 + 0x2440,// PORTCPLD0 I2C Master OSFP Port53 + 0x2460,// PORTCPLD0 I2C Master OSFP Port54 + 0x2280,// MESS_BOT_L_CPLD I2C Master OSFP Port55 + 0x22A0,// MESS_BOT_L_CPLD I2C Master OSFP Port56 + 0x22C0,// MESS_TOP_L_CPLD I2C Master OSFP Port57 + 0x22E0,// MESS_TOP_L_CPLD I2C Master OSFP Port58 + 0x2480,// PORTCPLD0 I2C Master OSFP Port59 + 0x24A0,// PORTCPLD0 I2C Master OSFP Port60 + 0x24C0,// PORTCPLD0 I2C Master OSFP Port61 + 0x24E0,// PORTCPLD0 I2C Master OSFP Port62 + 0x22C0,// MESS_BOT_L_CPLD I2C Master OSFP Port63 + 0x22E0,// MESS_BOT_L_CPLD I2C Master OSFP Port64 +////////////////////////////////////////////////////// + 0x2100,// MESS_TOP_R_CPLD I2C Master OSFP Port65 + 0x2120,// MESS_TOP_R_CPLD I2C Master OSFP Port66 + 0x2100,// PORTCPLD1 I2C Master OSFP Port67 + 0x2120,// PORTCPLD1 I2C Master OSFP Port68 + 0x2140,// PORTCPLD1 I2C Master OSFP Port69 + 0x2160,// PORTCPLD1 I2C Master OSFP Port70 + 0x2100,// MESS_BOT_R_CPLD I2C Master OSFP Port71 + 0x2120,// MESS_BOT_R_CPLD I2C Master OSFP Port72 + 0x2140,// MESS_TOP_R_CPLD I2C Master OSFP Port73 + 0x2160,// MESS_TOP_R_CPLD I2C Master OSFP Port74 + 0x2180,// PORTCPLD1 I2C Master OSFP Port75 + 0x21A0,// PORTCPLD1 I2C Master OSFP Port76 + 0x21C0,// PORTCPLD1 I2C Master OSFP Port77 + 0x21E0,// PORTCPLD1 I2C Master OSFP Port78 + 0x2140,// MESS_BOT_R_CPLD I2C Master OSFP Port79 + 0x2160,// MESS_BOT_R_CPLD I2C Master OSFP Port80 + 0x2180,// MESS_TOP_R_CPLD I2C Master OSFP Port81 + 0x21A0,// MESS_TOP_R_CPLD I2C Master OSFP Port82 + 0x2200,// PORTCPLD1 I2C Master OSFP Port83 + 0x2220,// PORTCPLD1 I2C Master OSFP Port84 + 0x2240,// PORTCPLD1 I2C Master OSFP Port85 + 0x2260,// PORTCPLD1 I2C Master OSFP Port86 + 0x2180,// MESS_BOT_R_CPLD I2C Master OSFP Port87 + 0x21A0,// MESS_BOT_R_CPLD I2C Master OSFP Port88 + 0x21C0,// MESS_TOP_R_CPLD I2C Master OSFP Port89 + 0x21E0,// MESS_TOP_R_CPLD I2C Master OSFP Port90 + 0x2280,// PORTCPLD1 I2C Master OSFP Port91 + 0x22A0,// PORTCPLD1 I2C Master OSFP Port92 + 0x22C0,// PORTCPLD1 I2C Master OSFP Port93 + 0x22E0,// PORTCPLD1 I2C Master OSFP Port94 + 0x21C0,// MESS_BOT_R_CPLD I2C Master OSFP Port95 + 0x21E0,// MESS_BOT_R_CPLD I2C Master OSFP Port96 +////////////////////////////////////////////////////// + 0x2200,// MESS_TOP_R_CPLD I2C Master OSFP Port97 + 0x2220,// MESS_TOP_R_CPLD I2C Master OSFP Port98 + 0x2300,// PORTCPLD1 I2C Master OSFP Port99 + 0x2320,// PORTCPLD1 I2C Master OSFP Port100 + 0x2340,// PORTCPLD1 I2C Master OSFP Port101 + 0x2360,// PORTCPLD1 I2C Master OSFP Port102 + 0x2200,// MESS_BOT_R_CPLD I2C Master OSFP Port103 + 0x2220,// MESS_BOT_R_CPLD I2C Master OSFP Port104 + 0x2240,// MESS_TOP_R_CPLD I2C Master OSFP Port105 + 0x2260,// MESS_TOP_R_CPLD I2C Master OSFP Port106 + 0x2380,// PORTCPLD1 I2C Master OSFP Port107 + 0x23A0,// PORTCPLD1 I2C Master OSFP Port108 + 0x23C0,// PORTCPLD1 I2C Master OSFP Port109 + 0x23E0,// PORTCPLD1 I2C Master OSFP Port110 + 0x2240,// MESS_BOT_R_CPLD I2C Master OSFP Port111 + 0x2260,// MESS_BOT_R_CPLD I2C Master OSFP Port112 + 0x2280,// MESS_TOP_R_CPLD I2C Master OSFP Port113 + 0x22A0,// MESS_TOP_R_CPLD I2C Master OSFP Port114 + 0x2400,// PORTCPLD1 I2C Master OSFP Port115 + 0x2420,// PORTCPLD1 I2C Master OSFP Port116 + 0x2440,// PORTCPLD1 I2C Master OSFP Port117 + 0x2460,// PORTCPLD1 I2C Master OSFP Port118 + 0x2280,// MESS_BOT_R_CPLD I2C Master OSFP Port119 + 0x22A0,// MESS_BOT_R_CPLD I2C Master OSFP Port120 + 0x22C0,// MESS_TOP_R_CPLD I2C Master OSFP Port121 + 0x22E0,// MESS_TOP_R_CPLD I2C Master OSFP Port122 + 0x2480,// PORTCPLD1 I2C Master OSFP Port123 + 0x24A0,// PORTCPLD1 I2C Master OSFP Port124 + 0x24C0,// PORTCPLD1 I2C Master OSFP Port125 + 0x24E0,// PORTCPLD1 I2C Master OSFP Port126 + 0x22C0,// MESS_BOT_R_CPLD I2C Master OSFP Port127 + 0x22E0,// MESS_BOT_R_CPLD I2C Master OSFP Port128 + 0x2500,// MESS_BOT_R_CPLD I2C Master SFP Port1 + 0x2520,// MESS_BOT_R_CPLD I2C Master SFP Port2 +}; + +#define PCIE_SPI_MUX_OFFSET 0x2f00 +static phys_addr_t pcie_bar0_phys_addr = 0; +static void __iomem *spi_mux_virt_base= NULL; /* * 'process_lock' exists because ocores_process() and ocores_process_timeout() * can't run in parallel. @@ -58,6 +229,7 @@ struct ocores_i2c { int bus_clock_khz; void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); u8 (*getreg)(struct ocores_i2c *i2c, int reg); + u8 cached_pdev_id; }; /* registers */ @@ -189,7 +361,6 @@ static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { u8 value; value = i2c->getreg(i2c, reg); - DEBUG("Read 0x%02x from 0x%02x\n", value, reg); return value; } @@ -408,12 +579,29 @@ static void ocores_process_polling(struct ocores_i2c *i2c) } } +// spinlock_t pcie_mux_lock; +static DEFINE_MUTEX(pcie_mux_lock); +static volatile int last_id = -1; static int ocores_xfer_core(struct ocores_i2c *i2c, struct i2c_msg *msgs, int num, bool polling) { int ret; u8 ctrl; + + if (i2c->cached_pdev_id >= ARRAY_SIZE(arr_spi_mux)) { + return -EINVAL; + } + + mutex_lock(&pcie_mux_lock); + + if (last_id != i2c->cached_pdev_id) + { + INFO("switch mux to %u i2c->cached_pdev_id =%u \n", arr_spi_mux[i2c->cached_pdev_id], i2c->cached_pdev_id); + iowrite8(arr_spi_mux[i2c->cached_pdev_id], spi_mux_virt_base); + last_id = i2c->cached_pdev_id; + (void)ioread8(spi_mux_virt_base); + } ctrl = oc_getreg(i2c, OCI2C_CONTROL); if (polling) @@ -432,16 +620,21 @@ static int ocores_xfer_core(struct ocores_i2c *i2c, if (polling) { ocores_process_polling(i2c); } else { + INFO("going to wait_event_timeout"); ret = wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || (i2c->state == STATE_DONE), HZ); if (ret == 0) { ocores_process_timeout(i2c); + mutex_unlock(&pcie_mux_lock); return -ETIMEDOUT; } } + ret = (i2c->state == STATE_DONE) ? num : -EIO; - return (i2c->state == STATE_DONE) ? num : -EIO; + mutex_unlock(&pcie_mux_lock); + + return ret; } static int ocores_xfer_polling(struct i2c_adapter *adap, @@ -683,6 +876,42 @@ static int ocores_i2c_probe(struct platform_device *pdev) if (res) { i2c->base = ocores_devm_ioremap(&pdev->dev, res); dev_info(&pdev->dev, "Resouce start:0x%llx, end:0x%llx", res->start, res->end); + dev_info(&pdev->dev,"dev id=%u \n", pdev->id); + + i2c->cached_pdev_id = pdev->id; + + mutex_lock(&pcie_mux_lock); + + if (spi_mux_virt_base == NULL) + { + if (i2c->cached_pdev_id >= 0 && i2c->cached_pdev_id < ARRAY_SIZE(arr_pcie_offset)) + { + pcie_bar0_phys_addr = res->start - arr_pcie_offset[i2c->cached_pdev_id]; + spi_mux_virt_base = ioremap(pcie_bar0_phys_addr + PCIE_SPI_MUX_OFFSET, 4); + if (!spi_mux_virt_base) + { + mutex_unlock(&pcie_mux_lock); + printk(KERN_ERR "ioremap failed\n"); + return -ENOMEM; + } + last_id = -1; + pr_info("Device %d: BAR0=0x%08llx, offset=0x%08x, mapped=0x%08llx,spi_mux_virt_base=0x%p\n", + i2c->cached_pdev_id, + pcie_bar0_phys_addr, + arr_pcie_offset[i2c->cached_pdev_id], + res->start, + spi_mux_virt_base); + } + } + + if (spi_mux_virt_base != NULL) { + iowrite8(arr_spi_mux[i2c->cached_pdev_id], spi_mux_virt_base); + last_id = i2c->cached_pdev_id; + dev_info(&pdev->dev,"switch mux to %d \n", arr_spi_mux[i2c->cached_pdev_id]); + (void)ioread8(spi_mux_virt_base); + } + mutex_unlock(&pcie_mux_lock); + if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); } else { @@ -827,6 +1056,11 @@ static int ocores_i2c_resume(struct device *dev) { struct ocores_i2c *i2c = dev_get_drvdata(dev); + pr_info("ocores_i2c_resume\n"); + mutex_lock(&pcie_mux_lock); + last_id = -1; + mutex_unlock(&pcie_mux_lock); + if (!IS_ERR(i2c->clk)) { unsigned long rate; int ret = clk_prepare_enable(i2c->clk); @@ -859,10 +1093,10 @@ static struct platform_driver ocores_i2c_driver = { }, }; -static int __init ocores_i2c_as1813_init(void) +static int __init ocores_i2c_init(void) { int err; - + pr_info("ocores init :timeout delay %u\n", param_timeout); err = platform_driver_register(&ocores_i2c_driver); if (err < 0) { ERR("Failed to register ocores_i2c_driver"); @@ -870,16 +1104,20 @@ static int __init ocores_i2c_as1813_init(void) } return 0; } -static void __exit ocores_i2c_as1813_exit(void) +static void __exit ocores_i2c_exit(void) { platform_driver_unregister(&ocores_i2c_driver); - + if (spi_mux_virt_base) { + iounmap(spi_mux_virt_base); + spi_mux_virt_base= NULL; + } } -module_init(ocores_i2c_as1813_init); -module_exit(ocores_i2c_as1813_exit); +module_init(ocores_i2c_init); +module_exit(ocores_i2c_exit); MODULE_AUTHOR("Peter Korsgaard "); MODULE_DESCRIPTION("OpenCores I2C bus driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ocores-i2c"); \ No newline at end of file +MODULE_ALIAS("platform:ocores-i2c"); +MODULE_VERSION(OCORE_DRIVER_VERSION); diff --git a/ixr7220h6-128/modules/port_cpld0.c b/ixr7220h6-128/modules/port_cpld0.c index a0e4682..d12aa95 100644 --- a/ixr7220h6-128/modules/port_cpld0.c +++ b/ixr7220h6-128/modules/port_cpld0.c @@ -107,7 +107,7 @@ static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, ch reg_major = cpld_i2c_read(data, VER_MAJOR_REG); reg_minor = cpld_i2c_read(data, VER_MINOR_REG); - return sprintf(buf, "%d.%d\n", reg_major, reg_minor); + return sprintf(buf, "%02x.%02x\n", reg_major, reg_minor); } static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) diff --git a/ixr7220h6-128/modules/port_cpld1.c b/ixr7220h6-128/modules/port_cpld1.c index f9dbe5d..9250cce 100644 --- a/ixr7220h6-128/modules/port_cpld1.c +++ b/ixr7220h6-128/modules/port_cpld1.c @@ -113,7 +113,7 @@ static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, ch reg_major = cpld_i2c_read(data, VER_MAJOR_REG); reg_minor = cpld_i2c_read(data, VER_MINOR_REG); - return sprintf(buf, "%d.%d\n", reg_major, reg_minor); + return sprintf(buf, "%02x.%02x\n", reg_major, reg_minor); } static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) diff --git a/ixr7220h6-128/modules/port_cpld2.c b/ixr7220h6-128/modules/port_cpld2.c index 557989a..77d3eea 100644 --- a/ixr7220h6-128/modules/port_cpld2.c +++ b/ixr7220h6-128/modules/port_cpld2.c @@ -100,7 +100,7 @@ static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, ch reg_major = cpld_i2c_read(data, VER_MAJOR_REG); reg_minor = cpld_i2c_read(data, VER_MINOR_REG); - return sprintf(buf, "%d.%d\n", reg_major, reg_minor); + return sprintf(buf, "%02x.%02x\n", reg_major, reg_minor); } static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) diff --git a/ixr7220h6-128/modules/sys_cpld.c b/ixr7220h6-128/modules/sys_cpld.c index 22b188d..e31c0ff 100644 --- a/ixr7220h6-128/modules/sys_cpld.c +++ b/ixr7220h6-128/modules/sys_cpld.c @@ -32,16 +32,11 @@ #define VER_MAJOR_REG 0x00 #define VER_MINOR_REG 0x01 #define SCRATCH_REG 0x04 -#define PSU_GOOD_REG 0x0B -#define PSU_PRES_REG 0x0C -#define RST_GROUP1_REG 0x11 -#define OSFP_EFUSE_REG0 0x70 -#define SYS_LED_REG0 0x80 -#define SYS_LED_REG1 0x81 +#define SYS_LED_REG2 0x8 +#define SYS_LED_REG3 0x9 +#define OSFP_EFUSE_REG0 0x10 -// REG BIT FIELD POSITION or MASK - -static const unsigned short cpld_address_list[] = {0x61, I2C_CLIENT_END}; +static const unsigned short cpld_address_list[] = {0x71, I2C_CLIENT_END}; struct cpld_data { struct i2c_client *client; @@ -84,7 +79,7 @@ static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, ch reg_major = cpld_i2c_read(data, VER_MAJOR_REG); reg_minor = cpld_i2c_read(data, VER_MINOR_REG); - return sprintf(buf, "%d.%d\n", reg_major, reg_minor); + return sprintf(buf, "%02x.%02x\n", reg_major, reg_minor); } static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) @@ -115,42 +110,20 @@ static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t show_psu_ok(struct device *dev, struct device_attribute *devattr, char *buf) -{ - struct cpld_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); - u8 val = 0; - - val = cpld_i2c_read(data, PSU_GOOD_REG); - - return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); -} - -static ssize_t show_psu_pres(struct device *dev, struct device_attribute *devattr, char *buf) -{ - struct cpld_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); - u8 val = 0; - - val = cpld_i2c_read(data, PSU_PRES_REG); - - return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); -} - -static ssize_t show_led0(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_led2(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); u8 val = 0; u8 mask = 0xF; - val = cpld_i2c_read(data, SYS_LED_REG0); + val = cpld_i2c_read(data, SYS_LED_REG2); if (sda->index == 0) mask = 0xF; else mask = 0x3; return sprintf(buf, "0x%x\n", (val>>sda->index) & mask); } -static ssize_t set_led0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +static ssize_t set_led2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); @@ -169,28 +142,28 @@ static ssize_t set_led0(struct device *dev, struct device_attribute *devattr, co return -EINVAL; } reg_mask = (~(mask << sda->index)) & 0xFF; - reg_val = cpld_i2c_read(data, SYS_LED_REG0); + reg_val = cpld_i2c_read(data, SYS_LED_REG2); reg_val = reg_val & reg_mask; usr_val = usr_val << sda->index; - cpld_i2c_write(data, SYS_LED_REG0, (reg_val | usr_val)); + cpld_i2c_write(data, SYS_LED_REG2, (reg_val | usr_val)); return count; } -static ssize_t show_led1(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_led3(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); u8 val = 0; u8 mask = 0xF; - val = cpld_i2c_read(data, SYS_LED_REG1); + val = cpld_i2c_read(data, SYS_LED_REG3); if (sda->index == 0) mask = 0xF; else mask = 0x3; return sprintf(buf, "0x%x\n", (val>>sda->index) & mask); } -static ssize_t set_led1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +static ssize_t set_led3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); @@ -209,46 +182,10 @@ static ssize_t set_led1(struct device *dev, struct device_attribute *devattr, co return -EINVAL; } reg_mask = (~(mask << sda->index)) & 0xFF; - reg_val = cpld_i2c_read(data, SYS_LED_REG1); + reg_val = cpld_i2c_read(data, SYS_LED_REG3); reg_val = reg_val & reg_mask; usr_val = usr_val << sda->index; - cpld_i2c_write(data, SYS_LED_REG1, (reg_val | usr_val)); - - return count; -} - -static ssize_t show_rst1(struct device *dev, struct device_attribute *devattr, char *buf) -{ - struct cpld_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); - u8 val = 0; - - val = cpld_i2c_read(data, RST_GROUP1_REG); - - return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); -} - -static ssize_t set_rst1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) -{ - struct cpld_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); - u8 reg_val = 0; - u8 usr_val = 0; - u8 mask; - - int ret = kstrtou8(buf, 10, &usr_val); - if (ret != 0) { - return ret; - } - if (usr_val > 1) { - return -EINVAL; - } - - mask = (~(1 << sda->index)) & 0xFF; - reg_val = cpld_i2c_read(data, RST_GROUP1_REG); - reg_val = reg_val & mask; - usr_val = usr_val << sda->index; - cpld_i2c_write(data, RST_GROUP1_REG, (reg_val | usr_val)); + cpld_i2c_write(data, SYS_LED_REG3, (reg_val | usr_val)); return count; } @@ -285,42 +222,22 @@ static ssize_t set_osfp_efuse(struct device *dev, struct device_attribute *devat static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); -static SENSOR_DEVICE_ATTR(psu1_ok, S_IRUGO, show_psu_ok, NULL, 0); -static SENSOR_DEVICE_ATTR(psu2_ok, S_IRUGO, show_psu_ok, NULL, 1); -static SENSOR_DEVICE_ATTR(psu3_ok, S_IRUGO, show_psu_ok, NULL, 2); -static SENSOR_DEVICE_ATTR(psu4_ok, S_IRUGO, show_psu_ok, NULL, 3); -static SENSOR_DEVICE_ATTR(psu1_pres, S_IRUGO, show_psu_pres, NULL, 4); -static SENSOR_DEVICE_ATTR(psu2_pres, S_IRUGO, show_psu_pres, NULL, 5); -static SENSOR_DEVICE_ATTR(psu3_pres, S_IRUGO, show_psu_pres, NULL, 6); -static SENSOR_DEVICE_ATTR(psu4_pres, S_IRUGO, show_psu_pres, NULL, 7); - -static SENSOR_DEVICE_ATTR(led_sys, S_IRUGO | S_IWUSR, show_led0, set_led0, 0); -static SENSOR_DEVICE_ATTR(led_psu, S_IRUGO, show_led0, NULL, 4); -static SENSOR_DEVICE_ATTR(led_loc, S_IRUGO | S_IWUSR, show_led1, set_led1, 0); -static SENSOR_DEVICE_ATTR(led_fan, S_IRUGO | S_IWUSR, show_led1, set_led1, 4); - -static SENSOR_DEVICE_ATTR(mac_pcie_rst, S_IRUGO | S_IWUSR, show_rst1, set_rst1, 3); +//static SENSOR_DEVICE_ATTR(led_sys, S_IRUGO | S_IWUSR, show_led0, set_led0, 0); +static SENSOR_DEVICE_ATTR(led_psu, S_IRUGO, show_led3, NULL, 0); +//static SENSOR_DEVICE_ATTR(led_loc, S_IRUGO | S_IWUSR, show_led2, set_led2, 0); +static SENSOR_DEVICE_ATTR(led_fan, S_IRUGO | S_IWUSR, show_led2, set_led2, 4); + static SENSOR_DEVICE_ATTR(osfp_efuse, S_IRUGO | S_IWUSR, show_osfp_efuse, set_osfp_efuse, 0); static struct attribute *sys_cpld_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, &sensor_dev_attr_scratch.dev_attr.attr, - &sensor_dev_attr_psu1_ok.dev_attr.attr, - &sensor_dev_attr_psu2_ok.dev_attr.attr, - &sensor_dev_attr_psu3_ok.dev_attr.attr, - &sensor_dev_attr_psu4_ok.dev_attr.attr, - &sensor_dev_attr_psu1_pres.dev_attr.attr, - &sensor_dev_attr_psu2_pres.dev_attr.attr, - &sensor_dev_attr_psu3_pres.dev_attr.attr, - &sensor_dev_attr_psu4_pres.dev_attr.attr, - - &sensor_dev_attr_led_sys.dev_attr.attr, + //&sensor_dev_attr_led_sys.dev_attr.attr, &sensor_dev_attr_led_psu.dev_attr.attr, - &sensor_dev_attr_led_loc.dev_attr.attr, + //&sensor_dev_attr_led_loc.dev_attr.attr, &sensor_dev_attr_led_fan.dev_attr.attr, - &sensor_dev_attr_mac_pcie_rst.dev_attr.attr, &sensor_dev_attr_osfp_efuse.dev_attr.attr, NULL @@ -360,9 +277,9 @@ static int sys_cpld_probe(struct i2c_client *client) goto exit; } - int i; - for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0xFF); - data->osfp_efuse = 1; + // int i; + // for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0xFF); + // data->osfp_efuse = 1; return 0; @@ -379,7 +296,7 @@ static void sys_cpld_remove(struct i2c_client *client) static const struct of_device_id sys_cpld_of_ids[] = { { - .compatible = "nokia,sys_cpld", + .compatible = "sys_cpld", .data = (void *) 0, }, { }, diff --git a/ixr7220h6-128/modules/sys_fpga.c b/ixr7220h6-128/modules/sys_fpga.c index 686ff33..c39ed95 100644 --- a/ixr7220h6-128/modules/sys_fpga.c +++ b/ixr7220h6-128/modules/sys_fpga.c @@ -32,12 +32,10 @@ #define HW_BOARD_VER_REG 0x00 #define VER_MAJOR_REG 0x01 #define VER_MINOR_REG 0x02 -#define BMC_TIMING_FCM_PSU_PRESENT_REG 0x07 +#define PSU_PRESENT_REG 0x07 #define SSD_PRESENT_REG 0x08 #define PSU_POWERGOOD_REG 0x51 -// REG BIT FIELD POSITION or MASK - static const unsigned short cpld_address_list[] = {0x60, I2C_CLIENT_END}; struct cpld_data { @@ -80,7 +78,7 @@ static ssize_t show_hw_board_ver(struct device *dev, struct device_attribute *de return sprintf(buf, "0x%x\n", val); } -static ssize_t show_fpga_ver(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_ver(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); u8 reg_major = 0; @@ -89,16 +87,16 @@ static ssize_t show_fpga_ver(struct device *dev, struct device_attribute *devatt reg_major = cpld_i2c_read(data, VER_MAJOR_REG); reg_minor = cpld_i2c_read(data, VER_MINOR_REG); - return sprintf(buf, "%d.%d\n", reg_major, reg_minor); + return sprintf(buf, "%02x.%02x\n", reg_major, reg_minor); } -static ssize_t show_bmc_timing_fcm_psu_present(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_psu_present(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); u8 val = 0; - val = cpld_i2c_read(data, BMC_TIMING_FCM_PSU_PRESENT_REG); + val = cpld_i2c_read(data, PSU_PRESENT_REG); return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); } @@ -124,21 +122,21 @@ static ssize_t show_ssd_present(struct device *dev, struct device_attribute *dev // sysfs attributes static SENSOR_DEVICE_ATTR(hw_board_version, S_IRUGO, show_hw_board_ver, NULL, 0); -static SENSOR_DEVICE_ATTR(fpga_version, S_IRUGO, show_fpga_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); static SENSOR_DEVICE_ATTR(psu1_ok, S_IRUGO, show_psu_ok, NULL, 0); static SENSOR_DEVICE_ATTR(psu2_ok, S_IRUGO, show_psu_ok, NULL, 1); static SENSOR_DEVICE_ATTR(psu3_ok, S_IRUGO, show_psu_ok, NULL, 2); static SENSOR_DEVICE_ATTR(psu4_ok, S_IRUGO, show_psu_ok, NULL, 3); -static SENSOR_DEVICE_ATTR(psu1_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 3); -static SENSOR_DEVICE_ATTR(psu2_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 2); -static SENSOR_DEVICE_ATTR(psu3_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 1); -static SENSOR_DEVICE_ATTR(psu4_pres, S_IRUGO, show_bmc_timing_fcm_psu_present, NULL, 0); +static SENSOR_DEVICE_ATTR(psu1_pres, S_IRUGO, show_psu_present, NULL, 3); +static SENSOR_DEVICE_ATTR(psu2_pres, S_IRUGO, show_psu_present, NULL, 2); +static SENSOR_DEVICE_ATTR(psu3_pres, S_IRUGO, show_psu_present, NULL, 1); +static SENSOR_DEVICE_ATTR(psu4_pres, S_IRUGO, show_psu_present, NULL, 0); static SENSOR_DEVICE_ATTR(ssd1_pres, S_IRUGO, show_ssd_present, NULL, 1); static SENSOR_DEVICE_ATTR(ssd2_pres, S_IRUGO, show_ssd_present, NULL, 0); static struct attribute *sys_fpga_attributes[] = { &sensor_dev_attr_hw_board_version.dev_attr.attr, - &sensor_dev_attr_fpga_version.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, &sensor_dev_attr_psu1_ok.dev_attr.attr, &sensor_dev_attr_psu2_ok.dev_attr.attr, &sensor_dev_attr_psu3_ok.dev_attr.attr, @@ -201,7 +199,7 @@ static void sys_fpga_remove(struct i2c_client *client) static const struct of_device_id sys_fpga_of_ids[] = { { - .compatible = "nokia,sys_fpga", + .compatible = "sys_fpga", .data = (void *) 0, }, { }, diff --git a/ixr7220h6-128/scripts/h6_128_platform_init.sh b/ixr7220h6-128/scripts/h6_128_platform_init.sh index d3649a3..ba10977 100755 --- a/ixr7220h6-128/scripts/h6_128_platform_init.sh +++ b/ixr7220h6-128/scripts/h6_128_platform_init.sh @@ -24,7 +24,8 @@ load_kernel_drivers() { h6-128_profile() { - MAC_ADDR=$(ip link show eth0 | grep ether | awk '{print $2}') + #MAC_ADDR=$(ip link show eth0 | grep ether | awk '{print $2}') + MAC_ADDR=$(sudo decode-syseeprom -m) sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" /usr/share/sonic/device/x86_64-nokia_ixr7220_h6_128-r0/Nokia-IXR7220-H6-128/profile.ini echo "Nokia-IXR7220-H6-128: Updated switch mac address ${MAC_ADDR}" } @@ -57,6 +58,8 @@ echo mux_fpga 0x77 > /sys/bus/i2c/devices/i2c-1/new_device sleep 1 echo mux_sys_cpld 0x72 > /sys/bus/i2c/devices/i2c-134/new_device +echo sys_cpld 0x71 > /sys/bus/i2c/devices/i2c-134/new_device + echo mux_fcm 0x75 > /sys/bus/i2c/devices/i2c-144/new_device echo mux_fcm 0x76 > /sys/bus/i2c/devices/i2c-145/new_device sleep 1 @@ -104,7 +107,6 @@ for i in {0..3}; do done echo embd_ctrl 0x21 > /sys/bus/i2c/devices/i2c-0/new_device -echo jc42 0x18 > /sys/bus/i2c/devices/i2c-0/new_device echo lm75 0x48 > /sys/bus/i2c/devices/i2c-143/new_device echo lm75 0x48 > /sys/bus/i2c/devices/i2c-154/new_device echo lm75 0x49 > /sys/bus/i2c/devices/i2c-154/new_device @@ -137,15 +139,15 @@ done echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-130/new_device echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-131/new_device -exit +h6-128_profile + +/usr/local/bin/set_ps.py for ch in {1..8}; do echo 60 > /sys/bus/i2c/devices/144-0032/hwmon/hwmon*/fan${ch}_pwm echo 60 > /sys/bus/i2c/devices/145-0033/hwmon/hwmon*/fan${ch}_pwm done -h6-128_profile - exit diff --git a/ixr7220h6-128/scripts/set_ps.py b/ixr7220h6-128/scripts/set_ps.py new file mode 100644 index 0000000..94af028 --- /dev/null +++ b/ixr7220h6-128/scripts/set_ps.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import struct +from os import * +from mmap import * + +RESOURCE = "/sys/bus/pci/devices/0000:02:00.0/resource0" +REG1 = [0x2100, 0x2120, 0x2140, 0x2160, 0x2180, 0x21A0, 0x21C0, 0x21E0, 0x2200, 0x2220, 0x2240, 0x2260, 0x2280, 0x22A0, 0x22C0, 0x22E0] +REG2 = [0x2300, 0x2320, 0x2340, 0x2360, 0x2380, 0x23A0, 0x23C0, 0x23E0, 0x2400, 0x2420, 0x2440, 0x2460, 0x2480, 0x24A0, 0x24C0, 0x24E0, 0x2500, 0x2520] + +def pci_set_data8(resource, val, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + mm.seek(offset) + mm.write(struct.pack('B', val)) + mm.close() + close(fd) + +def main(): + for p in range(5): + pci_set_data8(RESOURCE, p+1, 0x2f00) + #print(f"SPI_MUX: set mux to {(p+1)}:\n\n") + for i in range(len(REG1)): + pci_set_data8(RESOURCE, 0x80, REG1[i]+8) + pci_set_data8(RESOURCE, 0x0B, REG1[i]) + pci_set_data8(RESOURCE, 0x0, REG1[i]+4) + if p == 0: + for i in range(len(REG2)): + pci_set_data8(RESOURCE, 0x80, REG2[i]+8) + pci_set_data8(RESOURCE, 0x0B, REG2[i]) + pci_set_data8(RESOURCE, 0x0, REG2[i]+4) + + return + + +if __name__ == '__main__': + main() + \ No newline at end of file diff --git a/ixr7220h6-128/sonic_platform/chassis.py b/ixr7220h6-128/sonic_platform/chassis.py index 9364727..f2feb12 100755 --- a/ixr7220h6-128/sonic_platform/chassis.py +++ b/ixr7220h6-128/sonic_platform/chassis.py @@ -31,10 +31,10 @@ FAN_DRAWERS = 8 FANS_PER_DRAWER = 2 PSU_NUM = 4 -THERMAL_NUM = 21 -COMPONENT_NUM = 7 +THERMAL_NUM = 20 +COMPONENT_NUM = 11 -CPLD_DIR = "/sys/bus/i2c/devices/73-0061/" +CPLD_DIR = "/sys/bus/i2c/devices/134-0071/" SYSFPGA_DIR = "/sys/bus/i2c/devices/1-0060/" BUS_IDX = [1,2,9,10,17,18,25,26,33,34,41,42,49,50,57,58,65,66,73,74,81,82,89,90,97,98,105,106,113,114,121,122, 3,4,11,12,19,20,27,28,35,36,43,44,51,52,59,60,67,68,75,76,83,84,91,92,99,100,107,108,115,116,123,124, @@ -98,9 +98,9 @@ def __init__(self): psu = Psu(i) self._psu_list.append(psu) - # for i in range(COMPONENT_NUM): - # component = Component(i) - # self._component_list.append(component) + for i in range(COMPONENT_NUM): + component = Component(i) + self._component_list.append(component) def get_sfp(self, index): """ @@ -289,6 +289,8 @@ def get_reboot_cause(self): is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + result = read_sysfs_file(SYSFPGA_DIR + "reset_cause") if (int(result, 16) & 0x10) >> 4 == 1: @@ -361,6 +363,7 @@ def set_status_led(self, color): Returns: bool: True if system LED state is set successfully, False if not """ + return False color_to_value = { 'blue': '0x3', 'green': '0x5', @@ -387,6 +390,7 @@ def get_status_led(self): A string, one of the valid LED color strings which could be vendor specified. """ + return 'N/A' result = read_sysfs_file(CPLD_DIR + 'led_sys') val = int(result, 16) if (val & 0x8) == 0x8: diff --git a/ixr7220h6-128/sonic_platform/component.py b/ixr7220h6-128/sonic_platform/component.py index 17fca2e..fd87349 100755 --- a/ixr7220h6-128/sonic_platform/component.py +++ b/ixr7220h6-128/sonic_platform/component.py @@ -19,11 +19,15 @@ SYSFS_DIR = ["/sys/class/dmi/id/", "/sys/bus/i2c/devices/1-0060/", - "/sys/bus/i2c/devices/73-0061/", - "/sys/bus/i2c/devices/89-0064/", - "/sys/bus/i2c/devices/90-0065/", - "/sys/bus/i2c/devices/79-0033/hwmon/hwmon*/", - "/sys/bus/i2c/devices/80-0033/hwmon/hwmon*/"] + "/sys/bus/i2c/devices/134-0071/", + "/sys/bus/i2c/devices/148-0074/", + "/sys/bus/i2c/devices/149-0075/", + "/sys/bus/i2c/devices/152-0076/", + "/sys/bus/i2c/devices/153-0076/", + "/sys/bus/i2c/devices/150-0073/", + "/sys/bus/i2c/devices/151-0073/", + "/sys/bus/i2c/devices/144-0032/hwmon/hwmon*/", + "/sys/bus/i2c/devices/145-0033/hwmon/hwmon*/"] class Component(ComponentBase): """Nokia platform-specific Component class""" @@ -32,17 +36,26 @@ class Component(ComponentBase): ["BIOS", "Basic Input/Output System"], ["SYS_FPGA", "Used for managing CPU board"], ["SYS_CPLD", "Used for managing BCM chip, PSUs and LEDs"], - ["PORT_CPLD0", "Used for managing PORT 1-16, 33-48, SFP28"], - ["PORT_CPLD1", "Used for managing PORT 17-32, 49-64"], + ["PORT_CPLD0", "Used for managing PORT 33-48, 65-80"], + ["PORT_CPLD1", "Used for managing PORT 49-64, 81-96, SFP28"], + ["PORT_CPLD_TL", "Used for managing PORT 1-16"], + ["PORT_CPLD_TR", "Used for managing PORT 17-32"], + ["PORT_CPLD_BL", "Used for managing PORT 97-112"], + ["PORT_CPLD_BR", "Used for managing PORT 113-128"], ["FCM0_CPLD", "Used for managing upper fan drawers"], ["FCM1_CPLD", "Used for managing lower fan drawers"] ] - DEV_NAME = [" ", " ", "MAIN_CPLD", "MAIN_CPLD", "MAIN_CPLD", "FAN0_CPLD", "FAN1_CPLD"] - TFR_NAME = [" ", " ", "h6_128_sys_cpld_tfr.vme", "h6_128_port_cpld0_tfr.vme", - "h6_128_port_cpld1_tfr.vme", "h6_128_fan_cpld_tfr.vme", "h6_128_fan_cpld_tfr.vme"] - - BIOS_UPDATE_COMMAND = ['./afulnx_128', '', '/B', '/P', '/N', '/K'] + DEV_NAME = [" ", " ", "MAIN_CPLD", "MAIN_CPLD", "MAIN_CPLD", "MAIN_CPLD", + "MAIN_CPLD", "MAIN_CPLD","MAIN_CPLD", "FAN0_CPLD", "FAN1_CPLD"] + TFR_NAME = [" ", " ", "h6_64_sys_cpld_tfr.vme", "h6_64_port_cpld0_tfr.vme", + "h6_64_port_cpld1_tfr.vme", "h6_64_port_cpld_tl_tfr.vme", + "h6_64_port_cpld_tr_tfr.vme", "h6_64_port_cpld_bl_tfr.vme", + "h6_64_port_cpld_br_tfr.vme", "h6_64_fan_cpld_tfr.vme", + "h6_64_fan_cpld_tfr.vme"] + + BIOS_UPDATE_COMMAND = ['./afulnx_64', '', '/B', '/P', '/N', '/K'] FPGA_CHECK_COMMAND = ['./fpga_spi_flash.sh', '-rid'] FPGA_UPDATE_COMMAND = ['./fpga_spi_flash.sh', '-upd', '', '-all'] + CPLD_CHECK_COMMAND = ['./cpldupd', '-s', ''] CPLD_UPDATE_COMMAND = ['./cpldupd', '-u', '', ''] def __init__(self, component_index): @@ -69,12 +82,6 @@ def _get_command_result(self, cmdline): return result - def _get_cpld_version(self): - if self.name == "BIOS": - return read_sysfs_file(self.sysfs_dir + "bios_version") - else: - return read_sysfs_file(self.sysfs_dir + "version") - def get_name(self): """ Retrieves the name of the component @@ -149,7 +156,10 @@ def get_firmware_version(self): Returns: A string containing the firmware version of the component """ - return self._get_cpld_version() + if self.name == "BIOS": + return read_sysfs_file(self.sysfs_dir + "bios_version") + else: + return read_sysfs_file(self.sysfs_dir + "version") def install_firmware(self, image_path): """ @@ -163,16 +173,14 @@ def install_firmware(self, image_path): """ image_name = ntpath.basename(image_path) - # check whether the image file exists os.chdir("/tmp") if not os.path.isfile(image_name): print(f"ERROR: the image {image_name} doesn't exist in /tmp") return False if self.name == "BIOS": - # check whether the BIOS upgrade tool exists - if not os.path.isfile('/tmp/afulnx_128'): - print("ERROR: the BIOS upgrade tool /tmp/afulnx_128 doesn't exist ") + if not os.path.isfile('/tmp/afulnx_64'): + print("ERROR: the BIOS upgrade tool /tmp/afulnx_64 doesn't exist ") return False self.BIOS_UPDATE_COMMAND[1] = image_name try: @@ -183,7 +191,6 @@ def install_firmware(self, image_path): print("\nBIOS update has ended\n") elif self.name == "SYS_FPGA": - # check whether the fpga upgrade tool exists if not os.path.isfile('/tmp/fpga_spi_flash.sh'): print("ERROR: the fpga upgrade tool /tmp/fpga_spi_flash.sh doesn't exist ") return False @@ -213,12 +220,15 @@ def install_firmware(self, image_path): self._power_cycle() else: - # check whether the cpld upgrade tool exists if not os.path.isfile('/tmp/cpldupd'): print("ERROR: the cpld upgrade tool /tmp/cpldupd doesn't exist ") return False - val = [" ", " ", "0x4", "0x2", "0x1", "0x10", "0x8"] - write_sysfs_file("/sys/bus/i2c/devices/1-0060/hitless", val[self.index]) + self.CPLD_CHECK_COMMAND[2] = self.dev_name + try: + subprocess.run(self.CPLD_CHECK_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to Scan Jtag chain for {self.name}: rc={e.returncode}") + return False self.CPLD_UPDATE_COMMAND[2] = self.dev_name self.CPLD_UPDATE_COMMAND[3] = image_name try: @@ -232,11 +242,10 @@ def install_firmware(self, image_path): except subprocess.CalledProcessError as e: print(f"ERROR: Failed to upgrade {self.name}: rc={e.returncode}") return False - write_sysfs_file("/sys/bus/i2c/devices/1-0060/hitless", "0x0") print(f"\n{self.name} firmware update has ended\n") return True - + def update_firmware(self, image_path): """ Updates firmware of the component @@ -248,10 +257,14 @@ def update_firmware(self, image_path): Args: image_path: A string, path to firmware image + Returns: + Boolean False if image_path doesn't exist instead of throwing an exception error + Nothing when the update is successful + Raises: RuntimeError: update failed """ - return False + return self.install_firmware(image_path) def get_available_firmware_version(self, image_path): """ @@ -265,13 +278,17 @@ def get_available_firmware_version(self, image_path): Returns: A string containing the available firmware version of the component """ - return "N/A" + if image_path: + image_name = ntpath.basename(image_path) + return image_name + return 'NA' + def _power_cycle(self): os.system('sync') os.system('sync') time.sleep(3) for i in range(4): - file_path = f"/sys/bus/i2c/devices/{i+94}-00{hex(0x58+i)[2:]}/psu_rst" + file_path = f"/sys/bus/i2c/devices/{i+136}-00{hex(0x58+i)[2:]}/psu_rst" if os.path.exists(file_path): - write_sysfs_file(file_path, "Reset\n") \ No newline at end of file + write_sysfs_file(file_path, "Reset\n") diff --git a/ixr7220h6-128/sonic_platform/fan.py b/ixr7220h6-128/sonic_platform/fan.py index 364db68..a861ae9 100755 --- a/ixr7220h6-128/sonic_platform/fan.py +++ b/ixr7220h6-128/sonic_platform/fan.py @@ -14,8 +14,8 @@ raise ImportError(str(e) + "- required module not found") FANS_PER_DRAWER = 2 -MAX_FAN_F_SPEED = 20500 -MAX_FAN_R_SPEED = 21800 +MAX_FAN_F_SPEED = 13600 +MAX_FAN_R_SPEED = 15400 FAN_TOLERANCE = 50 WORKING_FAN_SPEED = 2000 diff --git a/ixr7220h6-128/sonic_platform/thermal.py b/ixr7220h6-128/sonic_platform/thermal.py index e476e92..aa11b60 100755 --- a/ixr7220h6-128/sonic_platform/thermal.py +++ b/ixr7220h6-128/sonic_platform/thermal.py @@ -15,31 +15,31 @@ sonic_logger = logger.Logger('thermal') -THERMAL_NUM = 21 +THERMAL_NUM = 20 class Thermal(ThermalBase): """Nokia platform-specific Thermal class""" HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" - I2C_DEV_LIST = ["0-0018", "143-0048", "154-004b", "154-004c", "154-004d", + I2C_DEV_LIST = ["143-0048", "154-004b", "154-004c", "154-004d", "154-0049", "154-0048", "154-004a", "174-0048", "177-0048", "180-0048", "183-0048", "167-004d","168-004e", "161-004d", "162-004e", "0-0021", "0-0021"] - THERMAL_NAME = ["CPU Board", "Carrier Board", "MB Top U34", "MB Top U178", "MB Bottom U196", + THERMAL_NAME = ["Carrier Board", "MB Top U34", "MB Top U178", "MB Bottom U196", "MB Bottom U183", "MB Top U3", "MB Top U15", "LDB Left", "LDB Right", "UDB Left", "UDB Right", "Top FCM 1", "Top FCM 2", "Bottom FCM 1", "Bottom FCM 2", "CPU", "DDR", "Max Port Temp.", "SSD", "ASIC TH6"] - THRESHHOLD = [65.0, 66.0, 68.0, 62.0, 75.0, - 105.0, 105.0, 105.0, 78.0, 65.0, - 66.0, 66.0, 95.0, 70.0, 85.0, - 85.0, 95.0, 70.0, 85.0,70.0, + THRESHHOLD = [62.0, 75.0, 75.0, 75.0, + 75.0, 75.0, 75.0, 60.0, 60.0, + 60.0, 60.0, 60.0, 60.0, 62.0, + 62.0, 95.0, 70.0, 75.0, 70.0, 95.0] - CRITICAL_THRESHHOLD = [70.0, 70.0, 72.0, 67.0, 80.0, - 115.0, 115.0, 115.0, 80.0, 70.0, - 69.0, 69.0, 99.0, 80.0, 90.0, - 90.0, 99.0, 80.0, 90.0,80.0, + CRITICAL_THRESHHOLD = [70.0, 85.0, 85.0, 85.0, + 85.0, 85.0, 85.0, 70.0, 70.0, + 70.0, 70.0, 70.0, 70.0, 72.0, + 72.0, 99.0, 80.0, 77.0, 80.0, 100.0] def __init__(self, thermal_index, sfps): @@ -192,9 +192,7 @@ def get_high_critical_threshold(self): A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - if self.index == THERMAL_NUM: - return 103.0 - return 80.0 + return self.CRITICAL_THRESHHOLD[self.index - 1] def set_high_critical_threshold(self): """ diff --git a/ixr7220h6-128/sonic_platform/thermal_actions.py b/ixr7220h6-128/sonic_platform/thermal_actions.py old mode 100755 new mode 100644 index e71359e..c98a85b --- a/ixr7220h6-128/sonic_platform/thermal_actions.py +++ b/ixr7220h6-128/sonic_platform/thermal_actions.py @@ -15,14 +15,16 @@ class SetFanSpeedAction(ThermalPolicyActionBase): JSON_FIELD_SPEED = 'speed' JSON_FIELD_DEFAULT_SPEED = 'default_speed' JSON_FIELD_THRESHOLD1_SPEED = 'threshold1_speed' + JSON_FIELD_THRESHOLD2_SPEED = 'threshold2_speed' JSON_FIELD_HIGHTEMP_SPEED = 'hightemp_speed' def __init__(self): """ Constructor of SetFanSpeedAction """ - self.default_speed = 46 - self.threshold1_speed=73 + self.default_speed = 47 + self.threshold1_speed = 60 + self.threshold2_speed = 80 self.hightemp_speed = 100 self.speed = self.default_speed @@ -77,8 +79,9 @@ def load_from_json(self, json_obj): Construct ThermalRecoverAction via JSON. JSON example: { "type": "thermal.temp_check_and_set_all_fan_speed" - "default_speed": "46", - "threshold1_speed": "73", + "default_speed": "25", + "threshold1_speed": "40", + "threshold2_speed": "75", "hightemp_speed": "100" } :param json_obj: A JSON object representing a ThermalRecoverAction action. @@ -104,6 +107,16 @@ def load_from_json(self, json_obj): raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. format(SetFanSpeedAction.JSON_FIELD_THRESHOLD1_SPEED)) + if SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED in json_obj: + threshold2_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED]) + if threshold2_speed < 0 or threshold2_speed > 100: + raise ValueError('SetFanSpeedAction invalid default speed value {} in JSON policy file, valid value should be [0, 100]'. + format(threshold2_speed)) + self.threshold2_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED]) + else: + raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. + format(SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED)) + if SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED in json_obj: hightemp_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED]) if hightemp_speed < 0 or hightemp_speed > 100: @@ -114,7 +127,7 @@ def load_from_json(self, json_obj): raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. format(SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED)) - sonic_logger.log_warning("ThermalRecoverAction: default: {}, threshold1: {}, hightemp: {}".format(self.default_speed, self.threshold1_speed, self.hightemp_speed)) + sonic_logger.log_warning("ThermalRecoverAction: default: {}, threshold1: {}, threshold2: {}, hightemp: {}".format(self.default_speed, self.threshold1_speed, self.threshold2_speed, self.hightemp_speed)) def execute(self, thermal_info_dict): """ @@ -129,6 +142,8 @@ def execute(self, thermal_info_dict): thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] if thermal_info_obj.is_set_fan_high_temp_speed(): ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.hightemp_speed) + elif thermal_info_obj.is_set_fan_threshold_two_speed(): + ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.threshold2_speed) elif thermal_info_obj.is_set_fan_threshold_one_speed(): ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.threshold1_speed) elif thermal_info_obj.is_set_fan_default_speed(): @@ -147,8 +162,29 @@ def execute(self, thermal_info_dict): :param thermal_info_dict: A dictionary stores all thermal information. :return: """ - sonic_logger.log_warning("Alarm for temperature critical is detected, reboot Device") + try: + import os + from sonic_platform.chassis import Chassis + for i in range(8): + fan_obj = Chassis().get_fan_drawer(i) + if fan_obj.get_presence(): + sonic_logger.log_warning(f"Fan {fan_obj.get_name()} speed: " + f"{fan_obj.get_fan(0).get_speed()}%, {fan_obj.get_fan(1).get_speed()}%.") + else: + sonic_logger.log_warning(f"Fan {fan_obj.get_name()} not presence.") + for i in range(4): + psu_obj = Chassis().get_psu(i) + if psu_obj.get_presence(): + sonic_logger.log_warning(f"{psu_obj.get_name()}: {psu_obj.get_voltage()}V, " + f"{psu_obj.get_current()}A, {psu_obj.get_power()}W.") + else: + sonic_logger.log_warning(f"{fan_obj.get_name()} not presence.") + except Exception as e: + sonic_logger.log_warning(" Fail to save fan and psu info {}".format(repr(e))) + sonic_logger.log_error("Alarm for temperature critical is detected, reboot Device") + os.system('reboot') + @thermal_json_object('thermal_control.control') class ControlThermalAlgoAction(ThermalPolicyActionBase): """ @@ -177,10 +213,12 @@ def load_from_json(self, json_obj): elif status_str == 'false': self.status = False else: - raise ValueError(f'Invalid {ControlThermalAlgoAction.JSON_FIELD_STATUS} field value, please specify true of false') + raise ValueError('Invalid {} field value, please specify true of false'. + format(ControlThermalAlgoAction.JSON_FIELD_STATUS)) else: raise ValueError('ControlThermalAlgoAction ' - f'missing mandatory field {ControlThermalAlgoAction.JSON_FIELD_STATUS} in JSON policy file') + 'missing mandatory field {} in JSON policy file'. + format(ControlThermalAlgoAction.JSON_FIELD_STATUS)) def execute(self, thermal_info_dict): """ diff --git a/ixr7220h6-128/sonic_platform/thermal_infos.py b/ixr7220h6-128/sonic_platform/thermal_infos.py old mode 100755 new mode 100644 index 5b60d3b..27b6d4a --- a/ixr7220h6-128/sonic_platform/thermal_infos.py +++ b/ixr7220h6-128/sonic_platform/thermal_infos.py @@ -71,10 +71,14 @@ class ThermalInfo(ThermalPolicyInfoBase): def __init__(self): self._old_threshold_level = -1 self._current_threshold_level = 0 - self._num_fan_levels = 1 - self._level_up_threshold = [[55, 60, 65, 55, 65, 100, 100, 100, 75, 60, 55, 55, 85, 65, 65, 60, 80]] + self._num_fan_levels = 3 + self._level_up_threshold = [[44, 54, 51, 52, 45, 53, 50, 44, 43, 45, 44, 43, 43, 47, 47, 83, 56, 58, 47, 73], + [50, 60, 57, 58, 51, 59, 56, 51, 50, 52, 51, 50, 50, 53, 53, 88, 61, 68, 51, 86], + [55, 65, 62, 63, 56, 64, 61, 56, 55, 57, 56, 55, 55, 57, 57, 93, 66, 73, 55, 91]] - self._level_down_threshold = [[45, 36, 45, 45, 50, 68, 68, 68, 60, 36, 45, 45, 68, 40, 45, 35, 55]] + self._level_down_threshold = [[31, 44, 41, 42, 35, 43, 40, 34, 33, 35, 34, 32, 32, 35, 35, 70, 42, 50, 33, 70], + [39, 52, 49, 50, 43, 51, 48, 42, 41, 43, 42, 41, 41, 45, 45, 78, 48, 60, 40, 75], + [48, 58, 55, 56, 49, 57, 54, 49, 48, 50, 49, 48, 48, 51, 51, 83, 54, 69, 47, 80]] def collect(self, chassis): """ @@ -86,6 +90,7 @@ def collect(self, chassis): self._over_high_critical_threshold = False self._set_fan_default_speed = False self._set_fan_threshold_one_speed = False + self._set_fan_threshold_two_speed = False self._set_fan_high_temp_speed = False # Calculate average temp within the device @@ -98,7 +103,6 @@ def collect(self, chassis): min_level = [self._num_fan_levels for i in range(num_of_thermals)] for index in range(num_of_thermals): for level in range(self._num_fan_levels): - if self._temps[index]>self._level_up_threshold[level][index]: if max_level Date: Thu, 19 Feb 2026 14:39:10 -0500 Subject: [PATCH 3/3] [H6-128]Update FPGA/CPLDs driver, add port_notify --- ...sonic-platform-nokia-ixr7220h6-128.install | 3 +- ...onic-platform-nokia-ixr7220h6-128.postinst | 7 +- ixr7220h6-128/modules/Makefile | 0 ixr7220h6-128/modules/h6_i2c_oc.c | 250 +++++++-------- ixr7220h6-128/modules/i2c-ocores.c | 288 +++++++++--------- ixr7220h6-128/modules/port_cpld0.c | 160 ++++++---- ixr7220h6-128/modules/port_cpld1.c | 160 ++++++---- ixr7220h6-128/modules/port_cpld2.c | 108 ++++--- ixr7220h6-128/modules/sys_cpld.c | 6 +- ixr7220h6-128/scripts/h6_128_platform_init.sh | 2 +- ixr7220h6-128/scripts/ports_notify.py | 121 ++++++++ ixr7220h6-128/scripts/set_ps.py | 2 +- .../service/h6_128_platform_init.service | 0 ixr7220h6-128/service/ports_notify.service | 15 + ixr7220h6-128/setup.py | 0 ixr7220h6-128/sonic_platform/__init__.py | 0 ixr7220h6-128/sonic_platform/chassis.py | 6 +- ixr7220h6-128/sonic_platform/component.py | 0 ixr7220h6-128/sonic_platform/eeprom.py | 0 ixr7220h6-128/sonic_platform/fan.py | 4 +- ixr7220h6-128/sonic_platform/fan_drawer.py | 0 ixr7220h6-128/sonic_platform/platform.py | 0 ixr7220h6-128/sonic_platform/psu.py | 2 +- ixr7220h6-128/sonic_platform/sfp.py | 0 ixr7220h6-128/sonic_platform/sfp_event.py | 0 ixr7220h6-128/sonic_platform/sysfs.py | 0 ixr7220h6-128/sonic_platform/test/README | 0 .../sonic_platform/test/test-chassis.py | 0 .../sonic_platform/test/test-component.py | 0 .../sonic_platform/test/test-eeprom.py | 0 .../sonic_platform/test/test-fan-drawer.py | 0 ixr7220h6-128/sonic_platform/test/test-fan.py | 0 ixr7220h6-128/sonic_platform/test/test-psu.py | 0 ixr7220h6-128/sonic_platform/test/test-sfp.py | 0 .../sonic_platform/test/test-thermal.py | 0 .../sonic_platform/test/test-watchdog.py | 0 ixr7220h6-128/sonic_platform/thermal.py | 0 .../sonic_platform/thermal_conditions.py | 0 .../sonic_platform/thermal_manager.py | 0 ixr7220h6-128/sonic_platform/watchdog.py | 0 40 files changed, 659 insertions(+), 475 deletions(-) mode change 100755 => 100644 ixr7220h6-128/modules/Makefile mode change 100755 => 100644 ixr7220h6-128/scripts/h6_128_platform_init.sh create mode 100644 ixr7220h6-128/scripts/ports_notify.py mode change 100755 => 100644 ixr7220h6-128/service/h6_128_platform_init.service create mode 100644 ixr7220h6-128/service/ports_notify.service mode change 100755 => 100644 ixr7220h6-128/setup.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/__init__.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/chassis.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/component.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/eeprom.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/fan.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/fan_drawer.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/platform.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/psu.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/sfp.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/sfp_event.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/sysfs.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/README mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-chassis.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-component.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-eeprom.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-fan-drawer.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-fan.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-psu.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-sfp.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-thermal.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/test/test-watchdog.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/thermal.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/thermal_conditions.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/thermal_manager.py mode change 100755 => 100644 ixr7220h6-128/sonic_platform/watchdog.py diff --git a/debian/sonic-platform-nokia-ixr7220h6-128.install b/debian/sonic-platform-nokia-ixr7220h6-128.install index fcb1a6d..61f96a5 100644 --- a/debian/sonic-platform-nokia-ixr7220h6-128.install +++ b/debian/sonic-platform-nokia-ixr7220h6-128.install @@ -1,5 +1,6 @@ ixr7220h6-128/scripts/h6_128_platform_init.sh usr/local/bin ixr7220h6-128/scripts/set_ps.py usr/local/bin +ixr7220h6-128/scripts/ports_notify.py usr/local/bin ixr7220h6-128/service/h6_128_platform_init.service etc/systemd/system -#ixr7220h6-128/service/ports_notify.service etc/systemd/system/ +ixr7220h6-128/service/ports_notify.service etc/systemd/system/ ixr7220h6-128/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-nokia_ixr7220_h6_128-r0 diff --git a/debian/sonic-platform-nokia-ixr7220h6-128.postinst b/debian/sonic-platform-nokia-ixr7220h6-128.postinst index f2b0921..640ea94 100644 --- a/debian/sonic-platform-nokia-ixr7220h6-128.postinst +++ b/debian/sonic-platform-nokia-ixr7220h6-128.postinst @@ -3,9 +3,10 @@ # # see: dh_installdeb(1) +chmod a+x /usr/local/bin/set_ps.py chmod a+x /usr/local/bin/h6_128_platform_init.sh systemctl enable h6_128_platform_init.service systemctl start h6_128_platform_init.service -chmod a+x /usr/local/bin/set_ps.py -# systemctl enable ports_notify.service -# systemctl start --no-block ports_notify.service +chmod a+x /usr/local/bin/ports_notify.py +systemctl enable ports_notify.service +systemctl start --no-block ports_notify.service diff --git a/ixr7220h6-128/modules/Makefile b/ixr7220h6-128/modules/Makefile old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/modules/h6_i2c_oc.c b/ixr7220h6-128/modules/h6_i2c_oc.c index 15162cc..c742853 100644 --- a/ixr7220h6-128/modules/h6_i2c_oc.c +++ b/ixr7220h6-128/modules/h6_i2c_oc.c @@ -55,137 +55,137 @@ MODULE_PARM_DESC(param_i2c_khz, "Target clock speed of i2c bus, in KHz."); static struct pci_dev *g_pcidev = NULL; static const uint adapt_offset[PORT_NUM]= { - 0x2100,// MESS_TOP_L_CPLD I2C Master OSFP Port1 +0x2100,// MESS_TOP_L_CPLD I2C Master OSFP Port1 0x2120,// MESS_TOP_L_CPLD I2C Master OSFP Port2 - 0x2100,// PORTCPLD0 I2C Master OSFP Port3 - 0x2120,// PORTCPLD0 I2C Master OSFP Port4 - 0x2140,// PORTCPLD0 I2C Master OSFP Port5 - 0x2160,// PORTCPLD0 I2C Master OSFP Port6 - 0x2100,// MESS_BOT_L_CPLD I2C Master OSFP Port7 - 0x2120,// MESS_BOT_L_CPLD I2C Master OSFP Port8 - 0x2140,// MESS_TOP_L_CPLD I2C Master OSFP Port9 - 0x2160,// MESS_TOP_L_CPLD I2C Master OSFP Port10 - 0x2180,// PORTCPLD0 I2C Master OSFP Port11 - 0x21A0,// PORTCPLD0 I2C Master OSFP Port12 - 0x21C0,// PORTCPLD0 I2C Master OSFP Port13 - 0x21E0,// PORTCPLD0 I2C Master OSFP Port14 - 0x2140,// MESS_BOT_L_CPLD I2C Master OSFP Port15 - 0x2160,// MESS_BOT_L_CPLD I2C Master OSFP Port16 - 0x2180,// MESS_TOP_L_CPLD I2C Master OSFP Port17 - 0x21A0,// MESS_TOP_L_CPLD I2C Master OSFP Port18 - 0x2200,// PORTCPLD0 I2C Master OSFP Port19 - 0x2220,// PORTCPLD0 I2C Master OSFP Port20 - 0x2240,// PORTCPLD0 I2C Master OSFP Port21 - 0x2260,// PORTCPLD0 I2C Master OSFP Port22 - 0x2180,// MESS_BOT_L_CPLD I2C Master OSFP Port23 - 0x21A0,// MESS_BOT_L_CPLD I2C Master OSFP Port24 - 0x21C0,// MESS_TOP_L_CPLD I2C Master OSFP Port25 - 0x21E0,// MESS_TOP_L_CPLD I2C Master OSFP Port26 - 0x2280,// PORTCPLD0 I2C Master OSFP Port27 - 0x22A0,// PORTCPLD0 I2C Master OSFP Port28 - 0x22C0,// PORTCPLD0 I2C Master OSFP Port29 - 0x22E0,// PORTCPLD0 I2C Master OSFP Port30 - 0x21C0,// MESS_BOT_L_CPLD I2C Master OSFP Port31 - 0x21E0,// MESS_BOT_L_CPLD I2C Master OSFP Port32 -////////////////////////////////////////////////////// - 0x2200,// MESS_TOP_L_CPLD I2C Master OSFP Port33 - 0x2220,// MESS_TOP_L_CPLD I2C Master OSFP Port34 - 0x2300,// PORTCPLD0 I2C Master OSFP Port35 - 0x2320,// PORTCPLD0 I2C Master OSFP Port36 - 0x2340,// PORTCPLD0 I2C Master OSFP Port37 - 0x2360,// PORTCPLD0 I2C Master OSFP Port38 - 0x2200,// MESS_BOT_L_CPLD I2C Master OSFP Port39 - 0x2220,// MESS_BOT_L_CPLD I2C Master OSFP Port40 - 0x2240,// MESS_TOP_L_CPLD I2C Master OSFP Port41 - 0x2260,// MESS_TOP_L_CPLD I2C Master OSFP Port42 + 0x2140,// MESS_TOP_L_CPLD I2C Master OSFP Port3 + 0x2160,// MESS_TOP_L_CPLD I2C Master OSFP Port4 + 0x2180,// MESS_TOP_L_CPLD I2C Master OSFP Port5 + 0x21A0,// MESS_TOP_L_CPLD I2C Master OSFP Port6 + 0x21C0,// MESS_TOP_L_CPLD I2C Master OSFP Port7 + 0x21E0,// MESS_TOP_L_CPLD I2C Master OSFP Port8 + 0x2200,// MESS_TOP_L_CPLD I2C Master OSFP Port9 + 0x2220,// MESS_TOP_L_CPLD I2C Master OSFP Port10 + 0x2240,// MESS_TOP_L_CPLD I2C Master OSFP Port11 + 0x2260,// MESS_TOP_L_CPLD I2C Master OSFP Port12 + 0x2280,// MESS_TOP_L_CPLD I2C Master OSFP Port13 + 0x22A0,// MESS_TOP_L_CPLD I2C Master OSFP Port14 + 0x22C0,// MESS_TOP_L_CPLD I2C Master OSFP Port15 + 0x22E0,// MESS_TOP_L_CPLD I2C Master OSFP Port16 + 0x2100,// MESS_TOP_R_CPLD I2C Master OSFP Port17 + 0x2120,// MESS_TOP_R_CPLD I2C Master OSFP Port18 + 0x2140,// MESS_TOP_R_CPLD I2C Master OSFP Port19 + 0x2160,// MESS_TOP_R_CPLD I2C Master OSFP Port20 + 0x2180,// MESS_TOP_R_CPLD I2C Master OSFP Port21 + 0x21A0,// MESS_TOP_R_CPLD I2C Master OSFP Port22 + 0x21C0,// MESS_TOP_R_CPLD I2C Master OSFP Port23 + 0x21E0,// MESS_TOP_R_CPLD I2C Master OSFP Port24 + 0x2200,// MESS_TOP_R_CPLD I2C Master OSFP Port25 + 0x2220,// MESS_TOP_R_CPLD I2C Master OSFP Port26 + 0x2240,// MESS_TOP_R_CPLD I2C Master OSFP Port27 + 0x2260,// MESS_TOP_R_CPLD I2C Master OSFP Port28 + 0x2280,// MESS_TOP_R_CPLD I2C Master OSFP Port29 + 0x22A0,// MESS_TOP_R_CPLD I2C Master OSFP Port30 + 0x22C0,// MESS_TOP_R_CPLD I2C Master OSFP Port31 + 0x22E0,// MESS_TOP_R_CPLD I2C Master OSFP Port32 +////////////////////////////////////////////////////// + 0x2100,// PORTCPLD0 I2C Master OSFP Port33 + 0x2120,// PORTCPLD0 I2C Master OSFP Port34 + 0x2180,// PORTCPLD0 I2C Master OSFP Port35 + 0x21A0,// PORTCPLD0 I2C Master OSFP Port36 + 0x2200,// PORTCPLD0 I2C Master OSFP Port37 + 0x2220,// PORTCPLD0 I2C Master OSFP Port38 + 0x2280,// PORTCPLD0 I2C Master OSFP Port39 + 0x22A0,// PORTCPLD0 I2C Master OSFP Port40 + 0x2300,// PORTCPLD0 I2C Master OSFP Port41 + 0x2320,// PORTCPLD0 I2C Master OSFP Port42 0x2380,// PORTCPLD0 I2C Master OSFP Port43 0x23A0,// PORTCPLD0 I2C Master OSFP Port44 - 0x23C0,// PORTCPLD0 I2C Master OSFP Port45 - 0x23E0,// PORTCPLD0 I2C Master OSFP Port46 - 0x2240,// MESS_BOT_L_CPLD I2C Master OSFP Port47 - 0x2260,// MESS_BOT_L_CPLD I2C Master OSFP Port48 - 0x2280,// MESS_TOP_L_CPLD I2C Master OSFP Port49 - 0x22A0,// MESS_TOP_L_CPLD I2C Master OSFP Port50 - 0x2400,// PORTCPLD0 I2C Master OSFP Port51 - 0x2420,// PORTCPLD0 I2C Master OSFP Port52 - 0x2440,// PORTCPLD0 I2C Master OSFP Port53 - 0x2460,// PORTCPLD0 I2C Master OSFP Port54 - 0x2280,// MESS_BOT_L_CPLD I2C Master OSFP Port55 - 0x22A0,// MESS_BOT_L_CPLD I2C Master OSFP Port56 - 0x22C0,// MESS_TOP_L_CPLD I2C Master OSFP Port57 - 0x22E0,// MESS_TOP_L_CPLD I2C Master OSFP Port58 - 0x2480,// PORTCPLD0 I2C Master OSFP Port59 - 0x24A0,// PORTCPLD0 I2C Master OSFP Port60 - 0x24C0,// PORTCPLD0 I2C Master OSFP Port61 - 0x24E0,// PORTCPLD0 I2C Master OSFP Port62 - 0x22C0,// MESS_BOT_L_CPLD I2C Master OSFP Port63 - 0x22E0,// MESS_BOT_L_CPLD I2C Master OSFP Port64 -////////////////////////////////////////////////////// - 0x2100,// MESS_TOP_R_CPLD I2C Master OSFP Port65 - 0x2120,// MESS_TOP_R_CPLD I2C Master OSFP Port66 - 0x2100,// PORTCPLD1 I2C Master OSFP Port67 - 0x2120,// PORTCPLD1 I2C Master OSFP Port68 - 0x2140,// PORTCPLD1 I2C Master OSFP Port69 - 0x2160,// PORTCPLD1 I2C Master OSFP Port70 - 0x2100,// MESS_BOT_R_CPLD I2C Master OSFP Port71 - 0x2120,// MESS_BOT_R_CPLD I2C Master OSFP Port72 - 0x2140,// MESS_TOP_R_CPLD I2C Master OSFP Port73 - 0x2160,// MESS_TOP_R_CPLD I2C Master OSFP Port74 - 0x2180,// PORTCPLD1 I2C Master OSFP Port75 - 0x21A0,// PORTCPLD1 I2C Master OSFP Port76 - 0x21C0,// PORTCPLD1 I2C Master OSFP Port77 - 0x21E0,// PORTCPLD1 I2C Master OSFP Port78 - 0x2140,// MESS_BOT_R_CPLD I2C Master OSFP Port79 - 0x2160,// MESS_BOT_R_CPLD I2C Master OSFP Port80 - 0x2180,// MESS_TOP_R_CPLD I2C Master OSFP Port81 - 0x21A0,// MESS_TOP_R_CPLD I2C Master OSFP Port82 - 0x2200,// PORTCPLD1 I2C Master OSFP Port83 - 0x2220,// PORTCPLD1 I2C Master OSFP Port84 + 0x2400,// PORTCPLD0 I2C Master OSFP Port45 + 0x2420,// PORTCPLD0 I2C Master OSFP Port46 + 0x2480,// PORTCPLD0 I2C Master OSFP Port47 + 0x24A0,// PORTCPLD0 I2C Master OSFP Port48 + 0x2100,// PORTCPLD1 I2C Master OSFP Port49 + 0x2120,// PORTCPLD1 I2C Master OSFP Port50 + 0x2180,// PORTCPLD1 I2C Master OSFP Port51 + 0x21A0,// PORTCPLD1 I2C Master OSFP Port52 + 0x2200,// PORTCPLD1 I2C Master OSFP Port53 + 0x2220,// PORTCPLD1 I2C Master OSFP Port54 + 0x2280,// PORTCPLD1 I2C Master OSFP Port55 + 0x22A0,// PORTCPLD1 I2C Master OSFP Port56 + 0x2300,// PORTCPLD1 I2C Master OSFP Port57 + 0x2320,// PORTCPLD1 I2C Master OSFP Port58 + 0x2380,// PORTCPLD1 I2C Master OSFP Port59 + 0x23A0,// PORTCPLD1 I2C Master OSFP Port60 + 0x2400,// PORTCPLD1 I2C Master OSFP Port61 + 0x2420,// PORTCPLD1 I2C Master OSFP Port62 + 0x2480,// PORTCPLD1 I2C Master OSFP Port63 + 0x24A0,// PORTCPLD1 I2C Master OSFP Port64 +////////////////////////////////////////////////////// + 0x2140,// PORTCPLD0 I2C Master OSFP Port65 + 0x2160,// PORTCPLD0 I2C Master OSFP Port66 + 0x21C0,// PORTCPLD0 I2C Master OSFP Port67 + 0x21E0,// PORTCPLD0 I2C Master OSFP Port68 + 0x2240,// PORTCPLD0 I2C Master OSFP Port69 + 0x2260,// PORTCPLD0 I2C Master OSFP Port70 + 0x22C0,// PORTCPLD0 I2C Master OSFP Port71 + 0x22E0,// PORTCPLD0 I2C Master OSFP Port72 + 0x2340,// PORTCPLD0 I2C Master OSFP Port73 + 0x2360,// PORTCPLD0 I2C Master OSFP Port74 + 0x23C0,// PORTCPLD0 I2C Master OSFP Port75 + 0x23E0,// PORTCPLD0 I2C Master OSFP Port76 + 0x2440,// PORTCPLD0 I2C Master OSFP Port77 + 0x2460,// PORTCPLD0 I2C Master OSFP Port78 + 0x24C0,// PORTCPLD0 I2C Master OSFP Port79 + 0x24E0,// PORTCPLD0 I2C Master OSFP Port80 + 0x2140,// PORTCPLD1 I2C Master OSFP Port81 + 0x2160,// PORTCPLD1 I2C Master OSFP Port82 + 0x21C0,// PORTCPLD1 I2C Master OSFP Port83 + 0x21E0,// PORTCPLD1 I2C Master OSFP Port84 0x2240,// PORTCPLD1 I2C Master OSFP Port85 0x2260,// PORTCPLD1 I2C Master OSFP Port86 - 0x2180,// MESS_BOT_R_CPLD I2C Master OSFP Port87 - 0x21A0,// MESS_BOT_R_CPLD I2C Master OSFP Port88 - 0x21C0,// MESS_TOP_R_CPLD I2C Master OSFP Port89 - 0x21E0,// MESS_TOP_R_CPLD I2C Master OSFP Port90 - 0x2280,// PORTCPLD1 I2C Master OSFP Port91 - 0x22A0,// PORTCPLD1 I2C Master OSFP Port92 - 0x22C0,// PORTCPLD1 I2C Master OSFP Port93 - 0x22E0,// PORTCPLD1 I2C Master OSFP Port94 - 0x21C0,// MESS_BOT_R_CPLD I2C Master OSFP Port95 - 0x21E0,// MESS_BOT_R_CPLD I2C Master OSFP Port96 -////////////////////////////////////////////////////// - 0x2200,// MESS_TOP_R_CPLD I2C Master OSFP Port97 - 0x2220,// MESS_TOP_R_CPLD I2C Master OSFP Port98 - 0x2300,// PORTCPLD1 I2C Master OSFP Port99 - 0x2320,// PORTCPLD1 I2C Master OSFP Port100 - 0x2340,// PORTCPLD1 I2C Master OSFP Port101 - 0x2360,// PORTCPLD1 I2C Master OSFP Port102 - 0x2200,// MESS_BOT_R_CPLD I2C Master OSFP Port103 - 0x2220,// MESS_BOT_R_CPLD I2C Master OSFP Port104 - 0x2240,// MESS_TOP_R_CPLD I2C Master OSFP Port105 - 0x2260,// MESS_TOP_R_CPLD I2C Master OSFP Port106 - 0x2380,// PORTCPLD1 I2C Master OSFP Port107 - 0x23A0,// PORTCPLD1 I2C Master OSFP Port108 - 0x23C0,// PORTCPLD1 I2C Master OSFP Port109 - 0x23E0,// PORTCPLD1 I2C Master OSFP Port110 - 0x2240,// MESS_BOT_R_CPLD I2C Master OSFP Port111 - 0x2260,// MESS_BOT_R_CPLD I2C Master OSFP Port112 - 0x2280,// MESS_TOP_R_CPLD I2C Master OSFP Port113 - 0x22A0,// MESS_TOP_R_CPLD I2C Master OSFP Port114 - 0x2400,// PORTCPLD1 I2C Master OSFP Port115 - 0x2420,// PORTCPLD1 I2C Master OSFP Port116 - 0x2440,// PORTCPLD1 I2C Master OSFP Port117 - 0x2460,// PORTCPLD1 I2C Master OSFP Port118 - 0x2280,// MESS_BOT_R_CPLD I2C Master OSFP Port119 - 0x22A0,// MESS_BOT_R_CPLD I2C Master OSFP Port120 - 0x22C0,// MESS_TOP_R_CPLD I2C Master OSFP Port121 - 0x22E0,// MESS_TOP_R_CPLD I2C Master OSFP Port122 - 0x2480,// PORTCPLD1 I2C Master OSFP Port123 - 0x24A0,// PORTCPLD1 I2C Master OSFP Port124 - 0x24C0,// PORTCPLD1 I2C Master OSFP Port125 - 0x24E0,// PORTCPLD1 I2C Master OSFP Port126 + 0x22C0,// PORTCPLD1 I2C Master OSFP Port87 + 0x22E0,// PORTCPLD1 I2C Master OSFP Port88 + 0x2340,// PORTCPLD1 I2C Master OSFP Port89 + 0x2360,// PORTCPLD1 I2C Master OSFP Port90 + 0x23C0,// PORTCPLD1 I2C Master OSFP Port91 + 0x23E0,// PORTCPLD1 I2C Master OSFP Port92 + 0x2440,// PORTCPLD1 I2C Master OSFP Port93 + 0x2460,// PORTCPLD1 I2C Master OSFP Port94 + 0x24C0,// PORTCPLD1 I2C Master OSFP Port95 + 0x24E0,// PORTCPLD1 I2C Master OSFP Port96 +////////////////////////////////////////////////////// + 0x2100,// MESS_BOT_L_CPLD I2C Master OSFP Port97 + 0x2120,// MESS_BOT_L_CPLD I2C Master OSFP Port98 + 0x2140,// MESS_BOT_L_CPLD I2C Master OSFP Port99 + 0x2160,// MESS_BOT_L_CPLD I2C Master OSFP Port100 + 0x2180,// MESS_BOT_L_CPLD I2C Master OSFP Port101 + 0x21A0,// MESS_BOT_L_CPLD I2C Master OSFP Port102 + 0x21C0,// MESS_BOT_L_CPLD I2C Master OSFP Port103 + 0x21E0,// MESS_BOT_L_CPLD I2C Master OSFP Port104 + 0x2200,// MESS_BOT_L_CPLD I2C Master OSFP Port105 + 0x2220,// MESS_BOT_L_CPLD I2C Master OSFP Port106 + 0x2240,// MESS_BOT_L_CPLD I2C Master OSFP Port107 + 0x2260,// MESS_BOT_L_CPLD I2C Master OSFP Port108 + 0x2280,// MESS_BOT_L_CPLD I2C Master OSFP Port109 + 0x22A0,// MESS_BOT_L_CPLD I2C Master OSFP Port110 + 0x22C0,// MESS_BOT_L_CPLD I2C Master OSFP Port111 + 0x22E0,// MESS_BOT_L_CPLD I2C Master OSFP Port112 + 0x2100,// MESS_BOT_R_CPLD I2C Master OSFP Port113 + 0x2120,// MESS_BOT_R_CPLD I2C Master OSFP Port114 + 0x2140,// MESS_BOT_R_CPLD I2C Master OSFP Port115 + 0x2160,// MESS_BOT_R_CPLD I2C Master OSFP Port116 + 0x2180,// MESS_BOT_R_CPLD I2C Master OSFP Port117 + 0x21A0,// MESS_BOT_R_CPLD I2C Master OSFP Port118 + 0x21C0,// MESS_BOT_R_CPLD I2C Master OSFP Port119 + 0x21E0,// MESS_BOT_R_CPLD I2C Master OSFP Port120 + 0x2200,// MESS_BOT_R_CPLD I2C Master OSFP Port121 + 0x2220,// MESS_BOT_R_CPLD I2C Master OSFP Port122 + 0x2240,// MESS_BOT_R_CPLD I2C Master OSFP Port123 + 0x2260,// MESS_BOT_R_CPLD I2C Master OSFP Port124 + 0x2280,// MESS_BOT_R_CPLD I2C Master OSFP Port125 + 0x22A0,// MESS_BOT_R_CPLD I2C Master OSFP Port126 0x22C0,// MESS_BOT_R_CPLD I2C Master OSFP Port127 - 0x22E0,// MESS_BOT_R_CPLD I2C Master OSFP Port128 + 0x22E0,// MESS_BOT_R_CPLD I2C Master OSFP Port128 0x2500,// MESS_BOT_R_CPLD I2C Master SFP Port1 0x2520,// MESS_BOT_R_CPLD I2C Master SFP Port2 }; diff --git a/ixr7220h6-128/modules/i2c-ocores.c b/ixr7220h6-128/modules/i2c-ocores.c index b4c7ddb..a6c87b8 100644 --- a/ixr7220h6-128/modules/i2c-ocores.c +++ b/ixr7220h6-128/modules/i2c-ocores.c @@ -41,27 +41,27 @@ MODULE_PARM_DESC(param_timeout, "for debugging. 1 ms should be enough"); // spi mux mapping table // ex : arr_spi_mux [0] = port 1 = dev_id 0 = spi mux 0x04 -// ex : arr_spi_mux [2] = port 3 = dev_id 2 = spi mux 0x0 +// ex : arr_spi_mux [32] = port 33 = dev_id 32 = spi mux 0x0 static uint8_t arr_spi_mux[] = { - // left part 64 port - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, - - // right part 64 port - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, - 0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, + // top part 64 port + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + + // bottom part 64 port + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // SFP 0x01, 0x01 @@ -71,135 +71,135 @@ static uint8_t arr_spi_mux[] = { static const uint arr_pcie_offset[PORT_NUM]= { 0x2100,// MESS_TOP_L_CPLD I2C Master OSFP Port1 0x2120,// MESS_TOP_L_CPLD I2C Master OSFP Port2 - 0x2100,// PORTCPLD0 I2C Master OSFP Port3 - 0x2120,// PORTCPLD0 I2C Master OSFP Port4 - 0x2140,// PORTCPLD0 I2C Master OSFP Port5 - 0x2160,// PORTCPLD0 I2C Master OSFP Port6 - 0x2100,// MESS_BOT_L_CPLD I2C Master OSFP Port7 - 0x2120,// MESS_BOT_L_CPLD I2C Master OSFP Port8 - 0x2140,// MESS_TOP_L_CPLD I2C Master OSFP Port9 - 0x2160,// MESS_TOP_L_CPLD I2C Master OSFP Port10 - 0x2180,// PORTCPLD0 I2C Master OSFP Port11 - 0x21A0,// PORTCPLD0 I2C Master OSFP Port12 - 0x21C0,// PORTCPLD0 I2C Master OSFP Port13 - 0x21E0,// PORTCPLD0 I2C Master OSFP Port14 - 0x2140,// MESS_BOT_L_CPLD I2C Master OSFP Port15 - 0x2160,// MESS_BOT_L_CPLD I2C Master OSFP Port16 - 0x2180,// MESS_TOP_L_CPLD I2C Master OSFP Port17 - 0x21A0,// MESS_TOP_L_CPLD I2C Master OSFP Port18 - 0x2200,// PORTCPLD0 I2C Master OSFP Port19 - 0x2220,// PORTCPLD0 I2C Master OSFP Port20 - 0x2240,// PORTCPLD0 I2C Master OSFP Port21 - 0x2260,// PORTCPLD0 I2C Master OSFP Port22 - 0x2180,// MESS_BOT_L_CPLD I2C Master OSFP Port23 - 0x21A0,// MESS_BOT_L_CPLD I2C Master OSFP Port24 - 0x21C0,// MESS_TOP_L_CPLD I2C Master OSFP Port25 - 0x21E0,// MESS_TOP_L_CPLD I2C Master OSFP Port26 - 0x2280,// PORTCPLD0 I2C Master OSFP Port27 - 0x22A0,// PORTCPLD0 I2C Master OSFP Port28 - 0x22C0,// PORTCPLD0 I2C Master OSFP Port29 - 0x22E0,// PORTCPLD0 I2C Master OSFP Port30 - 0x21C0,// MESS_BOT_L_CPLD I2C Master OSFP Port31 - 0x21E0,// MESS_BOT_L_CPLD I2C Master OSFP Port32 -////////////////////////////////////////////////////// - 0x2200,// MESS_TOP_L_CPLD I2C Master OSFP Port33 - 0x2220,// MESS_TOP_L_CPLD I2C Master OSFP Port34 - 0x2300,// PORTCPLD0 I2C Master OSFP Port35 - 0x2320,// PORTCPLD0 I2C Master OSFP Port36 - 0x2340,// PORTCPLD0 I2C Master OSFP Port37 - 0x2360,// PORTCPLD0 I2C Master OSFP Port38 - 0x2200,// MESS_BOT_L_CPLD I2C Master OSFP Port39 - 0x2220,// MESS_BOT_L_CPLD I2C Master OSFP Port40 - 0x2240,// MESS_TOP_L_CPLD I2C Master OSFP Port41 - 0x2260,// MESS_TOP_L_CPLD I2C Master OSFP Port42 + 0x2140,// MESS_TOP_L_CPLD I2C Master OSFP Port3 + 0x2160,// MESS_TOP_L_CPLD I2C Master OSFP Port4 + 0x2180,// MESS_TOP_L_CPLD I2C Master OSFP Port5 + 0x21A0,// MESS_TOP_L_CPLD I2C Master OSFP Port6 + 0x21C0,// MESS_TOP_L_CPLD I2C Master OSFP Port7 + 0x21E0,// MESS_TOP_L_CPLD I2C Master OSFP Port8 + 0x2200,// MESS_TOP_L_CPLD I2C Master OSFP Port9 + 0x2220,// MESS_TOP_L_CPLD I2C Master OSFP Port10 + 0x2240,// MESS_TOP_L_CPLD I2C Master OSFP Port11 + 0x2260,// MESS_TOP_L_CPLD I2C Master OSFP Port12 + 0x2280,// MESS_TOP_L_CPLD I2C Master OSFP Port13 + 0x22A0,// MESS_TOP_L_CPLD I2C Master OSFP Port14 + 0x22C0,// MESS_TOP_L_CPLD I2C Master OSFP Port15 + 0x22E0,// MESS_TOP_L_CPLD I2C Master OSFP Port16 + 0x2100,// MESS_TOP_R_CPLD I2C Master OSFP Port17 + 0x2120,// MESS_TOP_R_CPLD I2C Master OSFP Port18 + 0x2140,// MESS_TOP_R_CPLD I2C Master OSFP Port19 + 0x2160,// MESS_TOP_R_CPLD I2C Master OSFP Port20 + 0x2180,// MESS_TOP_R_CPLD I2C Master OSFP Port21 + 0x21A0,// MESS_TOP_R_CPLD I2C Master OSFP Port22 + 0x21C0,// MESS_TOP_R_CPLD I2C Master OSFP Port23 + 0x21E0,// MESS_TOP_R_CPLD I2C Master OSFP Port24 + 0x2200,// MESS_TOP_R_CPLD I2C Master OSFP Port25 + 0x2220,// MESS_TOP_R_CPLD I2C Master OSFP Port26 + 0x2240,// MESS_TOP_R_CPLD I2C Master OSFP Port27 + 0x2260,// MESS_TOP_R_CPLD I2C Master OSFP Port28 + 0x2280,// MESS_TOP_R_CPLD I2C Master OSFP Port29 + 0x22A0,// MESS_TOP_R_CPLD I2C Master OSFP Port30 + 0x22C0,// MESS_TOP_R_CPLD I2C Master OSFP Port31 + 0x22E0,// MESS_TOP_R_CPLD I2C Master OSFP Port32 +////////////////////////////////////////////////////// + 0x2100,// PORTCPLD0 I2C Master OSFP Port33 + 0x2120,// PORTCPLD0 I2C Master OSFP Port34 + 0x2180,// PORTCPLD0 I2C Master OSFP Port35 + 0x21A0,// PORTCPLD0 I2C Master OSFP Port36 + 0x2200,// PORTCPLD0 I2C Master OSFP Port37 + 0x2220,// PORTCPLD0 I2C Master OSFP Port38 + 0x2280,// PORTCPLD0 I2C Master OSFP Port39 + 0x22A0,// PORTCPLD0 I2C Master OSFP Port40 + 0x2300,// PORTCPLD0 I2C Master OSFP Port41 + 0x2320,// PORTCPLD0 I2C Master OSFP Port42 0x2380,// PORTCPLD0 I2C Master OSFP Port43 0x23A0,// PORTCPLD0 I2C Master OSFP Port44 - 0x23C0,// PORTCPLD0 I2C Master OSFP Port45 - 0x23E0,// PORTCPLD0 I2C Master OSFP Port46 - 0x2240,// MESS_BOT_L_CPLD I2C Master OSFP Port47 - 0x2260,// MESS_BOT_L_CPLD I2C Master OSFP Port48 - 0x2280,// MESS_TOP_L_CPLD I2C Master OSFP Port49 - 0x22A0,// MESS_TOP_L_CPLD I2C Master OSFP Port50 - 0x2400,// PORTCPLD0 I2C Master OSFP Port51 - 0x2420,// PORTCPLD0 I2C Master OSFP Port52 - 0x2440,// PORTCPLD0 I2C Master OSFP Port53 - 0x2460,// PORTCPLD0 I2C Master OSFP Port54 - 0x2280,// MESS_BOT_L_CPLD I2C Master OSFP Port55 - 0x22A0,// MESS_BOT_L_CPLD I2C Master OSFP Port56 - 0x22C0,// MESS_TOP_L_CPLD I2C Master OSFP Port57 - 0x22E0,// MESS_TOP_L_CPLD I2C Master OSFP Port58 - 0x2480,// PORTCPLD0 I2C Master OSFP Port59 - 0x24A0,// PORTCPLD0 I2C Master OSFP Port60 - 0x24C0,// PORTCPLD0 I2C Master OSFP Port61 - 0x24E0,// PORTCPLD0 I2C Master OSFP Port62 - 0x22C0,// MESS_BOT_L_CPLD I2C Master OSFP Port63 - 0x22E0,// MESS_BOT_L_CPLD I2C Master OSFP Port64 -////////////////////////////////////////////////////// - 0x2100,// MESS_TOP_R_CPLD I2C Master OSFP Port65 - 0x2120,// MESS_TOP_R_CPLD I2C Master OSFP Port66 - 0x2100,// PORTCPLD1 I2C Master OSFP Port67 - 0x2120,// PORTCPLD1 I2C Master OSFP Port68 - 0x2140,// PORTCPLD1 I2C Master OSFP Port69 - 0x2160,// PORTCPLD1 I2C Master OSFP Port70 - 0x2100,// MESS_BOT_R_CPLD I2C Master OSFP Port71 - 0x2120,// MESS_BOT_R_CPLD I2C Master OSFP Port72 - 0x2140,// MESS_TOP_R_CPLD I2C Master OSFP Port73 - 0x2160,// MESS_TOP_R_CPLD I2C Master OSFP Port74 - 0x2180,// PORTCPLD1 I2C Master OSFP Port75 - 0x21A0,// PORTCPLD1 I2C Master OSFP Port76 - 0x21C0,// PORTCPLD1 I2C Master OSFP Port77 - 0x21E0,// PORTCPLD1 I2C Master OSFP Port78 - 0x2140,// MESS_BOT_R_CPLD I2C Master OSFP Port79 - 0x2160,// MESS_BOT_R_CPLD I2C Master OSFP Port80 - 0x2180,// MESS_TOP_R_CPLD I2C Master OSFP Port81 - 0x21A0,// MESS_TOP_R_CPLD I2C Master OSFP Port82 - 0x2200,// PORTCPLD1 I2C Master OSFP Port83 - 0x2220,// PORTCPLD1 I2C Master OSFP Port84 + 0x2400,// PORTCPLD0 I2C Master OSFP Port45 + 0x2420,// PORTCPLD0 I2C Master OSFP Port46 + 0x2480,// PORTCPLD0 I2C Master OSFP Port47 + 0x24A0,// PORTCPLD0 I2C Master OSFP Port48 + 0x2100,// PORTCPLD1 I2C Master OSFP Port49 + 0x2120,// PORTCPLD1 I2C Master OSFP Port50 + 0x2180,// PORTCPLD1 I2C Master OSFP Port51 + 0x21A0,// PORTCPLD1 I2C Master OSFP Port52 + 0x2200,// PORTCPLD1 I2C Master OSFP Port53 + 0x2220,// PORTCPLD1 I2C Master OSFP Port54 + 0x2280,// PORTCPLD1 I2C Master OSFP Port55 + 0x22A0,// PORTCPLD1 I2C Master OSFP Port56 + 0x2300,// PORTCPLD1 I2C Master OSFP Port57 + 0x2320,// PORTCPLD1 I2C Master OSFP Port58 + 0x2380,// PORTCPLD1 I2C Master OSFP Port59 + 0x23A0,// PORTCPLD1 I2C Master OSFP Port60 + 0x2400,// PORTCPLD1 I2C Master OSFP Port61 + 0x2420,// PORTCPLD1 I2C Master OSFP Port62 + 0x2480,// PORTCPLD1 I2C Master OSFP Port63 + 0x24A0,// PORTCPLD1 I2C Master OSFP Port64 +////////////////////////////////////////////////////// + 0x2140,// PORTCPLD0 I2C Master OSFP Port65 + 0x2160,// PORTCPLD0 I2C Master OSFP Port66 + 0x21C0,// PORTCPLD0 I2C Master OSFP Port67 + 0x21E0,// PORTCPLD0 I2C Master OSFP Port68 + 0x2240,// PORTCPLD0 I2C Master OSFP Port69 + 0x2260,// PORTCPLD0 I2C Master OSFP Port70 + 0x22C0,// PORTCPLD0 I2C Master OSFP Port71 + 0x22E0,// PORTCPLD0 I2C Master OSFP Port72 + 0x2340,// PORTCPLD0 I2C Master OSFP Port73 + 0x2360,// PORTCPLD0 I2C Master OSFP Port74 + 0x23C0,// PORTCPLD0 I2C Master OSFP Port75 + 0x23E0,// PORTCPLD0 I2C Master OSFP Port76 + 0x2440,// PORTCPLD0 I2C Master OSFP Port77 + 0x2460,// PORTCPLD0 I2C Master OSFP Port78 + 0x24C0,// PORTCPLD0 I2C Master OSFP Port79 + 0x24E0,// PORTCPLD0 I2C Master OSFP Port80 + 0x2140,// PORTCPLD1 I2C Master OSFP Port81 + 0x2160,// PORTCPLD1 I2C Master OSFP Port82 + 0x21C0,// PORTCPLD1 I2C Master OSFP Port83 + 0x21E0,// PORTCPLD1 I2C Master OSFP Port84 0x2240,// PORTCPLD1 I2C Master OSFP Port85 0x2260,// PORTCPLD1 I2C Master OSFP Port86 - 0x2180,// MESS_BOT_R_CPLD I2C Master OSFP Port87 - 0x21A0,// MESS_BOT_R_CPLD I2C Master OSFP Port88 - 0x21C0,// MESS_TOP_R_CPLD I2C Master OSFP Port89 - 0x21E0,// MESS_TOP_R_CPLD I2C Master OSFP Port90 - 0x2280,// PORTCPLD1 I2C Master OSFP Port91 - 0x22A0,// PORTCPLD1 I2C Master OSFP Port92 - 0x22C0,// PORTCPLD1 I2C Master OSFP Port93 - 0x22E0,// PORTCPLD1 I2C Master OSFP Port94 - 0x21C0,// MESS_BOT_R_CPLD I2C Master OSFP Port95 - 0x21E0,// MESS_BOT_R_CPLD I2C Master OSFP Port96 -////////////////////////////////////////////////////// - 0x2200,// MESS_TOP_R_CPLD I2C Master OSFP Port97 - 0x2220,// MESS_TOP_R_CPLD I2C Master OSFP Port98 - 0x2300,// PORTCPLD1 I2C Master OSFP Port99 - 0x2320,// PORTCPLD1 I2C Master OSFP Port100 - 0x2340,// PORTCPLD1 I2C Master OSFP Port101 - 0x2360,// PORTCPLD1 I2C Master OSFP Port102 - 0x2200,// MESS_BOT_R_CPLD I2C Master OSFP Port103 - 0x2220,// MESS_BOT_R_CPLD I2C Master OSFP Port104 - 0x2240,// MESS_TOP_R_CPLD I2C Master OSFP Port105 - 0x2260,// MESS_TOP_R_CPLD I2C Master OSFP Port106 - 0x2380,// PORTCPLD1 I2C Master OSFP Port107 - 0x23A0,// PORTCPLD1 I2C Master OSFP Port108 - 0x23C0,// PORTCPLD1 I2C Master OSFP Port109 - 0x23E0,// PORTCPLD1 I2C Master OSFP Port110 - 0x2240,// MESS_BOT_R_CPLD I2C Master OSFP Port111 - 0x2260,// MESS_BOT_R_CPLD I2C Master OSFP Port112 - 0x2280,// MESS_TOP_R_CPLD I2C Master OSFP Port113 - 0x22A0,// MESS_TOP_R_CPLD I2C Master OSFP Port114 - 0x2400,// PORTCPLD1 I2C Master OSFP Port115 - 0x2420,// PORTCPLD1 I2C Master OSFP Port116 - 0x2440,// PORTCPLD1 I2C Master OSFP Port117 - 0x2460,// PORTCPLD1 I2C Master OSFP Port118 - 0x2280,// MESS_BOT_R_CPLD I2C Master OSFP Port119 - 0x22A0,// MESS_BOT_R_CPLD I2C Master OSFP Port120 - 0x22C0,// MESS_TOP_R_CPLD I2C Master OSFP Port121 - 0x22E0,// MESS_TOP_R_CPLD I2C Master OSFP Port122 - 0x2480,// PORTCPLD1 I2C Master OSFP Port123 - 0x24A0,// PORTCPLD1 I2C Master OSFP Port124 - 0x24C0,// PORTCPLD1 I2C Master OSFP Port125 - 0x24E0,// PORTCPLD1 I2C Master OSFP Port126 + 0x22C0,// PORTCPLD1 I2C Master OSFP Port87 + 0x22E0,// PORTCPLD1 I2C Master OSFP Port88 + 0x2340,// PORTCPLD1 I2C Master OSFP Port89 + 0x2360,// PORTCPLD1 I2C Master OSFP Port90 + 0x23C0,// PORTCPLD1 I2C Master OSFP Port91 + 0x23E0,// PORTCPLD1 I2C Master OSFP Port92 + 0x2440,// PORTCPLD1 I2C Master OSFP Port93 + 0x2460,// PORTCPLD1 I2C Master OSFP Port94 + 0x24C0,// PORTCPLD1 I2C Master OSFP Port95 + 0x24E0,// PORTCPLD1 I2C Master OSFP Port96 +////////////////////////////////////////////////////// + 0x2100,// MESS_BOT_L_CPLD I2C Master OSFP Port97 + 0x2120,// MESS_BOT_L_CPLD I2C Master OSFP Port98 + 0x2140,// MESS_BOT_L_CPLD I2C Master OSFP Port99 + 0x2160,// MESS_BOT_L_CPLD I2C Master OSFP Port100 + 0x2180,// MESS_BOT_L_CPLD I2C Master OSFP Port101 + 0x21A0,// MESS_BOT_L_CPLD I2C Master OSFP Port102 + 0x21C0,// MESS_BOT_L_CPLD I2C Master OSFP Port103 + 0x21E0,// MESS_BOT_L_CPLD I2C Master OSFP Port104 + 0x2200,// MESS_BOT_L_CPLD I2C Master OSFP Port105 + 0x2220,// MESS_BOT_L_CPLD I2C Master OSFP Port106 + 0x2240,// MESS_BOT_L_CPLD I2C Master OSFP Port107 + 0x2260,// MESS_BOT_L_CPLD I2C Master OSFP Port108 + 0x2280,// MESS_BOT_L_CPLD I2C Master OSFP Port109 + 0x22A0,// MESS_BOT_L_CPLD I2C Master OSFP Port110 + 0x22C0,// MESS_BOT_L_CPLD I2C Master OSFP Port111 + 0x22E0,// MESS_BOT_L_CPLD I2C Master OSFP Port112 + 0x2100,// MESS_BOT_R_CPLD I2C Master OSFP Port113 + 0x2120,// MESS_BOT_R_CPLD I2C Master OSFP Port114 + 0x2140,// MESS_BOT_R_CPLD I2C Master OSFP Port115 + 0x2160,// MESS_BOT_R_CPLD I2C Master OSFP Port116 + 0x2180,// MESS_BOT_R_CPLD I2C Master OSFP Port117 + 0x21A0,// MESS_BOT_R_CPLD I2C Master OSFP Port118 + 0x21C0,// MESS_BOT_R_CPLD I2C Master OSFP Port119 + 0x21E0,// MESS_BOT_R_CPLD I2C Master OSFP Port120 + 0x2200,// MESS_BOT_R_CPLD I2C Master OSFP Port121 + 0x2220,// MESS_BOT_R_CPLD I2C Master OSFP Port122 + 0x2240,// MESS_BOT_R_CPLD I2C Master OSFP Port123 + 0x2260,// MESS_BOT_R_CPLD I2C Master OSFP Port124 + 0x2280,// MESS_BOT_R_CPLD I2C Master OSFP Port125 + 0x22A0,// MESS_BOT_R_CPLD I2C Master OSFP Port126 0x22C0,// MESS_BOT_R_CPLD I2C Master OSFP Port127 - 0x22E0,// MESS_BOT_R_CPLD I2C Master OSFP Port128 + 0x22E0,// MESS_BOT_R_CPLD I2C Master OSFP Port128 0x2500,// MESS_BOT_R_CPLD I2C Master SFP Port1 0x2520,// MESS_BOT_R_CPLD I2C Master SFP Port2 }; diff --git a/ixr7220h6-128/modules/port_cpld0.c b/ixr7220h6-128/modules/port_cpld0.c index d12aa95..2518f1b 100644 --- a/ixr7220h6-128/modules/port_cpld0.c +++ b/ixr7220h6-128/modules/port_cpld0.c @@ -36,6 +36,7 @@ #define PORT_RST_REG0 0x78 #define PORT_MODPRS_REG0 0x88 #define PORT_PWGOOD_REG0 0x90 +#define PORT_ENABLE_REG0 0x98 static const unsigned short cpld_address_list[] = {0x74, I2C_CLIENT_END}; @@ -232,17 +233,44 @@ static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *deva return sprintf(buf, "0x%02x\n", val); } -static ssize_t show_port_pwgood(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_port_en(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); u8 val = 0; - val = cpld_i2c_read(data, PORT_PWGOOD_REG0 + (sda->index / 8)); + return sprintf(buf, "na\n"); + val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); } +static ssize_t set_port_en(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + return 0; + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_ENABLE_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + // sysfs attributes static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); @@ -351,38 +379,38 @@ static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 1); static SENSOR_DEVICE_ATTR(modprs_reg3, S_IRUGO, show_modprs_reg, NULL, 2); static SENSOR_DEVICE_ATTR(modprs_reg4, S_IRUGO, show_modprs_reg, NULL, 3); -static SENSOR_DEVICE_ATTR(port_1_pwgood, S_IRUGO, show_port_pwgood, NULL, 0); -static SENSOR_DEVICE_ATTR(port_2_pwgood, S_IRUGO, show_port_pwgood, NULL, 1); -static SENSOR_DEVICE_ATTR(port_3_pwgood, S_IRUGO, show_port_pwgood, NULL, 2); -static SENSOR_DEVICE_ATTR(port_4_pwgood, S_IRUGO, show_port_pwgood, NULL, 3); -static SENSOR_DEVICE_ATTR(port_5_pwgood, S_IRUGO, show_port_pwgood, NULL, 4); -static SENSOR_DEVICE_ATTR(port_6_pwgood, S_IRUGO, show_port_pwgood, NULL, 5); -static SENSOR_DEVICE_ATTR(port_7_pwgood, S_IRUGO, show_port_pwgood, NULL, 6); -static SENSOR_DEVICE_ATTR(port_8_pwgood, S_IRUGO, show_port_pwgood, NULL, 7); -static SENSOR_DEVICE_ATTR(port_9_pwgood, S_IRUGO, show_port_pwgood, NULL, 8); -static SENSOR_DEVICE_ATTR(port_10_pwgood, S_IRUGO, show_port_pwgood, NULL, 9); -static SENSOR_DEVICE_ATTR(port_11_pwgood, S_IRUGO, show_port_pwgood, NULL, 10); -static SENSOR_DEVICE_ATTR(port_12_pwgood, S_IRUGO, show_port_pwgood, NULL, 11); -static SENSOR_DEVICE_ATTR(port_13_pwgood, S_IRUGO, show_port_pwgood, NULL, 12); -static SENSOR_DEVICE_ATTR(port_14_pwgood, S_IRUGO, show_port_pwgood, NULL, 13); -static SENSOR_DEVICE_ATTR(port_15_pwgood, S_IRUGO, show_port_pwgood, NULL, 14); -static SENSOR_DEVICE_ATTR(port_16_pwgood, S_IRUGO, show_port_pwgood, NULL, 15); -static SENSOR_DEVICE_ATTR(port_17_pwgood, S_IRUGO, show_port_pwgood, NULL, 16); -static SENSOR_DEVICE_ATTR(port_18_pwgood, S_IRUGO, show_port_pwgood, NULL, 17); -static SENSOR_DEVICE_ATTR(port_19_pwgood, S_IRUGO, show_port_pwgood, NULL, 18); -static SENSOR_DEVICE_ATTR(port_20_pwgood, S_IRUGO, show_port_pwgood, NULL, 19); -static SENSOR_DEVICE_ATTR(port_21_pwgood, S_IRUGO, show_port_pwgood, NULL, 20); -static SENSOR_DEVICE_ATTR(port_22_pwgood, S_IRUGO, show_port_pwgood, NULL, 21); -static SENSOR_DEVICE_ATTR(port_23_pwgood, S_IRUGO, show_port_pwgood, NULL, 22); -static SENSOR_DEVICE_ATTR(port_24_pwgood, S_IRUGO, show_port_pwgood, NULL, 23); -static SENSOR_DEVICE_ATTR(port_25_pwgood, S_IRUGO, show_port_pwgood, NULL, 24); -static SENSOR_DEVICE_ATTR(port_26_pwgood, S_IRUGO, show_port_pwgood, NULL, 25); -static SENSOR_DEVICE_ATTR(port_27_pwgood, S_IRUGO, show_port_pwgood, NULL, 26); -static SENSOR_DEVICE_ATTR(port_28_pwgood, S_IRUGO, show_port_pwgood, NULL, 27); -static SENSOR_DEVICE_ATTR(port_29_pwgood, S_IRUGO, show_port_pwgood, NULL, 28); -static SENSOR_DEVICE_ATTR(port_30_pwgood, S_IRUGO, show_port_pwgood, NULL, 29); -static SENSOR_DEVICE_ATTR(port_31_pwgood, S_IRUGO, show_port_pwgood, NULL, 30); -static SENSOR_DEVICE_ATTR(port_32_pwgood, S_IRUGO, show_port_pwgood, NULL, 31); +static SENSOR_DEVICE_ATTR(port_1_en, S_IRUGO, show_port_en, set_port_en, 0); +static SENSOR_DEVICE_ATTR(port_2_en, S_IRUGO, show_port_en, set_port_en, 1); +static SENSOR_DEVICE_ATTR(port_3_en, S_IRUGO, show_port_en, set_port_en, 2); +static SENSOR_DEVICE_ATTR(port_4_en, S_IRUGO, show_port_en, set_port_en, 3); +static SENSOR_DEVICE_ATTR(port_5_en, S_IRUGO, show_port_en, set_port_en, 4); +static SENSOR_DEVICE_ATTR(port_6_en, S_IRUGO, show_port_en, set_port_en, 5); +static SENSOR_DEVICE_ATTR(port_7_en, S_IRUGO, show_port_en, set_port_en, 6); +static SENSOR_DEVICE_ATTR(port_8_en, S_IRUGO, show_port_en, set_port_en, 7); +static SENSOR_DEVICE_ATTR(port_9_en, S_IRUGO, show_port_en, set_port_en, 8); +static SENSOR_DEVICE_ATTR(port_10_en, S_IRUGO, show_port_en, set_port_en, 9); +static SENSOR_DEVICE_ATTR(port_11_en, S_IRUGO, show_port_en, set_port_en, 10); +static SENSOR_DEVICE_ATTR(port_12_en, S_IRUGO, show_port_en, set_port_en, 11); +static SENSOR_DEVICE_ATTR(port_13_en, S_IRUGO, show_port_en, set_port_en, 12); +static SENSOR_DEVICE_ATTR(port_14_en, S_IRUGO, show_port_en, set_port_en, 13); +static SENSOR_DEVICE_ATTR(port_15_en, S_IRUGO, show_port_en, set_port_en, 14); +static SENSOR_DEVICE_ATTR(port_16_en, S_IRUGO, show_port_en, set_port_en, 15); +static SENSOR_DEVICE_ATTR(port_17_en, S_IRUGO, show_port_en, set_port_en, 16); +static SENSOR_DEVICE_ATTR(port_18_en, S_IRUGO, show_port_en, set_port_en, 17); +static SENSOR_DEVICE_ATTR(port_19_en, S_IRUGO, show_port_en, set_port_en, 18); +static SENSOR_DEVICE_ATTR(port_20_en, S_IRUGO, show_port_en, set_port_en, 19); +static SENSOR_DEVICE_ATTR(port_21_en, S_IRUGO, show_port_en, set_port_en, 20); +static SENSOR_DEVICE_ATTR(port_22_en, S_IRUGO, show_port_en, set_port_en, 21); +static SENSOR_DEVICE_ATTR(port_23_en, S_IRUGO, show_port_en, set_port_en, 22); +static SENSOR_DEVICE_ATTR(port_24_en, S_IRUGO, show_port_en, set_port_en, 23); +static SENSOR_DEVICE_ATTR(port_25_en, S_IRUGO, show_port_en, set_port_en, 24); +static SENSOR_DEVICE_ATTR(port_26_en, S_IRUGO, show_port_en, set_port_en, 25); +static SENSOR_DEVICE_ATTR(port_27_en, S_IRUGO, show_port_en, set_port_en, 26); +static SENSOR_DEVICE_ATTR(port_28_en, S_IRUGO, show_port_en, set_port_en, 27); +static SENSOR_DEVICE_ATTR(port_29_en, S_IRUGO, show_port_en, set_port_en, 28); +static SENSOR_DEVICE_ATTR(port_30_en, S_IRUGO, show_port_en, set_port_en, 29); +static SENSOR_DEVICE_ATTR(port_31_en, S_IRUGO, show_port_en, set_port_en, 30); +static SENSOR_DEVICE_ATTR(port_32_en, S_IRUGO, show_port_en, set_port_en, 31); static struct attribute *port_cpld0_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, @@ -492,38 +520,38 @@ static struct attribute *port_cpld0_attributes[] = { &sensor_dev_attr_modprs_reg3.dev_attr.attr, &sensor_dev_attr_modprs_reg4.dev_attr.attr, - &sensor_dev_attr_port_1_pwgood.dev_attr.attr, - &sensor_dev_attr_port_2_pwgood.dev_attr.attr, - &sensor_dev_attr_port_3_pwgood.dev_attr.attr, - &sensor_dev_attr_port_4_pwgood.dev_attr.attr, - &sensor_dev_attr_port_5_pwgood.dev_attr.attr, - &sensor_dev_attr_port_6_pwgood.dev_attr.attr, - &sensor_dev_attr_port_7_pwgood.dev_attr.attr, - &sensor_dev_attr_port_8_pwgood.dev_attr.attr, - &sensor_dev_attr_port_9_pwgood.dev_attr.attr, - &sensor_dev_attr_port_10_pwgood.dev_attr.attr, - &sensor_dev_attr_port_11_pwgood.dev_attr.attr, - &sensor_dev_attr_port_12_pwgood.dev_attr.attr, - &sensor_dev_attr_port_13_pwgood.dev_attr.attr, - &sensor_dev_attr_port_14_pwgood.dev_attr.attr, - &sensor_dev_attr_port_15_pwgood.dev_attr.attr, - &sensor_dev_attr_port_16_pwgood.dev_attr.attr, - &sensor_dev_attr_port_17_pwgood.dev_attr.attr, - &sensor_dev_attr_port_18_pwgood.dev_attr.attr, - &sensor_dev_attr_port_19_pwgood.dev_attr.attr, - &sensor_dev_attr_port_20_pwgood.dev_attr.attr, - &sensor_dev_attr_port_21_pwgood.dev_attr.attr, - &sensor_dev_attr_port_22_pwgood.dev_attr.attr, - &sensor_dev_attr_port_23_pwgood.dev_attr.attr, - &sensor_dev_attr_port_24_pwgood.dev_attr.attr, - &sensor_dev_attr_port_25_pwgood.dev_attr.attr, - &sensor_dev_attr_port_26_pwgood.dev_attr.attr, - &sensor_dev_attr_port_27_pwgood.dev_attr.attr, - &sensor_dev_attr_port_28_pwgood.dev_attr.attr, - &sensor_dev_attr_port_29_pwgood.dev_attr.attr, - &sensor_dev_attr_port_30_pwgood.dev_attr.attr, - &sensor_dev_attr_port_31_pwgood.dev_attr.attr, - &sensor_dev_attr_port_32_pwgood.dev_attr.attr, + &sensor_dev_attr_port_1_en.dev_attr.attr, + &sensor_dev_attr_port_2_en.dev_attr.attr, + &sensor_dev_attr_port_3_en.dev_attr.attr, + &sensor_dev_attr_port_4_en.dev_attr.attr, + &sensor_dev_attr_port_5_en.dev_attr.attr, + &sensor_dev_attr_port_6_en.dev_attr.attr, + &sensor_dev_attr_port_7_en.dev_attr.attr, + &sensor_dev_attr_port_8_en.dev_attr.attr, + &sensor_dev_attr_port_9_en.dev_attr.attr, + &sensor_dev_attr_port_10_en.dev_attr.attr, + &sensor_dev_attr_port_11_en.dev_attr.attr, + &sensor_dev_attr_port_12_en.dev_attr.attr, + &sensor_dev_attr_port_13_en.dev_attr.attr, + &sensor_dev_attr_port_14_en.dev_attr.attr, + &sensor_dev_attr_port_15_en.dev_attr.attr, + &sensor_dev_attr_port_16_en.dev_attr.attr, + &sensor_dev_attr_port_17_en.dev_attr.attr, + &sensor_dev_attr_port_18_en.dev_attr.attr, + &sensor_dev_attr_port_19_en.dev_attr.attr, + &sensor_dev_attr_port_20_en.dev_attr.attr, + &sensor_dev_attr_port_21_en.dev_attr.attr, + &sensor_dev_attr_port_22_en.dev_attr.attr, + &sensor_dev_attr_port_23_en.dev_attr.attr, + &sensor_dev_attr_port_24_en.dev_attr.attr, + &sensor_dev_attr_port_25_en.dev_attr.attr, + &sensor_dev_attr_port_26_en.dev_attr.attr, + &sensor_dev_attr_port_27_en.dev_attr.attr, + &sensor_dev_attr_port_28_en.dev_attr.attr, + &sensor_dev_attr_port_29_en.dev_attr.attr, + &sensor_dev_attr_port_30_en.dev_attr.attr, + &sensor_dev_attr_port_31_en.dev_attr.attr, + &sensor_dev_attr_port_32_en.dev_attr.attr, NULL }; diff --git a/ixr7220h6-128/modules/port_cpld1.c b/ixr7220h6-128/modules/port_cpld1.c index 9250cce..81b94ff 100644 --- a/ixr7220h6-128/modules/port_cpld1.c +++ b/ixr7220h6-128/modules/port_cpld1.c @@ -42,6 +42,7 @@ #define PORT_RST_REG0 0x78 #define PORT_MODPRS_REG0 0x88 #define PORT_PWGOOD_REG0 0x90 +#define PORT_ENABLE_REG0 0x98 static const unsigned short cpld_address_list[] = {0x75, I2C_CLIENT_END}; @@ -307,17 +308,44 @@ static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *deva return sprintf(buf, "0x%02x\n", val); } -static ssize_t show_port_pwgood(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_port_en(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); u8 val = 0; - val = cpld_i2c_read(data, PORT_PWGOOD_REG0 + (sda->index / 8)); + return sprintf(buf, "na\n"); + val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); } +static ssize_t set_port_en(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + return 0; + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << (sda->index % 8))) & 0xFF; + reg_val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); + reg_val = reg_val & mask; + usr_val = usr_val << (sda->index % 8); + cpld_i2c_write(data, PORT_ENABLE_REG0 + (sda->index / 8), (reg_val | usr_val)); + + return count; +} + // sysfs attributes static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_ver, NULL, 0); static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); @@ -435,38 +463,38 @@ static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 1); static SENSOR_DEVICE_ATTR(modprs_reg3, S_IRUGO, show_modprs_reg, NULL, 2); static SENSOR_DEVICE_ATTR(modprs_reg4, S_IRUGO, show_modprs_reg, NULL, 3); -static SENSOR_DEVICE_ATTR(port_1_pwgood, S_IRUGO, show_port_pwgood, NULL, 0); -static SENSOR_DEVICE_ATTR(port_2_pwgood, S_IRUGO, show_port_pwgood, NULL, 1); -static SENSOR_DEVICE_ATTR(port_3_pwgood, S_IRUGO, show_port_pwgood, NULL, 2); -static SENSOR_DEVICE_ATTR(port_4_pwgood, S_IRUGO, show_port_pwgood, NULL, 3); -static SENSOR_DEVICE_ATTR(port_5_pwgood, S_IRUGO, show_port_pwgood, NULL, 4); -static SENSOR_DEVICE_ATTR(port_6_pwgood, S_IRUGO, show_port_pwgood, NULL, 5); -static SENSOR_DEVICE_ATTR(port_7_pwgood, S_IRUGO, show_port_pwgood, NULL, 6); -static SENSOR_DEVICE_ATTR(port_8_pwgood, S_IRUGO, show_port_pwgood, NULL, 7); -static SENSOR_DEVICE_ATTR(port_9_pwgood, S_IRUGO, show_port_pwgood, NULL, 8); -static SENSOR_DEVICE_ATTR(port_10_pwgood, S_IRUGO, show_port_pwgood, NULL, 9); -static SENSOR_DEVICE_ATTR(port_11_pwgood, S_IRUGO, show_port_pwgood, NULL, 10); -static SENSOR_DEVICE_ATTR(port_12_pwgood, S_IRUGO, show_port_pwgood, NULL, 11); -static SENSOR_DEVICE_ATTR(port_13_pwgood, S_IRUGO, show_port_pwgood, NULL, 12); -static SENSOR_DEVICE_ATTR(port_14_pwgood, S_IRUGO, show_port_pwgood, NULL, 13); -static SENSOR_DEVICE_ATTR(port_15_pwgood, S_IRUGO, show_port_pwgood, NULL, 14); -static SENSOR_DEVICE_ATTR(port_16_pwgood, S_IRUGO, show_port_pwgood, NULL, 15); -static SENSOR_DEVICE_ATTR(port_17_pwgood, S_IRUGO, show_port_pwgood, NULL, 16); -static SENSOR_DEVICE_ATTR(port_18_pwgood, S_IRUGO, show_port_pwgood, NULL, 17); -static SENSOR_DEVICE_ATTR(port_19_pwgood, S_IRUGO, show_port_pwgood, NULL, 18); -static SENSOR_DEVICE_ATTR(port_20_pwgood, S_IRUGO, show_port_pwgood, NULL, 19); -static SENSOR_DEVICE_ATTR(port_21_pwgood, S_IRUGO, show_port_pwgood, NULL, 20); -static SENSOR_DEVICE_ATTR(port_22_pwgood, S_IRUGO, show_port_pwgood, NULL, 21); -static SENSOR_DEVICE_ATTR(port_23_pwgood, S_IRUGO, show_port_pwgood, NULL, 22); -static SENSOR_DEVICE_ATTR(port_24_pwgood, S_IRUGO, show_port_pwgood, NULL, 23); -static SENSOR_DEVICE_ATTR(port_25_pwgood, S_IRUGO, show_port_pwgood, NULL, 24); -static SENSOR_DEVICE_ATTR(port_26_pwgood, S_IRUGO, show_port_pwgood, NULL, 25); -static SENSOR_DEVICE_ATTR(port_27_pwgood, S_IRUGO, show_port_pwgood, NULL, 26); -static SENSOR_DEVICE_ATTR(port_28_pwgood, S_IRUGO, show_port_pwgood, NULL, 27); -static SENSOR_DEVICE_ATTR(port_29_pwgood, S_IRUGO, show_port_pwgood, NULL, 28); -static SENSOR_DEVICE_ATTR(port_30_pwgood, S_IRUGO, show_port_pwgood, NULL, 29); -static SENSOR_DEVICE_ATTR(port_31_pwgood, S_IRUGO, show_port_pwgood, NULL, 30); -static SENSOR_DEVICE_ATTR(port_32_pwgood, S_IRUGO, show_port_pwgood, NULL, 31); +static SENSOR_DEVICE_ATTR(port_1_en, S_IRUGO, show_port_en, set_port_en, 0); +static SENSOR_DEVICE_ATTR(port_2_en, S_IRUGO, show_port_en, set_port_en, 1); +static SENSOR_DEVICE_ATTR(port_3_en, S_IRUGO, show_port_en, set_port_en, 2); +static SENSOR_DEVICE_ATTR(port_4_en, S_IRUGO, show_port_en, set_port_en, 3); +static SENSOR_DEVICE_ATTR(port_5_en, S_IRUGO, show_port_en, set_port_en, 4); +static SENSOR_DEVICE_ATTR(port_6_en, S_IRUGO, show_port_en, set_port_en, 5); +static SENSOR_DEVICE_ATTR(port_7_en, S_IRUGO, show_port_en, set_port_en, 6); +static SENSOR_DEVICE_ATTR(port_8_en, S_IRUGO, show_port_en, set_port_en, 7); +static SENSOR_DEVICE_ATTR(port_9_en, S_IRUGO, show_port_en, set_port_en, 8); +static SENSOR_DEVICE_ATTR(port_10_en, S_IRUGO, show_port_en, set_port_en, 9); +static SENSOR_DEVICE_ATTR(port_11_en, S_IRUGO, show_port_en, set_port_en, 10); +static SENSOR_DEVICE_ATTR(port_12_en, S_IRUGO, show_port_en, set_port_en, 11); +static SENSOR_DEVICE_ATTR(port_13_en, S_IRUGO, show_port_en, set_port_en, 12); +static SENSOR_DEVICE_ATTR(port_14_en, S_IRUGO, show_port_en, set_port_en, 13); +static SENSOR_DEVICE_ATTR(port_15_en, S_IRUGO, show_port_en, set_port_en, 14); +static SENSOR_DEVICE_ATTR(port_16_en, S_IRUGO, show_port_en, set_port_en, 15); +static SENSOR_DEVICE_ATTR(port_17_en, S_IRUGO, show_port_en, set_port_en, 16); +static SENSOR_DEVICE_ATTR(port_18_en, S_IRUGO, show_port_en, set_port_en, 17); +static SENSOR_DEVICE_ATTR(port_19_en, S_IRUGO, show_port_en, set_port_en, 18); +static SENSOR_DEVICE_ATTR(port_20_en, S_IRUGO, show_port_en, set_port_en, 19); +static SENSOR_DEVICE_ATTR(port_21_en, S_IRUGO, show_port_en, set_port_en, 20); +static SENSOR_DEVICE_ATTR(port_22_en, S_IRUGO, show_port_en, set_port_en, 21); +static SENSOR_DEVICE_ATTR(port_23_en, S_IRUGO, show_port_en, set_port_en, 22); +static SENSOR_DEVICE_ATTR(port_24_en, S_IRUGO, show_port_en, set_port_en, 23); +static SENSOR_DEVICE_ATTR(port_25_en, S_IRUGO, show_port_en, set_port_en, 24); +static SENSOR_DEVICE_ATTR(port_26_en, S_IRUGO, show_port_en, set_port_en, 25); +static SENSOR_DEVICE_ATTR(port_27_en, S_IRUGO, show_port_en, set_port_en, 26); +static SENSOR_DEVICE_ATTR(port_28_en, S_IRUGO, show_port_en, set_port_en, 27); +static SENSOR_DEVICE_ATTR(port_29_en, S_IRUGO, show_port_en, set_port_en, 28); +static SENSOR_DEVICE_ATTR(port_30_en, S_IRUGO, show_port_en, set_port_en, 29); +static SENSOR_DEVICE_ATTR(port_31_en, S_IRUGO, show_port_en, set_port_en, 30); +static SENSOR_DEVICE_ATTR(port_32_en, S_IRUGO, show_port_en, set_port_en, 31); static struct attribute *port_cpld1_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, @@ -585,38 +613,38 @@ static struct attribute *port_cpld1_attributes[] = { &sensor_dev_attr_modprs_reg3.dev_attr.attr, &sensor_dev_attr_modprs_reg4.dev_attr.attr, - &sensor_dev_attr_port_1_pwgood.dev_attr.attr, - &sensor_dev_attr_port_2_pwgood.dev_attr.attr, - &sensor_dev_attr_port_3_pwgood.dev_attr.attr, - &sensor_dev_attr_port_4_pwgood.dev_attr.attr, - &sensor_dev_attr_port_5_pwgood.dev_attr.attr, - &sensor_dev_attr_port_6_pwgood.dev_attr.attr, - &sensor_dev_attr_port_7_pwgood.dev_attr.attr, - &sensor_dev_attr_port_8_pwgood.dev_attr.attr, - &sensor_dev_attr_port_9_pwgood.dev_attr.attr, - &sensor_dev_attr_port_10_pwgood.dev_attr.attr, - &sensor_dev_attr_port_11_pwgood.dev_attr.attr, - &sensor_dev_attr_port_12_pwgood.dev_attr.attr, - &sensor_dev_attr_port_13_pwgood.dev_attr.attr, - &sensor_dev_attr_port_14_pwgood.dev_attr.attr, - &sensor_dev_attr_port_15_pwgood.dev_attr.attr, - &sensor_dev_attr_port_16_pwgood.dev_attr.attr, - &sensor_dev_attr_port_17_pwgood.dev_attr.attr, - &sensor_dev_attr_port_18_pwgood.dev_attr.attr, - &sensor_dev_attr_port_19_pwgood.dev_attr.attr, - &sensor_dev_attr_port_20_pwgood.dev_attr.attr, - &sensor_dev_attr_port_21_pwgood.dev_attr.attr, - &sensor_dev_attr_port_22_pwgood.dev_attr.attr, - &sensor_dev_attr_port_23_pwgood.dev_attr.attr, - &sensor_dev_attr_port_24_pwgood.dev_attr.attr, - &sensor_dev_attr_port_25_pwgood.dev_attr.attr, - &sensor_dev_attr_port_26_pwgood.dev_attr.attr, - &sensor_dev_attr_port_27_pwgood.dev_attr.attr, - &sensor_dev_attr_port_28_pwgood.dev_attr.attr, - &sensor_dev_attr_port_29_pwgood.dev_attr.attr, - &sensor_dev_attr_port_30_pwgood.dev_attr.attr, - &sensor_dev_attr_port_31_pwgood.dev_attr.attr, - &sensor_dev_attr_port_32_pwgood.dev_attr.attr, + &sensor_dev_attr_port_1_en.dev_attr.attr, + &sensor_dev_attr_port_2_en.dev_attr.attr, + &sensor_dev_attr_port_3_en.dev_attr.attr, + &sensor_dev_attr_port_4_en.dev_attr.attr, + &sensor_dev_attr_port_5_en.dev_attr.attr, + &sensor_dev_attr_port_6_en.dev_attr.attr, + &sensor_dev_attr_port_7_en.dev_attr.attr, + &sensor_dev_attr_port_8_en.dev_attr.attr, + &sensor_dev_attr_port_9_en.dev_attr.attr, + &sensor_dev_attr_port_10_en.dev_attr.attr, + &sensor_dev_attr_port_11_en.dev_attr.attr, + &sensor_dev_attr_port_12_en.dev_attr.attr, + &sensor_dev_attr_port_13_en.dev_attr.attr, + &sensor_dev_attr_port_14_en.dev_attr.attr, + &sensor_dev_attr_port_15_en.dev_attr.attr, + &sensor_dev_attr_port_16_en.dev_attr.attr, + &sensor_dev_attr_port_17_en.dev_attr.attr, + &sensor_dev_attr_port_18_en.dev_attr.attr, + &sensor_dev_attr_port_19_en.dev_attr.attr, + &sensor_dev_attr_port_20_en.dev_attr.attr, + &sensor_dev_attr_port_21_en.dev_attr.attr, + &sensor_dev_attr_port_22_en.dev_attr.attr, + &sensor_dev_attr_port_23_en.dev_attr.attr, + &sensor_dev_attr_port_24_en.dev_attr.attr, + &sensor_dev_attr_port_25_en.dev_attr.attr, + &sensor_dev_attr_port_26_en.dev_attr.attr, + &sensor_dev_attr_port_27_en.dev_attr.attr, + &sensor_dev_attr_port_28_en.dev_attr.attr, + &sensor_dev_attr_port_29_en.dev_attr.attr, + &sensor_dev_attr_port_30_en.dev_attr.attr, + &sensor_dev_attr_port_31_en.dev_attr.attr, + &sensor_dev_attr_port_32_en.dev_attr.attr, NULL }; diff --git a/ixr7220h6-128/modules/port_cpld2.c b/ixr7220h6-128/modules/port_cpld2.c index 77d3eea..8d1c3ae 100644 --- a/ixr7220h6-128/modules/port_cpld2.c +++ b/ixr7220h6-128/modules/port_cpld2.c @@ -33,16 +33,18 @@ #define VER_MINOR_REG 0x01 #define SCRATCH_REG 0x04 #define PORT_LPMODE_REG0 0x70 -#define PORT_ENABLE_REG0 0x72 +#define PORT_EFUSE_REG0 0x72 #define PORT_RST_REG0 0x78 #define PORT_MODPRS_REG0 0x88 #define PORT_PWGOOD_REG0 0x90 +#define PORT_ENABLE_REG0 0x98 static const unsigned short cpld_address_list[] = {0x73, 0x76, I2C_CLIENT_END}; struct cpld_data { struct i2c_client *client; struct mutex update_lock; + int port_efuse; }; static int cpld_i2c_read(struct cpld_data *data, u8 reg) @@ -225,15 +227,33 @@ static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *deva return sprintf(buf, "0x%02x\n", val); } -static ssize_t show_port_pwgood(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_port_efuse(struct device *dev, struct device_attribute *devattr, char *buf) { struct cpld_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); - u8 val = 0; + + return sprintf(buf, "%s\n", (data->port_efuse) ? "Enabled":"Disabled"); +} - val = cpld_i2c_read(data, PORT_PWGOOD_REG0 + (sda->index / 8)); +static ssize_t set_port_efuse(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + const char *str_en = "Enable\n"; + const char *str_dis = "Disable\n"; + + if (strcmp(buf, str_en) == 0) { + cpld_i2c_write(data, PORT_EFUSE_REG0, 0xFF); + cpld_i2c_write(data, PORT_EFUSE_REG0+1, 0xFF); + data->port_efuse = 1; + } + else if (strcmp(buf, str_dis) == 0) { + cpld_i2c_write(data, PORT_EFUSE_REG0, 0x0); + cpld_i2c_write(data, PORT_EFUSE_REG0+1, 0x0); + data->port_efuse = 0; + } + else + return -EINVAL; - return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); + return count; } static ssize_t show_port_en(struct device *dev, struct device_attribute *devattr, char *buf) @@ -242,6 +262,7 @@ static ssize_t show_port_en(struct device *dev, struct device_attribute *devattr struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); u8 val = 0; + return sprintf(buf, "na\n"); val = cpld_i2c_read(data, PORT_ENABLE_REG0 + (sda->index / 8)); return sprintf(buf, "%d\n", (val>>(sda->index % 8)) & 0x1 ? 1:0); @@ -255,6 +276,7 @@ static ssize_t set_port_en(struct device *dev, struct device_attribute *devattr, u8 usr_val = 0; u8 mask; + return 0; int ret = kstrtou8(buf, 10, &usr_val); if (ret != 0) { return ret; @@ -330,39 +352,24 @@ static SENSOR_DEVICE_ATTR(port_16_prs, S_IRUGO, show_port_prs, NULL, 15); static SENSOR_DEVICE_ATTR(modprs_reg1, S_IRUGO, show_modprs_reg, NULL, 0); static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 1); -static SENSOR_DEVICE_ATTR(port_1_pwgood, S_IRUGO, show_port_pwgood, NULL, 0); -static SENSOR_DEVICE_ATTR(port_2_pwgood, S_IRUGO, show_port_pwgood, NULL, 1); -static SENSOR_DEVICE_ATTR(port_3_pwgood, S_IRUGO, show_port_pwgood, NULL, 2); -static SENSOR_DEVICE_ATTR(port_4_pwgood, S_IRUGO, show_port_pwgood, NULL, 3); -static SENSOR_DEVICE_ATTR(port_5_pwgood, S_IRUGO, show_port_pwgood, NULL, 4); -static SENSOR_DEVICE_ATTR(port_6_pwgood, S_IRUGO, show_port_pwgood, NULL, 5); -static SENSOR_DEVICE_ATTR(port_7_pwgood, S_IRUGO, show_port_pwgood, NULL, 6); -static SENSOR_DEVICE_ATTR(port_8_pwgood, S_IRUGO, show_port_pwgood, NULL, 7); -static SENSOR_DEVICE_ATTR(port_9_pwgood, S_IRUGO, show_port_pwgood, NULL, 8); -static SENSOR_DEVICE_ATTR(port_10_pwgood, S_IRUGO, show_port_pwgood, NULL, 9); -static SENSOR_DEVICE_ATTR(port_11_pwgood, S_IRUGO, show_port_pwgood, NULL, 10); -static SENSOR_DEVICE_ATTR(port_12_pwgood, S_IRUGO, show_port_pwgood, NULL, 11); -static SENSOR_DEVICE_ATTR(port_13_pwgood, S_IRUGO, show_port_pwgood, NULL, 12); -static SENSOR_DEVICE_ATTR(port_14_pwgood, S_IRUGO, show_port_pwgood, NULL, 13); -static SENSOR_DEVICE_ATTR(port_15_pwgood, S_IRUGO, show_port_pwgood, NULL, 14); -static SENSOR_DEVICE_ATTR(port_16_pwgood, S_IRUGO, show_port_pwgood, NULL, 15); - -static SENSOR_DEVICE_ATTR(port_1_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 0); -static SENSOR_DEVICE_ATTR(port_2_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 1); -static SENSOR_DEVICE_ATTR(port_3_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 2); -static SENSOR_DEVICE_ATTR(port_4_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 3); -static SENSOR_DEVICE_ATTR(port_5_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 4); -static SENSOR_DEVICE_ATTR(port_6_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 5); -static SENSOR_DEVICE_ATTR(port_7_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 6); -static SENSOR_DEVICE_ATTR(port_8_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 7); -static SENSOR_DEVICE_ATTR(port_9_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 8); -static SENSOR_DEVICE_ATTR(port_10_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 9); -static SENSOR_DEVICE_ATTR(port_11_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 10); -static SENSOR_DEVICE_ATTR(port_12_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 11); -static SENSOR_DEVICE_ATTR(port_13_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 12); -static SENSOR_DEVICE_ATTR(port_14_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 13); -static SENSOR_DEVICE_ATTR(port_15_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 14); -static SENSOR_DEVICE_ATTR(port_16_en, S_IRUGO | S_IWUSR, show_port_en, set_port_en, 15); +static SENSOR_DEVICE_ATTR(port_1_en, S_IRUGO, show_port_en, set_port_en, 0); +static SENSOR_DEVICE_ATTR(port_2_en, S_IRUGO, show_port_en, set_port_en, 1); +static SENSOR_DEVICE_ATTR(port_3_en, S_IRUGO, show_port_en, set_port_en, 2); +static SENSOR_DEVICE_ATTR(port_4_en, S_IRUGO, show_port_en, set_port_en, 3); +static SENSOR_DEVICE_ATTR(port_5_en, S_IRUGO, show_port_en, set_port_en, 4); +static SENSOR_DEVICE_ATTR(port_6_en, S_IRUGO, show_port_en, set_port_en, 5); +static SENSOR_DEVICE_ATTR(port_7_en, S_IRUGO, show_port_en, set_port_en, 6); +static SENSOR_DEVICE_ATTR(port_8_en, S_IRUGO, show_port_en, set_port_en, 7); +static SENSOR_DEVICE_ATTR(port_9_en, S_IRUGO, show_port_en, set_port_en, 8); +static SENSOR_DEVICE_ATTR(port_10_en, S_IRUGO, show_port_en, set_port_en, 9); +static SENSOR_DEVICE_ATTR(port_11_en, S_IRUGO, show_port_en, set_port_en, 10); +static SENSOR_DEVICE_ATTR(port_12_en, S_IRUGO, show_port_en, set_port_en, 11); +static SENSOR_DEVICE_ATTR(port_13_en, S_IRUGO, show_port_en, set_port_en, 12); +static SENSOR_DEVICE_ATTR(port_14_en, S_IRUGO, show_port_en, set_port_en, 13); +static SENSOR_DEVICE_ATTR(port_15_en, S_IRUGO, show_port_en, set_port_en, 14); +static SENSOR_DEVICE_ATTR(port_16_en, S_IRUGO, show_port_en, set_port_en, 15); + +static SENSOR_DEVICE_ATTR(port_efuse, S_IRUGO | S_IWUSR, show_port_efuse, set_port_efuse, 0); static struct attribute *port_cpld2_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, @@ -422,23 +429,6 @@ static struct attribute *port_cpld2_attributes[] = { &sensor_dev_attr_modprs_reg1.dev_attr.attr, &sensor_dev_attr_modprs_reg2.dev_attr.attr, - &sensor_dev_attr_port_1_pwgood.dev_attr.attr, - &sensor_dev_attr_port_2_pwgood.dev_attr.attr, - &sensor_dev_attr_port_3_pwgood.dev_attr.attr, - &sensor_dev_attr_port_4_pwgood.dev_attr.attr, - &sensor_dev_attr_port_5_pwgood.dev_attr.attr, - &sensor_dev_attr_port_6_pwgood.dev_attr.attr, - &sensor_dev_attr_port_7_pwgood.dev_attr.attr, - &sensor_dev_attr_port_8_pwgood.dev_attr.attr, - &sensor_dev_attr_port_9_pwgood.dev_attr.attr, - &sensor_dev_attr_port_10_pwgood.dev_attr.attr, - &sensor_dev_attr_port_11_pwgood.dev_attr.attr, - &sensor_dev_attr_port_12_pwgood.dev_attr.attr, - &sensor_dev_attr_port_13_pwgood.dev_attr.attr, - &sensor_dev_attr_port_14_pwgood.dev_attr.attr, - &sensor_dev_attr_port_15_pwgood.dev_attr.attr, - &sensor_dev_attr_port_16_pwgood.dev_attr.attr, - &sensor_dev_attr_port_1_en.dev_attr.attr, &sensor_dev_attr_port_2_en.dev_attr.attr, &sensor_dev_attr_port_3_en.dev_attr.attr, @@ -456,6 +446,8 @@ static struct attribute *port_cpld2_attributes[] = { &sensor_dev_attr_port_15_en.dev_attr.attr, &sensor_dev_attr_port_16_en.dev_attr.attr, + &sensor_dev_attr_port_efuse.dev_attr.attr, + NULL }; @@ -492,8 +484,10 @@ static int port_cpld2_probe(struct i2c_client *client) dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); goto exit; } - + dump_reg(data); + cpld_i2c_write(data, PORT_EFUSE_REG0, 0xFF); + cpld_i2c_write(data, PORT_EFUSE_REG0+1, 0xFF); dev_info(&client->dev, "[PORT_CPLD2]Reseting PORTs ...\n"); cpld_i2c_write(data, PORT_LPMODE_REG0, 0x0); cpld_i2c_write(data, PORT_LPMODE_REG0+1, 0x0); diff --git a/ixr7220h6-128/modules/sys_cpld.c b/ixr7220h6-128/modules/sys_cpld.c index e31c0ff..1c28a9f 100644 --- a/ixr7220h6-128/modules/sys_cpld.c +++ b/ixr7220h6-128/modules/sys_cpld.c @@ -277,9 +277,9 @@ static int sys_cpld_probe(struct i2c_client *client) goto exit; } - // int i; - // for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0xFF); - // data->osfp_efuse = 1; + int i; + for (i=0;i<8;i++) cpld_i2c_write(data, OSFP_EFUSE_REG0+i, 0xFF); + data->osfp_efuse = 1; return 0; diff --git a/ixr7220h6-128/scripts/h6_128_platform_init.sh b/ixr7220h6-128/scripts/h6_128_platform_init.sh old mode 100755 new mode 100644 index ba10977..af14aec --- a/ixr7220h6-128/scripts/h6_128_platform_init.sh +++ b/ixr7220h6-128/scripts/h6_128_platform_init.sh @@ -10,7 +10,7 @@ load_kernel_drivers() { rmmod i2c-piix4 rmmod i2c_designware_platform modprobe igb - modprobe amd-xgbe +# modprobe amd-xgbe modprobe i2c_designware_platform modprobe i2c-i801 diff --git a/ixr7220h6-128/scripts/ports_notify.py b/ixr7220h6-128/scripts/ports_notify.py new file mode 100644 index 0000000..d52e490 --- /dev/null +++ b/ixr7220h6-128/scripts/ports_notify.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +""" + port_notify: + notify port status change from Sonic DB +""" + +try: + from swsscommon import swsscommon + from sonic_py_common import daemon_base, logger + from sonic_platform.sysfs import write_sysfs_file +except ImportError as e: + raise ImportError (str(e) + " - required module not found") + +SYSLOG_IDENTIFIER = "ports_notify" + +SELECT_TIMEOUT_MSECS = 1000 + +PORT_NUM = 130 +SYSFS_DIR = "/sys/bus/i2c/devices/{}/" +PORTPLD_ADDR = ["152-0076", "153-0076", "148-0074", "149-0075", "150-0073", "151-0073"] +ADDR_IDX = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,3] +PORT_IDX = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, + 1,2,5,6,9,10,13,14,17,18,21,22,25,26,29,30,1,2,5,6,9,10,13,14,17,18,21,22,25,26,29,30, + 3,4,7,8,11,12,15,16,19,20,23,24,27,28,31,32,3,4,7,8,11,12,15,16,19,20,23,24,27,28,31,32, + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,33,34] + +# Global logger class instance +sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) + +def wait_for_port_init_done(): + # Connect to APPL_DB and subscribe to PORT table notifications + appl_db = daemon_base.db_connect("APPL_DB") + sel = swsscommon.Select() + sst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) + sel.addSelectable(sst) + + # Make sure this daemon started after all port configured + while True: + (state, c) = sel.select(1000) + if state == swsscommon.Select.TIMEOUT: + continue + if state != swsscommon.Select.OBJECT: + sonic_logger.log_warning("sel.select() did not return swsscommon.Select.OBJECT") + continue + + (key, op, fvp) = sst.pop() + + # Wait until PortInitDone + if key in ["PortInitDone"]: + break + +def subscribe_port_config_change(): + sel = swsscommon.Select() + config_db = daemon_base.db_connect("CONFIG_DB") + port_tbl = swsscommon.SubscriberStateTable(config_db, swsscommon.CFG_PORT_TABLE_NAME) + port_tbl.filter = ['admin_status'] + sel.addSelectable(port_tbl) + return sel, port_tbl + +def handle_port_config_change(sel, port_config, logger): + """Select PORT table changes, once there is a port configuration add/remove, notify observers + """ + try: + (state, _) = sel.select(SELECT_TIMEOUT_MSECS) + except Exception: + return -1 + + if state == swsscommon.Select.TIMEOUT: + return 0 + if state != swsscommon.Select.OBJECT: + return -2 + + while True: + (port_name, op, fvp) = port_config.pop() + if not port_name: + break + + if fvp is not None: + fvp = dict(fvp) + + if 'admin_status' in fvp: + if 'index' in fvp: + port_index = int(fvp['index']) + if port_index in range(1, PORT_NUM+1): + pld_path = SYSFS_DIR.format(PORTPLD_ADDR[ADDR_IDX[port_index-1]]) + pld_port_idx = PORT_IDX[port_index-1] + file_name = pld_path + f"port_{pld_port_idx}_en" + else: + logger.log_warning(f"Wrong port index {port_index} for port {port_name}") + continue + else: + logger.log_warning(f"Wrong index from port {port_name}: {fvp}") + continue + + if fvp['admin_status'] == 'up': + write_sysfs_file(file_name, '1') + elif fvp['admin_status'] == 'down': + write_sysfs_file(file_name, '0') + + return 0 + +def main(): + + # Wait for PortInitDone + wait_for_port_init_done() + + sonic_logger.log_info("port init done!") + + sel, port_config = subscribe_port_config_change() + + while True: + status = handle_port_config_change(sel, port_config, sonic_logger) + if status < 0: + return -1 + + +if __name__ == '__main__': + main() diff --git a/ixr7220h6-128/scripts/set_ps.py b/ixr7220h6-128/scripts/set_ps.py index 94af028..a5abb07 100644 --- a/ixr7220h6-128/scripts/set_ps.py +++ b/ixr7220h6-128/scripts/set_ps.py @@ -4,7 +4,7 @@ from os import * from mmap import * -RESOURCE = "/sys/bus/pci/devices/0000:02:00.0/resource0" +RESOURCE = "/sys/bus/pci/devices/0000:03:00.0/resource0" REG1 = [0x2100, 0x2120, 0x2140, 0x2160, 0x2180, 0x21A0, 0x21C0, 0x21E0, 0x2200, 0x2220, 0x2240, 0x2260, 0x2280, 0x22A0, 0x22C0, 0x22E0] REG2 = [0x2300, 0x2320, 0x2340, 0x2360, 0x2380, 0x23A0, 0x23C0, 0x23E0, 0x2400, 0x2420, 0x2440, 0x2460, 0x2480, 0x24A0, 0x24C0, 0x24E0, 0x2500, 0x2520] diff --git a/ixr7220h6-128/service/h6_128_platform_init.service b/ixr7220h6-128/service/h6_128_platform_init.service old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/service/ports_notify.service b/ixr7220h6-128/service/ports_notify.service new file mode 100644 index 0000000..db83b0e --- /dev/null +++ b/ixr7220h6-128/service/ports_notify.service @@ -0,0 +1,15 @@ +[Unit] +Description=ports_notify Service +Requires=swss.service database.service +After=swss.service database.service +BindsTo=swss.service database.service + + +[Service] +ExecStart=/usr/local/bin/ports_notify.py +Restart=always +RestartSec=10s +KillSignal=SIGTERM + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/ixr7220h6-128/setup.py b/ixr7220h6-128/setup.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/__init__.py b/ixr7220h6-128/sonic_platform/__init__.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/chassis.py b/ixr7220h6-128/sonic_platform/chassis.py old mode 100755 new mode 100644 index f2feb12..7d70381 --- a/ixr7220h6-128/sonic_platform/chassis.py +++ b/ixr7220h6-128/sonic_platform/chassis.py @@ -36,10 +36,6 @@ CPLD_DIR = "/sys/bus/i2c/devices/134-0071/" SYSFPGA_DIR = "/sys/bus/i2c/devices/1-0060/" -BUS_IDX = [1,2,9,10,17,18,25,26,33,34,41,42,49,50,57,58,65,66,73,74,81,82,89,90,97,98,105,106,113,114,121,122, - 3,4,11,12,19,20,27,28,35,36,43,44,51,52,59,60,67,68,75,76,83,84,91,92,99,100,107,108,115,116,123,124, - 5,6,13,14,21,22,29,30,37,38,45,46,53,54,61,62,69,70,77,78,85,86,93,94,101,102,109,110,117,118,125,126, - 7,8,15,16,23,24,31,32,39,40,47,48,55,56,63,64,71,72,79,80,87,88,95,96,103,104,111,112,119,120,127,128,129,130] SYSLOG_IDENTIFIER = "chassis" sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) @@ -59,7 +55,7 @@ def __init__(self): # then create the sfp nodes eeprom_path = "/sys/bus/i2c/devices/{}-0050/eeprom" for index in range(PORT_START, PORT_START + PORT_END): - port_i2c_map = PORT_I2C_START + BUS_IDX[index-1] - 1 + port_i2c_map = PORT_I2C_START + index - 1 port_eeprom_path = eeprom_path.format(port_i2c_map) if not os.path.exists(port_eeprom_path): sonic_logger.log_info(f"path {port_eeprom_path} didnt exist") diff --git a/ixr7220h6-128/sonic_platform/component.py b/ixr7220h6-128/sonic_platform/component.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/eeprom.py b/ixr7220h6-128/sonic_platform/eeprom.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/fan.py b/ixr7220h6-128/sonic_platform/fan.py old mode 100755 new mode 100644 index a861ae9..ad1ea0a --- a/ixr7220h6-128/sonic_platform/fan.py +++ b/ixr7220h6-128/sonic_platform/fan.py @@ -14,8 +14,8 @@ raise ImportError(str(e) + "- required module not found") FANS_PER_DRAWER = 2 -MAX_FAN_F_SPEED = 13600 -MAX_FAN_R_SPEED = 15400 +MAX_FAN_F_SPEED = 15400 +MAX_FAN_R_SPEED = 13600 FAN_TOLERANCE = 50 WORKING_FAN_SPEED = 2000 diff --git a/ixr7220h6-128/sonic_platform/fan_drawer.py b/ixr7220h6-128/sonic_platform/fan_drawer.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/platform.py b/ixr7220h6-128/sonic_platform/platform.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/psu.py b/ixr7220h6-128/sonic_platform/psu.py old mode 100755 new mode 100644 index 2e3f501..23d21e1 --- a/ixr7220h6-128/sonic_platform/psu.py +++ b/ixr7220h6-128/sonic_platform/psu.py @@ -34,7 +34,7 @@ def __init__(self, psu_index): self.index = psu_index + 1 self.psu_dir = f"/sys/bus/i2c/devices/{I2C_BUS[psu_index]}-00{PSU_ADDR[psu_index]}/" self.eeprom_dir = f"/sys/bus/i2c/devices/{I2C_BUS[psu_index]}-00{EEPROM_ADDR[psu_index]}/" - self.new_psu_cmd = f"echo dni_psu 0x{PSU_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/new_device" + self.new_psu_cmd = f"echo pmbus_psu 0x{PSU_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/new_device" self.new_eeprom_cmd = f"echo eeprom_fru 0x{EEPROM_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/new_device" self.del_eeprom_cmd = f"echo 0x{EEPROM_ADDR[psu_index]} > /sys/bus/i2c/devices/i2c-{I2C_BUS[psu_index]}/delete_device" diff --git a/ixr7220h6-128/sonic_platform/sfp.py b/ixr7220h6-128/sonic_platform/sfp.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/sfp_event.py b/ixr7220h6-128/sonic_platform/sfp_event.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/sysfs.py b/ixr7220h6-128/sonic_platform/sysfs.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/README b/ixr7220h6-128/sonic_platform/test/README old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-chassis.py b/ixr7220h6-128/sonic_platform/test/test-chassis.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-component.py b/ixr7220h6-128/sonic_platform/test/test-component.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-eeprom.py b/ixr7220h6-128/sonic_platform/test/test-eeprom.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-fan-drawer.py b/ixr7220h6-128/sonic_platform/test/test-fan-drawer.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-fan.py b/ixr7220h6-128/sonic_platform/test/test-fan.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-psu.py b/ixr7220h6-128/sonic_platform/test/test-psu.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-sfp.py b/ixr7220h6-128/sonic_platform/test/test-sfp.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-thermal.py b/ixr7220h6-128/sonic_platform/test/test-thermal.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/test/test-watchdog.py b/ixr7220h6-128/sonic_platform/test/test-watchdog.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/thermal.py b/ixr7220h6-128/sonic_platform/thermal.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/thermal_conditions.py b/ixr7220h6-128/sonic_platform/thermal_conditions.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/thermal_manager.py b/ixr7220h6-128/sonic_platform/thermal_manager.py old mode 100755 new mode 100644 diff --git a/ixr7220h6-128/sonic_platform/watchdog.py b/ixr7220h6-128/sonic_platform/watchdog.py old mode 100755 new mode 100644